Out With the Old

This commit is contained in:
Josh Johnson 2018-01-27 17:45:58 -05:00
parent c828608867
commit 01b580768b
41 changed files with 0 additions and 4897 deletions

View file

@ -1,69 +0,0 @@
import * as vsc from "vscode";
import * as ext from "./Extension";
import * as xpath from "xpath";
import { RangeUtil } from "./utils/RangeUtil";
import { XmlFormatter } from "./services/XmlFormatter";
import { XPathFeatureProvider } from "./providers/XPath";
import { XQueryExecutionProvider } from "./providers/Execution";
import { XmlFormattingEditProvider } from "./providers/Formatting";
const CFG_SECTION: string = "xmlTools";
const CFG_REMOVE_COMMENTS: string = "removeCommentsOnMinify";
export class TextEditorCommands {
static minifyXml(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
let removeComments: boolean = vsc.workspace.getConfiguration(CFG_SECTION).get<boolean>(CFG_REMOVE_COMMENTS, false);
let range: vsc.Range = RangeUtil.getRangeForDocument(editor.document);
let formatter: XmlFormatter = new XmlFormatter();
let xml: string = formatter.minify(editor.document.getText());
edit.replace(range, xml);
}
static evaluateXPath(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
XPathFeatureProvider.evaluateXPathAsync(editor, edit);
}
static executeXQuery(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
XQueryExecutionProvider.executeXQueryAsync(editor);
}
static formatAsXml(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
let edits: vsc.TextEdit[];
let formattingEditProvider = new XmlFormattingEditProvider();
let formattingOptions: vsc.FormattingOptions = {
insertSpaces: (editor.options.insertSpaces as boolean),
tabSize: (editor.options.tabSize as number)
};
// if the user has selected text, only format what is selected
// otherwise, attempt to format the entire document
if (!editor.selection.isEmpty) {
edits = formattingEditProvider.provideDocumentRangeFormattingEdits(editor.document, editor.selection, formattingOptions);
}
else {
edits = formattingEditProvider.provideDocumentFormattingEdits(editor.document, formattingOptions);
}
if (edits) {
for (let i = 0; i < edits.length; i++) {
editor.edit(async (editBuilder) => {
editBuilder.replace(edits[i].range, edits[i].newText);
// wiggle the cursor to deselect the formatted XML (is there a non-hacky way to go about this?)
await vsc.commands.executeCommand("cursorMove", {
to: "left",
by: "character"
});
await vsc.commands.executeCommand("cursorMove", {
to: "right",
by: "character"
});
});
}
}
}
}

View file

@ -1,76 +0,0 @@
import * as vsc from "vscode";
import { TextEditorCommands } from "./Commands";
import { XmlFormattingEditProvider } from "./providers/Formatting";
import { XQueryLintingFeatureProvider } from "./providers/Linting";
import { XQueryCompletionItemProvider } from "./providers/Completion";
import { XmlTreeViewDataProvider } from "./providers/XmlTreeView";
export var GlobalState: vsc.Memento;
export var WorkspaceState: vsc.Memento;
const LANG_XML: string = "xml";
const LANG_XSL: string = "xsl";
const LANG_XQUERY: string = "xquery;"
const MEM_QUERY_HISTORY: string = "xpathQueryHistory";
export function activate(ctx: vsc.ExtensionContext) {
console.log("activate extension");
// expose global and workspace state to the entire extension
GlobalState = ctx.globalState;
WorkspaceState = ctx.workspaceState;
// register palette commands
ctx.subscriptions.push(
vsc.commands.registerTextEditorCommand("xmlTools.minifyXml", TextEditorCommands.minifyXml),
vsc.commands.registerTextEditorCommand("xmlTools.evaluateXPath", TextEditorCommands.evaluateXPath),
vsc.commands.registerTextEditorCommand("xmlTools.executeXQuery", TextEditorCommands.executeXQuery),
vsc.commands.registerTextEditorCommand("xmlTools.formatAsXml", TextEditorCommands.formatAsXml)
);
// register language feature providers
ctx.subscriptions.push(
vsc.languages.registerDocumentFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
vsc.languages.registerDocumentRangeFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
vsc.languages.registerCompletionItemProvider(LANG_XQUERY, new XQueryCompletionItemProvider(), ":", "$")
);
// listen to editor events (for linting)
ctx.subscriptions.push(
vsc.window.onDidChangeActiveTextEditor(_handleChangeActiveTextEditor),
vsc.window.onDidChangeTextEditorSelection(_handleChangeTextEditorSelection)
);
// add views
ctx.subscriptions.push(
vsc.window.registerTreeDataProvider("xmlTreeView", new XmlTreeViewDataProvider(ctx))
);
}
export function deactivate() {
// clean up xpath history
let memento: vsc.Memento = WorkspaceState || GlobalState;
let history = memento.get<any[]>(MEM_QUERY_HISTORY, []);
history.splice(0);
memento.update(MEM_QUERY_HISTORY, history);
}
function _handleContextChange(editor: vsc.TextEditor): void {
if (!editor || !editor.document) {
return;
}
switch (editor.document.languageId) {
case "xquery":
XQueryLintingFeatureProvider.provideXQueryDiagnostics(editor);
break;
}
}
function _handleChangeActiveTextEditor(editor: vsc.TextEditor): void {
_handleContextChange(editor);
}
function _handleChangeTextEditorSelection(e: vsc.TextEditorSelectionChangeEvent): void {
_handleContextChange(e.textEditor);
}

