From b039805a13b0089b38cdc4d67e9b79b04b127205 Mon Sep 17 00:00:00 2001 From: Daniil Zhuravlev Date: Wed, 8 Apr 2026 21:47:57 +0400 Subject: [PATCH 1/2] chore(deps): update prettier to 3.8.1 chore: update prettier config chore: remove eslint-plugin-prettier Apply prettier config from https://github.com/SunsetTechuila/is-bun-module/blob/2c1a618f2068010a69276c90dba9b663de5bccf5/.prettierrc.json. --- .prettierrc.json | 4 +++ package-lock.json | 89 +++-------------------------------------------- package.json | 18 +++------- 3 files changed, 12 insertions(+), 99 deletions(-) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..e515e10 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "printWidth": 100, + "quoteProps": "consistent" +} diff --git a/package-lock.json b/package-lock.json index f8524f1..d3fdc42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,10 +22,9 @@ "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.5", "eslint-config-xo": "^0.45.0", - "eslint-plugin-prettier": "^5.4.1", "glob": "^11.0.2", "mocha": "^11.6.0", - "prettier": "^3.5.3", + "prettier": "^3.8.1", "rimraf": "^6.0.1", "typescript": "~5.8.3", "vscode-test-utils": "^1.0.0" @@ -521,19 +520,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", - "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, "node_modules/@secretlint/config-creator": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-9.3.4.tgz", @@ -2461,37 +2447,6 @@ "eslint": ">=8.56.0" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz", - "integrity": "sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-visitor-keys": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", @@ -2687,13 +2642,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4843,9 +4791,9 @@ } }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -4858,19 +4806,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5648,22 +5583,6 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", - "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.4" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", diff --git a/package.json b/package.json index 3285845..ee34782 100644 --- a/package.json +++ b/package.json @@ -118,16 +118,15 @@ "@typescript-eslint/eslint-plugin": "^8.34.0", "@typescript-eslint/parser": "^8.34.0", "@vscode/test-electron": "^2.5.2", + "@vscode/vsce": "^3.5.0", "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.5", "eslint-config-xo": "^0.45.0", - "eslint-plugin-prettier": "^5.4.1", "glob": "^11.0.2", "mocha": "^11.6.0", - "prettier": "^3.5.3", + "prettier": "^3.8.1", "rimraf": "^6.0.1", "typescript": "~5.8.3", - "@vscode/vsce": "^3.5.0", "vscode-test-utils": "^1.0.0" }, "scripts": { @@ -135,6 +134,7 @@ "prebuild": "npm run clean", "build": "tsc", "postbuild": "cp -r src/test/suite/fixtures out/test/suite && cp -r src/test/untitled-suite/fixtures out/test/untitled-suite && cp src/DefaultTemplate.editorconfig out", + "format": "prettier --write .", "lint": "eslint src/**/*.ts", "pretest": "npm run lint && npm run build", "watch": "tsc -watch", @@ -153,16 +153,6 @@ }, "rules": { "prettier/prettier": "error" - }, - "plugins": [ - "prettier" - ] - }, - "prettier": { - "arrowParens": "avoid", - "proseWrap": "always", - "semi": false, - "singleQuote": true, - "trailingComma": "all" + } } } From 784ff20985bc4c47377c78b7839d5bb0b3b10fd4 Mon Sep 17 00:00:00 2001 From: Daniil Zhuravlev Date: Wed, 8 Apr 2026 21:56:52 +0400 Subject: [PATCH 2/2] style: format code --- .eslintrc.json | 6 +- .github/ISSUE_TEMPLATE.md | 5 +- README.md | 3 +- src/DocumentWatcher.ts | 177 ++++--- src/EditorConfigCompletionProvider.ts | 196 ++++---- src/api.ts | 145 +++--- src/commands/generateEditorConfig.ts | 178 ++++--- src/editorConfigMain.ts | 34 +- src/test/runTest.ts | 32 +- src/test/suite/api.test.ts | 87 ++-- src/test/suite/index.test.ts | 442 +++++++----------- src/test/suite/index.ts | 26 +- src/test/testUtils.ts | 46 +- src/test/untitled-suite/index.test.ts | 28 +- src/test/untitled-suite/index.ts | 26 +- src/transformations/InsertFinalNewline.ts | 53 +-- src/transformations/PreSaveTransformation.ts | 10 +- src/transformations/SetEndOfLine.ts | 16 +- src/transformations/TrimTrailingWhitespace.ts | 61 ++- src/transformations/index.ts | 8 +- 20 files changed, 703 insertions(+), 876 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 42b1ec8..ed671bd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,11 +17,7 @@ "tsconfigRootDir": "." }, "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "prettier", - "plugin:@typescript-eslint/recommended" - ], + "extends": ["eslint:recommended", "prettier", "plugin:@typescript-eslint/recommended"], "rules": { // Possible Errors "no-async-promise-executor": "error", diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index d050b1e..05f0554 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,12 +6,13 @@ Please fill-in this template. Delete the following condition if it doesn't apply to your case: If the extension is not picking up the expected configuration for a file: + - [ ] I tried `npm install editorconfig -g` and ran `editorconfig [file-in-question]` and the configuration was what I expected. If not, please file on the [`editorconfig-core-js` issue tracker](https://github.com/editorconfig/editorconfig-core-js/issues). ## Issue | | Visual Studio Code | editorconfig-vscode | -|-------------|--------------------|---------------------| +| ----------- | ------------------ | ------------------- | | **Version** | `x.x.x` | `x.x.x` | ### Root `.editorconfig` File @@ -27,7 +28,7 @@ indent_size = 2 Are there any other relevant `.editorconfig` files in your project? Yes / No | Visual Studio Code Setting | Default | User | Workspace | -|--------------------------------|---------|---------|-----------| +| ------------------------------ | ------- | ------- | --------- | | `editor.insertSpaces` | `true` | `____` | `____` | | `editor.tabSize` | `4` | `_` | `_` | | `editor.trimAutoWhitespace` | `true` | `____` | `____` | diff --git a/README.md b/README.md index aa66e5c..f8c00eb 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ [actions-img]: https://github.com/editorconfig/editorconfig-vscode/actions/workflows/test.yml/badge.svg [actions]: https://github.com/editorconfig/editorconfig-vscode/actions -[chat-img]: - https://img.shields.io/badge/Gitter-Join_the_EditorConfig_VSCode_chat-brightgreen.png?style=flat-square +[chat-img]: https://img.shields.io/badge/Gitter-Join_the_EditorConfig_VSCode_chat-brightgreen.png?style=flat-square [chat]: https://gitter.im/editorconfig/editorconfig-vscode This plugin [attempts](#known-issues) to override user/workspace settings with diff --git a/src/DocumentWatcher.ts b/src/DocumentWatcher.ts index 1d02efc..73ea46a 100644 --- a/src/DocumentWatcher.ts +++ b/src/DocumentWatcher.ts @@ -1,4 +1,4 @@ -import * as path from 'path' +import * as path from "path"; import { Disposable, TextDocument, @@ -7,201 +7,186 @@ import { TextEditorOptions, window, workspace, -} from 'vscode' -import { KnownProps } from 'editorconfig' +} from "vscode"; +import { KnownProps } from "editorconfig"; import { InsertFinalNewline, PreSaveTransformation, SetEndOfLine, TrimTrailingWhitespace, -} from './transformations' +} from "./transformations"; import { applyTextEditorOptions, resolveCoreConfig, resolveFile, resolveTextEditorOptions, -} from './api' +} from "./api"; -type Charset = Exclude -type EncodingMap = Record +type Charset = Exclude; +type EncodingMap = Record; const encodingMap = { - 'utf-8': 'utf8', - 'utf-8-bom': 'utf8bom', - 'utf-16le': 'utf16le', - 'utf-16be': 'utf16be', - latin1: 'iso88591', -} as const satisfies EncodingMap + "utf-8": "utf8", + "utf-8-bom": "utf8bom", + "utf-16le": "utf16le", + "utf-16be": "utf16be", + "latin1": "iso88591", +} as const satisfies EncodingMap; export default class DocumentWatcher { - private disposable: Disposable + private disposable: Disposable; private preSaveTransformations: PreSaveTransformation[] = [ new SetEndOfLine(), new TrimTrailingWhitespace(), new InsertFinalNewline(), - ] - private doc?: TextDocument + ]; + private doc?: TextDocument; - public constructor( - private outputChannel = window.createOutputChannel('EditorConfig'), - ) { - this.log('Initializing document watcher...') + public constructor(private outputChannel = window.createOutputChannel("EditorConfig")) { + this.log("Initializing document watcher..."); - const subscriptions: Disposable[] = [] + const subscriptions: Disposable[] = []; - this.handleTextEditorChange(window.activeTextEditor) + this.handleTextEditorChange(window.activeTextEditor); subscriptions.push( - window.onDidChangeActiveTextEditor(async editor => { - this.handleTextEditorChange(editor) + window.onDidChangeActiveTextEditor(async (editor) => { + this.handleTextEditorChange(editor); }), - ) + ); subscriptions.push( - window.onDidChangeWindowState(async state => { + window.onDidChangeWindowState(async (state) => { if (state.focused && this.doc) { const newOptions = await resolveTextEditorOptions(this.doc, { onEmptyConfig: this.onEmptyConfig, - }) + }); applyTextEditorOptions(newOptions, { onNoActiveTextEditor: this.onNoActiveTextEditor, onSuccess: this.onSuccess, - }) + }); } }), - ) + ); subscriptions.push( - workspace.onDidSaveTextDocument(doc => { - if (path.basename(doc.fileName) === '.editorconfig') { - this.log('.editorconfig file saved.') + workspace.onDidSaveTextDocument((doc) => { + if (path.basename(doc.fileName) === ".editorconfig") { + this.log(".editorconfig file saved."); } // in case document was dirty on text editor change - this.handleDocumentEncoding(doc) + this.handleDocumentEncoding(doc); }), - ) + ); subscriptions.push( - workspace.onWillSaveTextDocument(async e => { - const transformations = this.calculatePreSaveTransformations( - e.document, - e.reason, - ) - e.waitUntil(transformations) + workspace.onWillSaveTextDocument(async (e) => { + const transformations = this.calculatePreSaveTransformations(e.document, e.reason); + e.waitUntil(transformations); }), - ) + ); - this.disposable = Disposable.from.apply(this, subscriptions) - this.log('Document watcher initialized') + this.disposable = Disposable.from.apply(this, subscriptions); + this.log("Document watcher initialized"); } public onEmptyConfig = (relativePath: string) => { - this.log(`${relativePath}: No configuration.`) - } + this.log(`${relativePath}: No configuration.`); + }; public onBeforeResolve = (relativePath: string) => { - this.log(`${relativePath}: Using EditorConfig core...`) - } + this.log(`${relativePath}: Using EditorConfig core...`); + }; public onNoActiveTextEditor = () => { - this.log('No more open editors.') - } + this.log("No more open editors."); + }; public onSuccess = (newOptions: TextEditorOptions) => { if (!this.doc) { - this.log(`[no file]: ${JSON.stringify(newOptions)}`) - return + this.log(`[no file]: ${JSON.stringify(newOptions)}`); + return; } - const { relativePath } = resolveFile(this.doc) - this.log(`${relativePath}: ${JSON.stringify(newOptions)}`) - } + const { relativePath } = resolveFile(this.doc); + this.log(`${relativePath}: ${JSON.stringify(newOptions)}`); + }; public log(...messages: string[]) { - this.outputChannel.appendLine(messages.join(' ')) + this.outputChannel.appendLine(messages.join(" ")); } public dispose() { - this.disposable.dispose() + this.disposable.dispose(); } - private async calculatePreSaveTransformations( - doc: TextDocument, - reason: TextDocumentSaveReason, - ) { + private async calculatePreSaveTransformations(doc: TextDocument, reason: TextDocumentSaveReason) { const editorconfigSettings = await resolveCoreConfig(doc, { onBeforeResolve: this.onBeforeResolve, - }) - const relativePath = workspace.asRelativePath(doc.fileName) + }); + const relativePath = workspace.asRelativePath(doc.fileName); if (!editorconfigSettings) { - this.log(`${relativePath}: No configuration found for pre-save.`) - return [] + this.log(`${relativePath}: No configuration found for pre-save.`); + return []; } return [ - ...this.preSaveTransformations.flatMap(transformer => { - const { edits, message } = transformer.transform( - editorconfigSettings, - doc, - reason, - ) + ...this.preSaveTransformations.flatMap((transformer) => { + const { edits, message } = transformer.transform(editorconfigSettings, doc, reason); if (edits instanceof Error) { - this.log(`${relativePath}: ${edits.message}`) - return [] + this.log(`${relativePath}: ${edits.message}`); + return []; } if (message) { - this.log(`${relativePath}: ${message}`) + this.log(`${relativePath}: ${message}`); } - return edits + return edits; }), - ] + ]; } private async handleTextEditorChange(editor?: TextEditor) { if (editor?.document) { - const newOptions = await resolveTextEditorOptions( - (this.doc = editor.document), - { - onEmptyConfig: this.onEmptyConfig, - }, - ) + const newOptions = await resolveTextEditorOptions((this.doc = editor.document), { + onEmptyConfig: this.onEmptyConfig, + }); applyTextEditorOptions(newOptions, { onNoActiveTextEditor: this.onNoActiveTextEditor, onSuccess: this.onSuccess, - }) - this.handleDocumentEncoding(editor.document) + }); + this.handleDocumentEncoding(editor.document); } } private async handleDocumentEncoding(document: TextDocument) { - const relativePath = workspace.asRelativePath(document.fileName) + const relativePath = workspace.asRelativePath(document.fileName); const editorconfigSettings = await resolveCoreConfig(document, { onBeforeResolve: this.onBeforeResolve, - }) + }); - const { charset } = editorconfigSettings - this.log(`${relativePath}: Target charset is`, charset ?? 'not set') + const { charset } = editorconfigSettings; + this.log(`${relativePath}: Target charset is`, charset ?? "not set"); if (!charset) { - return + return; } if (!(charset in encodingMap)) { - this.log(`${relativePath}: Unsupported charset`) - return + this.log(`${relativePath}: Unsupported charset`); + return; } - const targetEncoding = encodingMap[charset as keyof typeof encodingMap] + const targetEncoding = encodingMap[charset as keyof typeof encodingMap]; if (targetEncoding === document.encoding) { - return + return; } if (document.isDirty) { - this.log(`${relativePath}: Cannot change encoding, document is dirty`) - return + this.log(`${relativePath}: Cannot change encoding, document is dirty`); + return; } - this.log(`${relativePath}: Re-opening document with ${targetEncoding} encoding...`) + this.log(`${relativePath}: Re-opening document with ${targetEncoding} encoding...`); await workspace.openTextDocument(document.uri, { encoding: targetEncoding, - }) + }); } } diff --git a/src/EditorConfigCompletionProvider.ts b/src/EditorConfigCompletionProvider.ts index a7c6860..2b72824 100644 --- a/src/EditorConfigCompletionProvider.ts +++ b/src/EditorConfigCompletionProvider.ts @@ -5,158 +5,143 @@ import { CompletionItemProvider, Position, TextDocument, -} from 'vscode' +} from "vscode"; class Property { - public name: string - public values: string[] - public description: string + public name: string; + public values: string[]; + public description: string; public constructor(name: string, values: string[], description: string) { - this.name = name - this.values = values - this.description = description + this.name = name; + this.values = values; + this.description = description; } } class EditorConfigCompletionProvider implements CompletionItemProvider { private readonly properties: Property[] = [ new Property( - 'root', - ['true', 'false', 'unset'], + "root", + ["true", "false", "unset"], [ - 'Special property that should be specified at the top of the file', - 'outside of any sections. Set to true to stop .editorconfig files', - 'search on current file.', - ].join(' '), + "Special property that should be specified at the top of the file", + "outside of any sections. Set to true to stop .editorconfig files", + "search on current file.", + ].join(" "), ), new Property( - 'charset', - ['utf-8', 'utf-8-bom', 'utf-16be', 'utf-16le', 'latin1', 'unset'], + "charset", + ["utf-8", "utf-8-bom", "utf-16be", "utf-16le", "latin1", "unset"], [ - 'Set to latin1, utf-8, utf-8-bom, utf-16be or utf-16le to control', - 'the character set. Use of utf-8-bom is discouraged.', - ].join(' '), + "Set to latin1, utf-8, utf-8-bom, utf-16be or utf-16le to control", + "the character set. Use of utf-8-bom is discouraged.", + ].join(" "), ), new Property( - 'end_of_line', - ['lf', 'cr', 'crlf', 'unset'], - 'Set to lf, cr, or crlf to control how line breaks are represented.', + "end_of_line", + ["lf", "cr", "crlf", "unset"], + "Set to lf, cr, or crlf to control how line breaks are represented.", ), new Property( - 'indent_style', - ['tab', 'space', 'unset'], - 'Set to tab or space to use hard tabs or soft tabs respectively.', + "indent_style", + ["tab", "space", "unset"], + "Set to tab or space to use hard tabs or soft tabs respectively.", ), new Property( - 'indent_size', - ['1', '2', '3', '4', '5', '6', '7', '8', 'tab', 'unset'], + "indent_size", + ["1", "2", "3", "4", "5", "6", "7", "8", "tab", "unset"], [ - 'A whole number defining the number of columns used for each', - 'indentation level and the width of soft tabs (when supported).', - 'When set to tab, the value of tab_width (if specified) will be', - 'used.', - ].join(' '), + "A whole number defining the number of columns used for each", + "indentation level and the width of soft tabs (when supported).", + "When set to tab, the value of tab_width (if specified) will be", + "used.", + ].join(" "), ), new Property( - 'insert_final_newline', - ['true', 'false', 'unset'], + "insert_final_newline", + ["true", "false", "unset"], [ - 'Set to true to ensure file ends with a newline when saving and', + "Set to true to ensure file ends with a newline when saving and", "false to ensure it doesn't.", - ].join(' '), + ].join(" "), ), new Property( - 'tab_width', - ['1', '2', '3', '4', '5', '6', '7', '8', 'unset'], + "tab_width", + ["1", "2", "3", "4", "5", "6", "7", "8", "unset"], [ - 'A whole number defining the number of columns used to represent a', - 'tab character. This defaults to the value of indent_size and', + "A whole number defining the number of columns used to represent a", + "tab character. This defaults to the value of indent_size and", "doesn't usually need to be specified.", - ].join(' '), + ].join(" "), ), new Property( - 'trim_trailing_whitespace', - ['true', 'false', 'unset'], + "trim_trailing_whitespace", + ["true", "false", "unset"], [ - 'Set to true to remove any whitespace characters preceding newline', + "Set to true to remove any whitespace characters preceding newline", "characters and false to ensure it doesn't.", - ].join(' '), + ].join(" "), ), - ] + ]; // ========================================================================= // PUBLIC INTERFACE // ========================================================================= - public provideCompletionItems( - document: TextDocument, - position: Position, - ): CompletionItem[] { + public provideCompletionItems(document: TextDocument, position: Position): CompletionItem[] { // get text where code completion was activated // used to determine if autocompleting a key or a value - const textOfEntireLine = document.getText( - document.lineAt(position.line).range, - ) - const textOfLineUpToCursor = textOfEntireLine.substring( - 0, - position.character, - ) + const textOfEntireLine = document.getText(document.lineAt(position.line).range); + const textOfLineUpToCursor = textOfEntireLine.substring(0, position.character); // conditionally generate autocomplete for property names or values if (this.hasPropertyKey(textOfLineUpToCursor)) { - return this.autoCompletePropertyValues(textOfLineUpToCursor) + return this.autoCompletePropertyValues(textOfLineUpToCursor); } else { - return this.autoCompletePropertyNames(textOfEntireLine) + return this.autoCompletePropertyNames(textOfEntireLine); } } public resolveCompletionItem(item: CompletionItem): CompletionItem { // return the item itself because it already contains all the info // necessary to display the details - return item + return item; } // ========================================================================= // AUTO COMPLETE // ========================================================================= - private autoCompletePropertyValues( - textOfLineUpToCursor: string, - ): CompletionItem[] { - const propertyName = this.extractPropertyName(textOfLineUpToCursor) - const propertyValues = this.filterPropertyValues(propertyName) - return this.convertPropertyValuesToCompletionItems(propertyValues) + private autoCompletePropertyValues(textOfLineUpToCursor: string): CompletionItem[] { + const propertyName = this.extractPropertyName(textOfLineUpToCursor); + const propertyValues = this.filterPropertyValues(propertyName); + return this.convertPropertyValuesToCompletionItems(propertyValues); } - private autoCompletePropertyNames( - textOfEntireLine: string, - ): CompletionItem[] { - return this.convertPropertyNamesToCompletionItems( - this.properties, - textOfEntireLine, - ) + private autoCompletePropertyNames(textOfEntireLine: string): CompletionItem[] { + return this.convertPropertyNamesToCompletionItems(this.properties, textOfEntireLine); } // ========================================================================= // CHECKS // ========================================================================= private hasPropertyKey(lineText: string): boolean { - return this.hasEqualsSign(lineText) + return this.hasEqualsSign(lineText); } private hasEqualsSign(lineText: string): boolean { - return lineText.indexOf('=') >= 0 + return lineText.indexOf("=") >= 0; } // ========================================================================= // PARSER // ========================================================================= private extractPropertyName(lineText: string): string { - const lineTextParts = lineText.split('=') + const lineTextParts = lineText.split("="); if (lineTextParts.length === 0) { - return '' + return ""; } - const propertyName = lineTextParts[0].trim().toLowerCase() - return propertyName + const propertyName = lineTextParts[0].trim().toLowerCase(); + return propertyName; } // ========================================================================= @@ -164,17 +149,15 @@ class EditorConfigCompletionProvider implements CompletionItemProvider { // ========================================================================= private filterPropertyValues(propertyName: string): string[] { // filter - const matchingProperty = this.properties.find( - property => property.name === propertyName, - ) + const matchingProperty = this.properties.find((property) => property.name === propertyName); // if not found anything, there are no values to display if (matchingProperty === undefined) { - return [] + return []; } // return values of the property - return matchingProperty.values + return matchingProperty.values; } // ========================================================================= @@ -185,48 +168,43 @@ class EditorConfigCompletionProvider implements CompletionItemProvider { textOfEntireLine: string, ): CompletionItem[] { const triggerSuggestCommand: Command = { - command: 'editorconfig._triggerSuggestAfterDelay', + command: "editorconfig._triggerSuggestAfterDelay", arguments: [], - title: '', - } + title: "", + }; - return properties.map(property => { + return properties.map((property) => { // basic info - const completionItem = new CompletionItem( - property.name, - CompletionItemKind.Property, - ) - completionItem.documentation = property.description + const completionItem = new CompletionItem(property.name, CompletionItemKind.Property); + completionItem.documentation = property.description; // append equals sign if line does not have one // also automatically displays IntelliSense for property values if (!this.hasEqualsSign(textOfEntireLine)) { - completionItem.insertText = property.name + ' = ' - completionItem.command = triggerSuggestCommand + completionItem.insertText = property.name + " = "; + completionItem.command = triggerSuggestCommand; } - return completionItem - }) + return completionItem; + }); } - private convertPropertyValuesToCompletionItems( - values: string[], - ): CompletionItem[] { + private convertPropertyValuesToCompletionItems(values: string[]): CompletionItem[] { const valuesSortOrder = { - true: '1', - false: '2', - unset: '9', - } - return values.map(value => { + true: "1", + false: "2", + unset: "9", + }; + return values.map((value) => { // basic info - const completionItem = new CompletionItem(value, CompletionItemKind.Value) + const completionItem = new CompletionItem(value, CompletionItemKind.Value); // sort predefined values to specific order completionItem.sortText = - valuesSortOrder[value as keyof typeof valuesSortOrder] || '3' + value - return completionItem - }) + valuesSortOrder[value as keyof typeof valuesSortOrder] || "3" + value; + return completionItem; + }); } } -export default EditorConfigCompletionProvider +export default EditorConfigCompletionProvider; diff --git a/src/api.ts b/src/api.ts index 342557d..fff5b47 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,5 +1,5 @@ -import * as editorconfig from 'editorconfig' -import { TextDocument, TextEditorOptions, Uri, window, workspace } from 'vscode' +import * as editorconfig from "editorconfig"; +import { TextDocument, TextEditorOptions, Uri, window, workspace } from "vscode"; /** * Resolves `TextEditorOptions` for a `TextDocument`, combining the editor's @@ -11,24 +11,24 @@ export async function resolveTextEditorOptions( onBeforeResolve, onEmptyConfig, }: { - onBeforeResolve?: (relativePath: string) => void - onEmptyConfig?: (relativePath: string) => void + onBeforeResolve?: (relativePath: string) => void; + onEmptyConfig?: (relativePath: string) => void; } = {}, ) { - const coreConfig = await resolveCoreConfig(doc, { onBeforeResolve }) + const coreConfig = await resolveCoreConfig(doc, { onBeforeResolve }); if (coreConfig) { - const defaults = pickWorkspaceDefaults(doc) - const { activeTextEditor: editor } = window - const current = editor?.document === doc ? editor.options : undefined - return fromEditorConfig(coreConfig, defaults, current) + const defaults = pickWorkspaceDefaults(doc); + const { activeTextEditor: editor } = window; + const current = editor?.document === doc ? editor.options : undefined; + return fromEditorConfig(coreConfig, defaults, current); } if (onEmptyConfig) { - const { relativePath } = resolveFile(doc) + const { relativePath } = resolveFile(doc); if (relativePath) { - onEmptyConfig(relativePath) + onEmptyConfig(relativePath); } } - return {} + return {}; } /** @@ -40,22 +40,22 @@ export async function applyTextEditorOptions( onNoActiveTextEditor, onSuccess, }: { - onNoActiveTextEditor?: () => void - onSuccess?: (newOptions: TextEditorOptions) => void + onNoActiveTextEditor?: () => void; + onSuccess?: (newOptions: TextEditorOptions) => void; } = {}, ) { - const editor = window.activeTextEditor + const editor = window.activeTextEditor; if (!editor) { if (onNoActiveTextEditor) { - onNoActiveTextEditor() + onNoActiveTextEditor(); } - return + return; } - editor.options = newOptions + editor.options = newOptions; if (onSuccess) { - onSuccess(newOptions) + onSuccess(newOptions); } } @@ -67,32 +67,32 @@ export function pickWorkspaceDefaults(doc?: TextDocument): { * The number of spaces a tab is equal to. When `editor.detectIndentation` * is on, this property value will be `undefined`. */ - tabSize?: number + tabSize?: number; /** * Insert spaces when pressing `Tab`. When `editor.detectIndentation` is on, * this property value will be `undefined`. */ - insertSpaces?: boolean + insertSpaces?: boolean; /** * The number of spaces used for indentation or `undefined` if * `editor.detectIndentation` is on. */ - indentSize?: number | string + indentSize?: number | string; } { - const workspaceConfig = workspace.getConfiguration('editor', doc) - const detectIndentation = workspaceConfig.get('detectIndentation') + const workspaceConfig = workspace.getConfiguration("editor", doc); + const detectIndentation = workspaceConfig.get("detectIndentation"); return detectIndentation ? {} : { - tabSize: workspaceConfig.get('tabSize'), - indentSize: workspaceConfig.get('indentSize'), - insertSpaces: workspaceConfig.get('insertSpaces'), - } + tabSize: workspaceConfig.get("tabSize"), + indentSize: workspaceConfig.get("indentSize"), + insertSpaces: workspaceConfig.get("insertSpaces"), + }; } export type ResolvedCoreConfig = editorconfig.KnownProps & - Record + Record; /** * Resolves an EditorConfig configuration for the file related to a @@ -100,42 +100,40 @@ export type ResolvedCoreConfig = editorconfig.KnownProps & */ export async function resolveCoreConfig( doc: TextDocument, - { - onBeforeResolve, - }: { onBeforeResolve?: (relativePath: string) => void } = {}, + { onBeforeResolve }: { onBeforeResolve?: (relativePath: string) => void } = {}, ): Promise { - const { fileName, relativePath } = resolveFile(doc) + const { fileName, relativePath } = resolveFile(doc); if (!fileName) { - return {} + return {}; } if (relativePath) { - onBeforeResolve?.(relativePath) + onBeforeResolve?.(relativePath); } - const config = await editorconfig.parse(fileName) - return config as ResolvedCoreConfig + const config = await editorconfig.parse(fileName); + return config as ResolvedCoreConfig; } export function resolveFile(doc: TextDocument): { - fileName?: string - relativePath?: string + fileName?: string; + relativePath?: string; } { - if (doc.languageId === 'Log') { - return {} + if (doc.languageId === "Log") { + return {}; } - const file = getFile() + const file = getFile(); return { fileName: file?.fsPath, relativePath: file && workspace.asRelativePath(file, true), - } + }; function getFile(): Uri | undefined { if (!doc.isUntitled) { - return doc.uri + return doc.uri; } if (workspace.workspaceFolders?.[0]) { - return Uri.joinPath(workspace.workspaceFolders[0].uri, doc.fileName) + return Uri.joinPath(workspace.workspaceFolders[0].uri, doc.fileName); } - return undefined + return undefined; } } @@ -147,72 +145,69 @@ export function fromEditorConfig( defaults: TextEditorOptions = pickWorkspaceDefaults(), current?: TextEditorOptions, ): TextEditorOptions { - const resolved: TextEditorOptions = {} + const resolved: TextEditorOptions = {}; if (Number.isInteger(config.indent_size)) { - resolved.indentSize = config.indent_size - } else if (config.indent_size === 'tab') { - resolved.indentSize = 'tabSize' + resolved.indentSize = config.indent_size; + } else if (config.indent_size === "tab") { + resolved.indentSize = "tabSize"; } if (Number.isInteger(config.tab_width)) { - resolved.tabSize = config.tab_width - } else if ( - Number.isInteger(config.indent_size) && - config.tab_width !== 'unset' - ) { - resolved.tabSize = config.indent_size + resolved.tabSize = config.tab_width; + } else if (Number.isInteger(config.indent_size) && config.tab_width !== "unset") { + resolved.tabSize = config.indent_size; } - if (config.indent_style === 'tab') { - resolved.insertSpaces = false - } else if (config.indent_style === 'space') { - resolved.insertSpaces = true + if (config.indent_style === "tab") { + resolved.insertSpaces = false; + } else if (config.indent_style === "space") { + resolved.insertSpaces = true; } - const combined = { ...current, ...defaults, ...resolved } + const combined = { ...current, ...defaults, ...resolved }; // decouple tabSize from indentSize when possible if ( !Number.isInteger(config.tab_width) && - !(combined.insertSpaces && combined.indentSize === 'tabSize') && - !(config.indent_style === 'tab' && Number.isInteger(config.indent_size)) && + !(combined.insertSpaces && combined.indentSize === "tabSize") && + !(config.indent_style === "tab" && Number.isInteger(config.indent_size)) && Number.isInteger(defaults.tabSize) ) { - combined.tabSize = defaults.tabSize + combined.tabSize = defaults.tabSize; } - return combined + return combined; } /** * Convert vscode editor options to .editorconfig values */ export function toEditorConfig(options: TextEditorOptions) { - const result: editorconfig.KnownProps = {} + const result: editorconfig.KnownProps = {}; switch (options.insertSpaces) { case true: - result.indent_style = 'space' + result.indent_style = "space"; if (options.tabSize) { - result.indent_size = resolveTabSize(options.tabSize) + result.indent_size = resolveTabSize(options.tabSize); } - break + break; case false: - case 'auto': - result.indent_style = 'tab' + case "auto": + result.indent_style = "tab"; if (options.tabSize) { - result.tab_width = resolveTabSize(options.tabSize) + result.tab_width = resolveTabSize(options.tabSize); } - break + break; } - return result + return result; /** * Convert vscode tabSize option into numeric value */ function resolveTabSize(tabSize: number | string) { - return tabSize === 'auto' ? 4 : parseInt(String(tabSize), 10) + return tabSize === "auto" ? 4 : parseInt(String(tabSize), 10); } } diff --git a/src/commands/generateEditorConfig.ts b/src/commands/generateEditorConfig.ts index 137ef13..14a06ff 100644 --- a/src/commands/generateEditorConfig.ts +++ b/src/commands/generateEditorConfig.ts @@ -1,175 +1,157 @@ -import { readFile as _readFile } from 'fs' -import { EOL } from 'os' -import { resolve } from 'path' -import { promisify } from 'util' -import { FileType, Uri, window, workspace } from 'vscode' +import { readFile as _readFile } from "fs"; +import { EOL } from "os"; +import { resolve } from "path"; +import { promisify } from "util"; +import { FileType, Uri, window, workspace } from "vscode"; -const readFile = promisify(_readFile) +const readFile = promisify(_readFile); /** * Generate a .editorconfig file in the root of the workspace based on the * current vscode settings. */ export async function generateEditorConfig(uri: Uri) { - const workspaceUri = workspace.workspaceFolders?.[0].uri - const currentUri = uri || workspaceUri + const workspaceUri = workspace.workspaceFolders?.[0].uri; + const currentUri = uri || workspaceUri; if (!currentUri) { - window.showErrorMessage("Workspace doesn't contain any folders.") - return + window.showErrorMessage("Workspace doesn't contain any folders."); + return; } - const editorConfigUri = Uri.parse(`${currentUri.toString()}/.editorconfig`) + const editorConfigUri = Uri.parse(`${currentUri.toString()}/.editorconfig`); try { - const stats = await workspace.fs.stat(editorConfigUri) + const stats = await workspace.fs.stat(editorConfigUri); if (stats.type === FileType.File) { - window.showErrorMessage( - 'An .editorconfig file already exists in this workspace.', - ) - return + window.showErrorMessage("An .editorconfig file already exists in this workspace."); + return; } } catch (err: unknown) { if ( - typeof err === 'object' && + typeof err === "object" && err !== null && - 'name' in err && - 'message' in err && - typeof err.message === 'string' + "name" in err && + "message" in err && + typeof err.message === "string" ) { - if (err.name === 'EntryNotFound (FileSystemError)') { - writeFile() + if (err.name === "EntryNotFound (FileSystemError)") { + writeFile(); } else { - window.showErrorMessage(err.message) + window.showErrorMessage(err.message); } - return + return; } } async function writeFile() { - const ec = workspace.getConfiguration('editorconfig') - const generateAuto = !!ec.get('generateAuto') + const ec = workspace.getConfiguration("editorconfig"); + const generateAuto = !!ec.get("generateAuto"); if (!generateAuto) { - const template = ec.get('template') || 'default' - const defaultTemplatePath = resolve( - __dirname, - '..', - 'DefaultTemplate.editorconfig', - ) - - let templateBuffer: Buffer + const template = ec.get("template") || "default"; + const defaultTemplatePath = resolve(__dirname, "..", "DefaultTemplate.editorconfig"); + + let templateBuffer: Buffer; try { templateBuffer = await readFile( /^default$/i.test(template) ? defaultTemplatePath : template, - ) + ); } catch (error) { if ( - typeof error !== 'object' || + typeof error !== "object" || error === null || - !('message' in error) || - typeof error.message !== 'string' + !("message" in error) || + typeof error.message !== "string" ) { - return + return; } window.showErrorMessage( - [ - `Could not read EditorConfig template file at ${template}`, - error.message, - ].join(EOL), - ) - return + [`Could not read EditorConfig template file at ${template}`, error.message].join(EOL), + ); + return; } try { - workspace.fs.writeFile(editorConfigUri, templateBuffer) + workspace.fs.writeFile(editorConfigUri, templateBuffer); } catch (error) { if ( - typeof error !== 'object' || + typeof error !== "object" || error === null || - !('message' in error) || - typeof error.message !== 'string' + !("message" in error) || + typeof error.message !== "string" ) { - return + return; } - window.showErrorMessage(error.message) + window.showErrorMessage(error.message); } - return + return; } - const editor = workspace.getConfiguration('editor', currentUri) - const files = workspace.getConfiguration('files', currentUri) + const editor = workspace.getConfiguration("editor", currentUri); + const files = workspace.getConfiguration("files", currentUri); const settingsLines = [ - '# EditorConfig is awesome: https://EditorConfig.org', - '', - '# top-most EditorConfig file', - 'root = true', - '', - '[*]', - ] + "# EditorConfig is awesome: https://EditorConfig.org", + "", + "# top-most EditorConfig file", + "root = true", + "", + "[*]", + ]; function addSetting(key: string, value?: string | number | boolean): void { if (value !== undefined) { - settingsLines.push(`${key} = ${value}`) + settingsLines.push(`${key} = ${value}`); } } - const insertSpaces = !!editor.get('insertSpaces') + const insertSpaces = !!editor.get("insertSpaces"); - addSetting('indent_style', insertSpaces ? 'space' : 'tab') + addSetting("indent_style", insertSpaces ? "space" : "tab"); - addSetting('indent_size', editor.get('tabSize')) + addSetting("indent_size", editor.get("tabSize")); const eolMap = { - '\r\n': 'crlf', - '\n': 'lf', - } - let eolKey = files.get('eol') || 'auto' - if (eolKey === 'auto') { - eolKey = EOL + "\r\n": "crlf", + "\n": "lf", + }; + let eolKey = files.get("eol") || "auto"; + if (eolKey === "auto") { + eolKey = EOL; } - addSetting('end_of_line', eolMap[eolKey as keyof typeof eolMap]) + addSetting("end_of_line", eolMap[eolKey as keyof typeof eolMap]); const encodingMap = { - iso88591: 'latin1', - utf8: 'utf-8', - utf8bom: 'utf-8-bom', - utf16be: 'utf-16-be', - utf16le: 'utf-16-le', - } - addSetting( - 'charset', - encodingMap[files.get('encoding') as keyof typeof encodingMap], - ) + iso88591: "latin1", + utf8: "utf-8", + utf8bom: "utf-8-bom", + utf16be: "utf-16-be", + utf16le: "utf-16-le", + }; + addSetting("charset", encodingMap[files.get("encoding") as keyof typeof encodingMap]); - addSetting( - 'trim_trailing_whitespace', - !!files.get('trimTrailingWhitespace'), - ) + addSetting("trim_trailing_whitespace", !!files.get("trimTrailingWhitespace")); - const insertFinalNewline = !!files.get('insertFinalNewline') - addSetting('insert_final_newline', insertFinalNewline) + const insertFinalNewline = !!files.get("insertFinalNewline"); + addSetting("insert_final_newline", insertFinalNewline); if (insertFinalNewline) { - settingsLines.push('') + settingsLines.push(""); } try { - await workspace.fs.writeFile( - editorConfigUri, - Buffer.from(settingsLines.join(eolKey)), - ) + await workspace.fs.writeFile(editorConfigUri, Buffer.from(settingsLines.join(eolKey))); } catch (err) { if ( - typeof err !== 'object' || + typeof err !== "object" || err === null || - !('message' in err) || - typeof err.message !== 'string' + !("message" in err) || + typeof err.message !== "string" ) { - return + return; } - window.showErrorMessage(err.message) + window.showErrorMessage(err.message); } } } diff --git a/src/editorConfigMain.ts b/src/editorConfigMain.ts index 346d63b..d41cf64 100644 --- a/src/editorConfigMain.ts +++ b/src/editorConfigMain.ts @@ -1,42 +1,42 @@ -import { commands, DocumentSelector, ExtensionContext, languages } from 'vscode' +import { commands, DocumentSelector, ExtensionContext, languages } from "vscode"; import { applyTextEditorOptions, fromEditorConfig, resolveCoreConfig, resolveTextEditorOptions, toEditorConfig, -} from './api' -import { generateEditorConfig } from './commands/generateEditorConfig' -import DocumentWatcher from './DocumentWatcher' -import EditorConfigCompletionProvider from './EditorConfigCompletionProvider' +} from "./api"; +import { generateEditorConfig } from "./commands/generateEditorConfig"; +import DocumentWatcher from "./DocumentWatcher"; +import EditorConfigCompletionProvider from "./EditorConfigCompletionProvider"; /** * Main entry */ export function activate(ctx: ExtensionContext) { - ctx.subscriptions.push(new DocumentWatcher()) + ctx.subscriptions.push(new DocumentWatcher()); // register .editorconfig file completion provider const editorConfigFileSelector: DocumentSelector = { - language: 'editorconfig', - pattern: '**/.editorconfig', - scheme: 'file', - } + language: "editorconfig", + pattern: "**/.editorconfig", + scheme: "file", + }; languages.registerCompletionItemProvider( editorConfigFileSelector, new EditorConfigCompletionProvider(), - ) + ); // register an internal command used to automatically display IntelliSense // when editing a .editorconfig file - commands.registerCommand('editorconfig._triggerSuggestAfterDelay', () => { + commands.registerCommand("editorconfig._triggerSuggestAfterDelay", () => { setTimeout(() => { - commands.executeCommand('editor.action.triggerSuggest') - }, 100) - }) + commands.executeCommand("editor.action.triggerSuggest"); + }, 100); + }); // register a command handler to generate a .editorconfig file - commands.registerCommand('EditorConfig.generate', generateEditorConfig) + commands.registerCommand("EditorConfig.generate", generateEditorConfig); return { applyTextEditorOptions, @@ -44,5 +44,5 @@ export function activate(ctx: ExtensionContext) { resolveCoreConfig, resolveTextEditorOptions, toEditorConfig, - } + }; } diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 01b1759..8c377de 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -1,42 +1,36 @@ -import * as path from 'path' +import * as path from "path"; -import { runTests } from '@vscode/test-electron' +import { runTests } from "@vscode/test-electron"; async function main() { try { // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../') + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); // The path to the extension test script // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/index') + const extensionTestsPath = path.resolve(__dirname, "./suite/index"); // Download VS Code, unzip it and run the integration test await runTests({ extensionDevelopmentPath, extensionTestsPath, - launchArgs: ['--disable-extensions'], - }) + launchArgs: ["--disable-extensions"], + }); // Run test using a specific workspace - const untitledExtensionTestsPath = path.resolve( - __dirname, - './untitled-suite/index', - ) - const untitledWorkspace = path.resolve( - __dirname, - './untitled-suite/fixtures/untitled', - ) + const untitledExtensionTestsPath = path.resolve(__dirname, "./untitled-suite/index"); + const untitledWorkspace = path.resolve(__dirname, "./untitled-suite/fixtures/untitled"); await runTests({ extensionDevelopmentPath, extensionTestsPath: untitledExtensionTestsPath, - launchArgs: [untitledWorkspace, '--disable-extensions'], - }) + launchArgs: [untitledWorkspace, "--disable-extensions"], + }); } catch { - console.error('Failed to run tests') - process.exit(1) + console.error("Failed to run tests"); + process.exit(1); } } -main() +main(); diff --git a/src/test/suite/api.test.ts b/src/test/suite/api.test.ts index 2eb9df9..62921c4 100644 --- a/src/test/suite/api.test.ts +++ b/src/test/suite/api.test.ts @@ -1,20 +1,20 @@ -import * as assert from 'assert' -import { KnownProps } from 'editorconfig' -import { TextEditorOptions } from 'vscode' +import * as assert from "assert"; +import { KnownProps } from "editorconfig"; +import { TextEditorOptions } from "vscode"; -import * as api from '../../api' +import * as api from "../../api"; -suite('EditorConfig extension', () => { +suite("EditorConfig extension", () => { // Defines a Mocha unit test - test('api.fromEditorConfig', () => { + test("api.fromEditorConfig", () => { const scenarios: { - config: KnownProps - defaults: TextEditorOptions - expected: TextEditorOptions + config: KnownProps; + defaults: TextEditorOptions; + expected: TextEditorOptions; }[] = [ { config: { - indent_style: 'tab', + indent_style: "tab", indent_size: 5, }, defaults: { @@ -29,7 +29,7 @@ suite('EditorConfig extension', () => { }, { config: { - indent_style: 'tab', + indent_style: "tab", tab_width: 5, }, defaults: { @@ -43,7 +43,7 @@ suite('EditorConfig extension', () => { }, { config: { - indent_style: 'space', + indent_style: "space", indent_size: 5, }, defaults: { @@ -112,7 +112,7 @@ suite('EditorConfig extension', () => { }, { config: { - indent_style: 'space', + indent_style: "space", }, defaults: { insertSpaces: false, @@ -125,7 +125,7 @@ suite('EditorConfig extension', () => { }, { config: { - indent_style: 'space', + indent_style: "space", }, defaults: { insertSpaces: false, @@ -138,7 +138,7 @@ suite('EditorConfig extension', () => { }, { config: { - indent_size: 'tab', + indent_size: "tab", tab_width: 3, }, defaults: { @@ -148,7 +148,7 @@ suite('EditorConfig extension', () => { expected: { insertSpaces: false, tabSize: 3, - indentSize: 'tabSize', + indentSize: "tabSize", }, }, { @@ -176,7 +176,7 @@ suite('EditorConfig extension', () => { { config: { indent_size: 2, - indent_style: 'space', + indent_style: "space", tab_width: 4, }, defaults: {}, @@ -188,9 +188,9 @@ suite('EditorConfig extension', () => { }, { config: { - indent_style: 'tab', + indent_style: "tab", indent_size: 8, - tab_width: 'unset', + tab_width: "unset", }, defaults: { tabSize: 2, @@ -201,19 +201,19 @@ suite('EditorConfig extension', () => { tabSize: 2, }, }, - ] - scenarios.forEach(scenario => { + ]; + scenarios.forEach((scenario) => { assert.deepStrictEqual( api.fromEditorConfig(scenario.config, scenario.defaults), scenario.expected, - ) - }) - }) + ); + }); + }); - test('api.toEditorConfig', () => { + test("api.toEditorConfig", () => { const scenarios: { - options: TextEditorOptions - expected: KnownProps + options: TextEditorOptions; + expected: KnownProps; }[] = [ { options: { @@ -221,7 +221,7 @@ suite('EditorConfig extension', () => { tabSize: 5, }, expected: { - indent_style: 'space', + indent_style: "space", indent_size: 5, }, }, @@ -231,46 +231,43 @@ suite('EditorConfig extension', () => { tabSize: 6, }, expected: { - indent_style: 'tab', + indent_style: "tab", tab_width: 6, }, }, { options: { insertSpaces: false, - tabSize: 'auto', + tabSize: "auto", }, expected: { - indent_style: 'tab', + indent_style: "tab", tab_width: 4, }, }, { options: { - insertSpaces: 'auto', + insertSpaces: "auto", tabSize: 7, }, expected: { - indent_style: 'tab', + indent_style: "tab", tab_width: 7, }, }, { options: { - insertSpaces: 'auto', - tabSize: 'auto', + insertSpaces: "auto", + tabSize: "auto", }, expected: { - indent_style: 'tab', + indent_style: "tab", tab_width: 4, }, }, - ] - scenarios.forEach(scenario => { - assert.deepStrictEqual( - api.toEditorConfig(scenario.options), - scenario.expected, - ) - }) - }) -}) + ]; + scenarios.forEach((scenario) => { + assert.deepStrictEqual(api.toEditorConfig(scenario.options), scenario.expected); + }); + }); +}); diff --git a/src/test/suite/index.test.ts b/src/test/suite/index.test.ts index 2d979c7..1146162 100644 --- a/src/test/suite/index.test.ts +++ b/src/test/suite/index.test.ts @@ -1,407 +1,325 @@ -import * as assert from 'assert' -import * as os from 'os' -import { Position, window, workspace, WorkspaceEdit } from 'vscode' -import { getFixturePath, getOptionsForFixture, wait } from '../testUtils' +import * as assert from "assert"; +import * as os from "os"; +import { Position, window, workspace, WorkspaceEdit } from "vscode"; +import { getFixturePath, getOptionsForFixture, wait } from "../testUtils"; -import * as utils from 'vscode-test-utils' +import * as utils from "vscode-test-utils"; -suite('EditorConfig extension', function () { - this.retries(2) - suiteTeardown(utils.closeAllFiles) +suite("EditorConfig extension", function () { + this.retries(2); + suiteTeardown(utils.closeAllFiles); - test('indent_style = tab; tab_width = n', async () => { + test("indent_style = tab; tab_width = n", async () => { for (const n of [2, 3, 4]) { - const options = await getOptionsForFixture([`tab-width-${n}`]) - assert.strictEqual( - options.insertSpaces, - false, - `editor has insertSpaces: true`, - ) + const options = await getOptionsForFixture([`tab-width-${n}`]); + assert.strictEqual(options.insertSpaces, false, `editor has insertSpaces: true`); assert.strictEqual( options.tabSize, n, `editor has a tabSize of ${options.tabSize} instead of ${n}`, - ) + ); } - }) + }); - test('indent_style = space; indent_size = n', async () => { + test("indent_style = space; indent_size = n", async () => { for (const n of [2, 3, 4]) { - const options = await getOptionsForFixture([`indent-size-${n}`]) - assert.strictEqual( - options.insertSpaces, - true, - `editor has insertSpaces: false`, - ) + const options = await getOptionsForFixture([`indent-size-${n}`]); + assert.strictEqual(options.insertSpaces, true, `editor has insertSpaces: false`); assert.strictEqual( options.tabSize, n, `editor has a tabSize of ${options.tabSize} instead of ${n}`, - ) + ); } - }) + }); - test('subfolder settings', async () => { - for (const n of [2, 3, 4, 'x']) { - const options = await getOptionsForFixture(['folder', `tab-width-${n}`]) - const expectedTabSize = n === 'x' ? 8 : n - assert.strictEqual( - options.insertSpaces, - false, - `editor has insertSpaces: true`, - ) + test("subfolder settings", async () => { + for (const n of [2, 3, 4, "x"]) { + const options = await getOptionsForFixture(["folder", `tab-width-${n}`]); + const expectedTabSize = n === "x" ? 8 : n; + assert.strictEqual(options.insertSpaces, false, `editor has insertSpaces: true`); assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); } - }) + }); - test('insert_final_newline = true', async () => { - const savedText = await withSetting( - 'insert_final_newline', - 'true', - ).saveText('foo') - assert.strictEqual( - savedText, - `foo${os.EOL}`, - 'editor fails to insert final newline on save', - ) - }) + test("insert_final_newline = true", async () => { + const savedText = await withSetting("insert_final_newline", "true").saveText("foo"); + assert.strictEqual(savedText, `foo${os.EOL}`, "editor fails to insert final newline on save"); + }); - test('insert_final_newline = false', async () => { - const text = `foo${os.EOL}` - const savedText = await withSetting( - 'insert_final_newline', - 'false', - ).saveText(text) - assert.strictEqual( - savedText, - text, - 'editor fails to preserve final newline on save', - ) - }) + test("insert_final_newline = false", async () => { + const text = `foo${os.EOL}`; + const savedText = await withSetting("insert_final_newline", "false").saveText(text); + assert.strictEqual(savedText, text, "editor fails to preserve final newline on save"); + }); - test('insert_final_newline = unset', async () => { - const text = `foo${os.EOL}` - const savedText1 = await withSetting( - 'insert_final_newline', - 'unset', - ).saveText(text) - assert.strictEqual( - savedText1, - text, - 'editor fails to preserve final newline on save', - ) + test("insert_final_newline = unset", async () => { + const text = `foo${os.EOL}`; + const savedText1 = await withSetting("insert_final_newline", "unset").saveText(text); + assert.strictEqual(savedText1, text, "editor fails to preserve final newline on save"); - const savedText2 = await withSetting( - 'insert_final_newline', - 'unset-2', - ).saveText('foo') - assert.strictEqual( - savedText2, - 'foo', - 'editor fails to preserve no final newline on save', - ) - }) + const savedText2 = await withSetting("insert_final_newline", "unset-2").saveText("foo"); + assert.strictEqual(savedText2, "foo", "editor fails to preserve no final newline on save"); + }); - test('trim_trailing_whitespace = true', async () => { - const savedText = await withSetting( - 'trim_trailing_whitespace', - 'true', - ).saveText('foo ') - assert.strictEqual( - savedText, - 'foo', - 'editor fails to trim trailing whitespace on save', - ) - }) + test("trim_trailing_whitespace = true", async () => { + const savedText = await withSetting("trim_trailing_whitespace", "true").saveText("foo "); + assert.strictEqual(savedText, "foo", "editor fails to trim trailing whitespace on save"); + }); - test('trim_trailing_whitespace = false', async () => { - const savedText = await withSetting( - 'trim_trailing_whitespace', - 'false', - ).saveText('foo ') - assert.strictEqual( - savedText, - 'foo ', - 'editor fails to preserve trailing whitespace on save', - ) - }) + test("trim_trailing_whitespace = false", async () => { + const savedText = await withSetting("trim_trailing_whitespace", "false").saveText("foo "); + assert.strictEqual(savedText, "foo ", "editor fails to preserve trailing whitespace on save"); + }); - test('trim_trailing_whitespace = unset', async () => { - const savedText = await withSetting( - 'trim_trailing_whitespace', - 'unset', - ).saveText('foo ') - assert.strictEqual( - savedText, - 'foo ', - 'editor fails to preserve trailing whitespace on save', - ) - }) + test("trim_trailing_whitespace = unset", async () => { + const savedText = await withSetting("trim_trailing_whitespace", "unset").saveText("foo "); + assert.strictEqual(savedText, "foo ", "editor fails to preserve trailing whitespace on save"); + }); - test('end_of_line = lf', async () => { - const savedText = await withSetting('end_of_line', 'lf').saveText('foo\r\n') + test("end_of_line = lf", async () => { + const savedText = await withSetting("end_of_line", "lf").saveText("foo\r\n"); assert.strictEqual( savedText, - 'foo\n', - 'editor fails to convert CRLF line endings into LF on save', - ) - }) + "foo\n", + "editor fails to convert CRLF line endings into LF on save", + ); + }); - test('end_of_line = crlf', async () => { - const savedText = await withSetting('end_of_line', 'crlf').saveText('foo\n') + test("end_of_line = crlf", async () => { + const savedText = await withSetting("end_of_line", "crlf").saveText("foo\n"); assert.strictEqual( savedText, - 'foo\r\n', - 'editor fails to convert LF line endings into CRLF on save', - ) - }) + "foo\r\n", + "editor fails to convert LF line endings into CRLF on save", + ); + }); - test('end_of_line = unset', async () => { - const savedText = await withSetting('end_of_line', 'unset', { - contents: '\r\n', - }).saveText('foo') - assert.strictEqual( - savedText, - 'foo\r\n', - 'editor fails to preserve CRLF line endings on save', - ) - }) + test("end_of_line = unset", async () => { + const savedText = await withSetting("end_of_line", "unset", { + contents: "\r\n", + }).saveText("foo"); + assert.strictEqual(savedText, "foo\r\n", "editor fails to preserve CRLF line endings on save"); + }); - test('detect indentation (space, empty root)', async () => { + test("detect indentation (space, empty root)", async () => { const options = await getOptionsForFixture([ - 'detect-indentation', - 'root', - 'indent-style-space', - ]) - const expectedTabSize = 2 + "detect-indentation", + "root", + "indent-style-space", + ]); + const expectedTabSize = 2; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.insertSpaces, true, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('detect indentation (tab, empty root)', async () => { - const options = await getOptionsForFixture([ - 'detect-indentation', - 'root', - 'indent-style-tab', - ]) - const expectedTabSize = 4 + test("detect indentation (tab, empty root)", async () => { + const options = await getOptionsForFixture(["detect-indentation", "root", "indent-style-tab"]); + const expectedTabSize = 4; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.insertSpaces, false, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('detect indentation (space, unset tab_width=8)', async () => { + test("detect indentation (space, unset tab_width=8)", async () => { const options = await getOptionsForFixture([ - 'detect-indentation', - 'tab_width', - 'indent-style-space', - ]) - const expectedTabSize = 8 - const expectedIndentSize = 2 + "detect-indentation", + "tab_width", + "indent-style-space", + ]); + const expectedTabSize = 8; + const expectedIndentSize = 2; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.indentSize, expectedIndentSize, `editor has an indentSize of ${options.indentSize} instead of ${expectedIndentSize}`, - ) + ); assert.strictEqual( options.insertSpaces, true, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('detect indentation (tab, unset tab_width=4)', async () => { + test("detect indentation (tab, unset tab_width=4)", async () => { const options = await getOptionsForFixture([ - 'detect-indentation', - 'tab_width', - 'indent-style-tab', - ]) - const expectedTabSize = 8 - const expectedIndentSize = 4 + "detect-indentation", + "tab_width", + "indent-style-tab", + ]); + const expectedTabSize = 8; + const expectedIndentSize = 4; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.indentSize, expectedIndentSize, `editor has an indentSize of ${options.indentSize} instead of ${expectedIndentSize}`, - ) + ); assert.strictEqual( options.insertSpaces, false, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('detect indentation (space, unset)', async () => { + test("detect indentation (space, unset)", async () => { const options = await getOptionsForFixture([ - 'detect-indentation', - 'unset', - 'indent-style-space', - ]) - const expectedTabSize = 2 + "detect-indentation", + "unset", + "indent-style-space", + ]); + const expectedTabSize = 2; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.insertSpaces, true, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('detect indentation (tab, unset)', async () => { - const options = await getOptionsForFixture([ - 'detect-indentation', - 'unset', - 'indent-style-tab', - ]) - const expectedTabSize = 4 + test("detect indentation (tab, unset)", async () => { + const options = await getOptionsForFixture(["detect-indentation", "unset", "indent-style-tab"]); + const expectedTabSize = 4; assert.strictEqual( options.tabSize, expectedTabSize, `editor has a tabSize of ${options.tabSize} instead of ${expectedTabSize}`, - ) + ); assert.strictEqual( options.insertSpaces, false, `editor has insertSpaces: ${options.insertSpaces}`, - ) - }) + ); + }); - test('keep selection on format', async () => { - await withSetting('insert_final_newline', 'true', { - fileName: 'test-selection', - }).saveText('foobar') - assert(window.activeTextEditor, 'no active editor') + test("keep selection on format", async () => { + await withSetting("insert_final_newline", "true", { + fileName: "test-selection", + }).saveText("foobar"); + assert(window.activeTextEditor, "no active editor"); // Before saving, the selection is on line 0. This should remain unchanged. assert.strictEqual( window.activeTextEditor.selection.start.line, 0, - 'editor selection start line changed', - ) + "editor selection start line changed", + ); assert.strictEqual( window.activeTextEditor.selection.end.line, 0, - 'editor selection end line changed', - ) - }) + "editor selection end line changed", + ); + }); - test('charset (utf-8)', async () => { - const document = await withSetting('charset', 'utf-8').createDoc() + test("charset (utf-8)", async () => { + const document = await withSetting("charset", "utf-8").createDoc(); assert.strictEqual( document.encoding, - 'utf8', + "utf8", `document encoding is ${document.encoding} instead of utf8`, - ) - }) + ); + }); - test('charset (utf-8-bom)', async () => { - const document = await withSetting('charset', 'utf-8-bom').createDoc() + test("charset (utf-8-bom)", async () => { + const document = await withSetting("charset", "utf-8-bom").createDoc(); assert.strictEqual( document.encoding, - 'utf8bom', + "utf8bom", `document encoding is ${document.encoding} instead of utf8bom`, - ) - }) + ); + }); - test('charset (utf-16le)', async () => { - const document = await withSetting('charset', 'utf-16le').createDoc() + test("charset (utf-16le)", async () => { + const document = await withSetting("charset", "utf-16le").createDoc(); assert.strictEqual( document.encoding, - 'utf16le', + "utf16le", `document encoding is ${document.encoding} instead of utf16le`, - ) - }) + ); + }); - test('charset (utf-16be)', async () => { - const document = await withSetting('charset', 'utf-16be').createDoc() + test("charset (utf-16be)", async () => { + const document = await withSetting("charset", "utf-16be").createDoc(); assert.strictEqual( document.encoding, - 'utf16be', + "utf16be", `document encoding is ${document.encoding} instead of utf16be`, - ) - }) + ); + }); - test('charset (latin1)', async () => { - const document = await withSetting('charset', 'latin1').createDoc() + test("charset (latin1)", async () => { + const document = await withSetting("charset", "latin1").createDoc(); assert.strictEqual( document.encoding, - 'iso88591', + "iso88591", `document encoding is ${document.encoding} instead of iso88591`, - ) - }) -}) + ); + }); +}); function withSetting( rule: string, value: string, options: { - contents?: string - fileName?: string + contents?: string; + fileName?: string; } = {}, ) { return { async getText() { - return ( - await this.createDoc(options.contents, options.fileName) - ).getText() + return (await this.createDoc(options.contents, options.fileName)).getText(); }, saveText(text: string) { - return new Promise(async resolve => { - const doc = await this.createDoc(options.contents, options.fileName) - workspace.onDidChangeTextDocument(doc.save) - workspace.onDidSaveTextDocument(savedDoc => { - assert.strictEqual(savedDoc.isDirty, false, 'dirty saved doc') - resolve(savedDoc.getText()) - }) - const edit = new WorkspaceEdit() - edit.insert(doc.uri, new Position(0, 0), text) - assert.strictEqual( - await workspace.applyEdit(edit), - true, - 'editor fails to apply edit', - ) - }) + return new Promise(async (resolve) => { + const doc = await this.createDoc(options.contents, options.fileName); + workspace.onDidChangeTextDocument(doc.save); + workspace.onDidSaveTextDocument((savedDoc) => { + assert.strictEqual(savedDoc.isDirty, false, "dirty saved doc"); + resolve(savedDoc.getText()); + }); + const edit = new WorkspaceEdit(); + edit.insert(doc.uri, new Position(0, 0), text); + assert.strictEqual(await workspace.applyEdit(edit), true, "editor fails to apply edit"); + }); }, - async createDoc(contents = '', name = 'test') { - const uri = await utils.createFile( - contents, - getFixturePath([rule, value, name]), - ) - const doc = await workspace.openTextDocument(uri) - await window.showTextDocument(doc) - await wait(50) // wait for EditorConfig to apply new settings - return doc + async createDoc(contents = "", name = "test") { + const uri = await utils.createFile(contents, getFixturePath([rule, value, name])); + const doc = await workspace.openTextDocument(uri); + await window.showTextDocument(doc); + await wait(50); // wait for EditorConfig to apply new settings + return doc; }, - } + }; } diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index ac12f9c..f31653e 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,32 +1,32 @@ -import { globSync } from 'glob' -import * as Mocha from 'mocha' -import * as path from 'path' +import { globSync } from "glob"; +import * as Mocha from "mocha"; +import * as path from "path"; export function run(): Promise { // Create the mocha test const mocha = new Mocha({ color: true, timeout: 5000, - ui: 'tdd', - }) + ui: "tdd", + }); return new Promise((c, e) => { - const files = globSync('./**/*.test.js', { cwd: __dirname }) + const files = globSync("./**/*.test.js", { cwd: __dirname }); // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(__dirname, f))) + files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); try { // Run the mocha test - mocha.run(failures => { + mocha.run((failures) => { if (failures > 0) { - e(new Error(`${failures} tests failed.`)) + e(new Error(`${failures} tests failed.`)); } else { - c() + c(); } - }) + }); } catch (err) { - e(err) + e(err); } - }) + }); } diff --git a/src/test/testUtils.ts b/src/test/testUtils.ts index f4c0b4a..6341605 100644 --- a/src/test/testUtils.ts +++ b/src/test/testUtils.ts @@ -1,39 +1,37 @@ -import * as assert from 'assert' -import * as path from 'path' -import { TextEditorOptions, Uri, window } from 'vscode' -import * as utils from 'vscode-test-utils' +import * as assert from "assert"; +import * as path from "path"; +import { TextEditorOptions, Uri, window } from "vscode"; +import * as utils from "vscode-test-utils"; export async function getOptionsForFixture(file: string[]) { - await utils.openFile(Uri.file(getFixturePath(file))) - return await getTextEditorOptions() + await utils.openFile(Uri.file(getFixturePath(file))); + return await getTextEditorOptions(); } export function getFixturePath(file: string[]) { - return path.resolve( - path.join(...[__dirname, '..', 'test', 'suite', 'fixtures'].concat(file)), - ) + return path.resolve(path.join(...[__dirname, "..", "test", "suite", "fixtures"].concat(file))); } export function wait(ms: number) { - return new Promise(resolve => { - setTimeout(resolve, ms) - }) + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); } async function getTextEditorOptions() { - let resolved = false + let resolved = false; - return new Promise(async resolve => { - window.onDidChangeTextEditorOptions(e => { - resolved = true - assert.ok(e.options) - resolve(e.options) - }) - await wait(100) + return new Promise(async (resolve) => { + window.onDidChangeTextEditorOptions((e) => { + resolved = true; + assert.ok(e.options); + resolve(e.options); + }); + await wait(100); if (resolved) { - return + return; } - assert.ok(window.activeTextEditor!.options) - resolve(window.activeTextEditor!.options) - }) + assert.ok(window.activeTextEditor!.options); + resolve(window.activeTextEditor!.options); + }); } diff --git a/src/test/untitled-suite/index.test.ts b/src/test/untitled-suite/index.test.ts index ad3405b..204dc0c 100644 --- a/src/test/untitled-suite/index.test.ts +++ b/src/test/untitled-suite/index.test.ts @@ -1,19 +1,19 @@ -import * as assert from 'assert' -import { commands, window } from 'vscode' -import { wait } from '../testUtils' +import * as assert from "assert"; +import { commands, window } from "vscode"; +import { wait } from "../testUtils"; -import * as utils from 'vscode-test-utils' +import * as utils from "vscode-test-utils"; -suite('EditorConfig extension untitled workspace', function () { - this.retries(2) - suiteTeardown(utils.closeAllFiles) +suite("EditorConfig extension untitled workspace", function () { + this.retries(2); + suiteTeardown(utils.closeAllFiles); - test('untitled editors use the first workspace folder config', async () => { - await commands.executeCommand('workbench.action.files.newUntitledFile') - await wait(200) + test("untitled editors use the first workspace folder config", async () => { + await commands.executeCommand("workbench.action.files.newUntitledFile"); + await wait(200); - const activeEditor = window.activeTextEditor + const activeEditor = window.activeTextEditor; - assert.strictEqual(activeEditor!.options.tabSize, 2) - }) -}) + assert.strictEqual(activeEditor!.options.tabSize, 2); + }); +}); diff --git a/src/test/untitled-suite/index.ts b/src/test/untitled-suite/index.ts index 448a016..8fd76c8 100644 --- a/src/test/untitled-suite/index.ts +++ b/src/test/untitled-suite/index.ts @@ -1,31 +1,31 @@ -import { globSync } from 'glob' -import * as Mocha from 'mocha' -import * as path from 'path' +import { globSync } from "glob"; +import * as Mocha from "mocha"; +import * as path from "path"; export function run(): Promise { // Create the mocha test const mocha = new Mocha({ color: true, timeout: 5000, - ui: 'tdd', - }) + ui: "tdd", + }); return new Promise((c, e) => { - const files = globSync('./**/*.test.js', { cwd: __dirname }) + const files = globSync("./**/*.test.js", { cwd: __dirname }); // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(__dirname, f))) + files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); try { // Run the mocha test - mocha.run(failures => { + mocha.run((failures) => { if (failures > 0) { - e(new Error(`${failures} tests failed.`)) + e(new Error(`${failures} tests failed.`)); } else { - c() + c(); } - }) + }); } catch (err) { - e(err) + e(err); } - }) + }); } diff --git a/src/transformations/InsertFinalNewline.ts b/src/transformations/InsertFinalNewline.ts index b6c289d..5b37b61 100644 --- a/src/transformations/InsertFinalNewline.ts +++ b/src/transformations/InsertFinalNewline.ts @@ -1,61 +1,48 @@ -import { KnownProps } from 'editorconfig' -import { - commands, - Position, - TextDocument, - TextEdit, - window, -} from 'vscode' +import { KnownProps } from "editorconfig"; +import { commands, Position, TextDocument, TextEdit, window } from "vscode"; -import { PreSaveTransformation } from './PreSaveTransformation' +import { PreSaveTransformation } from "./PreSaveTransformation"; const lineEndings = { - CR: '\r', - CRLF: '\r\n', - LF: '\n', -} + CR: "\r", + CRLF: "\r\n", + LF: "\n", +}; export class InsertFinalNewline extends PreSaveTransformation { - private lineEndings = lineEndings + private lineEndings = lineEndings; public transform(editorconfigProperties: KnownProps, doc: TextDocument) { - const lineCount = doc.lineCount - const lastLine = doc.lineAt(lineCount - 1) + const lineCount = doc.lineCount; + const lastLine = doc.lineAt(lineCount - 1); if ( shouldIgnoreSetting(editorconfigProperties.insert_final_newline) || lineCount === 0 || lastLine.isEmptyOrWhitespace ) { - return { edits: [] } + return { edits: [] }; } if (window.activeTextEditor?.document === doc) { - commands.executeCommand('editor.action.insertFinalNewLine') + commands.executeCommand("editor.action.insertFinalNewLine"); return { edits: [], - message: 'editor.action.insertFinalNewLine', - } + message: "editor.action.insertFinalNewLine", + }; } - const position = new Position(lastLine.lineNumber, lastLine.text.length) + const position = new Position(lastLine.lineNumber, lastLine.text.length); - const eol = (editorconfigProperties.end_of_line ?? 'lf').toUpperCase() + const eol = (editorconfigProperties.end_of_line ?? "lf").toUpperCase(); return { - edits: [ - TextEdit.insert( - position, - this.lineEndings[eol as keyof typeof lineEndings], - ), - ], + edits: [TextEdit.insert(position, this.lineEndings[eol as keyof typeof lineEndings])], message: `insertFinalNewline(${eol})`, - } + }; - function shouldIgnoreSetting( - value?: typeof editorconfigProperties.insert_final_newline, - ) { - return !value || value === 'unset' + function shouldIgnoreSetting(value?: typeof editorconfigProperties.insert_final_newline) { + return !value || value === "unset"; } } } diff --git a/src/transformations/PreSaveTransformation.ts b/src/transformations/PreSaveTransformation.ts index 8d0202b..5a47e3d 100644 --- a/src/transformations/PreSaveTransformation.ts +++ b/src/transformations/PreSaveTransformation.ts @@ -1,5 +1,5 @@ -import { KnownProps } from 'editorconfig' -import { TextDocument, TextDocumentSaveReason, TextEdit } from 'vscode' +import { KnownProps } from "editorconfig"; +import { TextDocument, TextDocumentSaveReason, TextEdit } from "vscode"; export abstract class PreSaveTransformation { public abstract transform( @@ -7,7 +7,7 @@ export abstract class PreSaveTransformation { doc?: TextDocument, reason?: TextDocumentSaveReason, ): { - edits: TextEdit[] | Error - message?: string - } + edits: TextEdit[] | Error; + message?: string; + }; } diff --git a/src/transformations/SetEndOfLine.ts b/src/transformations/SetEndOfLine.ts index c412525..5616e37 100644 --- a/src/transformations/SetEndOfLine.ts +++ b/src/transformations/SetEndOfLine.ts @@ -1,23 +1,23 @@ -import { KnownProps } from 'editorconfig' -import { EndOfLine, TextDocument, TextEdit } from 'vscode' +import { KnownProps } from "editorconfig"; +import { EndOfLine, TextDocument, TextEdit } from "vscode"; -import { PreSaveTransformation } from './PreSaveTransformation' +import { PreSaveTransformation } from "./PreSaveTransformation"; const eolMap = { LF: EndOfLine.LF, CRLF: EndOfLine.CRLF, -} +}; /** * Sets the end of line, but only when there is a reason to do so. * This is to preserve redo history when possible. */ export class SetEndOfLine extends PreSaveTransformation { - private eolMap = eolMap + private eolMap = eolMap; public transform(editorconfigProperties: KnownProps, doc: TextDocument) { - const eolKey = (editorconfigProperties.end_of_line || '').toUpperCase() - const eol = this.eolMap[eolKey as keyof typeof eolMap] + const eolKey = (editorconfigProperties.end_of_line || "").toUpperCase(); + const eol = this.eolMap[eolKey as keyof typeof eolMap]; /** * VSCode normalizes line endings on every file-save operation @@ -30,6 +30,6 @@ export class SetEndOfLine extends PreSaveTransformation { : { edits: [TextEdit.setEndOfLine(eol)], message: `setEndOfLine(${eolKey})`, - } + }; } } diff --git a/src/transformations/TrimTrailingWhitespace.ts b/src/transformations/TrimTrailingWhitespace.ts index c6fdcdc..5a8b51a 100644 --- a/src/transformations/TrimTrailingWhitespace.ts +++ b/src/transformations/TrimTrailingWhitespace.ts @@ -1,4 +1,4 @@ -import { KnownProps } from 'editorconfig' +import { KnownProps } from "editorconfig"; import { commands, Position, @@ -9,9 +9,9 @@ import { TextLine, window, workspace, -} from 'vscode' +} from "vscode"; -import { PreSaveTransformation } from './PreSaveTransformation' +import { PreSaveTransformation } from "./PreSaveTransformation"; export class TrimTrailingWhitespace extends PreSaveTransformation { public transform( @@ -20,74 +20,71 @@ export class TrimTrailingWhitespace extends PreSaveTransformation { reason: TextDocumentSaveReason, ) { const editorTrimsWhitespace = workspace - .getConfiguration('files', doc.uri) - .get('trimTrailingWhitespace', false) + .getConfiguration("files", doc.uri) + .get("trimTrailingWhitespace", false); if (editorTrimsWhitespace) { if (editorconfigProperties.trim_trailing_whitespace === false) { const message = [ - 'The trimTrailingWhitespace workspace or user setting', - 'is overriding the EditorConfig setting for this file.', - ].join(' ') + "The trimTrailingWhitespace workspace or user setting", + "is overriding the EditorConfig setting for this file.", + ].join(" "); return { edits: new Error(message), message, - } + }; } } if (shouldIgnoreSetting(editorconfigProperties.trim_trailing_whitespace)) { - return { edits: [] } + return { edits: [] }; } if (window.activeTextEditor?.document === doc) { - const trimReason = - reason !== TextDocumentSaveReason.Manual ? 'auto-save' : null - commands.executeCommand('editor.action.trimTrailingWhitespace', { + const trimReason = reason !== TextDocumentSaveReason.Manual ? "auto-save" : null; + commands.executeCommand("editor.action.trimTrailingWhitespace", { reason: trimReason, - }) + }); return { edits: [], - message: 'editor.action.trimTrailingWhitespace', - } + message: "editor.action.trimTrailingWhitespace", + }; } - const edits: TextEdit[] = [] + const edits: TextEdit[] = []; for (let i = 0; i < doc.lineCount; i++) { - const edit = this.trimLineTrailingWhitespace(doc.lineAt(i)) + const edit = this.trimLineTrailingWhitespace(doc.lineAt(i)); if (edit) { - edits.push(edit) + edits.push(edit); } } return { edits, - message: 'trimTrailingWhitespace()', - } + message: "trimTrailingWhitespace()", + }; - function shouldIgnoreSetting( - value: typeof editorconfigProperties.trim_trailing_whitespace, - ) { - return !value || value === 'unset' + function shouldIgnoreSetting(value: typeof editorconfigProperties.trim_trailing_whitespace) { + return !value || value === "unset"; } } private trimLineTrailingWhitespace(line: TextLine): TextEdit | void { - const trimmedLine = this.trimTrailingWhitespace(line.text) + const trimmedLine = this.trimTrailingWhitespace(line.text); if (trimmedLine === line.text) { - return + return; } - const whitespaceBegin = new Position(line.lineNumber, trimmedLine.length) - const whitespaceEnd = new Position(line.lineNumber, line.text.length) - const whitespace = new Range(whitespaceBegin, whitespaceEnd) + const whitespaceBegin = new Position(line.lineNumber, trimmedLine.length); + const whitespaceEnd = new Position(line.lineNumber, line.text.length); + const whitespace = new Range(whitespaceBegin, whitespaceEnd); - return TextEdit.delete(whitespace) + return TextEdit.delete(whitespace); } private trimTrailingWhitespace(input: string) { - return input.replace(/[\s\uFEFF\xA0]+$/g, '') + return input.replace(/[\s\uFEFF\xA0]+$/g, ""); } } diff --git a/src/transformations/index.ts b/src/transformations/index.ts index 4f9df58..58bb4c7 100644 --- a/src/transformations/index.ts +++ b/src/transformations/index.ts @@ -1,4 +1,4 @@ -export * from './InsertFinalNewline' -export * from './PreSaveTransformation' -export * from './SetEndOfLine' -export * from './TrimTrailingWhitespace' +export * from "./InsertFinalNewline"; +export * from "./PreSaveTransformation"; +export * from "./SetEndOfLine"; +export * from "./TrimTrailingWhitespace";