Merge pull request #113 from DotJoshJohnson/techdebt

Technical Debt 6/2017
This commit is contained in:
Josh Johnson 2017-06-23 21:11:53 -04:00 committed by GitHub
commit c828608867
16 changed files with 140 additions and 177 deletions

View file

@ -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:
1. Fork the repository.
2. Create a feature branch or commit directly to the `develop` branch.
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.
2. Create a feature branch and make your changes.
3. Create a pull request to request that your commits be merged to `master`.
## 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.
## Style Guide
### Quotes
Use double quotes for strings whenever possible.
### 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.
**Favor This**
`import * as abc from 'abclib';`
**Over This**
`import { SomeType, AnotherType, BigClassWithCrazyName, IwantThisToo, VeryAppealingClass, Gimmee } from 'abclib';`
As a general rule, always import the `vscode` namespace using the `vsc` alias for consistency.
### Static Classes
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
Where applicable, try to use constants instead of inline strings and numbers.
## 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).
## Folder Structure
All TypeScript files should reside under the top `src` folder. Under this, there are several subfolders and top-level files defined below:
### 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
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.
### 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.
### utils
This folder contains any utility classes/functions that might be used by providers.
This folder contains any utility classes/functions.
### 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.
Otherwise, if a command can be implemented in just a few lines, that code can be placed here.
### 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
and global `Memento` instances are exposed from this module, which can be used by providers as needed.
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.

View file

@ -16,9 +16,6 @@ Detailed release notes are available [here](https://github.com/DotJoshJohnson/vs
## 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
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

View file

@ -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.src('package.json').pipe(shell('tsc'));
gulp.task("compile-typescript", function () {
gulp.src("package.json").pipe(shell("tsc"));
});
gulp.task('build', ['compile-typescript']);
gulp.task("build", ["compile-typescript"]);

View file

@ -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';
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';
const CFG_SECTION: string = "xmlTools";
const CFG_REMOVE_COMMENTS: string = "removeCommentsOnMinify";
export class TextEditorCommands {
static minifyXml(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void {
@ -56,13 +54,13 @@ export class TextEditorCommands {
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: "left",
by: "character"
});
await vsc.commands.executeCommand('cursorMove', {
to: 'right',
by: 'character'
await vsc.commands.executeCommand("cursorMove", {
to: "right",
by: "character"
});
});
}

View file

@ -1,32 +1,30 @@
'use strict';
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 * 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';
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');
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)
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
@ -34,7 +32,7 @@ export function activate(ctx: vsc.ExtensionContext) {
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(), ':', '$')
vsc.languages.registerCompletionItemProvider(LANG_XQUERY, new XQueryCompletionItemProvider(), ":", "$")
);
// listen to editor events (for linting)
@ -63,7 +61,7 @@ function _handleContextChange(editor: vsc.TextEditor): void {
}
switch (editor.document.languageId) {
case 'xquery':
case "xquery":
XQueryLintingFeatureProvider.provideXQueryDiagnostics(editor);
break;
}

View file