View file

@ -1,44 +0,0 @@
import * as vsc from "vscode";
import { XQueryCompleter, XQueryCompletionItem } from "../services/XQueryCompleter";
export class XQueryCompletionItemProvider implements vsc.CompletionItemProvider {
provideCompletionItems(document: vsc.TextDocument, position: vsc.Position): vsc.CompletionItem[] {
let items: vsc.CompletionItem[] = new Array<vsc.CompletionItem>();
let completer: XQueryCompleter = new XQueryCompleter(document.getText());
let completions: XQueryCompletionItem[] = completer.getCompletions(position.line, position.character);
completions.forEach((completion: XQueryCompletionItem) => {
let item: vsc.CompletionItem = new vsc.CompletionItem(completion.name);
item.insertText = completion.value;
switch (completion.meta) {
// functions (always qualified with a colon)
case "function":
item.kind = vsc.CompletionItemKind.Function;
let funcStart = (completion.value.indexOf(":") + 1);
let funcEnd = completion.value.indexOf("(");
item.insertText = completion.value.substring(funcStart, funcEnd);
break;
// variables and parameters (always qualified with a dollar sign)
case "Let binding":
case "Local variable":
case "Window variable":
case "Function parameter":
item.kind = vsc.CompletionItemKind.Variable;
item.insertText = completion.value.substring(1);
break;
// everything else
default: item.kind = vsc.CompletionItemKind.Text;
}
items.push(item);
});
return items;
}
}

View file

