forked from external/vscode-xml
Merge pull request #113 from DotJoshJohnson/techdebt
Technical Debt 6/2017
This commit is contained in:
commit
c828608867
16 changed files with 140 additions and 177 deletions
|
@ -6,8 +6,8 @@ Keep in mind that these are guidelines, not rules. Use your best judgement and f
|
||||||
Please use the follow general workflow when making contributions to the code:
|
Please use the follow general workflow when making contributions to the code:
|
||||||
|
|
||||||
1. Fork the repository.
|
1. Fork the repository.
|
||||||
2. Create a feature branch or commit directly to the `develop` branch.
|
2. Create a feature branch and make your changes.
|
||||||
3. Create a pull request to request that your commits be merged to the `develop` branch of the `vscode-xml` repository. PRs submitted to the `master` branch will not be considered.
|
3. Create a pull request to request that your commits be merged to `master`.
|
||||||
|
|
||||||
|
|
||||||
## Building the Extension
|
## Building the Extension
|
||||||
|
@ -15,35 +15,29 @@ Please use the follow general workflow when making contributions to the code:
|
||||||
2. Run the `build` task in VS Code (`CTRL + SHIFT + B`) or start extension debugging (`F5`), which will run the `build` task for you.
|
2. Run the `build` task in VS Code (`CTRL + SHIFT + B`) or start extension debugging (`F5`), which will run the `build` task for you.
|
||||||
|
|
||||||
## Style Guide
|
## Style Guide
|
||||||
|
### Quotes
|
||||||
|
Use double quotes for strings whenever possible.
|
||||||
|
|
||||||
### Imports
|
### Imports
|
||||||
To keep *.ts files from getting too cluttered, use a namespace alias when pulling in more than 4 or 5 objects. As a general rule, always import the `vscode` namespace using the `vsc` alias for consistency.
|
As a general rule, always import the `vscode` namespace using the `vsc` alias for consistency.
|
||||||
|
|
||||||
**Favor This**
|
|
||||||
|
|
||||||
`import * as abc from 'abclib';`
|
|
||||||
|
|
||||||
**Over This**
|
|
||||||
|
|
||||||
`import { SomeType, AnotherType, BigClassWithCrazyName, IwantThisToo, VeryAppealingClass, Gimmee } from 'abclib';`
|
|
||||||
|
|
||||||
### Static Classes
|
### Static Classes
|
||||||
When possible, try to use a static class to wrap utility functions so you are importing the class, not just a function.
|
When possible, try to use a static class to wrap utility functions so you are importing the class, not just a function.
|
||||||
For libraries that do not follow this construct (such as the `xpath` module), *always* import the module using an alias (`import * as xpath from 'xpath').
|
For libraries that do not follow this construct (such as the `xpath` module), *always* import the module using an alias (`import * as xpath from "xpath").
|
||||||
|
|
||||||
### Constants
|
### Constants
|
||||||
Where applicable, try to use constants instead of inline strings and numbers.
|
Where applicable, try to use constants instead of inline strings and numbers.
|
||||||
|
|
||||||
## Implicit Types
|
## Implicit Types
|
||||||
Moving forward, the compiler is instructed (via tsconfig.json) to throw warnings if any expressions imply an "any" type. In other words, always use type declarations where applicable so it is clear what type is being used.
|
Moving forward, the compiler is instructed (via tsconfig.json) to throw warnings if any expressions imply an `any` type. In other words, always use type declarations where applicable so it is clear what type is being used.
|
||||||
There is an exception to this guideline. If you are using a thrid party library that does not have a *.d.ts file available, you do not need to write one. Just ensure the API is documented (either in this repo or in the library's repo).
|
There is an exception to this guideline. If you are using a thrid party library that does not have a *.d.ts file available, you do not need to write one. Just ensure the API is documented (either in this repo or in the library's repo).
|
||||||
|
|
||||||
|
|
||||||
## Folder Structure
|
## Folder Structure
|
||||||
All TypeScript files should reside under the top `src` folder. Under this, there are several subfolders and top-level files defined below:
|
All TypeScript files should reside under the top `src` folder. Under this, there are several subfolders and top-level files defined below:
|
||||||
|
|
||||||
### providers
|
### providers
|
||||||
This folder contains any classes that implement provider interfaces from the `vscode` namespace. This folder also contains any code that works directly with the
|
This folder contains any classes that implement provider interfaces from the `vscode` namespace. This folder also contains any code that works directly with the
|
||||||
APIs exposed by the `vscode` namespace, such as user interaction or configuration access. Aside for the `vscode` module, no code in this folder should be dependent on
|
APIs exposed by the `vscode` namespace, such as user interaction or configuration access. Aside for the `vscode` module, no code in this folder should be directly dependent on
|
||||||
any external NodeJS modules or libraries.
|
any external NodeJS modules or libraries.
|
||||||
|
|
||||||
### services
|
### services
|
||||||
|
@ -51,12 +45,10 @@ This folder contains any classes that perform actions/logic required by the prov
|
||||||
dependent on external Node modules and libraries.
|
dependent on external Node modules and libraries.
|
||||||
|
|
||||||
### utils
|
### utils
|
||||||
This folder contains any utility classes/functions that might be used by providers.
|
This folder contains any utility classes/functions.
|
||||||
|
|
||||||
### Commands.ts
|
### Commands.ts
|
||||||
This file acts as an interface to all registered commands in the extension. If a substantial amount of code is required to implement a command, it should be moved to a provider and/or service.
|
This file acts as an interface to all registered commands in the extension. If a substantial amount of code is required to implement a command, it should be moved to a provider and/or service.
|
||||||
Otherwise, if a command can be implemented in just a few lines, that code can be placed here.
|
|
||||||
|
|
||||||
### Extension.ts
|
### Extension.ts
|
||||||
Previously named `main.ts`, this is the primary entry point to the extension. Anything that needs done on activation or deactivation of the extension is done here. Both the workspace
|
Previously named `main.ts`, this is the primary entry point to the extension. Anything that needs done on activation or deactivation of the extension is done here. Both the workspace and global `Memento` instances are exposed from this module, which can be used by providers as needed.
|
||||||
and global `Memento` instances are exposed from this module, which can be used by providers as needed.
|
|
||||||
|
|
|
@ -16,9 +16,6 @@ Detailed release notes are available [here](https://github.com/DotJoshJohnson/vs
|
||||||
## Issues
|
## Issues
|
||||||
Run into a bug? Report it [here](https://github.com/DotJoshJohnson/vscode-xml/issues).
|
Run into a bug? Report it [here](https://github.com/DotJoshJohnson/vscode-xml/issues).
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
Check out development progress [here](https://github.com/DotJoshJohnson/vscode-xml/projects/1).
|
|
||||||
|
|
||||||
## Icon Credits
|
## Icon Credits
|
||||||
Icons used in the XML Tree View are used under the Creative Commons 3.0 BY license.
|
Icons used in the XML Tree View are used under the Creative Commons 3.0 BY license.
|
||||||
* "Code" icon by Dave Gandy from www.flaticon.com
|
* "Code" icon by Dave Gandy from www.flaticon.com
|
||||||
|
|
10
gulpfile.js
10
gulpfile.js
|
@ -1,9 +1,9 @@
|
||||||
var gulp = require('gulp');
|
var gulp = require("gulp");
|
||||||
|
|
||||||
var shell = require('gulp-shell');
|
var shell = require("gulp-shell");
|
||||||
|
|
||||||
gulp.task('compile-typescript', function () {
|
gulp.task("compile-typescript", function () {
|
||||||
gulp.src('package.json').pipe(shell('tsc'));
|
gulp.src("package.json").pipe(shell("tsc"));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build', ['compile-typescript']);
|
gulp.task("build", ["compile-typescript"]);
|
|
@ -1,16 +1,14 @@
|
||||||
'use strict';
|
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";
|
||||||
|
|
||||||
import * as vsc from 'vscode';
|
const CFG_SECTION: string = "xmlTools";
|
||||||
import * as ext from './Extension';
|
const CFG_REMOVE_COMMENTS: string = "removeCommentsOnMinify";
|
||||||
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 {
|
export class TextEditorCommands {
|
||||||
static minifyXml(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
|
static minifyXml(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
|
||||||
|
@ -56,13 +54,13 @@ export class TextEditorCommands {
|
||||||
editBuilder.replace(edits[i].range, edits[i].newText);
|
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?)
|
// wiggle the cursor to deselect the formatted XML (is there a non-hacky way to go about this?)
|
||||||
await vsc.commands.executeCommand('cursorMove', {
|
await vsc.commands.executeCommand("cursorMove", {
|
||||||
to: 'left',
|
to: "left",
|
||||||
by: 'character'
|
by: "character"
|
||||||
});
|
});
|
||||||
await vsc.commands.executeCommand('cursorMove', {
|
await vsc.commands.executeCommand("cursorMove", {
|
||||||
to: 'right',
|
to: "right",
|
||||||
by: 'character'
|
by: "character"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import { TextEditorCommands } from "./Commands";
|
||||||
import * as vsc from 'vscode';
|
import { XmlFormattingEditProvider } from "./providers/Formatting";
|
||||||
import { TextEditorCommands } from './Commands';
|
import { XQueryLintingFeatureProvider } from "./providers/Linting";
|
||||||
import { XmlFormattingEditProvider } from './providers/Formatting';
|
import { XQueryCompletionItemProvider } from "./providers/Completion";
|
||||||
import { XQueryLintingFeatureProvider } from './providers/Linting';
|
|
||||||
import { XQueryCompletionItemProvider } from './providers/Completion';
|
|
||||||
import { XmlTreeViewDataProvider } from "./providers/XmlTreeView";
|
import { XmlTreeViewDataProvider } from "./providers/XmlTreeView";
|
||||||
|
|
||||||
export var GlobalState: vsc.Memento;
|
export var GlobalState: vsc.Memento;
|
||||||
export var WorkspaceState: vsc.Memento;
|
export var WorkspaceState: vsc.Memento;
|
||||||
|
|
||||||
const LANG_XML: string = 'xml';
|
const LANG_XML: string = "xml";
|
||||||
const LANG_XSL: string = 'xsl';
|
const LANG_XSL: string = "xsl";
|
||||||
const LANG_XQUERY: string = 'xquery;'
|
const LANG_XQUERY: string = "xquery;"
|
||||||
const MEM_QUERY_HISTORY: string = 'xpathQueryHistory';
|
const MEM_QUERY_HISTORY: string = "xpathQueryHistory";
|
||||||
|
|
||||||
export function activate(ctx: vsc.ExtensionContext) {
|
export function activate(ctx: vsc.ExtensionContext) {
|
||||||
console.log('activate extension');
|
console.log("activate extension");
|
||||||
// expose global and workspace state to the entire extension
|
// expose global and workspace state to the entire extension
|
||||||
GlobalState = ctx.globalState;
|
GlobalState = ctx.globalState;
|
||||||
WorkspaceState = ctx.workspaceState;
|
WorkspaceState = ctx.workspaceState;
|
||||||
|
|
||||||
// register palette commands
|
// register palette commands
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
vsc.commands.registerTextEditorCommand('xmlTools.minifyXml', TextEditorCommands.minifyXml),
|
vsc.commands.registerTextEditorCommand("xmlTools.minifyXml", TextEditorCommands.minifyXml),
|
||||||
vsc.commands.registerTextEditorCommand('xmlTools.evaluateXPath', TextEditorCommands.evaluateXPath),
|
vsc.commands.registerTextEditorCommand("xmlTools.evaluateXPath", TextEditorCommands.evaluateXPath),
|
||||||
vsc.commands.registerTextEditorCommand('xmlTools.executeXQuery', TextEditorCommands.executeXQuery),
|
vsc.commands.registerTextEditorCommand("xmlTools.executeXQuery", TextEditorCommands.executeXQuery),
|
||||||
vsc.commands.registerTextEditorCommand('xmlTools.formatAsXml', TextEditorCommands.formatAsXml)
|
vsc.commands.registerTextEditorCommand("xmlTools.formatAsXml", TextEditorCommands.formatAsXml)
|
||||||
);
|
);
|
||||||
|
|
||||||
// register language feature providers
|
// register language feature providers
|
||||||
|
@ -34,7 +32,7 @@ export function activate(ctx: vsc.ExtensionContext) {
|
||||||
vsc.languages.registerDocumentFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
|
vsc.languages.registerDocumentFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
|
||||||
vsc.languages.registerDocumentRangeFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
|
vsc.languages.registerDocumentRangeFormattingEditProvider([LANG_XML, LANG_XSL], new XmlFormattingEditProvider()),
|
||||||
|
|
||||||
vsc.languages.registerCompletionItemProvider(LANG_XQUERY, new XQueryCompletionItemProvider(), ':', '$')
|
vsc.languages.registerCompletionItemProvider(LANG_XQUERY, new XQueryCompletionItemProvider(), ":", "$")
|
||||||
);
|
);
|
||||||
|
|
||||||
// listen to editor events (for linting)
|
// listen to editor events (for linting)
|
||||||
|
@ -63,7 +61,7 @@ function _handleContextChange(editor: vsc.TextEditor): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (editor.document.languageId) {
|
switch (editor.document.languageId) {
|
||||||
case 'xquery':
|
case "xquery":
|
||||||
XQueryLintingFeatureProvider.provideXQueryDiagnostics(editor);
|
XQueryLintingFeatureProvider.provideXQueryDiagnostics(editor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import { XQueryCompleter, XQueryCompletionItem } from "../services/XQueryCompleter";
|
||||||
import * as vsc from 'vscode';
|
|
||||||
import { XQueryCompleter, XQueryCompletionItem } from '../services/XQueryCompleter';
|
|
||||||
|
|
||||||
export class XQueryCompletionItemProvider implements vsc.CompletionItemProvider {
|
export class XQueryCompletionItemProvider implements vsc.CompletionItemProvider {
|
||||||
provideCompletionItems(document: vsc.TextDocument, position: vsc.Position): vsc.CompletionItem[] {
|
provideCompletionItems(document: vsc.TextDocument, position: vsc.Position): vsc.CompletionItem[] {
|
||||||
|
@ -16,20 +14,20 @@ export class XQueryCompletionItemProvider implements vsc.CompletionItemProvider
|
||||||
|
|
||||||
switch (completion.meta) {
|
switch (completion.meta) {
|
||||||
// functions (always qualified with a colon)
|
// functions (always qualified with a colon)
|
||||||
case 'function':
|
case "function":
|
||||||
item.kind = vsc.CompletionItemKind.Function;
|
item.kind = vsc.CompletionItemKind.Function;
|
||||||
|
|
||||||
let funcStart = (completion.value.indexOf(':') + 1);
|
let funcStart = (completion.value.indexOf(":") + 1);
|
||||||
let funcEnd = completion.value.indexOf('(');
|
let funcEnd = completion.value.indexOf("(");
|
||||||
|
|
||||||
item.insertText = completion.value.substring(funcStart, funcEnd);
|
item.insertText = completion.value.substring(funcStart, funcEnd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// variables and parameters (always qualified with a dollar sign)
|
// variables and parameters (always qualified with a dollar sign)
|
||||||
case 'Let binding':
|
case "Let binding":
|
||||||
case 'Local variable':
|
case "Local variable":
|
||||||
case 'Window variable':
|
case "Window variable":
|
||||||
case 'Function parameter':
|
case "Function parameter":
|
||||||
item.kind = vsc.CompletionItemKind.Variable;
|
item.kind = vsc.CompletionItemKind.Variable;
|
||||||
item.insertText = completion.value.substring(1);
|
item.insertText = completion.value.substring(1);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,43 +1,41 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import { ChildProcess } from "../services/ChildProcess";
|
||||||
|
|
||||||
import * as vsc from 'vscode';
|
const CFG_SECTION: string = "xmlTools";
|
||||||
import { ChildProcess } from '../services/ChildProcess';
|
const CFG_XQEXEC: string = "xqueryExecutionEngine";
|
||||||
|
const CFG_XQARGS: string = "xqueryExecutionArguments";
|
||||||
const CFG_SECTION: string = 'xmlTools';
|
|
||||||
const CFG_XQEXEC: string = 'xqueryExecutionEngine';
|
|
||||||
const CFG_XQARGS: string = 'xqueryExecutionArguments';
|
|
||||||
|
|
||||||
export class XQueryExecutionProvider {
|
export class XQueryExecutionProvider {
|
||||||
static async executeXQueryAsync(editor: vsc.TextEditor): Promise<void> {
|
static async executeXQueryAsync(editor: vsc.TextEditor): Promise<void> {
|
||||||
// this disposable will be used for creating status bar messages
|
// this disposable will be used for creating status bar messages
|
||||||
let disposable: vsc.Disposable;
|
let disposable: vsc.Disposable;
|
||||||
|
|
||||||
if (editor.document.languageId !== 'xquery') {
|
if (editor.document.languageId !== "xquery") {
|
||||||
vsc.window.showErrorMessage('This action can only be performed on an XQuery file.');
|
vsc.window.showErrorMessage("This action can only be performed on an XQuery file.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let executable = vsc.workspace.getConfiguration(CFG_SECTION).get<string>(CFG_XQEXEC, null);
|
let executable = vsc.workspace.getConfiguration(CFG_SECTION).get<string>(CFG_XQEXEC, null);
|
||||||
let args = vsc.workspace.getConfiguration(CFG_SECTION).get<string[]>(CFG_XQARGS, []);
|
let args = vsc.workspace.getConfiguration(CFG_SECTION).get<string[]>(CFG_XQARGS, []);
|
||||||
|
|
||||||
if (!executable || executable == '') {
|
if (!executable || executable == "") {
|
||||||
let action = await vsc.window.showWarningMessage('An XQuery execution engine has not been defined.', 'Define Now');
|
let action = await vsc.window.showWarningMessage("An XQuery execution engine has not been defined.", "Define Now");
|
||||||
|
|
||||||
if (action == 'Define Now') {
|
if (action == "Define Now") {
|
||||||
vsc.commands.executeCommand('workbench.action.openGlobalSettings');
|
vsc.commands.executeCommand("workbench.action.openGlobalSettings");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputFile: vsc.Uri;
|
let inputFile: vsc.Uri;
|
||||||
disposable = vsc.window.setStatusBarMessage('Searching for XML files in folder...');
|
disposable = vsc.window.setStatusBarMessage("Searching for XML files in folder...");
|
||||||
let files: vsc.Uri[] = await vsc.workspace.findFiles('**/*.xml', '', 100);
|
let files: vsc.Uri[] = await vsc.workspace.findFiles("**/*.xml", "", 100);
|
||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
|
|
||||||
// user does not have a folder open - prompt for file name
|
// user does not have a folder open - prompt for file name
|
||||||
if (typeof files === 'undefined') {
|
if (typeof files === "undefined") {
|
||||||
vsc.window.showErrorMessage('You must have a folder opened in VS Code to use this feature.');
|
vsc.window.showErrorMessage("You must have a folder opened in VS Code to use this feature.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +45,16 @@ export class XQueryExecutionProvider {
|
||||||
let qpItems: any[] = new Array<any>();
|
let qpItems: any[] = new Array<any>();
|
||||||
|
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
let filename: string = file.fsPath.replace('\\', '/');
|
let filename: string = file.fsPath.replace("\\", "/");
|
||||||
|
|
||||||
qpItems.push({ // must implement vscode.QuickPickItem
|
qpItems.push({ // must implement vscode.QuickPickItem
|
||||||
label: filename.substring(filename.lastIndexOf('/') + 1),
|
label: filename.substring(filename.lastIndexOf("/") + 1),
|
||||||
description: file.fsPath,
|
description: file.fsPath,
|
||||||
file: file
|
file: file
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let selection = await vsc.window.showQuickPick(qpItems, { placeHolder: 'Please select an input file.' });
|
let selection = await vsc.window.showQuickPick(qpItems, { placeHolder: "Please select an input file." });
|
||||||
|
|
||||||
if (!selection) {
|
if (!selection) {
|
||||||
return;
|
return;
|
||||||
|
@ -84,8 +82,8 @@ export class XQueryExecutionProvider {
|
||||||
|
|
||||||
if (outputPath) {
|
if (outputPath) {
|
||||||
outputPath = await vsc.window.showInputBox({
|
outputPath = await vsc.window.showInputBox({
|
||||||
placeHolder: 'ex. C:\\TEMP\XQueryOutput\\MyOutputFile.xml',
|
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.',
|
prompt: "Please specify the output file path. Existing file behavior is determined by the execution engine you have specified.",
|
||||||
value: outputPath
|
value: outputPath
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,12 +91,12 @@ export class XQueryExecutionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// call out to the execution engine
|
// call out to the execution engine
|
||||||
disposable = vsc.window.setStatusBarMessage('Executing XQuery Script...');
|
disposable = vsc.window.setStatusBarMessage("Executing XQuery Script...");
|
||||||
args = args.map<string>((value: string) => {
|
args = args.map<string>((value: string) => {
|
||||||
return value
|
return value
|
||||||
.replace('$(script)', editor.document.uri.fsPath)
|
.replace("$(script)", editor.document.uri.fsPath)
|
||||||
.replace('$(input)', inputFile.fsPath)
|
.replace("$(input)", inputFile.fsPath)
|
||||||
.replace('$(project)', vsc.workspace.rootPath);
|
.replace("$(project)", vsc.workspace.rootPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -108,7 +106,7 @@ export class XQueryExecutionProvider {
|
||||||
catch (error) {
|
catch (error) {
|
||||||
if (error.message.search(/[Ll]ine:?\s*\d+/gm) > -1) {
|
if (error.message.search(/[Ll]ine:?\s*\d+/gm) > -1) {
|
||||||
let match: RegExpExecArray = /[Ll]ine:?\s*\d+/gm.exec(error.message);
|
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 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}`);
|
let selection: string = await vsc.window.showErrorMessage(error.message, `Go to Line ${line}`);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import { RangeUtil } from "../utils/RangeUtil";
|
||||||
|
import { XmlFormatter, IXmlFormatterOptions } from "../services/XmlFormatter";
|
||||||
|
|
||||||
import * as vsc from 'vscode';
|
const CFG_SECTION: string = "xmlTools";
|
||||||
import { RangeUtil } from '../utils/RangeUtil';
|
const CFG_SPLIT_NAMESPACES: string = "splitXmlnsOnFormat";
|
||||||
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 {
|
export class XmlFormattingEditProvider implements vsc.DocumentFormattingEditProvider, vsc.DocumentRangeFormattingEditProvider {
|
||||||
provideDocumentFormattingEdits(document: vsc.TextDocument, options: vsc.FormattingOptions): vsc.TextEdit[] {
|
provideDocumentFormattingEdits(document: vsc.TextDocument, options: vsc.FormattingOptions): vsc.TextEdit[] {
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import { XQueryLinter, XQueryDiagnostic } from "../services/XQueryLinter";
|
||||||
import * as vsc from 'vscode';
|
|
||||||
import { XQueryLinter, XQueryDiagnostic } from '../services/XQueryLinter';
|
|
||||||
|
|
||||||
export class XQueryLintingFeatureProvider {
|
export class XQueryLintingFeatureProvider {
|
||||||
private static _coreDiagnostics: vsc.DiagnosticCollection;
|
private static _coreDiagnostics: vsc.DiagnosticCollection;
|
||||||
|
|
||||||
static get coreDiagnostics(): vsc.DiagnosticCollection {
|
static get coreDiagnostics(): vsc.DiagnosticCollection {
|
||||||
if (!XQueryLintingFeatureProvider._coreDiagnostics) {
|
if (!XQueryLintingFeatureProvider._coreDiagnostics) {
|
||||||
XQueryLintingFeatureProvider._coreDiagnostics = vsc.languages.createDiagnosticCollection('XQueryDiagnostics');
|
XQueryLintingFeatureProvider._coreDiagnostics = vsc.languages.createDiagnosticCollection("XQueryDiagnostics");
|
||||||
}
|
}
|
||||||
|
|
||||||
return XQueryLintingFeatureProvider._coreDiagnostics;
|
return XQueryLintingFeatureProvider._coreDiagnostics;
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
import * as ext from "../Extension";
|
||||||
|
import { XPathEvaluator, EvaluatorResult, EvaluatorResultType } from "../services/XPathEvaluator";
|
||||||
|
|
||||||
import * as vsc from 'vscode';
|
const CFG_SECTION: string = "xmlTools";
|
||||||
import * as ext from '../Extension';
|
const CFG_PERSIST_QUERY: string = "persistXPathQuery";
|
||||||
import { XPathEvaluator, EvaluatorResult, EvaluatorResultType } from '../services/XPathEvaluator';
|
const CFG_IGNORE_DEFAULT_XMLNS: string = "ignoreDefaultNamespace";
|
||||||
|
const MEM_QUERY_HISTORY: string = "xpathQueryHistory";
|
||||||
const CFG_SECTION: string = 'xmlTools';
|
const MEM_QUERY_LAST: string = "xPathQueryLast";
|
||||||
const CFG_PERSIST_QUERY: string = 'persistXPathQuery';
|
const OUTPUT_CHANNEL: string = "XPath Results";
|
||||||
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 {
|
export class XPathFeatureProvider {
|
||||||
static async evaluateXPathAsync(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): Promise<void> {
|
static async evaluateXPathAsync(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): Promise<void> {
|
||||||
|
@ -23,7 +21,7 @@ export class XPathFeatureProvider {
|
||||||
// if not, try pulling the last query ran, regardless of 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
|
// 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 history: HistoricQuery[] = memento.get<HistoricQuery[]>(MEM_QUERY_HISTORY, new Array<HistoricQuery>());
|
||||||
let globalLastQuery: string = memento.get<string>(MEM_QUERY_LAST, '');
|
let globalLastQuery: string = memento.get<string>(MEM_QUERY_LAST, "");
|
||||||
|
|
||||||
let lastQuery: HistoricQuery = history.find((item: HistoricQuery) => {
|
let lastQuery: HistoricQuery = history.find((item: HistoricQuery) => {
|
||||||
if (item.uri == editor.document.uri.toString()) {
|
if (item.uri == editor.document.uri.toString()) {
|
||||||
|
@ -34,7 +32,7 @@ export class XPathFeatureProvider {
|
||||||
});
|
});
|
||||||
|
|
||||||
// set the inital display value and prompt the user
|
// set the inital display value and prompt the user
|
||||||
let query: string = '';
|
let query: string = "";
|
||||||
|
|
||||||
if (persistQueries) {
|
if (persistQueries) {
|
||||||
if (lastQuery) {
|
if (lastQuery) {
|
||||||
|
@ -47,8 +45,8 @@ export class XPathFeatureProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
query = await vsc.window.showInputBox({
|
query = await vsc.window.showInputBox({
|
||||||
placeHolder: 'XPath Query',
|
placeHolder: "XPath Query",
|
||||||
prompt: 'Please enter an XPath query to evaluate.',
|
prompt: "Please enter an XPath query to evaluate.",
|
||||||
value: query
|
value: query
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -75,7 +73,7 @@ export class XPathFeatureProvider {
|
||||||
outputChannel.clear();
|
outputChannel.clear();
|
||||||
|
|
||||||
outputChannel.appendLine(`XPath Query: ${query}`);
|
outputChannel.appendLine(`XPath Query: ${query}`);
|
||||||
outputChannel.append('\n');
|
outputChannel.append("\n");
|
||||||
|
|
||||||
if (evalResult.type === EvaluatorResultType.NODE_COLLECTION) {
|
if (evalResult.type === EvaluatorResultType.NODE_COLLECTION) {
|
||||||
(evalResult.result as Node[]).forEach((node: XmlNode) => {
|
(evalResult.result as Node[]).forEach((node: XmlNode) => {
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
'use strict';
|
let child_process = require("child_process");
|
||||||
|
|
||||||
let child_process = require('child_process');
|
|
||||||
|
|
||||||
export class ChildProcess {
|
export class ChildProcess {
|
||||||
static async spawnAsync(executable: string, args: string[]): Promise<void> {
|
static async spawnAsync(executable: string, args: string[]): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
|
||||||
let output: string = '';
|
let output: string = "";
|
||||||
let handle = child_process.spawn(executable, args);
|
let handle = child_process.spawn(executable, args);
|
||||||
|
|
||||||
handle.stdout.on('data', (data: string) => {
|
handle.stdout.on("data", (data: string) => {
|
||||||
output += data;
|
output += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
handle.stderr.on('data', (data: string) => {
|
handle.stderr.on("data", (data: string) => {
|
||||||
output += data;
|
output += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
handle.on('close', (code: string) => {
|
handle.on("close", (code: string) => {
|
||||||
if (code == '0') {
|
if (code == "0") {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
'use strict';
|
import * as xpath from "xpath";
|
||||||
|
|
||||||
import * as xpath from 'xpath';
|
let DOMParser = require("xmldom").DOMParser;
|
||||||
|
|
||||||
let DOMParser = require('xmldom').DOMParser;
|
|
||||||
|
|
||||||
export class EvaluatorResult {
|
export class EvaluatorResult {
|
||||||
type: EvaluatorResultType;
|
type: EvaluatorResultType;
|
||||||
|
@ -18,13 +16,13 @@ export class XPathEvaluator {
|
||||||
static evaluate(query: string, xml: string, ignoreDefaultNamespace: boolean): EvaluatorResult {
|
static evaluate(query: string, xml: string, ignoreDefaultNamespace: boolean): EvaluatorResult {
|
||||||
if (ignoreDefaultNamespace) {
|
if (ignoreDefaultNamespace) {
|
||||||
xml = xml.replace(/xmlns=".+"/g, (match: string) => {
|
xml = xml.replace(/xmlns=".+"/g, (match: string) => {
|
||||||
return match.replace(/xmlns/g, 'xmlns:default');
|
return match.replace(/xmlns/g, "xmlns:default");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodes: Node[] = new Array<Node>();
|
let nodes: Node[] = new Array<Node>();
|
||||||
|
|
||||||
let xdoc: Document = new DOMParser().parseFromString(xml, 'text/xml');
|
let xdoc: Document = new DOMParser().parseFromString(xml, "text/xml");
|
||||||
|
|
||||||
let resolver: xpath.XPathNSResolver = xpath.createNSResolver(xdoc);
|
let resolver: xpath.XPathNSResolver = xpath.createNSResolver(xdoc);
|
||||||
let result: xpath.XPathResult = xpath.evaluate(
|
let result: xpath.XPathResult = xpath.evaluate(
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
'use strict';
|
let XQLint = require("xqlint").XQLint;
|
||||||
|
|
||||||
let XQLint = require('xqlint').XQLint;
|
|
||||||
|
|
||||||
export class XQueryCompleter {
|
export class XQueryCompleter {
|
||||||
constructor(script: string) {
|
constructor(script: string) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
'use strict';
|
let XQLint = require("xqlint").XQLint;
|
||||||
|
|
||||||
let XQLint = require('xqlint').XQLint;
|
|
||||||
|
|
||||||
export class XQueryLinter {
|
export class XQueryLinter {
|
||||||
static SEVERITY_WARNING: number = 1;
|
static SEVERITY_WARNING: number = 1;
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Based on pretty-data (https://github.com/vkiryukhin/pretty-data)
|
// Based on pretty-data (https://github.com/vkiryukhin/pretty-data)
|
||||||
export class XmlFormatter {
|
export class XmlFormatter {
|
||||||
constructor(options?: IXmlFormatterOptions) {
|
constructor(options?: IXmlFormatterOptions) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
if (typeof options.preferSpaces === 'undefined') {
|
if (typeof options.preferSpaces === "undefined") {
|
||||||
options.preferSpaces = false;
|
options.preferSpaces = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options.splitNamespaces === 'undefined') {
|
if (typeof options.splitNamespaces === "undefined") {
|
||||||
options.splitNamespaces = true;
|
options.splitNamespaces = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.tabSize = options.tabSize || 4;
|
options.tabSize = options.tabSize || 4;
|
||||||
options.newLine = options.newLine || '\n';
|
options.newLine = options.newLine || "\n";
|
||||||
|
|
||||||
this.newLine = options.newLine || '\n';
|
this.newLine = options.newLine || "\n";
|
||||||
this.indentPattern = (options.preferSpaces) ? ' '.repeat(options.tabSize) : '\t';
|
this.indentPattern = (options.preferSpaces) ? " ".repeat(options.tabSize) : "\t";
|
||||||
this.splitNamespaces = options.splitNamespaces;
|
this.splitNamespaces = options.splitNamespaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,19 +25,19 @@ export class XmlFormatter {
|
||||||
|
|
||||||
format(xml: string): string {
|
format(xml: string): string {
|
||||||
xml = this.minify(xml, false);
|
xml = this.minify(xml, false);
|
||||||
xml = xml.replace(/</g, '~::~<');
|
xml = xml.replace(/</g, "~::~<");
|
||||||
|
|
||||||
if (this.splitNamespaces) {
|
if (this.splitNamespaces) {
|
||||||
xml = xml
|
xml = xml
|
||||||
.replace(/xmlns\:/g, '~::~xmlns:')
|
.replace(/xmlns\:/g, "~::~xmlns:")
|
||||||
.replace(/xmlns\=/g, '~::~xmlns=');
|
.replace(/xmlns\=/g, "~::~xmlns=");
|
||||||
}
|
}
|
||||||
|
|
||||||
let parts: string[] = xml.split('~::~');
|
let parts: string[] = xml.split("~::~");
|
||||||
console.log(parts);
|
console.log(parts);
|
||||||
let inComment: boolean = false;
|
let inComment: boolean = false;
|
||||||
let level: number = 0;
|
let level: number = 0;
|
||||||
let output: string = '';
|
let output: string = "";
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
// <!
|
// <!
|
||||||
|
@ -61,7 +59,7 @@ export class XmlFormatter {
|
||||||
|
|
||||||
// <elm></elm>
|
// <elm></elm>
|
||||||
else if (/^<(\w|:)/.test(parts[i - 1]) && /^<\/(\w|:)/.test(parts[i])
|
else if (/^<(\w|:)/.test(parts[i - 1]) && /^<\/(\w|:)/.test(parts[i])
|
||||||
&& /^<[\w:\-\.\,\/]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace('/', '')) {
|
&& /^<[\w:\-\.\,\/]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace("/", "")) {
|
||||||
|
|
||||||
output += parts[i];
|
output += parts[i];
|
||||||
if (!inComment) level--;
|
if (!inComment) level--;
|
||||||
|
@ -120,31 +118,31 @@ export class XmlFormatter {
|
||||||
}
|
}
|
||||||
|
|
||||||
minify(xml: string, removeComments?: boolean): string {
|
minify(xml: string, removeComments?: boolean): string {
|
||||||
if (typeof removeComments === 'undefined') {
|
if (typeof removeComments === "undefined") {
|
||||||
removeComments = false;
|
removeComments = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml = this._stripLineBreaks(xml); // all line breaks outside of CDATA elements
|
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 = (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{0,}</g, "><"); // insignificant whitespace between tags
|
||||||
xml = xml.replace(/"\s+(?=[^\s]+=)/g, '" '); // spaces between attributes
|
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, '" '); // 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
|
xml = xml.replace(/[^ <>="]\s+[^ <>="]+=/g, (match: string) => { // spaces between the node name and the first attribute
|
||||||
return match.replace(/\s+/g, ' ');
|
return match.replace(/\s+/g, " ");
|
||||||
});
|
});
|
||||||
|
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getIndent(level: number, trailingValue?: string): string {
|
private _getIndent(level: number, trailingValue?: string): string {
|
||||||
trailingValue = trailingValue || '';
|
trailingValue = trailingValue || "";
|
||||||
|
|
||||||
return `${this.newLine}${this.indentPattern.repeat(level)}${trailingValue}`;
|
return `${this.newLine}${this.indentPattern.repeat(level)}${trailingValue}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _stripLineBreaks(xml: string): string {
|
private _stripLineBreaks(xml: string): string {
|
||||||
let output: string = '';
|
let output: string = "";
|
||||||
let inTag: boolean = false;
|
let inTag: boolean = false;
|
||||||
let inTagName: boolean = false;
|
let inTagName: boolean = false;
|
||||||
let inCdata: boolean = false;
|
let inCdata: boolean = false;
|
||||||
|
@ -155,15 +153,15 @@ export class XmlFormatter {
|
||||||
let prev: string = xml.charAt(i - 1);
|
let prev: string = xml.charAt(i - 1);
|
||||||
let next: string = xml.charAt(i + 1);
|
let next: string = xml.charAt(i + 1);
|
||||||
|
|
||||||
if (char == '!' && (xml.substr(i, 8) == '![CDATA[' || xml.substr(i, 3) == '!--')) {
|
if (char == "!" && (xml.substr(i, 8) == "![CDATA[" || xml.substr(i, 3) == "!--")) {
|
||||||
inCdata = true;
|
inCdata = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (char == ']' && (xml.substr(i, 3) == ']]>')) {
|
else if (char == "]" && (xml.substr(i, 3) == "]]>")) {
|
||||||
inCdata = false;
|
inCdata = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (char == '-' && (xml.substr(i, 3) == '-->')) {
|
else if (char == "-" && (xml.substr(i, 3) == "-->")) {
|
||||||
inCdata = false;
|
inCdata = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
'use strict';
|
import * as vsc from "vscode";
|
||||||
|
|
||||||
import * as vsc from 'vscode';
|
|
||||||
|
|
||||||
export class RangeUtil {
|
export class RangeUtil {
|
||||||
static getRangeForDocument(document: vsc.TextDocument): vsc.Range {
|
static getRangeForDocument(document: vsc.TextDocument): vsc.Range {
|
||||||
|
|
Loading…
Add table
Reference in a new issue