@ -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 {
provideCompletionItems(document: vsc.TextDocument, position: vsc.Position): vsc.CompletionItem[] {
@ -16,20 +14,20 @@ export class XQueryCompletionItemProvider implements vsc.CompletionItemProvider
switch (completion.meta) {
// functions (always qualified with a colon)
case 'function':
case "function":
item.kind = vsc.CompletionItemKind.Function;
let funcStart = (completion.value.indexOf(':') + 1);
let funcEnd = completion.value.indexOf('(');
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':
case "Let binding":
case "Local variable":
case "Window variable":
case "Function parameter":
item.kind = vsc.CompletionItemKind.Variable;
item.insertText = completion.value.substring(1);
break;

View file

@ -1,43 +1,41 @@
'use strict';
import * as vsc from "vscode";
import { ChildProcess } from "../services/ChildProcess";
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';
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.');
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 (!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');
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 = 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.');
if (typeof files === "undefined") {
vsc.window.showErrorMessage("You must have a folder opened in VS Code to use this feature.");
return;
}
@ -47,16 +45,16 @@ export class XQueryExecutionProvider {
let qpItems: any[] = new Array<any>();
files.forEach((file) => {
let filename: string = file.fsPath.replace('\\', '/');
let filename: string = file.fsPath.replace("\\", "/");
qpItems.push({ // must implement vscode.QuickPickItem
label: filename.substring(filename.lastIndexOf('/') + 1),
label: filename.substring(filename.lastIndexOf("/") + 1),
description: file.fsPath,
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) {
return;
@ -84,8 +82,8 @@ export class XQueryExecutionProvider {
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.',
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
});
@ -93,12 +91,12 @@ export class XQueryExecutionProvider {
}
// 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) => {
return value
.replace('$(script)', editor.document.uri.fsPath)
.replace('$(input)', inputFile.fsPath)
.replace('$(project)', vsc.workspace.rootPath);
.replace("$(script)", editor.document.uri.fsPath)
.replace("$(input)", inputFile.fsPath)
.replace("$(project)", vsc.workspace.rootPath);
});
try {
@ -108,7 +106,7 @@ export class XQueryExecutionProvider {
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 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}`);

View file

@ -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';
import { RangeUtil } from '../utils/RangeUtil';
import { XmlFormatter, IXmlFormatterOptions } from '../services/XmlFormatter';
const CFG_SECTION: string = 'xmlTools';
const CFG_SPLIT_NAMESPACES: string = 'splitXmlnsOnFormat';
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[] {

View file

@ -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 {
private static _coreDiagnostics: vsc.DiagnosticCollection;
static get coreDiagnostics(): vsc.DiagnosticCollection {
if (!XQueryLintingFeatureProvider._coreDiagnostics) {
XQueryLintingFeatureProvider._coreDiagnostics = vsc.languages.createDiagnosticCollection('XQueryDiagnostics');
XQueryLintingFeatureProvider._coreDiagnostics = vsc.languages.createDiagnosticCollection("XQueryDiagnostics");
}
return XQueryLintingFeatureProvider._coreDiagnostics;

View file

@ -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';
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';
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> {
@ -23,7 +21,7 @@ export class XPathFeatureProvider {
// 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 globalLastQuery: string = memento.get<string>(MEM_QUERY_LAST, "");
let lastQuery: HistoricQuery = history.find((item: HistoricQuery) => {
if (item.uri == editor.document.uri.toString()) {
@ -34,7 +32,7 @@ export class XPathFeatureProvider {
});
// set the inital display value and prompt the user
let query: string = '';
let query: string = "";
if (persistQueries) {
if (lastQuery) {
@ -47,8 +45,8 @@ export class XPathFeatureProvider {
}
query = await vsc.window.showInputBox({
placeHolder: 'XPath Query',
prompt: 'Please enter an XPath query to evaluate.',
placeHolder: "XPath Query",
prompt: "Please enter an XPath query to evaluate.",
value: query
});
@ -75,7 +73,7 @@ export class XPathFeatureProvider {
outputChannel.clear();
outputChannel.appendLine(`XPath Query: ${query}`);
outputChannel.append('\n');
outputChannel.append("\n");
if (evalResult.type === EvaluatorResultType.NODE_COLLECTION) {
(evalResult.result as Node[]).forEach((node: XmlNode) => {

View file

@ -1,24 +1,22 @@
'use strict';
let child_process = require('child_process');
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 output: string = "";
let handle = child_process.spawn(executable, args);
handle.stdout.on('data', (data: string) => {
handle.stdout.on("data", (data: string) => {
output += data;
});
handle.stderr.on('data', (data: string) => {
handle.stderr.on("data", (data: string) => {
output += data;
});
handle.on('close', (code: string) => {
if (code == '0') {
handle.on("close", (code: string) => {
if (code == "0") {
resolve();
}

View file

@ -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 {
type: EvaluatorResultType;
@ -18,13 +16,13 @@ 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');
return match.replace(/xmlns/g, "xmlns:default");
});
}
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 result: xpath.XPathResult = xpath.evaluate(

View file

@ -1,6 +1,4 @@
'use strict';
let XQLint = require('xqlint').XQLint;
let XQLint = require("xqlint").XQLint;
export class XQueryCompleter {
constructor(script: string) {

View file

@ -1,6 +1,4 @@
'use strict';
let XQLint = require('xqlint').XQLint;
let XQLint = require("xqlint").XQLint;
export class XQueryLinter {
static SEVERITY_WARNING: number = 1;

View file

@ -1,23 +1,21 @@
'use strict';
// Based on pretty-data (https://github.com/vkiryukhin/pretty-data)
export class XmlFormatter {
constructor(options?: IXmlFormatterOptions) {
options = options || {};
if (typeof options.preferSpaces === 'undefined') {
if (typeof options.preferSpaces === "undefined") {
options.preferSpaces = false;
}
if (typeof options.splitNamespaces === 'undefined') {
if (typeof options.splitNamespaces === "undefined") {
options.splitNamespaces = true;
}
options.tabSize = options.tabSize || 4;
options.newLine = options.newLine || '\n';
options.newLine = options.newLine || "\n";
this.newLine = options.newLine || '\n';
this.indentPattern = (options.preferSpaces) ? ' '.repeat(options.tabSize) : '\t';
this.newLine = options.newLine || "\n";
this.indentPattern = (options.preferSpaces) ? " ".repeat(options.tabSize) : "\t";
this.splitNamespaces = options.splitNamespaces;
}
@ -27,19 +25,19 @@ export class XmlFormatter {
format(xml: string): string {
xml = this.minify(xml, false);
xml = xml.replace(/</g, '~::~<');
xml = xml.replace(/</g, "~::~<");
if (this.splitNamespaces) {
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);
let inComment: boolean = false;
let level: number = 0;
let output: string = '';
let output: string = "";
for (let i = 0; i < parts.length; i++) {
// <!
@ -61,7 +59,7 @@ export class XmlFormatter {
// <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('/', '')) {
&& /^<[\w:\-\.\,\/]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace("/", "")) {
output += parts[i];
if (!inComment) level--;
@ -120,31 +118,31 @@ export class XmlFormatter {
}
minify(xml: string, removeComments?: boolean): string {
if (typeof removeComments === 'undefined') {
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 = (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 match.replace(/\s+/g, " ");
});
return xml;
}
private _getIndent(level: number, trailingValue?: string): string {
trailingValue = trailingValue || '';
trailingValue = trailingValue || "";
return `${this.newLine}${this.indentPattern.repeat(level)}${trailingValue}`;
}
private _stripLineBreaks(xml: string): string {
let output: string = '';
let output: string = "";
let inTag: boolean = false;
let inTagName: boolean = false;
let inCdata: boolean = false;
@ -155,15 +153,15 @@ export class XmlFormatter {
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) == '!--')) {
if (char == "!" && (xml.substr(i, 8) == "![CDATA[" || xml.substr(i, 3) == "!--")) {
inCdata = true;
}
else if (char == ']' && (xml.substr(i, 3) == ']]>')) {
else if (char == "]" && (xml.substr(i, 3) == "]]>")) {
inCdata = false;
}
else if (char == '-' && (xml.substr(i, 3) == '-->')) {
else if (char == "-" && (xml.substr(i, 3) == "-->")) {
inCdata = false;
}

View file

@ -1,6 +1,4 @@
'use strict';
import * as vsc from 'vscode';
import * as vsc from "vscode";
export class RangeUtil {
static getRangeForDocument(document: vsc.TextDocument): vsc.Range {