@ -1,127 +0,0 @@
import * as vsc from "vscode";
import { ChildProcess } from "../services/ChildProcess";
const CFG_SECTION: string = "xmlTools";
const CFG_XQEXEC: string = "xqueryExecutionEngine";
const CFG_XQARGS: string = "xqueryExecutionArguments";
export class XQueryExecutionProvider {
static async executeXQueryAsync(editor: vsc.TextEditor): Promise<void> {
// this disposable will be used for creating status bar messages
let disposable: vsc.Disposable;
if (editor.document.languageId !== "xquery") {
vsc.window.showErrorMessage("This action can only be performed on an XQuery file.");
return;
}
let executable = vsc.workspace.getConfiguration(CFG_SECTION).get<string>(CFG_XQEXEC, null);
let args = vsc.workspace.getConfiguration(CFG_SECTION).get<string[]>(CFG_XQARGS, []);
if (!executable || executable == "") {
let action = await vsc.window.showWarningMessage("An XQuery execution engine has not been defined.", "Define Now");
if (action == "Define Now") {
vsc.commands.executeCommand("workbench.action.openGlobalSettings");
}
return;
}
let inputFile: vsc.Uri;
disposable = vsc.window.setStatusBarMessage("Searching for XML files in folder...");
let files: vsc.Uri[] = await vsc.workspace.findFiles("**/*.xml", "", 100);
disposable.dispose();
// user does not have a folder open - prompt for file name
if (typeof files === "undefined") {
vsc.window.showErrorMessage("You must have a folder opened in VS Code to use this feature.");
return;
}
// if there is only one XML file, default it
// otherwise, prompt the user to select one from the open folder
if (files.length > 1) {
let qpItems: any[] = new Array<any>();
files.forEach((file) => {
let filename: string = file.fsPath.replace("\\", "/");
qpItems.push({ // must implement vscode.QuickPickItem
label: filename.substring(filename.lastIndexOf("/") + 1),
description: file.fsPath,
file: file
});
});
let selection = await vsc.window.showQuickPick(qpItems, { placeHolder: "Please select an input file." });
if (!selection) {
return;
}
inputFile = selection.file;
}
else {
inputFile = files[0];
}
// prompt for output file name
let outputPath: string = null;
let outputPathPos: number = -1;
for (let i = 0; i < args.length; i++) {
if (i > 0) {
if (args[i - 1].search(/out|result/)) {
outputPath = args[i];
outputPathPos = i;
}
}
}
if (outputPath) {
outputPath = await vsc.window.showInputBox({
placeHolder: "ex. C:\\TEMP\XQueryOutput\\MyOutputFile.xml",
prompt: "Please specify the output file path. Existing file behavior is determined by the execution engine you have specified.",
value: outputPath
});
args[outputPathPos] = outputPath;
}
// call out to the execution engine
disposable = vsc.window.setStatusBarMessage("Executing XQuery Script...");
args = args.map<string>((value: string) => {
return value
.replace("$(script)", editor.document.uri.fsPath)
.replace("$(input)", inputFile.fsPath)
.replace("$(project)", vsc.workspace.rootPath);
});
try {
await ChildProcess.spawnAsync(executable, args);
}
catch (error) {
if (error.message.search(/[Ll]ine:?\s*\d+/gm) > -1) {
let match: RegExpExecArray = /[Ll]ine:?\s*\d+/gm.exec(error.message);
let line: number = (Number.parseInt(match[0].replace(/([Ll]ine:?\s*)|\s/, "")) - 1);
let selection: string = await vsc.window.showErrorMessage(error.message, `Go to Line ${line}`);
if (selection == `Go to Line ${line}`) {
editor.revealRange(new vsc.Range(line, 0, line, 0));
}
}
else {
vsc.window.showErrorMessage(error.message);
}
}
finally {
disposable.dispose();
}
}
}

View file

@ -1,33 +0,0 @@
import * as vsc from "vscode";
import { RangeUtil } from "../utils/RangeUtil";
import { XmlFormatter, IXmlFormatterOptions } from "../services/XmlFormatter";
const CFG_SECTION: string = "xmlTools";
const CFG_SPLIT_NAMESPACES: string = "splitXmlnsOnFormat";
export class XmlFormattingEditProvider implements vsc.DocumentFormattingEditProvider, vsc.DocumentRangeFormattingEditProvider {
provideDocumentFormattingEdits(document: vsc.TextDocument, options: vsc.FormattingOptions): vsc.TextEdit[] {
let range = RangeUtil.getRangeForDocument(document);
return this._provideFormattingEdits(document, range, options);
}
provideDocumentRangeFormattingEdits(document: vsc.TextDocument, range: vsc.Range, options: vsc.FormattingOptions): vsc.TextEdit[] {
return this._provideFormattingEdits(document, range, options);
}
private _provideFormattingEdits(document: vsc.TextDocument, range: vsc.Range, options: vsc.FormattingOptions): vsc.TextEdit[] {
let splitNamespaces: boolean = vsc.workspace.getConfiguration(CFG_SECTION).get<boolean>(CFG_SPLIT_NAMESPACES, true);
let formatterOptions: IXmlFormatterOptions = {
preferSpaces: options.insertSpaces,
tabSize: options.tabSize,
splitNamespaces: splitNamespaces
};
let formatter = new XmlFormatter(formatterOptions);
let xml = formatter.format(document.getText(range));
return [ vsc.TextEdit.replace(range, xml) ];
}
}

View file

@ -1,32 +0,0 @@
import * as vsc from "vscode";
import { XQueryLinter, XQueryDiagnostic } from "../services/XQueryLinter";
export class XQueryLintingFeatureProvider {
private static _coreDiagnostics: vsc.DiagnosticCollection;
static get coreDiagnostics(): vsc.DiagnosticCollection {
if (!XQueryLintingFeatureProvider._coreDiagnostics) {
XQueryLintingFeatureProvider._coreDiagnostics = vsc.languages.createDiagnosticCollection("XQueryDiagnostics");
}
return XQueryLintingFeatureProvider._coreDiagnostics;
}
static provideXQueryDiagnostics(editor: vsc.TextEditor): void {
let diagnostics: vsc.Diagnostic[] = new Array<vsc.Diagnostic>();
let xqDiagnostics: XQueryDiagnostic[] = XQueryLinter.lint(editor.document.getText());
xqDiagnostics.forEach((xqd: XQueryDiagnostic) => {
let vSeverity: vsc.DiagnosticSeverity = (xqd.severity == 1) ? vsc.DiagnosticSeverity.Warning : vsc.DiagnosticSeverity.Error;
let startPos: vsc.Position = new vsc.Position(xqd.startLine, xqd.startColumn);
let endPos: vsc.Position = new vsc.Position(xqd.endLine, xqd.endColumn);
let range: vsc.Range = new vsc.Range(startPos, endPos);
let diagnostic: vsc.Diagnostic = new vsc.Diagnostic(range, xqd.message, vSeverity);
diagnostics.push(diagnostic);
});
XQueryLintingFeatureProvider.coreDiagnostics.set(editor.document.uri, diagnostics);
}
}

View file

@ -1,120 +0,0 @@
import * as vsc from "vscode";
import * as ext from "../Extension";
import { XPathEvaluator, EvaluatorResult, EvaluatorResultType } from "../services/XPathEvaluator";
const CFG_SECTION: string = "xmlTools";
const CFG_PERSIST_QUERY: string = "persistXPathQuery";
const CFG_IGNORE_DEFAULT_XMLNS: string = "ignoreDefaultNamespace";
const MEM_QUERY_HISTORY: string = "xpathQueryHistory";
const MEM_QUERY_LAST: string = "xPathQueryLast";
const OUTPUT_CHANNEL: string = "XPath Results";
export class XPathFeatureProvider {
static async evaluateXPathAsync(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): Promise<void> {
// if there is no workspace, we will track queries in the global Memento
let memento: vsc.Memento = ext.WorkspaceState || ext.GlobalState;
// get the xpath persistence setting
let persistQueries: boolean = vsc.workspace.getConfiguration(CFG_SECTION).get<boolean>(CFG_PERSIST_QUERY, true);
// get the last query if there is one for this document
// if not, try pulling the last query ran, regardless of document
// NOTE: if the user has focus on the output channel when opening the xquery prompt, the channel is the "active" document
let history: HistoricQuery[] = memento.get<HistoricQuery[]>(MEM_QUERY_HISTORY, new Array<HistoricQuery>());
let globalLastQuery: string = memento.get<string>(MEM_QUERY_LAST, "");
let lastQuery: HistoricQuery = history.find((item: HistoricQuery) => {
if (item.uri == editor.document.uri.toString()) {
return true;
}
return false;
});
// set the inital display value and prompt the user
let query: string = "";
if (persistQueries) {
if (lastQuery) {
query = lastQuery.query;
}
else {
query = globalLastQuery;
}
}
query = await vsc.window.showInputBox({
placeHolder: "XPath Query",
prompt: "Please enter an XPath query to evaluate.",
value: query
});
// showInputBox() will return undefined if the user dimissed the prompt
if (query) {
let ignoreDefaultNamespace: boolean = vsc.workspace.getConfiguration(CFG_SECTION).get<boolean>(CFG_IGNORE_DEFAULT_XMLNS, true);
// run the query
let xml: string = editor.document.getText();
let evalResult: EvaluatorResult;
try {
evalResult = XPathEvaluator.evaluate(query, xml, ignoreDefaultNamespace);
}
catch (error) {
console.error(error);
vsc.window.showErrorMessage(`Something went wrong while evaluating the XPath: ${error}`);
return;
}
// show the results to the user
let outputChannel: vsc.OutputChannel = vsc.window.createOutputChannel(OUTPUT_CHANNEL);
outputChannel.clear();
outputChannel.appendLine(`XPath Query: ${query}`);
outputChannel.append("\n");
if (evalResult.type === EvaluatorResultType.NODE_COLLECTION) {
(evalResult.result as Node[]).forEach((node: XmlNode) => {
outputChannel.appendLine(`[Line ${node.lineNumber}] ${node.localName}: ${node.textContent}`);
});
} else {
outputChannel.appendLine(`[Result]: ${evalResult.result}`);
}
outputChannel.show(vsc.ViewColumn.Three);
// if persistence is enabled, save the query for later
if (persistQueries) {
lastQuery = new HistoricQuery(editor.document.uri.toString(), query);
let affectedIndex: number = -1;
history = history.map<HistoricQuery>((item: HistoricQuery, index: number) => {
if (item.uri == lastQuery.uri) {
item.query = query;
affectedIndex = index;
}
return item;
});
if (affectedIndex == -1) {
history.push(lastQuery);
}
memento.update(MEM_QUERY_HISTORY, history);
memento.update(MEM_QUERY_LAST, query);
}
}
}
}
class HistoricQuery {
constructor(uri: string, query: string) {
this.uri = uri;
this.query = query;
}
uri: string;
query: string;
}

View file

@ -1,128 +0,0 @@
import * as vsc from "vscode";
import * as path from "path";
let DOMParser = require("xmldom").DOMParser;
export class XmlTreeViewDataProvider implements vsc.TreeDataProvider<Node> {
private _onDidChangeTreeData: vsc.EventEmitter<Node | null> = new vsc.EventEmitter<Node | null>();
private _xmlDocument: Document;
constructor(private _context: vsc.ExtensionContext) {
vsc.window.onDidChangeActiveTextEditor((editor) => {
this._refreshTree();
});
vsc.workspace.onDidChangeTextDocument((e) => {
this._refreshTree();
});
}
readonly onDidChangeTreeData: vsc.Event<Node | null> = this._onDidChangeTreeData.event;
get activeEditor(): vsc.TextEditor | null {
return vsc.window.activeTextEditor || null;
}
getChildren(element?: Node): Node[] {
if (!this._xmlDocument) {
this._refreshTree();
}
if (element) {
return [].concat(this._getChildAttributeArray(element), this._getChildElementArray(element));
}
else if (this._xmlDocument) {
return [ this._xmlDocument.lastChild ];
}
else {
return [];
}
}
getTreeItem(element: Node): vsc.TreeItem {
let treeItem = new vsc.TreeItem(element.localName);
if (this._getChildAttributeArray(element).length > 0) {
treeItem.collapsibleState = vsc.TreeItemCollapsibleState.Collapsed;
}
if (this._getChildElementArray(element).length > 0) {
treeItem.collapsibleState = vsc.TreeItemCollapsibleState.Collapsed;
}
treeItem.command = {
command: "revealLine",
title: "",
arguments: [{
lineNumber: (element as any).lineNumber - 1,
at: "top"
}]
};
treeItem.iconPath = this._getIcon(element);
return treeItem;
}
private _getChildAttributeArray(node: Node): Node[] {
if (!node.attributes) {
return [];
}
let array = new Array<Node>();
for (let i = 0; i < node.attributes.length; i++) {
array.push(node.attributes[i]);
}
return array;
}
private _getChildElementArray(node: Node): Node[] {
if (!node.childNodes) {
return [];
}
let array = new Array<Node>();
for (let i = 0; i < node.childNodes.length; i++) {
let child = node.childNodes[i];
if ((child as any).tagName) {
array.push(child);
}
}
return array;
}
private _getIcon(element: Node): any {
let type = "element";
if (!(element as any).tagName) {
type = "attribute";
}
let icon = {
dark: this._context.asAbsolutePath(path.join("resources", "icons", `${type}.dark.svg`)),
light: this._context.asAbsolutePath(path.join("resources", "icons", `${type}.light.svg`))
};
return icon;
}
private _refreshTree(): void {
if (!this.activeEditor || this.activeEditor.document.languageId !== "xml") {
this._xmlDocument = null;
this._onDidChangeTreeData.fire();
return;
}
let xml = this.activeEditor.document.getText();
this._xmlDocument = new DOMParser().parseFromString(xml, "text/xml");
this._onDidChangeTreeData.fire();
}
}

View file

@ -1,30 +0,0 @@
let child_process = require("child_process");
export class ChildProcess {
static async spawnAsync(executable: string, args: string[]): Promise<void> {
return new Promise<void>((resolve, reject) => {
let output: string = "";
let handle = child_process.spawn(executable, args);
handle.stdout.on("data", (data: string) => {
output += data;
});
handle.stderr.on("data", (data: string) => {
output += data;
});
handle.on("close", (code: string) => {
if (code == "0") {
resolve();
}
else {
reject({ code: code, message: output });
}
});
});
}
}

View file

@ -1,63 +0,0 @@
import * as xpath from "xpath";
let DOMParser = require("xmldom").DOMParser;
export class EvaluatorResult {
type: EvaluatorResultType;
result: Node[]|number|string|boolean;
}
export class EvaluatorResultType {
static SCALAR_TYPE: number = 0;
static NODE_COLLECTION: number = 1;
}
export class XPathEvaluator {
static evaluate(query: string, xml: string, ignoreDefaultNamespace: boolean): EvaluatorResult {
if (ignoreDefaultNamespace) {
xml = xml.replace(/xmlns=".+"/g, (match: string) => {
return match.replace(/xmlns/g, "xmlns:default");
});
}
let nodes: Node[] = new Array<Node>();
let xdoc: Document = new DOMParser().parseFromString(xml, "text/xml");
let resolver: xpath.XPathNSResolver = xpath.createNSResolver(xdoc);
let result: xpath.XPathResult = xpath.evaluate(
query, // xpathExpression
xdoc, // contextNode
resolver, // namespaceResolver
xpath.XPathResult.ANY_TYPE, // resultType
null // result
)
let evalResult = new EvaluatorResult();
evalResult.type = EvaluatorResultType.SCALAR_TYPE;
switch(result.resultType) {
case xpath.XPathResult.NUMBER_TYPE:
evalResult.result = result.numberValue;
break;
case xpath.XPathResult.STRING_TYPE:
evalResult.result = result.stringValue;
break;
case xpath.XPathResult.BOOLEAN_TYPE:
evalResult.result = result.booleanValue;
break;
case xpath.XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case xpath.XPathResult.ORDERED_NODE_ITERATOR_TYPE:
evalResult.result = result.booleanValue;
let node: Node;
while (node = result.iterateNext()) {
nodes.push(node);
}
evalResult.result = nodes;
evalResult.type = EvaluatorResultType.NODE_COLLECTION;
break;
}
return evalResult;
}
}

View file

@ -1,41 +0,0 @@
let XQLint = require("xqlint").XQLint;
export class XQueryCompleter {
constructor(script: string) {
this.script = script;
}
private _script: string;
private _linter: any;
get script(): string {
return this._script;
}
set script(value: string) {
this._script = value;
this._linter = new XQLint(this._script);
}
getCompletions(line: number, column: number): XQueryCompletionItem[] {
let items: XQueryCompletionItem[] = new Array<XQueryCompletionItem>();
this._linter.getCompletions({line: line, col: column}).forEach((completion: any) => {
items.push(new XQueryCompletionItem(completion.name, completion.value, completion.meta));
});
return items;
}
}
export class XQueryCompletionItem {
constructor(name: string, value: string, meta: string) {
this.name = name;
this.value = value;
this.meta = meta;
}
name: string;
value: string;
meta: string;
}

View file

@ -1,39 +0,0 @@
let XQLint = require("xqlint").XQLint;
export class XQueryLinter {
static SEVERITY_WARNING: number = 1;
static SEVERITY_ERROR: number = 2;
static lint(text: string): XQueryDiagnostic[] {
let linter = new XQLint(text);
let diagnostics: XQueryDiagnostic[] = new Array<XQueryDiagnostic>();
linter.getErrors().forEach((error: any) => {
diagnostics.push(new XQueryDiagnostic(XQueryLinter.SEVERITY_ERROR, error.message, error.pos.sl, error.pos.sc, error.pos.el, error.pos.ec));
});
linter.getWarnings().forEach((warning: any) => {
diagnostics.push(new XQueryDiagnostic(XQueryLinter.SEVERITY_WARNING, warning.message, warning.pos.sl, warning.pos.sc, warning.pos.el, warning.pos.ec));
});
return diagnostics;
}
}
export class XQueryDiagnostic {
constructor(severity: number, message: string, startLine: number, startColumn: number, endLine: number, endColumn: number) {
this.severity = severity;
this.message = message;
this.startLine = startLine;
this.startColumn = startColumn;
this.endLine = endLine;
this.endColumn = endColumn;
}
severity: number;
message: string;
startLine: number;
startColumn: number;
endLine: number;
endColumn: number;
}

View file

@ -1,192 +0,0 @@
// Based on pretty-data (https://github.com/vkiryukhin/pretty-data)
export class XmlFormatter {
constructor(options?: IXmlFormatterOptions) {
options = options || {};
if (typeof options.preferSpaces === "undefined") {
options.preferSpaces = false;
}
if (typeof options.splitNamespaces === "undefined") {
options.splitNamespaces = true;
}
options.tabSize = options.tabSize || 4;
options.newLine = options.newLine || "\n";
this.newLine = options.newLine || "\n";
this.indentPattern = (options.preferSpaces) ? " ".repeat(options.tabSize) : "\t";
this.splitNamespaces = options.splitNamespaces;
}
newLine: string;
indentPattern: string;
splitNamespaces: boolean;
format(xml: string): string {
xml = this.minify(xml, false);
xml = xml.replace(/</g, "~::~<");
if (this.splitNamespaces) {
xml = xml
.replace(/xmlns\:/g, "~::~xmlns:")
.replace(/xmlns\=/g, "~::~xmlns=");
}
let parts: string[] = xml.split("~::~");
console.log(parts);
let inComment: boolean = false;
let level: number = 0;
let output: string = "";
for (let i = 0; i < parts.length; i++) {
// <!
if (parts[i].search(/<!/) > -1) {
output += this._getIndent(level, parts[i]);
inComment = true;
// end <!
if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1 || parts[i].search(/!DOCTYPE/) > -1) {
inComment = false;
}
}
// end <!
else if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1) {
output += parts[i];
inComment = false;
}
// <elm></elm>
else if (/^<(\w|:)/.test(parts[i - 1]) && /^<\/(\w|:)/.test(parts[i])
&& /^<[\w:\-\.\,\/]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace("/", "")) {
output += parts[i];
if (!inComment) level--;
}
// <elm>
else if (parts[i].search(/<(\w|:)/) > -1 && parts[i].search(/<\//) == -1 && parts[i].search(/\/>/) == -1) {
output = (!inComment) ? output += this._getIndent(level++, parts[i]) : output += parts[i];
}
// <elm>...</elm>
else if (parts[i].search(/<(\w|:)/) > -1 && parts[i].search(/<\//) > -1) {
output = (!inComment) ? output += this._getIndent(level, parts[i]) : output += parts[i];
}
// </elm>
else if (parts[i].search(/<\//) > -1) {
output = (!inComment) ? output += this._getIndent(--level, parts[i]) : output += parts[i];
}
// <elm />
else if (parts[i].search(/\/>/) > -1 && (!this.splitNamespaces || parts[i].search(/xmlns(:|=)/) == -1)) {
output = (!inComment) ? output += this._getIndent(level, parts[i]) : output += parts[i];
}
// xmlns />
else if (parts[i].search(/\/>/) > -1 && parts[i].search(/xmlns(:|=)/) > -1 && this.splitNamespaces) {
output = (!inComment) ? output += this._getIndent(level--, parts[i]) : output += parts[i];
}
// <?xml ... ?>
else if (parts[i].search(/<\?/) > -1) {
output += this._getIndent(level, parts[i]);
}
// xmlns
else if (this.splitNamespaces && (parts[i].search(/xmlns\:/) > -1 || parts[i].search(/xmlns\=/) > -1)) {
output += this._getIndent(level, parts[i]);
}
else {
output += parts[i];
}
}
// remove leading newline
if (output[0] == this.newLine) {
output = output.slice(1);
}
else if (output.substring(0, 1) == this.newLine) {
output = output.slice(2);
}
return output;
}
minify(xml: string, removeComments?: boolean): string {
if (typeof removeComments === "undefined") {
removeComments = false;
}
xml = this._stripLineBreaks(xml); // all line breaks outside of CDATA elements
xml = (removeComments) ? xml.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g, "") : xml;
xml = xml.replace(/>\s{0,}</g, "><"); // insignificant whitespace between tags
xml = xml.replace(/"\s+(?=[^\s]+=)/g, "\" "); // spaces between attributes
xml = xml.replace(/"\s+(?=>)/g, "\""); // spaces between the last attribute and tag close (>)
xml = xml.replace(/"\s+(?=\/>)/g, "\" "); // spaces between the last attribute and tag close (/>)
xml = xml.replace(/[^ <>="]\s+[^ <>="]+=/g, (match: string) => { // spaces between the node name and the first attribute
return match.replace(/\s+/g, " ");
});
return xml;
}
private _getIndent(level: number, trailingValue?: string): string {
trailingValue = trailingValue || "";
return `${this.newLine}${this.indentPattern.repeat(level)}${trailingValue}`;
}
private _stripLineBreaks(xml: string): string {
let output: string = "";
let inTag: boolean = false;
let inTagName: boolean = false;
let inCdata: boolean = false;
let inAttribute: boolean = false;
for (let i = 0; i < xml.length; i++) {
let char: string = xml.charAt(i);
let prev: string = xml.charAt(i - 1);
let next: string = xml.charAt(i + 1);
if (char == "!" && (xml.substr(i, 8) == "![CDATA[" || xml.substr(i, 3) == "!--")) {
inCdata = true;
}
else if (char == "]" && (xml.substr(i, 3) == "]]>")) {
inCdata = false;
}
else if (char == "-" && (xml.substr(i, 3) == "-->")) {
inCdata = false;
}
else if (char.search(/[\r\n]/g) > -1 && !inCdata) {
if (/\r/.test(char) && /\S|\r|\n/.test(prev) && /\S|\r|\n/.test(xml.charAt(i + this.newLine.length))) {
output += char;
}
else if (/\n/.test(char) && /\S|\r|\n/.test(xml.charAt(i - this.newLine.length)) && /\S|\r|\n/.test(next)) {
output += char;
}
continue;
}
output += char;
}
return output;
}
}
export interface IXmlFormatterOptions {
preferSpaces?: boolean;
tabSize?: number;
newLine?: string;
splitNamespaces?: boolean;
}

View file

@ -1,11 +0,0 @@
import * as vsc from "vscode";
export class RangeUtil {
static getRangeForDocument(document: vsc.TextDocument): vsc.Range {
let lastLineIndex = (document.lineCount - 1);
let range = new vsc.Range(new vsc.Position(0, 0), new vsc.Position(lastLineIndex, Number.MAX_VALUE));
range = document.validateRange(range);
return range;
}
}