diff --git a/.eslintrc.js b/.eslintrc.js
index 03cd5ce38..419dbbb00 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,30 +1,30 @@
module.exports = {
- root: true,
- extends: '@sveltejs',
- plugins: ['import'],
- env: {
- node: true
- },
- rules: {
- // enabling these rules makes the linting extremely slow.
- // (it's conceivable some subset of them could be enabled without impacting speed)
- // see https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md#eslint-plugin-import
- 'import/named': 'off',
- 'import/namespace': 'off',
- 'import/default': 'off',
- 'import/no-named-as-default-member': 'off',
- 'import/no-named-as-default': 'off',
- 'import/no-cycle': 'off',
- 'import/no-unused-modules': 'off',
- 'import/no-deprecated': 'off',
- // project-specific settings
- 'max-len': ['error', { code: 100, ignoreComments: true, ignoreStrings: true }],
- 'no-trailing-spaces': 'error',
- 'one-var': ['error', 'never'],
- '@typescript-eslint/no-unused-vars': ['error', { args: 'none' }],
- '@typescript-eslint/no-namespace': 'warn',
- '@typescript-eslint/no-non-null-assertion': 'warn',
- // exclude workspace dependencies
- 'import/no-unresolved': [2, { ignore: ['svelte-language-server'] }]
- }
+ root: true,
+ extends: '@sveltejs',
+ plugins: ['import'],
+ env: {
+ node: true
+ },
+ rules: {
+ // enabling these rules makes the linting extremely slow.
+ // (it's conceivable some subset of them could be enabled without impacting speed)
+ // see https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md#eslint-plugin-import
+ 'import/named': 'off',
+ 'import/namespace': 'off',
+ 'import/default': 'off',
+ 'import/no-named-as-default-member': 'off',
+ 'import/no-named-as-default': 'off',
+ 'import/no-cycle': 'off',
+ 'import/no-unused-modules': 'off',
+ 'import/no-deprecated': 'off',
+ // project-specific settings
+ 'max-len': ['error', { code: 100, ignoreComments: true, ignoreStrings: true }],
+ 'no-trailing-spaces': 'error',
+ 'one-var': ['error', 'never'],
+ '@typescript-eslint/no-unused-vars': ['error', { args: 'none' }],
+ '@typescript-eslint/no-namespace': 'warn',
+ '@typescript-eslint/no-non-null-assertion': 'warn',
+ // exclude workspace dependencies
+ 'import/no-unresolved': [2, { ignore: ['svelte-language-server'] }]
+ }
};
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d933d4de7..45f2c3aaa 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -29,13 +29,14 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**System (please complete the following information):**
- - OS: [e.g. Windows]
- - IDE: [e.g. VSCode, Atom]
- - Plugin/Package: [e.g. "Svelte for VSCode", or `svelte-language-server`, `svelte-check`, or `svelte2tsx` if you use one of the npm packages directly]
+
+- OS: [e.g. Windows]
+- IDE: [e.g. VSCode, Atom]
+- Plugin/Package: [e.g. "Svelte for VSCode", or `svelte-language-server`, `svelte-check`, or `svelte2tsx` if you use one of the npm packages directly]
**Additional context**
Add any other context about the problem here.
\ No newline at end of file
+-->
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index e80bc46c4..6d1b1fd96 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -21,4 +21,4 @@ Add any other context or screenshots about the feature request here.
\ No newline at end of file
+-->
diff --git a/.github/ISSUE_TEMPLATE/something-else.md b/.github/ISSUE_TEMPLATE/something-else.md
index 65f6e38a8..196e33d4a 100644
--- a/.github/ISSUE_TEMPLATE/something-else.md
+++ b/.github/ISSUE_TEMPLATE/something-else.md
@@ -6,5 +6,3 @@ labels: ''
assignees: ''
---
-
-
diff --git a/.prettierrc b/.prettierrc
index 5a219d934..b8797bfb7 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,8 +1,23 @@
{
- "useTabs": false,
- "printWidth": 100,
- "tabWidth": 4,
- "semi": true,
- "trailingComma": "none",
- "singleQuote": true
+ "arrowParens": "always",
+ "useTabs": true,
+ "printWidth": 100,
+ "tabWidth": 4,
+ "semi": true,
+ "trailingComma": "none",
+ "singleQuote": true,
+ "overrides": [
+ {
+ "files": ["package.json"],
+ "options": {
+ "tabWidth": 2
+ }
+ },
+ {
+ "files": ["*.md"],
+ "options": {
+ "useTabs": false
+ }
+ }
+ ]
}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 6dc886f5e..fb96cba06 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,57 +1,57 @@
{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Run VS Code Extension",
- "type": "extensionHost",
- "request": "launch",
- "runtimeExecutable": "${execPath}",
- "args": ["--extensionDevelopmentPath=${workspaceRoot}/packages/svelte-vscode"],
- "stopOnEntry": false,
- "sourceMaps": true,
- "outFiles": ["${workspaceRoot}/packages/svelte-vscode/dist/**/*.js"],
- "preLaunchTask": "npm: watch"
- },
- {
- "type": "node",
- "request": "launch",
- "name": "Run 'svelte2tsx/repl/debug.ts' with debugger",
- "runtimeArgs": ["-r", "ts-node/register"],
- "args": ["${workspaceFolder}/packages/svelte2tsx/repl/debug.ts"],
- "env": {
- "TS_NODE_COMPILER_OPTIONS": "{\"esModuleInterop\":true, \"target\": \"es2018\"}",
- "TS_NODE_TRANSPILE_ONLY": "true"
- },
- "console": "integratedTerminal",
- "internalConsoleOptions": "neverOpen"
- },
- {
- "type": "node",
- "request": "launch",
- "name": "Run tests with debugger",
- "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
- "args": [
- "-r",
- "ts-node/register",
- "--colors",
- "${workspaceFolder}/packages/*/test/**/*.ts"
- ],
- "env": {
- "TS_NODE_COMPILER_OPTIONS": "{\"esModuleInterop\":true}"
- },
- "console": "integratedTerminal",
- "internalConsoleOptions": "neverOpen"
- },
- {
- "type": "node",
- "request": "attach",
- "name": "Attach debugger to language server",
- "port": 6009,
- "outFiles": [
- "${workspaceRoot}/packages/language-server/dist/**/*.js",
- "${workspaceRoot}/packages/svelte2tsx/index.js"
- ],
- "skipFiles": ["/**"]
- }
- ]
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Run VS Code Extension",
+ "type": "extensionHost",
+ "request": "launch",
+ "runtimeExecutable": "${execPath}",
+ "args": ["--extensionDevelopmentPath=${workspaceRoot}/packages/svelte-vscode"],
+ "stopOnEntry": false,
+ "sourceMaps": true,
+ "outFiles": ["${workspaceRoot}/packages/svelte-vscode/dist/**/*.js"],
+ "preLaunchTask": "npm: watch"
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Run 'svelte2tsx/repl/debug.ts' with debugger",
+ "runtimeArgs": ["-r", "ts-node/register"],
+ "args": ["${workspaceFolder}/packages/svelte2tsx/repl/debug.ts"],
+ "env": {
+ "TS_NODE_COMPILER_OPTIONS": "{\"esModuleInterop\":true, \"target\": \"es2018\"}",
+ "TS_NODE_TRANSPILE_ONLY": "true"
+ },
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen"
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Run tests with debugger",
+ "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
+ "args": [
+ "-r",
+ "ts-node/register",
+ "--colors",
+ "${workspaceFolder}/packages/*/test/**/*.ts"
+ ],
+ "env": {
+ "TS_NODE_COMPILER_OPTIONS": "{\"esModuleInterop\":true}"
+ },
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen"
+ },
+ {
+ "type": "node",
+ "request": "attach",
+ "name": "Attach debugger to language server",
+ "port": 6009,
+ "outFiles": [
+ "${workspaceRoot}/packages/language-server/dist/**/*.js",
+ "${workspaceRoot}/packages/svelte2tsx/index.js"
+ ],
+ "skipFiles": ["/**"]
+ }
+ ]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f865d2f2c..dc0756a56 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
{
- "typescript.preferences.quoteStyle": "single"
+ "typescript.preferences.quoteStyle": "single"
}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 05af6c90b..8a491bd31 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,18 +1,18 @@
{
- "version": "2.0.0",
- "tasks": [
- {
- "type": "npm",
- "script": "watch",
- "problemMatcher": "$tsc-watch",
- "isBackground": true,
- "presentation": {
- "reveal": "never"
- },
- "group": {
- "kind": "build",
- "isDefault": true
- }
- }
- ]
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "npm",
+ "script": "watch",
+ "problemMatcher": "$tsc-watch",
+ "isBackground": true,
+ "presentation": {
+ "reveal": "never"
+ },
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ }
+ ]
}
diff --git a/README.md b/README.md
index b3b4732e5..39afdd248 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
@@ -20,7 +20,7 @@ Svelte Language Tools contains a library implementing the Language Server Protoc
A `.svelte` file would look something like this:
-```html
+```svelte
-
+
{count} * 2 = {doubled}
{doubled} * 2 = {quadrupled}
diff --git a/docs/README.md b/docs/README.md
index 4f42d85ac..bd4210bba 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -47,19 +47,19 @@ LSP-compatible editors, you can use an HTML comment with the `@component` tag:
The VS Code extension comes with its own syntax highlighting grammar which defines special scopes. If your syntax highlighting seems to be not working for Svelte components or you feel that some colors are wrong, you can add something like the following to your `settings.json`:
-```
+```json
{
"editor.tokenColorCustomizations": {
"[]": {
"textMateRules": [
{
"settings": {
- "foreground": "#569CD6", // any color you like
+ "foreground": "#569CD6" // any color you like
},
"scope": "support.class.component.svelte" // scope name you want to adjust highlighting for
}
- ],
- },
+ ]
+ }
}
}
```
@@ -80,7 +80,7 @@ You need to save the file to see the changes. If the problem persists after savi
```json
"files.watcherExclude": {
- "**/*": true,
+ "**/*": true,
}
```
@@ -94,13 +94,13 @@ If you have the `Babel Javascript` plugin installed, this may be the cause. Disa
Your default formatter for Svelte files may be wrong.
-- Mabye it's set to the old Svelte extension, if so, remove the setting
+- Maybe it's set to the old Svelte extension, if so, remove the setting
- Maybe you set all files to be formatted by the prettier extension. Then you have two options: Either install `prettier-plugin-svelte` from npm, or tell VSCode to format the code with the `Svelte for VSCode extension`:
```json
- "[svelte]": {
+"[svelte]": {
"editor.defaultFormatter": "svelte.svelte-vscode"
- },
+},
```
## Internals
diff --git a/docs/internal/overview.md b/docs/internal/overview.md
index b9ff47fe2..96e1c1bb0 100644
--- a/docs/internal/overview.md
+++ b/docs/internal/overview.md
@@ -30,10 +30,11 @@ Our `language-server` can roughly be split into [four areas](/packages/language-
The last area, TS/JS, is where most of the work is done. Svelte is a mix of JavaScript/TypeScript inside `script` and more of it within Svelte's template syntax. To get a holistic view of the file, we need to account for both.
This is also the reason why preprocessors such as `svelte-preprocess` cannot do type checking because it produces wrong diagnostics. To preprocess the script content, it only gets the content from the script. Think of this situation:
-```html
+```svelte
+
{a}
```
@@ -64,7 +65,7 @@ This example shows how our `language-server` uses `svelte2tsx`:
1. Svelte file comes in
-```html
+```svelte
diff --git a/docs/preprocessors/in-general.md b/docs/preprocessors/in-general.md
index 496908688..299e15183 100644
--- a/docs/preprocessors/in-general.md
+++ b/docs/preprocessors/in-general.md
@@ -17,7 +17,7 @@ module.exports = {
It's also necessary to add a `type="text/language-name"` or `lang="language-name"` to your `style` and `script` tags, which defines how that code should be interpreted by the extension.
-```html
+```svelte
Hello, world!
diff --git a/docs/preprocessors/scss-less.md b/docs/preprocessors/scss-less.md
index c185032d7..f292f00fc 100644
--- a/docs/preprocessors/scss-less.md
+++ b/docs/preprocessors/scss-less.md
@@ -35,7 +35,7 @@ module.exports = {
To gain syntax highlighing for your SCSS code and to make us understand the language you are using, add a `type` or `lang` attribute to your style tags like so:
-```html
+```svelte
');
- assert.deepEqual(document.scriptInfo, {
- content: 'a',
- attributes: {
- lang: 'javascript'
- },
- start: 8,
- end: 9,
- startPos: Position.create(0, 8),
- endPos: Position.create(0, 9),
- container: { start: 0, end: 18 }
- });
- assert.deepEqual(document.styleInfo, {
- content: 'b',
- attributes: {
- lang: 'css'
- },
- start: 25,
- end: 26,
- startPos: Position.create(0, 25),
- endPos: Position.create(0, 26),
- container: { start: 18, end: 34 }
- });
-
- document.setText('');
- assert.deepEqual(document.scriptInfo, {
- content: 'b',
- attributes: {
- lang: 'javascript'
- },
- start: 8,
- end: 9,
- startPos: Position.create(0, 8),
- endPos: Position.create(0, 9),
- container: { start: 0, end: 18 }
- });
- assert.strictEqual(document.styleInfo, null);
- });
-
- it('returns the correct file path', () => {
- const document = new Document('file:///hello.svelte', 'hello');
-
- assert.strictEqual(document.getFilePath(), '/hello.svelte');
- });
-
- it('returns null for non file urls', () => {
- const document = new Document('ftp:///hello.svelte', 'hello');
-
- assert.strictEqual(document.getFilePath(), null);
- });
-
- it('gets the text length', () => {
- const document = new Document('file:///hello.svelte', 'Hello, world!');
- assert.strictEqual(document.getTextLength(), 13);
- });
-
- it('updates the text range', () => {
- const document = new Document('file:///hello.svelte', 'Hello, world!');
- document.update('svelte', 7, 12);
- assert.strictEqual(document.getText(), 'Hello, svelte!');
- });
-
- it('gets the correct position from offset', () => {
- const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
- assert.deepStrictEqual(document.positionAt(1), { line: 0, character: 1 });
- assert.deepStrictEqual(document.positionAt(9), { line: 1, character: 3 });
- assert.deepStrictEqual(document.positionAt(12), { line: 2, character: 0 });
- });
-
- it('gets the correct offset from position', () => {
- const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
- assert.strictEqual(document.offsetAt({ line: 0, character: 1 }), 1);
- assert.strictEqual(document.offsetAt({ line: 1, character: 3 }), 9);
- assert.strictEqual(document.offsetAt({ line: 2, character: 0 }), 12);
- });
-
- it('gets the correct position from offset with CRLF', () => {
- const document = new Document('file:///hello.svelte', 'Hello\r\nworld\r\n');
- assert.deepStrictEqual(document.positionAt(1), { line: 0, character: 1 });
- assert.deepStrictEqual(document.positionAt(10), { line: 1, character: 3 });
- assert.deepStrictEqual(document.positionAt(14), { line: 2, character: 0 });
- });
-
- it('gets the correct offset from position with CRLF', () => {
- const document = new Document('file:///hello.svelte', 'Hello\r\nworld\r\n');
- assert.strictEqual(document.offsetAt({ line: 0, character: 1 }), 1);
- assert.strictEqual(document.offsetAt({ line: 1, character: 3 }), 10);
- assert.strictEqual(document.offsetAt({ line: 2, character: 0 }), 14);
- });
-
- it('limits the position when offset is out of bounds', () => {
- const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
- assert.deepStrictEqual(document.positionAt(20), { line: 2, character: 0 });
- assert.deepStrictEqual(document.positionAt(-1), { line: 0, character: 0 });
- });
-
- it('limits the offset when position is out of bounds', () => {
- const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
- assert.strictEqual(document.offsetAt({ line: 5, character: 0 }), 12);
- assert.strictEqual(document.offsetAt({ line: 1, character: 20 }), 12);
- assert.strictEqual(document.offsetAt({ line: -1, character: 0 }), 0);
- });
-
- it('supports empty contents', () => {
- const document = new Document('file:///hello.svelte', '');
- assert.strictEqual(document.offsetAt({ line: 0, character: 0 }), 0);
- assert.deepStrictEqual(document.positionAt(0), { line: 0, character: 0 });
- });
+ it('gets the correct text', () => {
+ const document = new Document('file:///hello.svelte', 'Hello, world!
');
+ assert.strictEqual(document.getText(), 'Hello, world!
');
+ });
+
+ it('sets the text', () => {
+ const document = new Document('file:///hello.svelte', 'Hello, world!
');
+ document.setText('Hello, svelte!
');
+ assert.strictEqual(document.getText(), 'Hello, svelte!
');
+ });
+
+ it('increments the version on edits', () => {
+ const document = new Document('file:///hello.svelte', 'hello');
+ assert.strictEqual(document.version, 0);
+
+ document.setText('Hello, world!');
+ assert.strictEqual(document.version, 1);
+ document.update('svelte', 7, 12);
+ assert.strictEqual(document.version, 2);
+ });
+
+ it('recalculates the tag infos on edits', () => {
+ const document = new Document('file:///hello.svelte', '');
+ assert.deepEqual(document.scriptInfo, {
+ content: 'a',
+ attributes: {
+ lang: 'javascript'
+ },
+ start: 8,
+ end: 9,
+ startPos: Position.create(0, 8),
+ endPos: Position.create(0, 9),
+ container: { start: 0, end: 18 }
+ });
+ assert.deepEqual(document.styleInfo, {
+ content: 'b',
+ attributes: {
+ lang: 'css'
+ },
+ start: 25,
+ end: 26,
+ startPos: Position.create(0, 25),
+ endPos: Position.create(0, 26),
+ container: { start: 18, end: 34 }
+ });
+
+ document.setText('');
+ assert.deepEqual(document.scriptInfo, {
+ content: 'b',
+ attributes: {
+ lang: 'javascript'
+ },
+ start: 8,
+ end: 9,
+ startPos: Position.create(0, 8),
+ endPos: Position.create(0, 9),
+ container: { start: 0, end: 18 }
+ });
+ assert.strictEqual(document.styleInfo, null);
+ });
+
+ it('returns the correct file path', () => {
+ const document = new Document('file:///hello.svelte', 'hello');
+
+ assert.strictEqual(document.getFilePath(), '/hello.svelte');
+ });
+
+ it('returns null for non file urls', () => {
+ const document = new Document('ftp:///hello.svelte', 'hello');
+
+ assert.strictEqual(document.getFilePath(), null);
+ });
+
+ it('gets the text length', () => {
+ const document = new Document('file:///hello.svelte', 'Hello, world!');
+ assert.strictEqual(document.getTextLength(), 13);
+ });
+
+ it('updates the text range', () => {
+ const document = new Document('file:///hello.svelte', 'Hello, world!');
+ document.update('svelte', 7, 12);
+ assert.strictEqual(document.getText(), 'Hello, svelte!');
+ });
+
+ it('gets the correct position from offset', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
+ assert.deepStrictEqual(document.positionAt(1), { line: 0, character: 1 });
+ assert.deepStrictEqual(document.positionAt(9), { line: 1, character: 3 });
+ assert.deepStrictEqual(document.positionAt(12), { line: 2, character: 0 });
+ });
+
+ it('gets the correct offset from position', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
+ assert.strictEqual(document.offsetAt({ line: 0, character: 1 }), 1);
+ assert.strictEqual(document.offsetAt({ line: 1, character: 3 }), 9);
+ assert.strictEqual(document.offsetAt({ line: 2, character: 0 }), 12);
+ });
+
+ it('gets the correct position from offset with CRLF', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\r\nworld\r\n');
+ assert.deepStrictEqual(document.positionAt(1), { line: 0, character: 1 });
+ assert.deepStrictEqual(document.positionAt(10), { line: 1, character: 3 });
+ assert.deepStrictEqual(document.positionAt(14), { line: 2, character: 0 });
+ });
+
+ it('gets the correct offset from position with CRLF', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\r\nworld\r\n');
+ assert.strictEqual(document.offsetAt({ line: 0, character: 1 }), 1);
+ assert.strictEqual(document.offsetAt({ line: 1, character: 3 }), 10);
+ assert.strictEqual(document.offsetAt({ line: 2, character: 0 }), 14);
+ });
+
+ it('limits the position when offset is out of bounds', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
+ assert.deepStrictEqual(document.positionAt(20), { line: 2, character: 0 });
+ assert.deepStrictEqual(document.positionAt(-1), { line: 0, character: 0 });
+ });
+
+ it('limits the offset when position is out of bounds', () => {
+ const document = new Document('file:///hello.svelte', 'Hello\nworld\n');
+ assert.strictEqual(document.offsetAt({ line: 5, character: 0 }), 12);
+ assert.strictEqual(document.offsetAt({ line: 1, character: 20 }), 12);
+ assert.strictEqual(document.offsetAt({ line: -1, character: 0 }), 0);
+ });
+
+ it('supports empty contents', () => {
+ const document = new Document('file:///hello.svelte', '');
+ assert.strictEqual(document.offsetAt({ line: 0, character: 0 }), 0);
+ assert.deepStrictEqual(document.positionAt(0), { line: 0, character: 0 });
+ });
});
diff --git a/packages/language-server/test/lib/documents/DocumentManager.test.ts b/packages/language-server/test/lib/documents/DocumentManager.test.ts
index 05c737b9c..7ff332a58 100644
--- a/packages/language-server/test/lib/documents/DocumentManager.test.ts
+++ b/packages/language-server/test/lib/documents/DocumentManager.test.ts
@@ -4,80 +4,80 @@ import { TextDocumentItem, Range } from 'vscode-languageserver-types';
import { DocumentManager, Document } from '../../../src/lib/documents';
describe('Document Manager', () => {
- const textDocument: TextDocumentItem = {
- uri: 'file:///hello.svelte',
- version: 0,
- languageId: 'svelte',
- text: 'Hello, world!'
- };
-
- const createTextDocument = (textDocument: Pick) =>
- new Document(textDocument.uri, textDocument.text);
-
- it('opens documents', () => {
- const createDocument = sinon.spy();
- const manager = new DocumentManager(createDocument);
-
- manager.openDocument(textDocument);
-
- sinon.assert.calledOnce(createDocument);
- sinon.assert.calledWith(createDocument.firstCall, textDocument);
- });
-
- it('updates the whole document', () => {
- const document = createTextDocument(textDocument);
- const update = sinon.spy(document, 'update');
- const createDocument = sinon.stub().returns(document);
- const manager = new DocumentManager(createDocument);
-
- manager.openDocument(textDocument);
- manager.updateDocument(textDocument, [{ text: 'New content' }]);
-
- sinon.assert.calledOnce(update);
- sinon.assert.calledWith(update.firstCall, 'New content', 0, textDocument.text.length);
- });
-
- it('updates the parts of the document', () => {
- const document = createTextDocument(textDocument);
- const update = sinon.spy(document, 'update');
- const createDocument = sinon.stub().returns(document);
- const manager = new DocumentManager(createDocument);
-
- manager.openDocument(textDocument);
- manager.updateDocument(textDocument, [
- {
- text: 'svelte',
- range: Range.create(0, 7, 0, 12),
- rangeLength: 5
- },
- {
- text: 'Greetings',
- range: Range.create(0, 0, 0, 5),
- rangeLength: 5
- }
- ]);
-
- sinon.assert.calledTwice(update);
- sinon.assert.calledWith(update.firstCall, 'svelte', 7, 12);
- sinon.assert.calledWith(update.secondCall, 'Greetings', 0, 5);
- });
-
- it("fails to update if document isn't open", () => {
- const manager = new DocumentManager(createTextDocument);
-
- assert.throws(() => manager.updateDocument(textDocument, []));
- });
-
- it('emits a document change event on open and update', () => {
- const manager = new DocumentManager(createTextDocument);
- const cb = sinon.spy();
-
- manager.on('documentChange', cb);
-
- manager.openDocument(textDocument);
- sinon.assert.calledOnce(cb);
-
- manager.updateDocument(textDocument, []);
- sinon.assert.calledTwice(cb);
- });
+ const textDocument: TextDocumentItem = {
+ uri: 'file:///hello.svelte',
+ version: 0,
+ languageId: 'svelte',
+ text: 'Hello, world!'
+ };
+
+ const createTextDocument = (textDocument: Pick) =>
+ new Document(textDocument.uri, textDocument.text);
+
+ it('opens documents', () => {
+ const createDocument = sinon.spy();
+ const manager = new DocumentManager(createDocument);
+
+ manager.openDocument(textDocument);
+
+ sinon.assert.calledOnce(createDocument);
+ sinon.assert.calledWith(createDocument.firstCall, textDocument);
+ });
+
+ it('updates the whole document', () => {
+ const document = createTextDocument(textDocument);
+ const update = sinon.spy(document, 'update');
+ const createDocument = sinon.stub().returns(document);
+ const manager = new DocumentManager(createDocument);
+
+ manager.openDocument(textDocument);
+ manager.updateDocument(textDocument, [{ text: 'New content' }]);
+
+ sinon.assert.calledOnce(update);
+ sinon.assert.calledWith(update.firstCall, 'New content', 0, textDocument.text.length);
+ });
+
+ it('updates the parts of the document', () => {
+ const document = createTextDocument(textDocument);
+ const update = sinon.spy(document, 'update');
+ const createDocument = sinon.stub().returns(document);
+ const manager = new DocumentManager(createDocument);
+
+ manager.openDocument(textDocument);
+ manager.updateDocument(textDocument, [
+ {
+ text: 'svelte',
+ range: Range.create(0, 7, 0, 12),
+ rangeLength: 5
+ },
+ {
+ text: 'Greetings',
+ range: Range.create(0, 0, 0, 5),
+ rangeLength: 5
+ }
+ ]);
+
+ sinon.assert.calledTwice(update);
+ sinon.assert.calledWith(update.firstCall, 'svelte', 7, 12);
+ sinon.assert.calledWith(update.secondCall, 'Greetings', 0, 5);
+ });
+
+ it("fails to update if document isn't open", () => {
+ const manager = new DocumentManager(createTextDocument);
+
+ assert.throws(() => manager.updateDocument(textDocument, []));
+ });
+
+ it('emits a document change event on open and update', () => {
+ const manager = new DocumentManager(createTextDocument);
+ const cb = sinon.spy();
+
+ manager.on('documentChange', cb);
+
+ manager.openDocument(textDocument);
+ sinon.assert.calledOnce(cb);
+
+ manager.updateDocument(textDocument, []);
+ sinon.assert.calledTwice(cb);
+ });
});
diff --git a/packages/language-server/test/lib/documents/DocumentMapper.test.ts b/packages/language-server/test/lib/documents/DocumentMapper.test.ts
index 3c21edb38..a84d5d6df 100644
--- a/packages/language-server/test/lib/documents/DocumentMapper.test.ts
+++ b/packages/language-server/test/lib/documents/DocumentMapper.test.ts
@@ -2,45 +2,45 @@ import * as assert from 'assert';
import { FragmentMapper, positionAt } from '../../../src/lib/documents';
describe('DocumentMapper', () => {
- describe('FragmentMapper', () => {
- function setup(content: string, start: number, end: number) {
- return new FragmentMapper(
- content,
- {
- start,
- end,
- endPos: positionAt(end, content),
- content: content.substring(start, end)
- },
- 'file:///hello.svelte'
- );
- }
+ describe('FragmentMapper', () => {
+ function setup(content: string, start: number, end: number) {
+ return new FragmentMapper(
+ content,
+ {
+ start,
+ end,
+ endPos: positionAt(end, content),
+ content: content.substring(start, end)
+ },
+ 'file:///hello.svelte'
+ );
+ }
- it('isInGenerated works', () => {
- const fragment = setup('Hello, \nworld!', 8, 13);
+ it('isInGenerated works', () => {
+ const fragment = setup('Hello, \nworld!', 8, 13);
- assert.strictEqual(fragment.isInGenerated({ line: 0, character: 0 }), false);
- assert.strictEqual(fragment.isInGenerated({ line: 1, character: 0 }), true);
- assert.strictEqual(fragment.isInGenerated({ line: 1, character: 5 }), true);
- assert.strictEqual(fragment.isInGenerated({ line: 1, character: 6 }), false);
- });
+ assert.strictEqual(fragment.isInGenerated({ line: 0, character: 0 }), false);
+ assert.strictEqual(fragment.isInGenerated({ line: 1, character: 0 }), true);
+ assert.strictEqual(fragment.isInGenerated({ line: 1, character: 5 }), true);
+ assert.strictEqual(fragment.isInGenerated({ line: 1, character: 6 }), false);
+ });
- it('calculates the position in parent', () => {
- const fragment = setup('Hello, \nworld!', 8, 13);
+ it('calculates the position in parent', () => {
+ const fragment = setup('Hello, \nworld!', 8, 13);
- assert.deepStrictEqual(fragment.getOriginalPosition({ line: 0, character: 2 }), {
- line: 1,
- character: 2
- });
- });
+ assert.deepStrictEqual(fragment.getOriginalPosition({ line: 0, character: 2 }), {
+ line: 1,
+ character: 2
+ });
+ });
- it('calculates the position in fragment', () => {
- const fragment = setup('Hello, \nworld!', 8, 13);
+ it('calculates the position in fragment', () => {
+ const fragment = setup('Hello, \nworld!', 8, 13);
- assert.deepStrictEqual(fragment.getGeneratedPosition({ line: 1, character: 2 }), {
- line: 0,
- character: 2
- });
- });
- });
+ assert.deepStrictEqual(fragment.getGeneratedPosition({ line: 1, character: 2 }), {
+ line: 0,
+ character: 2
+ });
+ });
+ });
});
diff --git a/packages/language-server/test/lib/documents/configLoader.test.ts b/packages/language-server/test/lib/documents/configLoader.test.ts
index 676b999ec..288cee74f 100644
--- a/packages/language-server/test/lib/documents/configLoader.test.ts
+++ b/packages/language-server/test/lib/documents/configLoader.test.ts
@@ -4,146 +4,146 @@ import { pathToFileURL, URL } from 'url';
import assert from 'assert';
describe('ConfigLoader', () => {
- function configFrom(path: string) {
- return {
- compilerOptions: {
- dev: true,
- generate: false
- },
- preprocess: pathToFileURL(path).toString()
- };
- }
+ function configFrom(path: string) {
+ return {
+ compilerOptions: {
+ dev: true,
+ generate: false
+ },
+ preprocess: pathToFileURL(path).toString()
+ };
+ }
- async function assertFindsConfig(
- configLoader: ConfigLoader,
- filePath: string,
- configPath: string
- ) {
- filePath = path.join(...filePath.split('/'));
- configPath = path.join(...configPath.split('/'));
- assert.deepStrictEqual(configLoader.getConfig(filePath), configFrom(configPath));
- assert.deepStrictEqual(await configLoader.awaitConfig(filePath), configFrom(configPath));
- }
+ async function assertFindsConfig(
+ configLoader: ConfigLoader,
+ filePath: string,
+ configPath: string
+ ) {
+ filePath = path.join(...filePath.split('/'));
+ configPath = path.join(...configPath.split('/'));
+ assert.deepStrictEqual(configLoader.getConfig(filePath), configFrom(configPath));
+ assert.deepStrictEqual(await configLoader.awaitConfig(filePath), configFrom(configPath));
+ }
- it('should load all config files below and the one inside/above given directory', async () => {
- const configLoader = new ConfigLoader(
- () => ['svelte.config.js', 'below/svelte.config.js'],
- { existsSync: () => true },
- path,
- (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
- );
- await configLoader.loadConfigs('/some/path');
+ it('should load all config files below and the one inside/above given directory', async () => {
+ const configLoader = new ConfigLoader(
+ () => ['svelte.config.js', 'below/svelte.config.js'],
+ { existsSync: () => true },
+ path,
+ (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
+ );
+ await configLoader.loadConfigs('/some/path');
- assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/path/svelte.config.js');
- assertFindsConfig(
- configLoader,
- '/some/path/aside/comp.svelte',
- '/some/path/svelte.config.js'
- );
- assertFindsConfig(
- configLoader,
- '/some/path/below/comp.svelte',
- '/some/path/below/svelte.config.js'
- );
- assertFindsConfig(
- configLoader,
- '/some/path/below/further/comp.svelte',
- '/some/path/below/svelte.config.js'
- );
- });
+ assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/path/svelte.config.js');
+ assertFindsConfig(
+ configLoader,
+ '/some/path/aside/comp.svelte',
+ '/some/path/svelte.config.js'
+ );
+ assertFindsConfig(
+ configLoader,
+ '/some/path/below/comp.svelte',
+ '/some/path/below/svelte.config.js'
+ );
+ assertFindsConfig(
+ configLoader,
+ '/some/path/below/further/comp.svelte',
+ '/some/path/below/svelte.config.js'
+ );
+ });
- it('finds first above if none found inside/below directory', async () => {
- const configLoader = new ConfigLoader(
- () => [],
- {
- existsSync: (p) =>
- typeof p === 'string' && p.endsWith(path.join('some', 'svelte.config.js'))
- },
- path,
- (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
- );
- await configLoader.loadConfigs('/some/path');
+ it('finds first above if none found inside/below directory', async () => {
+ const configLoader = new ConfigLoader(
+ () => [],
+ {
+ existsSync: (p) =>
+ typeof p === 'string' && p.endsWith(path.join('some', 'svelte.config.js'))
+ },
+ path,
+ (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
+ );
+ await configLoader.loadConfigs('/some/path');
- assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/svelte.config.js');
- });
+ assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/svelte.config.js');
+ });
- it('adds fallback if no config found', async () => {
- const configLoader = new ConfigLoader(
- () => [],
- { existsSync: () => false },
- path,
- (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
- );
- await configLoader.loadConfigs('/some/path');
+ it('adds fallback if no config found', async () => {
+ const configLoader = new ConfigLoader(
+ () => [],
+ { existsSync: () => false },
+ path,
+ (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
+ );
+ await configLoader.loadConfigs('/some/path');
- assert.deepStrictEqual(
- // Can't do the equal-check directly, instead check if it's the expected object props
- // of svelte-preprocess
- Object.keys(configLoader.getConfig('/some/path/comp.svelte')?.preprocess || {}).sort(),
- ['defaultLanguages', 'markup', 'script', 'style'].sort()
- );
- });
+ assert.deepStrictEqual(
+ // Can't do the equal-check directly, instead check if it's the expected object props
+ // of svelte-preprocess
+ Object.keys(configLoader.getConfig('/some/path/comp.svelte')?.preprocess || {}).sort(),
+ ['defaultLanguages', 'markup', 'script', 'style'].sort()
+ );
+ });
- it('will not load config multiple times if config loading started in parallel', async () => {
- let firstGlobCall = true;
- let nrImportCalls = 0;
- const configLoader = new ConfigLoader(
- () => {
- if (firstGlobCall) {
- firstGlobCall = false;
- return ['svelte.config.js'];
- } else {
- return [];
- }
- },
- {
- existsSync: (p) =>
- typeof p === 'string' &&
- p.endsWith(path.join('some', 'path', 'svelte.config.js'))
- },
- path,
- (module: URL) => {
- nrImportCalls++;
- return new Promise((resolve) => {
- setTimeout(() => resolve({ default: { preprocess: module.toString() } }), 500);
- });
- }
- );
- await Promise.all([
- configLoader.loadConfigs('/some/path'),
- configLoader.loadConfigs('/some/path/sub'),
- configLoader.awaitConfig('/some/path/file.svelte')
- ]);
+ it('will not load config multiple times if config loading started in parallel', async () => {
+ let firstGlobCall = true;
+ let nrImportCalls = 0;
+ const configLoader = new ConfigLoader(
+ () => {
+ if (firstGlobCall) {
+ firstGlobCall = false;
+ return ['svelte.config.js'];
+ } else {
+ return [];
+ }
+ },
+ {
+ existsSync: (p) =>
+ typeof p === 'string' &&
+ p.endsWith(path.join('some', 'path', 'svelte.config.js'))
+ },
+ path,
+ (module: URL) => {
+ nrImportCalls++;
+ return new Promise((resolve) => {
+ setTimeout(() => resolve({ default: { preprocess: module.toString() } }), 500);
+ });
+ }
+ );
+ await Promise.all([
+ configLoader.loadConfigs('/some/path'),
+ configLoader.loadConfigs('/some/path/sub'),
+ configLoader.awaitConfig('/some/path/file.svelte')
+ ]);
- assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/path/svelte.config.js');
- assertFindsConfig(
- configLoader,
- '/some/path/sub/comp.svelte',
- '/some/path/svelte.config.js'
- );
- assert.deepStrictEqual(nrImportCalls, 1);
- });
+ assertFindsConfig(configLoader, '/some/path/comp.svelte', '/some/path/svelte.config.js');
+ assertFindsConfig(
+ configLoader,
+ '/some/path/sub/comp.svelte',
+ '/some/path/svelte.config.js'
+ );
+ assert.deepStrictEqual(nrImportCalls, 1);
+ });
- it('can deal with missing config', () => {
- const configLoader = new ConfigLoader(
- () => [],
- { existsSync: () => false },
- path,
- () => Promise.resolve('unimportant')
- );
- assert.deepStrictEqual(configLoader.getConfig('/some/file.svelte'), undefined);
- });
+ it('can deal with missing config', () => {
+ const configLoader = new ConfigLoader(
+ () => [],
+ { existsSync: () => false },
+ path,
+ () => Promise.resolve('unimportant')
+ );
+ assert.deepStrictEqual(configLoader.getConfig('/some/file.svelte'), undefined);
+ });
- it('should await config', async () => {
- const configLoader = new ConfigLoader(
- () => [],
- { existsSync: () => true },
- path,
- (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
- );
- assert.deepStrictEqual(
- await configLoader.awaitConfig(path.join('some', 'file.svelte')),
- configFrom(path.join('some', 'svelte.config.js'))
- );
- });
+ it('should await config', async () => {
+ const configLoader = new ConfigLoader(
+ () => [],
+ { existsSync: () => true },
+ path,
+ (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } })
+ );
+ assert.deepStrictEqual(
+ await configLoader.awaitConfig(path.join('some', 'file.svelte')),
+ configFrom(path.join('some', 'svelte.config.js'))
+ );
+ });
});
diff --git a/packages/language-server/test/lib/documents/parseHtml.test.ts b/packages/language-server/test/lib/documents/parseHtml.test.ts
index 0d6d814a5..32d192801 100644
--- a/packages/language-server/test/lib/documents/parseHtml.test.ts
+++ b/packages/language-server/test/lib/documents/parseHtml.test.ts
@@ -3,74 +3,74 @@ import { HTMLDocument } from 'vscode-html-languageservice';
import { parseHtml } from '../../../src/lib/documents/parseHtml';
describe('parseHtml', () => {
- const testRootElements = (document: HTMLDocument) => {
- assert.deepStrictEqual(
- document.roots.map((r) => r.tag),
- ['Foo', 'style']
- );
- };
+ const testRootElements = (document: HTMLDocument) => {
+ assert.deepStrictEqual(
+ document.roots.map((r) => r.tag),
+ ['Foo', 'style']
+ );
+ };
- it('ignore arrow inside moustache', () => {
- testRootElements(
- parseHtml(
- ` console.log('ya!!!')} />
+ it('ignore arrow inside moustache', () => {
+ testRootElements(
+ parseHtml(
+ ` console.log('ya!!!')} />
`
- )
- );
- });
+ )
+ );
+ });
- it('ignore greater than operator inside moustache', () => {
- testRootElements(
- parseHtml(
- ` 1} />
+ it('ignore greater than operator inside moustache', () => {
+ testRootElements(
+ parseHtml(
+ ` 1} />
`
- )
- );
- });
+ )
+ );
+ });
- it('ignore less than operator inside moustache', () => {
- testRootElements(
- parseHtml(
- `
+ it('ignore less than operator inside moustache', () => {
+ testRootElements(
+ parseHtml(
+ `
`
- )
- );
- });
+ )
+ );
+ });
- it('ignore less than operator inside moustache with tag not self closed', () => {
- testRootElements(
- parseHtml(
- `
+ it('ignore less than operator inside moustache with tag not self closed', () => {
+ testRootElements(
+ parseHtml(
+ `
`
- )
- );
- });
+ )
+ );
+ });
- it('parse baseline html', () => {
- testRootElements(
- parseHtml(
- `
+ it('parse baseline html', () => {
+ testRootElements(
+ parseHtml(
+ `
`
- )
- );
- });
+ )
+ );
+ });
- it('parse baseline html with moustache', () => {
- testRootElements(
- parseHtml(
- `
+ it('parse baseline html with moustache', () => {
+ testRootElements(
+ parseHtml(
+ `
`
- )
- );
- });
+ )
+ );
+ });
- it('parse baseline html with possibly un-closed start tag', () => {
- testRootElements(
- parseHtml(
- ` {
+ testRootElements(
+ parseHtml(
+ ``
- )
- );
- });
+ )
+ );
+ });
});
diff --git a/packages/language-server/test/lib/documents/utils.test.ts b/packages/language-server/test/lib/documents/utils.test.ts
index a76fd97eb..d90eb161c 100644
--- a/packages/language-server/test/lib/documents/utils.test.ts
+++ b/packages/language-server/test/lib/documents/utils.test.ts
@@ -1,167 +1,167 @@
import * as assert from 'assert';
import {
- getLineAtPosition,
- extractStyleTag,
- extractScriptTags,
- updateRelativeImport,
- getWordAt
+ getLineAtPosition,
+ extractStyleTag,
+ extractScriptTags,
+ updateRelativeImport,
+ getWordAt
} from '../../../src/lib/documents/utils';
import { Position } from 'vscode-languageserver';
describe('document/utils', () => {
- describe('extractTag', () => {
- it('supports boolean attributes', () => {
- const extracted = extractStyleTag('');
- assert.deepStrictEqual(extracted?.attributes, { test: 'test' });
- });
+ describe('extractTag', () => {
+ it('supports boolean attributes', () => {
+ const extracted = extractStyleTag('');
+ assert.deepStrictEqual(extracted?.attributes, { test: 'test' });
+ });
- it('supports unquoted attributes', () => {
- const extracted = extractStyleTag('');
- assert.deepStrictEqual(extracted?.attributes, {
- type: 'text/css'
- });
- });
+ it('supports unquoted attributes', () => {
+ const extracted = extractStyleTag('');
+ assert.deepStrictEqual(extracted?.attributes, {
+ type: 'text/css'
+ });
+ });
- it('does not extract style tag inside comment', () => {
- const text = `
+ it('does not extract style tag inside comment', () => {
+ const text = `
bla
`;
- assert.deepStrictEqual(extractStyleTag(text), {
- content: 'p{ color: blue; }',
- attributes: {},
- start: 108,
- end: 125,
- startPos: Position.create(3, 23),
- endPos: Position.create(3, 40),
- container: { start: 101, end: 133 }
- });
- });
+ assert.deepStrictEqual(extractStyleTag(text), {
+ content: 'p{ color: blue; }',
+ attributes: {},
+ start: 108,
+ end: 125,
+ startPos: Position.create(3, 23),
+ endPos: Position.create(3, 40),
+ container: { start: 101, end: 133 }
+ });
+ });
- it('does not extract tags starting with style/script', () => {
- // https://github.com/sveltejs/language-tools/issues/43
- // this would previously match .... due to misconfigured attribute matching regex
- const text = `
+ it('does not extract tags starting with style/script', () => {
+ // https://github.com/sveltejs/language-tools/issues/43
+ // this would previously match .... due to misconfigured attribute matching regex
+ const text = `
p{ color: blue; }
bla
>
`;
- assert.deepStrictEqual(extractStyleTag(text), null);
- });
+ assert.deepStrictEqual(extractStyleTag(text), null);
+ });
- it('is canse sensitive to style/script', () => {
- const text = `
+ it('is canse sensitive to style/script', () => {
+ const text = `
`;
- assert.deepStrictEqual(extractStyleTag(text), null);
- assert.deepStrictEqual(extractScriptTags(text), null);
- });
+ assert.deepStrictEqual(extractStyleTag(text), null);
+ assert.deepStrictEqual(extractScriptTags(text), null);
+ });
- it('only extract attribute until tag ends', () => {
- const text = `
+ it('only extract attribute until tag ends', () => {
+ const text = `
`;
- const extracted = extractScriptTags(text);
- const attributes = extracted?.script?.attributes;
- assert.deepStrictEqual(attributes, { type: 'typescript' });
- });
+ const extracted = extractScriptTags(text);
+ const attributes = extracted?.script?.attributes;
+ assert.deepStrictEqual(attributes, { type: 'typescript' });
+ });
- it('can extract with self-closing component before it', () => {
- const extracted = extractStyleTag('');
- assert.deepStrictEqual(extracted, {
- start: 22,
- end: 22,
- startPos: {
- character: 22,
- line: 0
- },
- endPos: {
- character: 22,
- line: 0
- },
- attributes: {},
- content: '',
- container: {
- end: 30,
- start: 15
- }
- });
- });
+ it('can extract with self-closing component before it', () => {
+ const extracted = extractStyleTag('');
+ assert.deepStrictEqual(extracted, {
+ start: 22,
+ end: 22,
+ startPos: {
+ character: 22,
+ line: 0
+ },
+ endPos: {
+ character: 22,
+ line: 0
+ },
+ attributes: {},
+ content: '',
+ container: {
+ end: 30,
+ start: 15
+ }
+ });
+ });
- it('can extract with unclosed component after it', () => {
- const extracted = extractStyleTag('asd
{/if}');
- assert.deepStrictEqual(extracted, {
- start: 7,
- end: 7,
- startPos: {
- character: 7,
- line: 0
- },
- endPos: {
- character: 7,
- line: 0
- },
- attributes: {},
- content: '',
- container: {
- start: 0,
- end: 15
- }
- });
- });
+ it('can extract with unclosed component after it', () => {
+ const extracted = extractStyleTag('asd{/if}');
+ assert.deepStrictEqual(extracted, {
+ start: 7,
+ end: 7,
+ startPos: {
+ character: 7,
+ line: 0
+ },
+ endPos: {
+ character: 7,
+ line: 0
+ },
+ attributes: {},
+ content: '',
+ container: {
+ start: 0,
+ end: 15
+ }
+ });
+ });
- it('extracts style tag', () => {
- const text = `
+ it('extracts style tag', () => {
+ const text = `
bla
`;
- assert.deepStrictEqual(extractStyleTag(text), {
- content: 'p{ color: blue; }',
- attributes: {},
- start: 51,
- end: 68,
- startPos: Position.create(2, 23),
- endPos: Position.create(2, 40),
- container: { start: 44, end: 76 }
- });
- });
+ assert.deepStrictEqual(extractStyleTag(text), {
+ content: 'p{ color: blue; }',
+ attributes: {},
+ start: 51,
+ end: 68,
+ startPos: Position.create(2, 23),
+ endPos: Position.create(2, 40),
+ container: { start: 44, end: 76 }
+ });
+ });
- it('extracts style tag with attributes', () => {
- const text = `
+ it('extracts style tag with attributes', () => {
+ const text = `
`;
- assert.deepStrictEqual(extractStyleTag(text), {
- content: 'p{ color: blue; }',
- attributes: { lang: 'scss' },
- start: 36,
- end: 53,
- startPos: Position.create(1, 35),
- endPos: Position.create(1, 52),
- container: { start: 17, end: 61 }
- });
- });
+ assert.deepStrictEqual(extractStyleTag(text), {
+ content: 'p{ color: blue; }',
+ attributes: { lang: 'scss' },
+ start: 36,
+ end: 53,
+ startPos: Position.create(1, 35),
+ endPos: Position.create(1, 52),
+ container: { start: 17, end: 61 }
+ });
+ });
- it('extracts style tag with attributes and extra whitespace', () => {
- const text = `
+ it('extracts style tag with attributes and extra whitespace', () => {
+ const text = `
`;
- assert.deepStrictEqual(extractStyleTag(text), {
- content: ' p{ color: blue; } ',
- attributes: { lang: 'scss' },
- start: 44,
- end: 65,
- startPos: Position.create(1, 43),
- endPos: Position.create(1, 64),
- container: { start: 17, end: 73 }
- });
- });
+ assert.deepStrictEqual(extractStyleTag(text), {
+ content: ' p{ color: blue; } ',
+ attributes: { lang: 'scss' },
+ start: 44,
+ end: 65,
+ startPos: Position.create(1, 43),
+ endPos: Position.create(1, 64),
+ container: { start: 17, end: 73 }
+ });
+ });
- it('extracts top level script tag only', () => {
- const text = `
+ it('extracts top level script tag only', () => {
+ const text = `
{#if name}
`;
- assert.deepStrictEqual(extractScriptTags(text)?.script, {
- content: 'top level script',
- attributes: {},
- start: 1243,
- end: 1259,
- startPos: Position.create(34, 24),
- endPos: Position.create(34, 40),
- container: { start: 1235, end: 1268 }
- });
- });
+ assert.deepStrictEqual(extractScriptTags(text)?.script, {
+ content: 'top level script',
+ attributes: {},
+ start: 1243,
+ end: 1259,
+ startPos: Position.create(34, 24),
+ endPos: Position.create(34, 40),
+ container: { start: 1235, end: 1268 }
+ });
+ });
- it('ignores script tag in svelte:head', () => {
- // https://github.com/sveltejs/language-tools/issues/143#issuecomment-636422045
- const text = `
+ it('ignores script tag in svelte:head', () => {
+ // https://github.com/sveltejs/language-tools/issues/143#issuecomment-636422045
+ const text = `
`;
- assert.deepStrictEqual(extractScriptTags(text), {
- moduleScript: {
- attributes: {
- context: 'module'
- },
- container: {
- end: 48,
- start: 13
- },
- content: 'a',
- start: 38,
- end: 39,
- startPos: {
- character: 37,
- line: 1
- },
- endPos: {
- character: 38,
- line: 1
- }
- },
- script: {
- attributes: {},
- container: {
- end: 79,
- start: 61
- },
- content: 'b',
- start: 69,
- end: 70,
- startPos: {
- character: 20,
- line: 2
- },
- endPos: {
- character: 21,
- line: 2
- }
- }
- });
- });
+ assert.deepStrictEqual(extractScriptTags(text), {
+ moduleScript: {
+ attributes: {
+ context: 'module'
+ },
+ container: {
+ end: 48,
+ start: 13
+ },
+ content: 'a',
+ start: 38,
+ end: 39,
+ startPos: {
+ character: 37,
+ line: 1
+ },
+ endPos: {
+ character: 38,
+ line: 1
+ }
+ },
+ script: {
+ attributes: {},
+ container: {
+ end: 79,
+ start: 61
+ },
+ content: 'b',
+ start: 69,
+ end: 70,
+ startPos: {
+ character: 20,
+ line: 2
+ },
+ endPos: {
+ character: 21,
+ line: 2
+ }
+ }
+ });
+ });
- it('extract tag correctly with #if and < operator', () => {
- const text = `
+ it('extract tag correctly with #if and < operator', () => {
+ const text = `
{#if value < 3}
bla
@@ -298,98 +298,98 @@ describe('document/utils', () => {
{:else if value < 4}
{/if}
`;
- assert.deepStrictEqual(extractScriptTags(text)?.script, {
- content: 'let value = 2',
- attributes: {},
- start: 159,
- end: 172,
- startPos: Position.create(7, 18),
- endPos: Position.create(7, 31),
- container: { start: 151, end: 181 }
- });
- });
- });
+ assert.deepStrictEqual(extractScriptTags(text)?.script, {
+ content: 'let value = 2',
+ attributes: {},
+ start: 159,
+ end: 172,
+ startPos: Position.create(7, 18),
+ endPos: Position.create(7, 31),
+ container: { start: 151, end: 181 }
+ });
+ });
+ });
- describe('#getLineAtPosition', () => {
- it('should return line at position (only one line)', () => {
- assert.deepStrictEqual(getLineAtPosition(Position.create(0, 1), 'ABC'), 'ABC');
- });
+ describe('#getLineAtPosition', () => {
+ it('should return line at position (only one line)', () => {
+ assert.deepStrictEqual(getLineAtPosition(Position.create(0, 1), 'ABC'), 'ABC');
+ });
- it('should return line at position (multiple lines)', () => {
- assert.deepStrictEqual(
- getLineAtPosition(Position.create(1, 1), 'ABC\nDEF\nGHI'),
- 'DEF\n'
- );
- });
- });
+ it('should return line at position (multiple lines)', () => {
+ assert.deepStrictEqual(
+ getLineAtPosition(Position.create(1, 1), 'ABC\nDEF\nGHI'),
+ 'DEF\n'
+ );
+ });
+ });
- describe('#updateRelativeImport', () => {
- it('should update path of component with ending', () => {
- const newPath = updateRelativeImport(
- 'C:/absolute/path/oldPath',
- 'C:/absolute/newPath',
- './Component.svelte'
- );
- assert.deepStrictEqual(newPath, '../path/oldPath/Component.svelte');
- });
+ describe('#updateRelativeImport', () => {
+ it('should update path of component with ending', () => {
+ const newPath = updateRelativeImport(
+ 'C:/absolute/path/oldPath',
+ 'C:/absolute/newPath',
+ './Component.svelte'
+ );
+ assert.deepStrictEqual(newPath, '../path/oldPath/Component.svelte');
+ });
- it('should update path of file without ending', () => {
- const newPath = updateRelativeImport(
- 'C:/absolute/path/oldPath',
- 'C:/absolute/newPath',
- './someTsFile'
- );
- assert.deepStrictEqual(newPath, '../path/oldPath/someTsFile');
- });
+ it('should update path of file without ending', () => {
+ const newPath = updateRelativeImport(
+ 'C:/absolute/path/oldPath',
+ 'C:/absolute/newPath',
+ './someTsFile'
+ );
+ assert.deepStrictEqual(newPath, '../path/oldPath/someTsFile');
+ });
- it('should update path of file going one up', () => {
- const newPath = updateRelativeImport(
- 'C:/absolute/path/oldPath',
- 'C:/absolute/path',
- './someTsFile'
- );
- assert.deepStrictEqual(newPath, './oldPath/someTsFile');
- });
- });
+ it('should update path of file going one up', () => {
+ const newPath = updateRelativeImport(
+ 'C:/absolute/path/oldPath',
+ 'C:/absolute/path',
+ './someTsFile'
+ );
+ assert.deepStrictEqual(newPath, './oldPath/someTsFile');
+ });
+ });
- describe('#getWordAt', () => {
- it('returns word between whitespaces', () => {
- assert.equal(getWordAt('qwd asd qwd', 5), 'asd');
- });
+ describe('#getWordAt', () => {
+ it('returns word between whitespaces', () => {
+ assert.equal(getWordAt('qwd asd qwd', 5), 'asd');
+ });
- it('returns word between whitespace and end of string', () => {
- assert.equal(getWordAt('qwd asd', 5), 'asd');
- });
+ it('returns word between whitespace and end of string', () => {
+ assert.equal(getWordAt('qwd asd', 5), 'asd');
+ });
- it('returns word between start of string and whitespace', () => {
- assert.equal(getWordAt('asd qwd', 2), 'asd');
- });
+ it('returns word between start of string and whitespace', () => {
+ assert.equal(getWordAt('asd qwd', 2), 'asd');
+ });
- it('returns word between start of string and end of string', () => {
- assert.equal(getWordAt('asd', 2), 'asd');
- });
+ it('returns word between start of string and end of string', () => {
+ assert.equal(getWordAt('asd', 2), 'asd');
+ });
- it('returns word with custom delimiters', () => {
- assert.equal(
- getWordAt('asd on:asd-qwd="asd" ', 10, { left: /\S+$/, right: /[\s=]/ }),
- 'on:asd-qwd'
- );
- });
+ it('returns word with custom delimiters', () => {
+ assert.equal(
+ getWordAt('asd on:asd-qwd="asd" ', 10, { left: /\S+$/, right: /[\s=]/ }),
+ 'on:asd-qwd'
+ );
+ });
- function testEvent(str: string, pos: number, expected: string) {
- assert.equal(getWordAt(str, pos, { left: /\S+$/, right: /[^\w$:]/ }), expected);
- }
+ function testEvent(str: string, pos: number, expected: string) {
+ assert.equal(getWordAt(str, pos, { left: /\S+$/, right: /[^\w$:]/ }), expected);
+ }
- it('returns event #1', () => {
- testEvent('', 8, 'on:');
- });
+ it('returns event #1', () => {
+ testEvent('
', 8, 'on:');
+ });
- it('returns event #2', () => {
- testEvent('
', 8, 'on:');
- });
+ it('returns event #2', () => {
+ testEvent('
', 8, 'on:');
+ });
- it('returns empty string when only whitespace', () => {
- assert.equal(getWordAt('a a', 2), '');
- });
- });
+ it('returns empty string when only whitespace', () => {
+ assert.equal(getWordAt('a a', 2), '');
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/PluginHost.test.ts b/packages/language-server/test/plugins/PluginHost.test.ts
index bfe733a35..8c0fd5c3e 100644
--- a/packages/language-server/test/plugins/PluginHost.test.ts
+++ b/packages/language-server/test/plugins/PluginHost.test.ts
@@ -1,11 +1,11 @@
import sinon from 'sinon';
import {
- CompletionItem,
- Location,
- LocationLink,
- Position,
- Range,
- TextDocumentItem
+ CompletionItem,
+ Location,
+ LocationLink,
+ Position,
+ Range,
+ TextDocumentItem
} from 'vscode-languageserver-types';
import { DocumentManager, Document } from '../../src/lib/documents';
import { LSPProviderConfig, PluginHost } from '../../src/plugins';
@@ -13,171 +13,171 @@ import { CompletionTriggerKind } from 'vscode-languageserver';
import assert from 'assert';
describe('PluginHost', () => {
- const textDocument: TextDocumentItem = {
- uri: 'file:///hello.svelte',
- version: 0,
- languageId: 'svelte',
- text: 'Hello, world!'
- };
-
- function setup
(
- pluginProviderStubs: T,
- config: LSPProviderConfig = {
- definitionLinkSupport: true,
- filterIncompleteCompletions: false
- }
- ) {
- const docManager = new DocumentManager(
- (textDocument) => new Document(textDocument.uri, textDocument.text)
- );
-
- const pluginHost = new PluginHost(docManager);
- const plugin = {
- ...pluginProviderStubs
- };
-
- pluginHost.initialize(config);
- pluginHost.register(plugin);
-
- return { docManager, pluginHost, plugin };
- }
-
- it('executes getDiagnostics on plugins', async () => {
- const { docManager, pluginHost, plugin } = setup({
- getDiagnostics: sinon.stub().returns([])
- });
- const document = docManager.openDocument(textDocument);
-
- await pluginHost.getDiagnostics(textDocument);
-
- sinon.assert.calledOnce(plugin.getDiagnostics);
- sinon.assert.calledWithExactly(plugin.getDiagnostics, document);
- });
-
- it('executes doHover on plugins', async () => {
- const { docManager, pluginHost, plugin } = setup({
- doHover: sinon.stub().returns(null)
- });
- const document = docManager.openDocument(textDocument);
- const pos = Position.create(0, 0);
-
- await pluginHost.doHover(textDocument, pos);
-
- sinon.assert.calledOnce(plugin.doHover);
- sinon.assert.calledWithExactly(plugin.doHover, document, pos);
- });
-
- it('executes getCompletions on plugins', async () => {
- const { docManager, pluginHost, plugin } = setup({
- getCompletions: sinon.stub().returns({ items: [] })
- });
- const document = docManager.openDocument(textDocument);
- const pos = Position.create(0, 0);
-
- await pluginHost.getCompletions(textDocument, pos, {
- triggerKind: CompletionTriggerKind.TriggerCharacter,
- triggerCharacter: '.'
- });
-
- sinon.assert.calledOnce(plugin.getCompletions);
- sinon.assert.calledWithExactly(plugin.getCompletions, document, pos, {
- triggerKind: CompletionTriggerKind.TriggerCharacter,
- triggerCharacter: '.'
- });
- });
-
- describe('getCompletions (incomplete)', () => {
- function setupGetIncompleteCompletions(filterServerSide: boolean) {
- const { docManager, pluginHost } = setup(
- {
- getCompletions: sinon.stub().returns({
- isIncomplete: true,
- items: [{ label: 'Hello' }, { label: 'foo' }]
- })
- },
- { definitionLinkSupport: true, filterIncompleteCompletions: filterServerSide }
- );
- docManager.openDocument(textDocument);
- return pluginHost;
- }
-
- it('filters client side', async () => {
- const pluginHost = setupGetIncompleteCompletions(false);
- const completions = await pluginHost.getCompletions(
- textDocument,
- Position.create(0, 2)
- );
-
- assert.deepStrictEqual(completions.items, [
- { label: 'Hello' },
- { label: 'foo' }
- ]);
- });
-
- it('filters server side', async () => {
- const pluginHost = setupGetIncompleteCompletions(true);
- const completions = await pluginHost.getCompletions(
- textDocument,
- Position.create(0, 2)
- );
-
- assert.deepStrictEqual(completions.items, [{ label: 'Hello' }]);
- });
- });
-
- describe('getDefinitions', () => {
- function setupGetDefinitions(linkSupport: boolean) {
- const { pluginHost, docManager } = setup(
- {
- getDefinitions: sinon.stub().returns([
- {
- targetRange: Range.create(Position.create(0, 0), Position.create(0, 2)),
- targetSelectionRange: Range.create(
- Position.create(0, 0),
- Position.create(0, 1)
- ),
- targetUri: 'uri'
- }
- ])
- },
- { definitionLinkSupport: linkSupport, filterIncompleteCompletions: false }
- );
- docManager.openDocument(textDocument);
- return pluginHost;
- }
-
- it('uses LocationLink', async () => {
- const pluginHost = setupGetDefinitions(true);
- const definitions = await pluginHost.getDefinitions(
- textDocument,
- Position.create(0, 0)
- );
-
- assert.deepStrictEqual(definitions, [
- {
- targetRange: Range.create(Position.create(0, 0), Position.create(0, 2)),
- targetSelectionRange: Range.create(
- Position.create(0, 0),
- Position.create(0, 1)
- ),
- targetUri: 'uri'
- }
- ]);
- });
-
- it('uses Location', async () => {
- const pluginHost = setupGetDefinitions(false);
- const definitions = await pluginHost.getDefinitions(
- textDocument,
- Position.create(0, 0)
- );
-
- assert.deepStrictEqual(definitions, [
- {
- range: Range.create(Position.create(0, 0), Position.create(0, 1)),
- uri: 'uri'
- }
- ]);
- });
- });
+ const textDocument: TextDocumentItem = {
+ uri: 'file:///hello.svelte',
+ version: 0,
+ languageId: 'svelte',
+ text: 'Hello, world!'
+ };
+
+ function setup(
+ pluginProviderStubs: T,
+ config: LSPProviderConfig = {
+ definitionLinkSupport: true,
+ filterIncompleteCompletions: false
+ }
+ ) {
+ const docManager = new DocumentManager(
+ (textDocument) => new Document(textDocument.uri, textDocument.text)
+ );
+
+ const pluginHost = new PluginHost(docManager);
+ const plugin = {
+ ...pluginProviderStubs
+ };
+
+ pluginHost.initialize(config);
+ pluginHost.register(plugin);
+
+ return { docManager, pluginHost, plugin };
+ }
+
+ it('executes getDiagnostics on plugins', async () => {
+ const { docManager, pluginHost, plugin } = setup({
+ getDiagnostics: sinon.stub().returns([])
+ });
+ const document = docManager.openDocument(textDocument);
+
+ await pluginHost.getDiagnostics(textDocument);
+
+ sinon.assert.calledOnce(plugin.getDiagnostics);
+ sinon.assert.calledWithExactly(plugin.getDiagnostics, document);
+ });
+
+ it('executes doHover on plugins', async () => {
+ const { docManager, pluginHost, plugin } = setup({
+ doHover: sinon.stub().returns(null)
+ });
+ const document = docManager.openDocument(textDocument);
+ const pos = Position.create(0, 0);
+
+ await pluginHost.doHover(textDocument, pos);
+
+ sinon.assert.calledOnce(plugin.doHover);
+ sinon.assert.calledWithExactly(plugin.doHover, document, pos);
+ });
+
+ it('executes getCompletions on plugins', async () => {
+ const { docManager, pluginHost, plugin } = setup({
+ getCompletions: sinon.stub().returns({ items: [] })
+ });
+ const document = docManager.openDocument(textDocument);
+ const pos = Position.create(0, 0);
+
+ await pluginHost.getCompletions(textDocument, pos, {
+ triggerKind: CompletionTriggerKind.TriggerCharacter,
+ triggerCharacter: '.'
+ });
+
+ sinon.assert.calledOnce(plugin.getCompletions);
+ sinon.assert.calledWithExactly(plugin.getCompletions, document, pos, {
+ triggerKind: CompletionTriggerKind.TriggerCharacter,
+ triggerCharacter: '.'
+ });
+ });
+
+ describe('getCompletions (incomplete)', () => {
+ function setupGetIncompleteCompletions(filterServerSide: boolean) {
+ const { docManager, pluginHost } = setup(
+ {
+ getCompletions: sinon.stub().returns({
+ isIncomplete: true,
+ items: [{ label: 'Hello' }, { label: 'foo' }]
+ })
+ },
+ { definitionLinkSupport: true, filterIncompleteCompletions: filterServerSide }
+ );
+ docManager.openDocument(textDocument);
+ return pluginHost;
+ }
+
+ it('filters client side', async () => {
+ const pluginHost = setupGetIncompleteCompletions(false);
+ const completions = await pluginHost.getCompletions(
+ textDocument,
+ Position.create(0, 2)
+ );
+
+ assert.deepStrictEqual(completions.items, [
+ { label: 'Hello' },
+ { label: 'foo' }
+ ]);
+ });
+
+ it('filters server side', async () => {
+ const pluginHost = setupGetIncompleteCompletions(true);
+ const completions = await pluginHost.getCompletions(
+ textDocument,
+ Position.create(0, 2)
+ );
+
+ assert.deepStrictEqual(completions.items, [{ label: 'Hello' }]);
+ });
+ });
+
+ describe('getDefinitions', () => {
+ function setupGetDefinitions(linkSupport: boolean) {
+ const { pluginHost, docManager } = setup(
+ {
+ getDefinitions: sinon.stub().returns([
+ {
+ targetRange: Range.create(Position.create(0, 0), Position.create(0, 2)),
+ targetSelectionRange: Range.create(
+ Position.create(0, 0),
+ Position.create(0, 1)
+ ),
+ targetUri: 'uri'
+ }
+ ])
+ },
+ { definitionLinkSupport: linkSupport, filterIncompleteCompletions: false }
+ );
+ docManager.openDocument(textDocument);
+ return pluginHost;
+ }
+
+ it('uses LocationLink', async () => {
+ const pluginHost = setupGetDefinitions(true);
+ const definitions = await pluginHost.getDefinitions(
+ textDocument,
+ Position.create(0, 0)
+ );
+
+ assert.deepStrictEqual(definitions, [
+ {
+ targetRange: Range.create(Position.create(0, 0), Position.create(0, 2)),
+ targetSelectionRange: Range.create(
+ Position.create(0, 0),
+ Position.create(0, 1)
+ ),
+ targetUri: 'uri'
+ }
+ ]);
+ });
+
+ it('uses Location', async () => {
+ const pluginHost = setupGetDefinitions(false);
+ const definitions = await pluginHost.getDefinitions(
+ textDocument,
+ Position.create(0, 0)
+ );
+
+ assert.deepStrictEqual(definitions, [
+ {
+ range: Range.create(Position.create(0, 0), Position.create(0, 1)),
+ uri: 'uri'
+ }
+ ]);
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/css/CSSPlugin.test.ts b/packages/language-server/test/plugins/css/CSSPlugin.test.ts
index c29cc1695..759ea2a0f 100644
--- a/packages/language-server/test/plugins/css/CSSPlugin.test.ts
+++ b/packages/language-server/test/plugins/css/CSSPlugin.test.ts
@@ -1,411 +1,411 @@
import * as assert from 'assert';
import {
- Range,
- Position,
- Hover,
- CompletionItem,
- CompletionItemKind,
- TextEdit,
- CompletionContext,
- SelectionRange,
- CompletionTriggerKind
+ Range,
+ Position,
+ Hover,
+ CompletionItem,
+ CompletionItemKind,
+ TextEdit,
+ CompletionContext,
+ SelectionRange,
+ CompletionTriggerKind
} from 'vscode-languageserver';
import { DocumentManager, Document } from '../../../src/lib/documents';
import { CSSPlugin } from '../../../src/plugins';
import { LSConfigManager } from '../../../src/ls-config';
describe('CSS Plugin', () => {
- function setup(content: string) {
- const document = new Document('file:///hello.svelte', content);
- const docManager = new DocumentManager(() => document);
- const pluginManager = new LSConfigManager();
- const plugin = new CSSPlugin(docManager, pluginManager);
- docManager.openDocument('some doc');
- return { plugin, document };
- }
-
- describe('provides hover info', () => {
- it('for normal css', () => {
- const { plugin, document } = setup('');
-
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 8)), {
- contents: [
- { language: 'html', value: '' },
- '[Selector Specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity): (0, 0, 1)'
- ],
- range: Range.create(0, 7, 0, 9)
- });
-
- assert.strictEqual(plugin.doHover(document, Position.create(0, 10)), null);
- });
-
- it('not for SASS', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 20)), null);
- });
-
- it('not for stylus', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 22)), null);
- });
-
- it('for style attribute', () => {
- const { plugin, document } = setup('
');
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 13)), {
- contents: {
- kind: 'markdown',
- value:
- 'Specifies the height of the content area,' +
- " padding area or border area \\(depending on 'box\\-sizing'\\)" +
- ' of certain boxes\\.\n' +
- '\nSyntax: <viewport\\-length>\\{1,2\\}\n\n' +
- '[MDN Reference](https://developer.mozilla.org/docs/Web/CSS/height)'
- },
- range: Range.create(0, 12, 0, 24)
- });
- });
-
- it('not for style attribute with interpolation', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 13)), null);
- });
- });
-
- describe('provides completions', () => {
- it('for normal css', () => {
- const { plugin, document } = setup('');
-
- const completions = plugin.getCompletions(document, Position.create(0, 7), {
- triggerCharacter: '.'
- } as CompletionContext);
- assert.ok(
- Array.isArray(completions && completions.items),
- 'Expected completion items to be an array'
- );
- assert.ok(completions!.items.length > 0, 'Expected completions to have length');
-
- assert.deepStrictEqual(completions!.items[0], {
- label: '@charset',
- kind: CompletionItemKind.Keyword,
- documentation: {
- kind: 'markdown',
- value:
- 'Defines character set of the document\\.\n\n[MDN Reference](https://developer.mozilla.org/docs/Web/CSS/@charset)'
- },
- textEdit: TextEdit.insert(Position.create(0, 7), '@charset'),
- tags: []
- });
- });
-
- it('for :global modifier', () => {
- const { plugin, document } = setup('');
-
- const completions = plugin.getCompletions(document, Position.create(0, 9), {
- triggerCharacter: ':'
- } as CompletionContext);
- const globalCompletion = completions?.items.find((item) => item.label === ':global()');
- assert.ok(globalCompletion);
- });
-
- it('not for stylus', () => {
- const { plugin, document } = setup('');
- const completions = plugin.getCompletions(document, Position.create(0, 21), {
- triggerCharacter: '.'
- } as CompletionContext);
- assert.deepStrictEqual(completions, null);
- });
-
- it('for style attribute', () => {
- const { plugin, document } = setup('');
- const completions = plugin.getCompletions(document, Position.create(0, 22), {
- triggerKind: CompletionTriggerKind.Invoked
- } as CompletionContext);
- assert.deepStrictEqual(
- completions?.items.find((item) => item.label === 'none'),
- {
- insertTextFormat: undefined,
- kind: 12,
- label: 'none',
- documentation: {
- kind: 'markdown',
- value: 'The element and its descendants generates no boxes\\.'
- },
- sortText: ' ',
- tags: [],
- textEdit: {
- newText: 'none',
- range: {
- start: {
- line: 0,
- character: 21
- },
- end: {
- line: 0,
- character: 22
- }
- }
- }
- }
- );
- });
-
- it('not for style attribute with interpolation', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getCompletions(document, Position.create(0, 21)), null);
- });
- });
-
- describe('provides diagnostics', () => {
- it('- everything ok', () => {
- const { plugin, document } = setup('');
-
- const diagnostics = plugin.getDiagnostics(document);
-
- assert.deepStrictEqual(diagnostics, []);
- });
-
- it('- has error', () => {
- const { plugin, document } = setup('');
-
- const diagnostics = plugin.getDiagnostics(document);
-
- assert.deepStrictEqual(diagnostics, [
- {
- code: 'unknownProperties',
- message: "Unknown property: 'iDunnoDisProperty'",
- range: {
- end: {
- character: 28,
- line: 0
- },
- start: {
- character: 11,
- line: 0
- }
- },
- severity: 2,
- source: 'css'
- }
- ]);
- });
-
- it('- no diagnostics for sass', () => {
- const { plugin, document } = setup(
- `');
+
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 8)), {
+ contents: [
+ { language: 'html', value: '' },
+ '[Selector Specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity): (0, 0, 1)'
+ ],
+ range: Range.create(0, 7, 0, 9)
+ });
+
+ assert.strictEqual(plugin.doHover(document, Position.create(0, 10)), null);
+ });
+
+ it('not for SASS', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 20)), null);
+ });
+
+ it('not for stylus', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 22)), null);
+ });
+
+ it('for style attribute', () => {
+ const { plugin, document } = setup('
');
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 13)), {
+ contents: {
+ kind: 'markdown',
+ value:
+ 'Specifies the height of the content area,' +
+ " padding area or border area \\(depending on 'box\\-sizing'\\)" +
+ ' of certain boxes\\.\n' +
+ '\nSyntax: <viewport\\-length>\\{1,2\\}\n\n' +
+ '[MDN Reference](https://developer.mozilla.org/docs/Web/CSS/height)'
+ },
+ range: Range.create(0, 12, 0, 24)
+ });
+ });
+
+ it('not for style attribute with interpolation', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 13)), null);
+ });
+ });
+
+ describe('provides completions', () => {
+ it('for normal css', () => {
+ const { plugin, document } = setup('');
+
+ const completions = plugin.getCompletions(document, Position.create(0, 7), {
+ triggerCharacter: '.'
+ } as CompletionContext);
+ assert.ok(
+ Array.isArray(completions && completions.items),
+ 'Expected completion items to be an array'
+ );
+ assert.ok(completions!.items.length > 0, 'Expected completions to have length');
+
+ assert.deepStrictEqual(completions!.items[0], {
+ label: '@charset',
+ kind: CompletionItemKind.Keyword,
+ documentation: {
+ kind: 'markdown',
+ value:
+ 'Defines character set of the document\\.\n\n[MDN Reference](https://developer.mozilla.org/docs/Web/CSS/@charset)'
+ },
+ textEdit: TextEdit.insert(Position.create(0, 7), '@charset'),
+ tags: []
+ });
+ });
+
+ it('for :global modifier', () => {
+ const { plugin, document } = setup('');
+
+ const completions = plugin.getCompletions(document, Position.create(0, 9), {
+ triggerCharacter: ':'
+ } as CompletionContext);
+ const globalCompletion = completions?.items.find((item) => item.label === ':global()');
+ assert.ok(globalCompletion);
+ });
+
+ it('not for stylus', () => {
+ const { plugin, document } = setup('');
+ const completions = plugin.getCompletions(document, Position.create(0, 21), {
+ triggerCharacter: '.'
+ } as CompletionContext);
+ assert.deepStrictEqual(completions, null);
+ });
+
+ it('for style attribute', () => {
+ const { plugin, document } = setup('');
+ const completions = plugin.getCompletions(document, Position.create(0, 22), {
+ triggerKind: CompletionTriggerKind.Invoked
+ } as CompletionContext);
+ assert.deepStrictEqual(
+ completions?.items.find((item) => item.label === 'none'),
+ {
+ insertTextFormat: undefined,
+ kind: 12,
+ label: 'none',
+ documentation: {
+ kind: 'markdown',
+ value: 'The element and its descendants generates no boxes\\.'
+ },
+ sortText: ' ',
+ tags: [],
+ textEdit: {
+ newText: 'none',
+ range: {
+ start: {
+ line: 0,
+ character: 21
+ },
+ end: {
+ line: 0,
+ character: 22
+ }
+ }
+ }
+ }
+ );
+ });
+
+ it('not for style attribute with interpolation', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getCompletions(document, Position.create(0, 21)), null);
+ });
+ });
+
+ describe('provides diagnostics', () => {
+ it('- everything ok', () => {
+ const { plugin, document } = setup('');
+
+ const diagnostics = plugin.getDiagnostics(document);
+
+ assert.deepStrictEqual(diagnostics, []);
+ });
+
+ it('- has error', () => {
+ const { plugin, document } = setup('');
+
+ const diagnostics = plugin.getDiagnostics(document);
+
+ assert.deepStrictEqual(diagnostics, [
+ {
+ code: 'unknownProperties',
+ message: "Unknown property: 'iDunnoDisProperty'",
+ range: {
+ end: {
+ character: 28,
+ line: 0
+ },
+ start: {
+ character: 11,
+ line: 0
+ }
+ },
+ severity: 2,
+ source: 'css'
+ }
+ ]);
+ });
+
+ it('- no diagnostics for sass', () => {
+ const { plugin, document } = setup(
+ ``
- );
- const diagnostics = plugin.getDiagnostics(document);
- assert.deepStrictEqual(diagnostics, []);
- });
-
- it('- no diagnostics for stylus', () => {
- const { plugin, document } = setup(
- ``
- );
- const diagnostics = plugin.getDiagnostics(document);
- assert.deepStrictEqual(diagnostics, []);
- });
- });
-
- describe('provides document colors', () => {
- it('for normal css', () => {
- const { plugin, document } = setup('');
-
- const colors = plugin.getColorPresentations(
- document,
- {
- start: { line: 0, character: 17 },
- end: { line: 0, character: 21 }
- },
- { alpha: 1, blue: 255, green: 0, red: 0 }
- );
-
- assert.deepStrictEqual(colors, [
- {
- label: 'rgb(0, 0, 65025)',
- textEdit: {
- range: {
- end: {
- character: 21,
- line: 0
- },
- start: {
- character: 17,
- line: 0
- }
- },
- newText: 'rgb(0, 0, 65025)'
- }
- },
- {
- label: '#00000fe01',
- textEdit: {
- range: {
- end: {
- character: 21,
- line: 0
- },
- start: {
- character: 17,
- line: 0
- }
- },
- newText: '#00000fe01'
- }
- },
- {
- label: 'hsl(240, -101%, 12750%)',
- textEdit: {
- range: {
- end: {
- character: 21,
- line: 0
- },
- start: {
- character: 17,
- line: 0
- }
- },
- newText: 'hsl(240, -101%, 12750%)'
- }
- }
- ]);
- });
-
- it('not for SASS', () => {
- const { plugin, document } = setup(`');
+
+ const colors = plugin.getColorPresentations(
+ document,
+ {
+ start: { line: 0, character: 17 },
+ end: { line: 0, character: 21 }
+ },
+ { alpha: 1, blue: 255, green: 0, red: 0 }
+ );
+
+ assert.deepStrictEqual(colors, [
+ {
+ label: 'rgb(0, 0, 65025)',
+ textEdit: {
+ range: {
+ end: {
+ character: 21,
+ line: 0
+ },
+ start: {
+ character: 17,
+ line: 0
+ }
+ },
+ newText: 'rgb(0, 0, 65025)'
+ }
+ },
+ {
+ label: '#00000fe01',
+ textEdit: {
+ range: {
+ end: {
+ character: 21,
+ line: 0
+ },
+ start: {
+ character: 17,
+ line: 0
+ }
+ },
+ newText: '#00000fe01'
+ }
+ },
+ {
+ label: 'hsl(240, -101%, 12750%)',
+ textEdit: {
+ range: {
+ end: {
+ character: 21,
+ line: 0
+ },
+ start: {
+ character: 17,
+ line: 0
+ }
+ },
+ newText: 'hsl(240, -101%, 12750%)'
+ }
+ }
+ ]);
+ });
+
+ it('not for SASS', () => {
+ const { plugin, document } = setup(``);
- assert.deepStrictEqual(
- plugin.getColorPresentations(
- document,
- {
- start: { line: 2, character: 22 },
- end: { line: 2, character: 26 }
- },
- { alpha: 1, blue: 255, green: 0, red: 0 }
- ),
- []
- );
- assert.deepStrictEqual(plugin.getDocumentColors(document), []);
- });
-
- it('not for stylus', () => {
- const { plugin, document } = setup(``);
- assert.deepStrictEqual(
- plugin.getColorPresentations(
- document,
- {
- start: { line: 2, character: 22 },
- end: { line: 2, character: 26 }
- },
- { alpha: 1, blue: 255, green: 0, red: 0 }
- ),
- []
- );
- assert.deepStrictEqual(plugin.getDocumentColors(document), []);
- });
- });
-
- describe('provides document symbols', () => {
- it('for normal css', () => {
- const { plugin, document } = setup('');
-
- const symbols = plugin.getDocumentSymbols(document);
-
- assert.deepStrictEqual(symbols, [
- {
- containerName: 'style',
- kind: 5,
- location: {
- range: {
- end: {
- character: 23,
- line: 0
- },
- start: {
- character: 7,
- line: 0
- }
- },
- uri: 'file:///hello.svelte'
- },
- name: 'h1'
- }
- ]);
- });
-
- it('not for SASS', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getDocumentSymbols(document), []);
- });
-
- it('not for stylus', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getDocumentSymbols(document), []);
- });
- });
-
- it('provides selection range', () => {
- const { plugin, document } = setup('');
-
- const selectionRange = plugin.getSelectionRange(document, Position.create(0, 11));
-
- assert.deepStrictEqual(selectionRange, {
- parent: {
- parent: {
- parent: undefined,
- range: {
- end: {
- character: 12,
- line: 0
- },
- start: {
- character: 7,
- line: 0
- }
- }
- },
- range: {
- end: {
- character: 12,
- line: 0
- },
- start: {
- character: 10,
- line: 0
- }
- }
- },
- range: {
- end: {
- character: 11,
- line: 0
- },
- start: {
- character: 11,
- line: 0
- }
- }
- });
- });
-
- it('return null for selection range when not in style', () => {
- const { plugin, document } = setup('');
-
- const selectionRange = plugin.getSelectionRange(document, Position.create(0, 10));
-
- assert.equal(selectionRange, null);
- });
+ assert.deepStrictEqual(
+ plugin.getColorPresentations(
+ document,
+ {
+ start: { line: 2, character: 22 },
+ end: { line: 2, character: 26 }
+ },
+ { alpha: 1, blue: 255, green: 0, red: 0 }
+ ),
+ []
+ );
+ assert.deepStrictEqual(plugin.getDocumentColors(document), []);
+ });
+ });
+
+ describe('provides document symbols', () => {
+ it('for normal css', () => {
+ const { plugin, document } = setup('');
+
+ const symbols = plugin.getDocumentSymbols(document);
+
+ assert.deepStrictEqual(symbols, [
+ {
+ containerName: 'style',
+ kind: 5,
+ location: {
+ range: {
+ end: {
+ character: 23,
+ line: 0
+ },
+ start: {
+ character: 7,
+ line: 0
+ }
+ },
+ uri: 'file:///hello.svelte'
+ },
+ name: 'h1'
+ }
+ ]);
+ });
+
+ it('not for SASS', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getDocumentSymbols(document), []);
+ });
+
+ it('not for stylus', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getDocumentSymbols(document), []);
+ });
+ });
+
+ it('provides selection range', () => {
+ const { plugin, document } = setup('');
+
+ const selectionRange = plugin.getSelectionRange(document, Position.create(0, 11));
+
+ assert.deepStrictEqual(selectionRange, {
+ parent: {
+ parent: {
+ parent: undefined,
+ range: {
+ end: {
+ character: 12,
+ line: 0
+ },
+ start: {
+ character: 7,
+ line: 0
+ }
+ }
+ },
+ range: {
+ end: {
+ character: 12,
+ line: 0
+ },
+ start: {
+ character: 10,
+ line: 0
+ }
+ }
+ },
+ range: {
+ end: {
+ character: 11,
+ line: 0
+ },
+ start: {
+ character: 11,
+ line: 0
+ }
+ }
+ });
+ });
+
+ it('return null for selection range when not in style', () => {
+ const { plugin, document } = setup('');
+
+ const selectionRange = plugin.getSelectionRange(document, Position.create(0, 10));
+
+ assert.equal(selectionRange, null);
+ });
});
diff --git a/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts b/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts
index 6d3321246..1630c10eb 100644
--- a/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts
+++ b/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts
@@ -5,74 +5,74 @@ import { LSConfigManager } from '../../../../src/ls-config';
import { CSSPlugin } from '../../../../src/plugins';
import { CSSDocument } from '../../../../src/plugins/css/CSSDocument';
import {
- collectSelectors,
- NodeType,
- CSSNode
+ collectSelectors,
+ NodeType,
+ CSSNode
} from '../../../../src/plugins/css/features/getIdClassCompletion';
describe('getIdClassCompletion', () => {
- function createDocument(content: string) {
- return new Document('file:///hello.svelte', content);
- }
+ function createDocument(content: string) {
+ return new Document('file:///hello.svelte', content);
+ }
- function createCSSDocument(content: string) {
- return new CSSDocument(createDocument(content));
- }
+ function createCSSDocument(content: string) {
+ return new CSSDocument(createDocument(content));
+ }
- function testSelectors(items: CompletionItem[], expectedSelectors: string[]) {
- assert.deepStrictEqual(
- items.map((item) => item.label),
- expectedSelectors,
- 'vscode-language-services might have changed the NodeType enum. Check if we need to update it'
- );
- }
+ function testSelectors(items: CompletionItem[], expectedSelectors: string[]) {
+ assert.deepStrictEqual(
+ items.map((item) => item.label),
+ expectedSelectors,
+ 'vscode-language-services might have changed the NodeType enum. Check if we need to update it'
+ );
+ }
- it('collect css classes', () => {
- const actual = collectSelectors(
- createCSSDocument('').stylesheet as CSSNode,
- NodeType.ClassSelector
- );
- testSelectors(actual, ['abc']);
- });
+ it('collect css classes', () => {
+ const actual = collectSelectors(
+ createCSSDocument('').stylesheet as CSSNode,
+ NodeType.ClassSelector
+ );
+ testSelectors(actual, ['abc']);
+ });
- it('collect css ids', () => {
- const actual = collectSelectors(
- createCSSDocument('').stylesheet as CSSNode,
- NodeType.IdentifierSelector
- );
- testSelectors(actual, ['abc']);
- });
+ it('collect css ids', () => {
+ const actual = collectSelectors(
+ createCSSDocument('').stylesheet as CSSNode,
+ NodeType.IdentifierSelector
+ );
+ testSelectors(actual, ['abc']);
+ });
- function setup(content: string) {
- const document = createDocument(content);
- const docManager = new DocumentManager(() => document);
- const pluginManager = new LSConfigManager();
- const plugin = new CSSPlugin(docManager, pluginManager);
- docManager.openDocument('some doc');
- return { plugin, document };
- }
+ function setup(content: string) {
+ const document = createDocument(content);
+ const docManager = new DocumentManager(() => document);
+ const pluginManager = new LSConfigManager();
+ const plugin = new CSSPlugin(docManager, pluginManager);
+ docManager.openDocument('some doc');
+ return { plugin, document };
+ }
- it('provides css classes completion for class attribute', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 11 }), {
- isIncomplete: false,
- items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
- } as CompletionList);
- });
+ it('provides css classes completion for class attribute', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 11 }), {
+ isIncomplete: false,
+ items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
+ } as CompletionList);
+ });
- it('provides css classes completion for class directive', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 11 }), {
- isIncomplete: false,
- items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
- } as CompletionList);
- });
+ it('provides css classes completion for class directive', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 11 }), {
+ isIncomplete: false,
+ items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
+ } as CompletionList);
+ });
- it('provides css id completion for id attribute', () => {
- const { plugin, document } = setup('');
- assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 8 }), {
- isIncomplete: false,
- items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
- } as CompletionList);
- });
+ it('provides css id completion for id attribute', () => {
+ const { plugin, document } = setup('');
+ assert.deepStrictEqual(plugin.getCompletions(document, { line: 0, character: 8 }), {
+ isIncomplete: false,
+ items: [{ label: 'abc', kind: CompletionItemKind.Keyword }]
+ } as CompletionList);
+ });
});
diff --git a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts
index f1301c421..439efe96e 100644
--- a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts
+++ b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts
@@ -1,192 +1,192 @@
import * as assert from 'assert';
import {
- Range,
- Position,
- Hover,
- CompletionItem,
- TextEdit,
- CompletionItemKind,
- InsertTextFormat
+ Range,
+ Position,
+ Hover,
+ CompletionItem,
+ TextEdit,
+ CompletionItemKind,
+ InsertTextFormat
} from 'vscode-languageserver';
import { HTMLPlugin } from '../../../src/plugins';
import { DocumentManager, Document } from '../../../src/lib/documents';
import { LSConfigManager } from '../../../src/ls-config';
describe('HTML Plugin', () => {
- function setup(content: string) {
- const document = new Document('file:///hello.svelte', content);
- const docManager = new DocumentManager(() => document);
- const pluginManager = new LSConfigManager();
- const plugin = new HTMLPlugin(docManager, pluginManager);
- docManager.openDocument('some doc');
- return { plugin, document };
- }
-
- it('provides hover info', async () => {
- const { plugin, document } = setup('Hello, world!
');
-
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 2)), {
- contents: {
- kind: 'markdown',
- value:
- 'The h1 element represents a section heading.\n\n[MDN Reference](https://developer.mozilla.org/docs/Web/HTML/Element/Heading_Elements)'
- },
-
- range: Range.create(0, 1, 0, 3)
- });
-
- assert.strictEqual(plugin.doHover(document, Position.create(0, 10)), null);
- });
-
- it('does not provide hover info for component having the same name as a html element but being uppercase', async () => {
- const { plugin, document } = setup('');
-
- assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 2)), null);
- });
-
- it('provides completions', async () => {
- const { plugin, document } = setup('<');
-
- const completions = plugin.getCompletions(document, Position.create(0, 1));
- assert.ok(Array.isArray(completions && completions.items));
- assert.ok(completions!.items.length > 0);
-
- assert.deepStrictEqual(completions!.items[0], {
- label: '!DOCTYPE',
- kind: CompletionItemKind.Property,
- documentation: 'A preamble for an HTML document.',
- textEdit: TextEdit.insert(Position.create(0, 1), '!DOCTYPE html>'),
- insertTextFormat: InsertTextFormat.PlainText
- });
- });
-
- it('does not provide completions inside of moustache tag', async () => {
- const { plugin, document } = setup('');
-
- const completions = plugin.getCompletions(document, Position.create(0, 20));
- assert.strictEqual(completions, null);
-
- const tagCompletion = plugin.doTagComplete(document, Position.create(0, 20));
- assert.strictEqual(tagCompletion, null);
- });
-
- it('does provide completions outside of moustache tag', async () => {
- const { plugin, document } = setup('
');
-
- const completions = plugin.getCompletions(document, Position.create(0, 21));
- assert.deepEqual(completions?.items[0], {
- filterText: '
',
- insertTextFormat: 2,
- kind: 10,
- label: '
',
- textEdit: {
- newText: '$0',
- range: {
- end: {
- character: 21,
- line: 0
- },
- start: {
- character: 21,
- line: 0
- }
- }
- }
- });
-
- const tagCompletion = plugin.doTagComplete(document, Position.create(0, 21));
- assert.strictEqual(tagCompletion, '$0
');
- });
-
- it('does provide lang in completions', async () => {
- const { plugin, document } = setup('
item.label === 'style (lang="less")'));
- });
-
- it('does not provide lang in completions for attributes', async () => {
- const { plugin, document } = setup(' item.label === 'style (lang="less")'),
- undefined
- );
- });
-
- it('does not provide rename for element being uppercase', async () => {
- const { plugin, document } = setup('
');
-
- assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 2)), null);
- assert.deepStrictEqual(plugin.rename(document, Position.create(0, 2), 'p'), null);
- });
-
- it('does not provide rename for valid element but incorrect position', () => {
- const { plugin, document } = setup('
ab}>asd
');
- const newName = 'p';
-
- assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 16)), null);
- assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 5)), null);
- assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 26)), null);
-
- assert.deepStrictEqual(plugin.rename(document, Position.create(0, 16), newName), null);
- assert.deepStrictEqual(plugin.rename(document, Position.create(0, 5), newName), null);
- assert.deepStrictEqual(plugin.rename(document, Position.create(0, 26), newName), null);
- });
-
- it('provides rename for element', () => {
- const { plugin, document } = setup('
{}}>
');
- const newName = 'p';
-
- const pepareRenameInfo = Range.create(Position.create(0, 1), Position.create(0, 4));
- assert.deepStrictEqual(
- plugin.prepareRename(document, Position.create(0, 2)),
- pepareRenameInfo
- );
- assert.deepStrictEqual(
- plugin.prepareRename(document, Position.create(0, 28)),
- pepareRenameInfo
- );
-
- const renameInfo = {
- changes: {
- [document.uri]: [
- {
- newText: 'p',
- range: {
- start: { line: 0, character: 1 },
- end: { line: 0, character: 4 }
- }
- },
- {
- newText: 'p',
- range: {
- start: { line: 0, character: 27 },
- end: { line: 0, character: 30 }
- }
- }
- ]
- }
- };
- assert.deepStrictEqual(plugin.rename(document, Position.create(0, 2), newName), renameInfo);
- assert.deepStrictEqual(
- plugin.rename(document, Position.create(0, 28), newName),
- renameInfo
- );
- });
-
- it('provides linked editing ranges', async () => {
- const { plugin, document } = setup('
');
-
- const ranges = plugin.getLinkedEditingRanges(document, Position.create(0, 3));
- assert.deepStrictEqual(ranges, {
- ranges: [
- { start: { line: 0, character: 1 }, end: { line: 0, character: 4 } },
- { start: { line: 0, character: 7 }, end: { line: 0, character: 10 } }
- ]
- });
- });
+ function setup(content: string) {
+ const document = new Document('file:///hello.svelte', content);
+ const docManager = new DocumentManager(() => document);
+ const pluginManager = new LSConfigManager();
+ const plugin = new HTMLPlugin(docManager, pluginManager);
+ docManager.openDocument(
'some doc');
+ return { plugin, document };
+ }
+
+ it('provides hover info', async () => {
+ const { plugin, document } = setup('Hello, world!
');
+
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 2)), {
+ contents: {
+ kind: 'markdown',
+ value:
+ 'The h1 element represents a section heading.\n\n[MDN Reference](https://developer.mozilla.org/docs/Web/HTML/Element/Heading_Elements)'
+ },
+
+ range: Range.create(0, 1, 0, 3)
+ });
+
+ assert.strictEqual(plugin.doHover(document, Position.create(0, 10)), null);
+ });
+
+ it('does not provide hover info for component having the same name as a html element but being uppercase', async () => {
+ const { plugin, document } = setup('');
+
+ assert.deepStrictEqual(plugin.doHover(document, Position.create(0, 2)), null);
+ });
+
+ it('provides completions', async () => {
+ const { plugin, document } = setup('<');
+
+ const completions = plugin.getCompletions(document, Position.create(0, 1));
+ assert.ok(Array.isArray(completions && completions.items));
+ assert.ok(completions!.items.length > 0);
+
+ assert.deepStrictEqual(completions!.items[0], {
+ label: '!DOCTYPE',
+ kind: CompletionItemKind.Property,
+ documentation: 'A preamble for an HTML document.',
+ textEdit: TextEdit.insert(Position.create(0, 1), '!DOCTYPE html>'),
+ insertTextFormat: InsertTextFormat.PlainText
+ });
+ });
+
+ it('does not provide completions inside of moustache tag', async () => {
+ const { plugin, document } = setup('');
+
+ const completions = plugin.getCompletions(document, Position.create(0, 20));
+ assert.strictEqual(completions, null);
+
+ const tagCompletion = plugin.doTagComplete(document, Position.create(0, 20));
+ assert.strictEqual(tagCompletion, null);
+ });
+
+ it('does provide completions outside of moustache tag', async () => {
+ const { plugin, document } = setup('
');
+
+ const completions = plugin.getCompletions(document, Position.create(0, 21));
+ assert.deepEqual(completions?.items[0], {
+ filterText: '
',
+ insertTextFormat: 2,
+ kind: 10,
+ label: '
',
+ textEdit: {
+ newText: '$0 ',
+ range: {
+ end: {
+ character: 21,
+ line: 0
+ },
+ start: {
+ character: 21,
+ line: 0
+ }
+ }
+ }
+ });
+
+ const tagCompletion = plugin.doTagComplete(document, Position.create(0, 21));
+ assert.strictEqual(tagCompletion, '$0');
+ });
+
+ it('does provide lang in completions', async () => {
+ const { plugin, document } = setup('
item.label === 'style (lang="less")'));
+ });
+
+ it('does not provide lang in completions for attributes', async () => {
+ const { plugin, document } = setup(' item.label === 'style (lang="less")'),
+ undefined
+ );
+ });
+
+ it('does not provide rename for element being uppercase', async () => {
+ const { plugin, document } = setup('
');
+
+ assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 2)), null);
+ assert.deepStrictEqual(plugin.rename(document, Position.create(0, 2), 'p'), null);
+ });
+
+ it('does not provide rename for valid element but incorrect position', () => {
+ const { plugin, document } = setup('
ab}>asd
');
+ const newName = 'p';
+
+ assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 16)), null);
+ assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 5)), null);
+ assert.deepStrictEqual(plugin.prepareRename(document, Position.create(0, 26)), null);
+
+ assert.deepStrictEqual(plugin.rename(document, Position.create(0, 16), newName), null);
+ assert.deepStrictEqual(plugin.rename(document, Position.create(0, 5), newName), null);
+ assert.deepStrictEqual(plugin.rename(document, Position.create(0, 26), newName), null);
+ });
+
+ it('provides rename for element', () => {
+ const { plugin, document } = setup('
{}}>
');
+ const newName = 'p';
+
+ const pepareRenameInfo = Range.create(Position.create(0, 1), Position.create(0, 4));
+ assert.deepStrictEqual(
+ plugin.prepareRename(document, Position.create(0, 2)),
+ pepareRenameInfo
+ );
+ assert.deepStrictEqual(
+ plugin.prepareRename(document, Position.create(0, 28)),
+ pepareRenameInfo
+ );
+
+ const renameInfo = {
+ changes: {
+ [document.uri]: [
+ {
+ newText: 'p',
+ range: {
+ start: { line: 0, character: 1 },
+ end: { line: 0, character: 4 }
+ }
+ },
+ {
+ newText: 'p',
+ range: {
+ start: { line: 0, character: 27 },
+ end: { line: 0, character: 30 }
+ }
+ }
+ ]
+ }
+ };
+ assert.deepStrictEqual(plugin.rename(document, Position.create(0, 2), newName), renameInfo);
+ assert.deepStrictEqual(
+ plugin.rename(document, Position.create(0, 28), newName),
+ renameInfo
+ );
+ });
+
+ it('provides linked editing ranges', async () => {
+ const { plugin, document } = setup('
');
+
+ const ranges = plugin.getLinkedEditingRanges(document, Position.create(0, 3));
+ assert.deepStrictEqual(ranges, {
+ ranges: [
+ { start: { line: 0, character: 1 }, end: { line: 0, character: 4 } },
+ { start: { line: 0, character: 7 }, end: { line: 0, character: 10 } }
+ ]
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/svelte/SvelteDocument.test.ts b/packages/language-server/test/plugins/svelte/SvelteDocument.test.ts
index 02d24cc7d..c44dcdb57 100644
--- a/packages/language-server/test/plugins/svelte/SvelteDocument.test.ts
+++ b/packages/language-server/test/plugins/svelte/SvelteDocument.test.ts
@@ -4,126 +4,126 @@ import { Position } from 'vscode-languageserver';
import { Document } from '../../../src/lib/documents';
import * as importPackage from '../../../src/importPackage';
import {
- SvelteDocument,
- TranspiledSvelteDocument
+ SvelteDocument,
+ TranspiledSvelteDocument
} from '../../../src/plugins/svelte/SvelteDocument';
import { configLoader, SvelteConfig } from '../../../src/lib/documents/configLoader';
describe('Svelte Document', () => {
- function getSourceCode(transpiled: boolean): string {
- return `
+ function getSourceCode(transpiled: boolean): string {
+ return `
jo
Hello, world!
`;
- }
-
- function setup(config: SvelteConfig = {}) {
- sinon.stub(configLoader, 'getConfig').returns(config);
- const parent = new Document('file:///hello.svelte', getSourceCode(false));
- sinon.restore();
- const svelteDoc = new SvelteDocument(parent);
- return { parent, svelteDoc };
- }
-
- it('gets the parents text', () => {
- const { parent, svelteDoc } = setup();
- assert.strictEqual(svelteDoc.getText(), parent.getText());
- });
-
- describe('#transpiled', () => {
- async function setupTranspiled() {
- const { parent, svelteDoc } = setup({
- preprocess: {
- script: () => ({
- code: '',
- map: JSON.stringify({
- version: 3,
- file: '',
- names: [],
- sources: [],
- sourceRoot: '',
- mappings: ''
- })
- })
- }
- });
-
- // stub svelte preprocess and getOriginalPosition
- // to fake a source mapping process
- sinon.stub(importPackage, 'importSvelte').returns({
- preprocess: (text, preprocessor) => {
- preprocessor = Array.isArray(preprocessor) ? preprocessor : [preprocessor];
- preprocessor.forEach((p) => p.script?.(
{}));
- return Promise.resolve({
- code: getSourceCode(true),
- dependencies: [],
- toString: () => getSourceCode(true),
- map: null
- });
- },
- walk: null,
- VERSION: '',
- compile: null,
- parse: null
- });
- const transpiled = await svelteDoc.getTranspiled();
- const scriptSourceMapper = (transpiled.scriptMapper).sourceMapper;
- // hacky reset of method because mocking the SourceMap constructor is an impossible task
- scriptSourceMapper.getOriginalPosition = ({ line, character }: Position) => ({
- line: line - 1,
- character
- });
- scriptSourceMapper.getGeneratedPosition = ({ line, character }: Position) => ({
- line: line + 1,
- character
- });
- sinon.restore();
-
- return { parent, svelteDoc, transpiled };
- }
-
- function assertCanMapBackAndForth(
- transpiled: TranspiledSvelteDocument,
- generatedPosition: Position,
- originalPosition: Position
- ) {
- assert.deepStrictEqual(
- transpiled.getOriginalPosition(generatedPosition),
- originalPosition,
- 'error mapping to original position'
- );
-
- assert.deepStrictEqual(
- transpiled.getGeneratedPosition(originalPosition),
- generatedPosition,
- 'error mapping to generated position'
- );
- }
-
- it('should map correctly within sourcemapped script', async () => {
- const { transpiled } = await setupTranspiled();
-
- assertCanMapBackAndForth(transpiled, Position.create(3, 2), Position.create(2, 18));
- });
-
- it('should map correctly in template before script', async () => {
- const { transpiled } = await setupTranspiled();
-
- assertCanMapBackAndForth(transpiled, Position.create(1, 1), Position.create(1, 1));
- });
-
- it('should map correctly in template after script', async () => {
- const { transpiled } = await setupTranspiled();
-
- assertCanMapBackAndForth(transpiled, Position.create(4, 1), Position.create(3, 1));
- });
-
- it('should map correctly in style', async () => {
- const { transpiled } = await setupTranspiled();
-
- assertCanMapBackAndForth(transpiled, Position.create(5, 18), Position.create(4, 18));
- });
- });
+ }
+
+ function setup(config: SvelteConfig = {}) {
+ sinon.stub(configLoader, 'getConfig').returns(config);
+ const parent = new Document('file:///hello.svelte', getSourceCode(false));
+ sinon.restore();
+ const svelteDoc = new SvelteDocument(parent);
+ return { parent, svelteDoc };
+ }
+
+ it('gets the parents text', () => {
+ const { parent, svelteDoc } = setup();
+ assert.strictEqual(svelteDoc.getText(), parent.getText());
+ });
+
+ describe('#transpiled', () => {
+ async function setupTranspiled() {
+ const { parent, svelteDoc } = setup({
+ preprocess: {
+ script: () => ({
+ code: '',
+ map: JSON.stringify({
+ version: 3,
+ file: '',
+ names: [],
+ sources: [],
+ sourceRoot: '',
+ mappings: ''
+ })
+ })
+ }
+ });
+
+ // stub svelte preprocess and getOriginalPosition
+ // to fake a source mapping process
+ sinon.stub(importPackage, 'importSvelte').returns({
+ preprocess: (text, preprocessor) => {
+ preprocessor = Array.isArray(preprocessor) ? preprocessor : [preprocessor];
+ preprocessor.forEach((p) => p.script?.({}));
+ return Promise.resolve({
+ code: getSourceCode(true),
+ dependencies: [],
+ toString: () => getSourceCode(true),
+ map: null
+ });
+ },
+ walk: null,
+ VERSION: '',
+ compile: null,
+ parse: null
+ });
+ const transpiled = await svelteDoc.getTranspiled();
+ const scriptSourceMapper = (transpiled.scriptMapper).sourceMapper;
+ // hacky reset of method because mocking the SourceMap constructor is an impossible task
+ scriptSourceMapper.getOriginalPosition = ({ line, character }: Position) => ({
+ line: line - 1,
+ character
+ });
+ scriptSourceMapper.getGeneratedPosition = ({ line, character }: Position) => ({
+ line: line + 1,
+ character
+ });
+ sinon.restore();
+
+ return { parent, svelteDoc, transpiled };
+ }
+
+ function assertCanMapBackAndForth(
+ transpiled: TranspiledSvelteDocument,
+ generatedPosition: Position,
+ originalPosition: Position
+ ) {
+ assert.deepStrictEqual(
+ transpiled.getOriginalPosition(generatedPosition),
+ originalPosition,
+ 'error mapping to original position'
+ );
+
+ assert.deepStrictEqual(
+ transpiled.getGeneratedPosition(originalPosition),
+ generatedPosition,
+ 'error mapping to generated position'
+ );
+ }
+
+ it('should map correctly within sourcemapped script', async () => {
+ const { transpiled } = await setupTranspiled();
+
+ assertCanMapBackAndForth(transpiled, Position.create(3, 2), Position.create(2, 18));
+ });
+
+ it('should map correctly in template before script', async () => {
+ const { transpiled } = await setupTranspiled();
+
+ assertCanMapBackAndForth(transpiled, Position.create(1, 1), Position.create(1, 1));
+ });
+
+ it('should map correctly in template after script', async () => {
+ const { transpiled } = await setupTranspiled();
+
+ assertCanMapBackAndForth(transpiled, Position.create(4, 1), Position.create(3, 1));
+ });
+
+ it('should map correctly in style', async () => {
+ const { transpiled } = await setupTranspiled();
+
+ assertCanMapBackAndForth(transpiled, Position.create(5, 18), Position.create(4, 18));
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
index 78646827c..a82df4252 100644
--- a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
+++ b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
@@ -7,140 +7,140 @@ import * as importPackage from '../../../src/importPackage';
import sinon from 'sinon';
describe('Svelte Plugin', () => {
- function setup(content: string, prettierConfig?: any) {
- const document = new Document('file:///hello.svelte', content);
- const docManager = new DocumentManager(() => document);
- const pluginManager = new LSConfigManager();
- pluginManager.updatePrettierConfig(prettierConfig);
- const plugin = new SveltePlugin(pluginManager);
- docManager.openDocument('some doc');
- return { plugin, document };
- }
-
- it('provides diagnostic warnings', async () => {
- const { plugin, document } = setup('Hello, world!
\n
');
-
- const diagnostics = await plugin.getDiagnostics(document);
- const diagnostic = Diagnostic.create(
- Range.create(1, 0, 1, 21),
- 'A11y:
element should have an alt attribute',
- DiagnosticSeverity.Warning,
- 'a11y-missing-attribute',
- 'svelte'
- );
-
- assert.deepStrictEqual(diagnostics, [diagnostic]);
- });
-
- it('provides diagnostic errors', async () => {
- const { plugin, document } = setup('');
-
- const diagnostics = await plugin.getDiagnostics(document);
- const diagnostic = Diagnostic.create(
- Range.create(0, 10, 0, 18),
- 'whatever is not declared',
- DiagnosticSeverity.Error,
- 'binding-undeclared',
- 'svelte'
- );
-
- assert.deepStrictEqual(diagnostics, [diagnostic]);
- });
-
- describe('#formatDocument', () => {
- function stubPrettier(config: any) {
- const formatStub = sinon.stub().returns('formatted');
-
- sinon.stub(importPackage, 'importPrettier').returns({
- resolveConfig: () => Promise.resolve(config),
- getFileInfo: () => ({ ignored: false }),
- format: formatStub,
- getSupportInfo: () => ({ languages: [{ name: 'svelte' }] })
- });
-
- return formatStub;
- }
-
- async function testFormat(config: any, fallbackPrettierConfig: any) {
- const { plugin, document } = setup('unformatted', fallbackPrettierConfig);
- const formatStub = stubPrettier(config);
-
- const formatted = await plugin.formatDocument(document, {
- insertSpaces: true,
- tabSize: 4
- });
- assert.deepStrictEqual(formatted, [
- {
- newText: 'formatted',
- range: {
- end: {
- character: 11,
- line: 0
- },
- start: {
- character: 0,
- line: 0
- }
- }
- }
- ]);
-
- return formatStub;
- }
-
- afterEach(() => {
- sinon.restore();
- });
-
- it('should use config for formatting', async () => {
- const formatStub = await testFormat({ fromConfig: true }, { fallbackConfig: true });
- sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
- fromConfig: true,
- plugins: [],
- parser: 'svelte'
- });
- });
-
- const defaultSettings = {
- svelteSortOrder: 'options-scripts-markup-styles',
- svelteStrictMode: false,
- svelteAllowShorthand: true,
- svelteBracketNewLine: true,
- svelteIndentScriptAndStyle: true,
- printWidth: 80,
- singleQuote: false
- };
-
- it('should use prettier fallback config for formatting', async () => {
- const formatStub = await testFormat(undefined, { fallbackConfig: true });
- sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
- fallbackConfig: true,
- plugins: [],
- parser: 'svelte',
- ...defaultSettings
- });
- });
-
- it('should use FormattingOptions for formatting', async () => {
- const formatStub = await testFormat(undefined, undefined);
- sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
- tabWidth: 4,
- useTabs: false,
- plugins: [],
- parser: 'svelte',
- ...defaultSettings
- });
- });
-
- it('should use FormattingOptions for formatting when configs are empty objects', async () => {
- const formatStub = await testFormat({}, {});
- sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
- tabWidth: 4,
- useTabs: false,
- plugins: [],
- parser: 'svelte',
- ...defaultSettings
- });
- });
- });
+ function setup(content: string, prettierConfig?: any) {
+ const document = new Document('file:///hello.svelte', content);
+ const docManager = new DocumentManager(() => document);
+ const pluginManager = new LSConfigManager();
+ pluginManager.updatePrettierConfig(prettierConfig);
+ const plugin = new SveltePlugin(pluginManager);
+ docManager.openDocument('some doc');
+ return { plugin, document };
+ }
+
+ it('provides diagnostic warnings', async () => {
+ const { plugin, document } = setup('Hello, world!
\n
');
+
+ const diagnostics = await plugin.getDiagnostics(document);
+ const diagnostic = Diagnostic.create(
+ Range.create(1, 0, 1, 21),
+ 'A11y:
element should have an alt attribute',
+ DiagnosticSeverity.Warning,
+ 'a11y-missing-attribute',
+ 'svelte'
+ );
+
+ assert.deepStrictEqual(diagnostics, [diagnostic]);
+ });
+
+ it('provides diagnostic errors', async () => {
+ const { plugin, document } = setup('');
+
+ const diagnostics = await plugin.getDiagnostics(document);
+ const diagnostic = Diagnostic.create(
+ Range.create(0, 10, 0, 18),
+ 'whatever is not declared',
+ DiagnosticSeverity.Error,
+ 'binding-undeclared',
+ 'svelte'
+ );
+
+ assert.deepStrictEqual(diagnostics, [diagnostic]);
+ });
+
+ describe('#formatDocument', () => {
+ function stubPrettier(config: any) {
+ const formatStub = sinon.stub().returns('formatted');
+
+ sinon.stub(importPackage, 'importPrettier').returns({
+ resolveConfig: () => Promise.resolve(config),
+ getFileInfo: () => ({ ignored: false }),
+ format: formatStub,
+ getSupportInfo: () => ({ languages: [{ name: 'svelte' }] })
+ });
+
+ return formatStub;
+ }
+
+ async function testFormat(config: any, fallbackPrettierConfig: any) {
+ const { plugin, document } = setup('unformatted', fallbackPrettierConfig);
+ const formatStub = stubPrettier(config);
+
+ const formatted = await plugin.formatDocument(document, {
+ insertSpaces: true,
+ tabSize: 4
+ });
+ assert.deepStrictEqual(formatted, [
+ {
+ newText: 'formatted',
+ range: {
+ end: {
+ character: 11,
+ line: 0
+ },
+ start: {
+ character: 0,
+ line: 0
+ }
+ }
+ }
+ ]);
+
+ return formatStub;
+ }
+
+ afterEach(() => {
+ sinon.restore();
+ });
+
+ it('should use config for formatting', async () => {
+ const formatStub = await testFormat({ fromConfig: true }, { fallbackConfig: true });
+ sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
+ fromConfig: true,
+ plugins: [],
+ parser: 'svelte'
+ });
+ });
+
+ const defaultSettings = {
+ svelteSortOrder: 'options-scripts-markup-styles',
+ svelteStrictMode: false,
+ svelteAllowShorthand: true,
+ svelteBracketNewLine: true,
+ svelteIndentScriptAndStyle: true,
+ printWidth: 80,
+ singleQuote: false
+ };
+
+ it('should use prettier fallback config for formatting', async () => {
+ const formatStub = await testFormat(undefined, { fallbackConfig: true });
+ sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
+ fallbackConfig: true,
+ plugins: [],
+ parser: 'svelte',
+ ...defaultSettings
+ });
+ });
+
+ it('should use FormattingOptions for formatting', async () => {
+ const formatStub = await testFormat(undefined, undefined);
+ sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
+ tabWidth: 4,
+ useTabs: false,
+ plugins: [],
+ parser: 'svelte',
+ ...defaultSettings
+ });
+ });
+
+ it('should use FormattingOptions for formatting when configs are empty objects', async () => {
+ const formatStub = await testFormat({}, {});
+ sinon.assert.calledOnceWithExactly(formatStub, 'unformatted', {
+ tabWidth: 4,
+ useTabs: false,
+ plugins: [],
+ parser: 'svelte',
+ ...defaultSettings
+ });
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/svelte/features/getCodeAction.test.ts b/packages/language-server/test/plugins/svelte/features/getCodeAction.test.ts
index 6f014a87d..432baa959 100644
--- a/packages/language-server/test/plugins/svelte/features/getCodeAction.test.ts
+++ b/packages/language-server/test/plugins/svelte/features/getCodeAction.test.ts
@@ -3,343 +3,343 @@ import * as fs from 'fs';
import { EOL } from 'os';
import * as path from 'path';
import {
- CodeAction,
- CodeActionContext,
- CreateFile,
- DiagnosticSeverity,
- Position,
- Range,
- TextDocumentEdit,
- TextEdit,
- OptionalVersionedTextDocumentIdentifier,
- WorkspaceEdit
+ CodeAction,
+ CodeActionContext,
+ CreateFile,
+ DiagnosticSeverity,
+ Position,
+ Range,
+ TextDocumentEdit,
+ TextEdit,
+ OptionalVersionedTextDocumentIdentifier,
+ WorkspaceEdit
} from 'vscode-languageserver';
import { Document } from '../../../../src/lib/documents';
import { getCodeActions } from '../../../../src/plugins/svelte/features/getCodeActions';
import {
- executeRefactoringCommand,
- ExtractComponentArgs,
- extractComponentCommand
+ executeRefactoringCommand,
+ ExtractComponentArgs,
+ extractComponentCommand
} from '../../../../src/plugins/svelte/features/getCodeActions/getRefactorings';
import { SvelteDocument } from '../../../../src/plugins/svelte/SvelteDocument';
import { pathToUrl } from '../../../../src/utils';
describe('SveltePlugin#getCodeAction', () => {
- const testDir = path.join(__dirname, '..', 'testfiles');
+ const testDir = path.join(__dirname, '..', 'testfiles');
- function getFullPath(filename: string) {
- return path.join(testDir, filename);
- }
+ function getFullPath(filename: string) {
+ return path.join(testDir, filename);
+ }
- function getUri(filename: string) {
- return pathToUrl(getFullPath(filename));
- }
+ function getUri(filename: string) {
+ return pathToUrl(getFullPath(filename));
+ }
- async function expectCodeActionFor(filename: string, context: CodeActionContext) {
- const filePath = path.join(testDir, filename);
- const document = new Document(
- pathToUrl(filePath),
- filename ? fs.readFileSync(filePath)?.toString() : ''
- );
- const svelteDoc = new SvelteDocument(document);
- const codeAction = await getCodeActions(
- svelteDoc,
- Range.create(Position.create(0, 0), Position.create(0, 0)),
- context
- );
- return {
- toEqual: (expected: CodeAction[]) => assert.deepStrictEqual(codeAction, expected)
- };
- }
+ async function expectCodeActionFor(filename: string, context: CodeActionContext) {
+ const filePath = path.join(testDir, filename);
+ const document = new Document(
+ pathToUrl(filePath),
+ filename ? fs.readFileSync(filePath)?.toString() : ''
+ );
+ const svelteDoc = new SvelteDocument(document);
+ const codeAction = await getCodeActions(
+ svelteDoc,
+ Range.create(Position.create(0, 0), Position.create(0, 0)),
+ context
+ );
+ return {
+ toEqual: (expected: CodeAction[]) => assert.deepStrictEqual(codeAction, expected)
+ };
+ }
- describe('It should not provide svelte ignore code actions', () => {
- const startRange: Range = Range.create(
- { line: 0, character: 0 },
- { line: 0, character: 1 }
- );
- it('if no svelte diagnostic', async () => {
- (
- await expectCodeActionFor('', {
- diagnostics: [
- {
- code: 'whatever',
- source: 'eslint',
- range: startRange,
- message: ''
- }
- ]
- })
- ).toEqual([]);
- });
+ describe('It should not provide svelte ignore code actions', () => {
+ const startRange: Range = Range.create(
+ { line: 0, character: 0 },
+ { line: 0, character: 1 }
+ );
+ it('if no svelte diagnostic', async () => {
+ (
+ await expectCodeActionFor('', {
+ diagnostics: [
+ {
+ code: 'whatever',
+ source: 'eslint',
+ range: startRange,
+ message: ''
+ }
+ ]
+ })
+ ).toEqual([]);
+ });
- it('if no diagnostic code', async () => {
- (
- await expectCodeActionFor('', {
- diagnostics: [
- {
- source: 'svelte',
- range: startRange,
- message: ''
- }
- ]
- })
- ).toEqual([]);
- });
+ it('if no diagnostic code', async () => {
+ (
+ await expectCodeActionFor('', {
+ diagnostics: [
+ {
+ source: 'svelte',
+ range: startRange,
+ message: ''
+ }
+ ]
+ })
+ ).toEqual([]);
+ });
- it('if diagnostic is error', async () => {
- (
- await expectCodeActionFor('', {
- diagnostics: [
- {
- source: 'svelte',
- range: startRange,
- message: '',
- severity: DiagnosticSeverity.Error
- }
- ]
- })
- ).toEqual([]);
- });
- });
+ it('if diagnostic is error', async () => {
+ (
+ await expectCodeActionFor('', {
+ diagnostics: [
+ {
+ source: 'svelte',
+ range: startRange,
+ message: '',
+ severity: DiagnosticSeverity.Error
+ }
+ ]
+ })
+ ).toEqual([]);
+ });
+ });
- describe('It should provide svelte ignore code actions ', () => {
- const svelteIgnoreCodeAction = 'svelte-ignore-code-action.svelte';
+ describe('It should provide svelte ignore code actions ', () => {
+ const svelteIgnoreCodeAction = 'svelte-ignore-code-action.svelte';
- it('should provide ignore comment', async () => {
- (
- await expectCodeActionFor(svelteIgnoreCodeAction, {
- diagnostics: [
- {
- severity: DiagnosticSeverity.Warning,
- code: 'a11y-missing-attribute',
- range: Range.create(
- { line: 0, character: 0 },
- { line: 0, character: 6 }
- ),
- message: '',
- source: 'svelte'
- }
- ]
- })
- ).toEqual([
- {
- edit: {
- documentChanges: [
- {
- edits: [
- {
- // eslint-disable-next-line max-len
- newText: `${EOL}`,
- range: {
- end: {
- character: 0,
- line: 0
- },
- start: {
- character: 0,
- line: 0
- }
- }
- }
- ],
- textDocument: {
- uri: getUri(svelteIgnoreCodeAction),
- version: null
- }
- }
- ]
- },
- title: '(svelte) Disable a11y-missing-attribute for this line',
- kind: 'quickfix'
- }
- ]);
- });
+ it('should provide ignore comment', async () => {
+ (
+ await expectCodeActionFor(svelteIgnoreCodeAction, {
+ diagnostics: [
+ {
+ severity: DiagnosticSeverity.Warning,
+ code: 'a11y-missing-attribute',
+ range: Range.create(
+ { line: 0, character: 0 },
+ { line: 0, character: 6 }
+ ),
+ message: '',
+ source: 'svelte'
+ }
+ ]
+ })
+ ).toEqual([
+ {
+ edit: {
+ documentChanges: [
+ {
+ edits: [
+ {
+ // eslint-disable-next-line max-len
+ newText: `${EOL}`,
+ range: {
+ end: {
+ character: 0,
+ line: 0
+ },
+ start: {
+ character: 0,
+ line: 0
+ }
+ }
+ }
+ ],
+ textDocument: {
+ uri: getUri(svelteIgnoreCodeAction),
+ version: null
+ }
+ }
+ ]
+ },
+ title: '(svelte) Disable a11y-missing-attribute for this line',
+ kind: 'quickfix'
+ }
+ ]);
+ });
- it('should provide ignore comment with indent', async () => {
- (
- await expectCodeActionFor(svelteIgnoreCodeAction, {
- diagnostics: [
- {
- severity: DiagnosticSeverity.Warning,
- code: 'a11y-missing-attribute',
- range: Range.create(
- { line: 3, character: 4 },
- { line: 3, character: 11 }
- ),
- message: '',
- source: 'svelte'
- }
- ]
- })
- ).toEqual([
- {
- edit: {
- documentChanges: [
- {
- edits: [
- {
- newText: `${' '.repeat(
- 4
- )}${EOL}`,
- range: {
- end: {
- character: 0,
- line: 3
- },
- start: {
- character: 0,
- line: 3
- }
- }
- }
- ],
- textDocument: {
- uri: getUri(svelteIgnoreCodeAction),
- version: null
- }
- }
- ]
- },
- title: '(svelte) Disable a11y-missing-attribute for this line',
- kind: 'quickfix'
- }
- ]);
- });
+ it('should provide ignore comment with indent', async () => {
+ (
+ await expectCodeActionFor(svelteIgnoreCodeAction, {
+ diagnostics: [
+ {
+ severity: DiagnosticSeverity.Warning,
+ code: 'a11y-missing-attribute',
+ range: Range.create(
+ { line: 3, character: 4 },
+ { line: 3, character: 11 }
+ ),
+ message: '',
+ source: 'svelte'
+ }
+ ]
+ })
+ ).toEqual([
+ {
+ edit: {
+ documentChanges: [
+ {
+ edits: [
+ {
+ newText: `${' '.repeat(
+ 4
+ )}${EOL}`,
+ range: {
+ end: {
+ character: 0,
+ line: 3
+ },
+ start: {
+ character: 0,
+ line: 3
+ }
+ }
+ }
+ ],
+ textDocument: {
+ uri: getUri(svelteIgnoreCodeAction),
+ version: null
+ }
+ }
+ ]
+ },
+ title: '(svelte) Disable a11y-missing-attribute for this line',
+ kind: 'quickfix'
+ }
+ ]);
+ });
- it('should provide ignore comment with indent of parent tag', async () => {
- (
- await expectCodeActionFor(svelteIgnoreCodeAction, {
- diagnostics: [
- {
- severity: DiagnosticSeverity.Warning,
- code: 'a11y-invalid-attribute',
- range: Range.create(
- { line: 6, character: 8 },
- { line: 6, character: 15 }
- ),
- message: '',
- source: 'svelte'
- }
- ]
- })
- ).toEqual([
- {
- edit: {
- documentChanges: [
- {
- edits: [
- {
- newText: `${' '.repeat(
- 4
- )}${EOL}`,
- range: {
- end: {
- character: 0,
- line: 5
- },
- start: {
- character: 0,
- line: 5
- }
- }
- }
- ],
- textDocument: {
- uri: getUri(svelteIgnoreCodeAction),
- version: null
- }
- }
- ]
- },
- title: '(svelte) Disable a11y-invalid-attribute for this line',
- kind: 'quickfix'
- }
- ]);
- });
- });
+ it('should provide ignore comment with indent of parent tag', async () => {
+ (
+ await expectCodeActionFor(svelteIgnoreCodeAction, {
+ diagnostics: [
+ {
+ severity: DiagnosticSeverity.Warning,
+ code: 'a11y-invalid-attribute',
+ range: Range.create(
+ { line: 6, character: 8 },
+ { line: 6, character: 15 }
+ ),
+ message: '',
+ source: 'svelte'
+ }
+ ]
+ })
+ ).toEqual([
+ {
+ edit: {
+ documentChanges: [
+ {
+ edits: [
+ {
+ newText: `${' '.repeat(
+ 4
+ )}${EOL}`,
+ range: {
+ end: {
+ character: 0,
+ line: 5
+ },
+ start: {
+ character: 0,
+ line: 5
+ }
+ }
+ }
+ ],
+ textDocument: {
+ uri: getUri(svelteIgnoreCodeAction),
+ version: null
+ }
+ }
+ ]
+ },
+ title: '(svelte) Disable a11y-invalid-attribute for this line',
+ kind: 'quickfix'
+ }
+ ]);
+ });
+ });
- describe('#extractComponent', async () => {
- const scriptContent = ``;
- const styleContent = '';
- const content = `
+ const styleContent = '';
+ const content = `
${scriptContent}
something else
extract me
${styleContent}`;
- const doc = new SvelteDocument(new Document('someUrl', content));
+ const doc = new SvelteDocument(new Document('someUrl', content));
- async function extractComponent(filePath: string, range: Range) {
- return executeRefactoringCommand(doc, extractComponentCommand, [
- '',
- {
- filePath,
- range,
- uri: ''
- }
- ]);
- }
+ async function extractComponent(filePath: string, range: Range) {
+ return executeRefactoringCommand(doc, extractComponentCommand, [
+ '',
+ {
+ filePath,
+ range,
+ uri: ''
+ }
+ ]);
+ }
- async function shouldExtractComponent(
- path: 'NewComp' | 'NewComp.svelte' | './NewComp' | './NewComp.svelte'
- ) {
- const range = Range.create(Position.create(5, 8), Position.create(5, 25));
- const result = await extractComponent(path, range);
- assert.deepStrictEqual(result, {
- documentChanges: [
- TextDocumentEdit.create(
- OptionalVersionedTextDocumentIdentifier.create('someUrl', null),
- [
- TextEdit.replace(range, ''),
- TextEdit.insert(
- doc.script?.startPos || Position.create(0, 0),
- "\n import NewComp from './NewComp.svelte';\n"
- )
- ]
- ),
- CreateFile.create('file:///NewComp.svelte', { overwrite: true }),
- TextDocumentEdit.create(
- OptionalVersionedTextDocumentIdentifier.create(
- 'file:///NewComp.svelte',
- null
- ),
- [
- TextEdit.insert(
- Position.create(0, 0),
- `${scriptContent}\n\nextract me
\n\n${styleContent}\n\n`
- )
- ]
- )
- ]
- });
- }
+ async function shouldExtractComponent(
+ path: 'NewComp' | 'NewComp.svelte' | './NewComp' | './NewComp.svelte'
+ ) {
+ const range = Range.create(Position.create(5, 8), Position.create(5, 25));
+ const result = await extractComponent(path, range);
+ assert.deepStrictEqual(result, {
+ documentChanges: [
+ TextDocumentEdit.create(
+ OptionalVersionedTextDocumentIdentifier.create('someUrl', null),
+ [
+ TextEdit.replace(range, ''),
+ TextEdit.insert(
+ doc.script?.startPos || Position.create(0, 0),
+ "\n import NewComp from './NewComp.svelte';\n"
+ )
+ ]
+ ),
+ CreateFile.create('file:///NewComp.svelte', { overwrite: true }),
+ TextDocumentEdit.create(
+ OptionalVersionedTextDocumentIdentifier.create(
+ 'file:///NewComp.svelte',
+ null
+ ),
+ [
+ TextEdit.insert(
+ Position.create(0, 0),
+ `${scriptContent}\n\nextract me
\n\n${styleContent}\n\n`
+ )
+ ]
+ )
+ ]
+ });
+ }
- it('should extract component (no .svelte at the end)', async () => {
- await shouldExtractComponent('./NewComp');
- });
+ it('should extract component (no .svelte at the end)', async () => {
+ await shouldExtractComponent('./NewComp');
+ });
- it('should extract component (no .svelte at the end, no relative path)', async () => {
- await shouldExtractComponent('NewComp');
- });
+ it('should extract component (no .svelte at the end, no relative path)', async () => {
+ await shouldExtractComponent('NewComp');
+ });
- it('should extract component (.svelte at the end, no relative path', async () => {
- await shouldExtractComponent('NewComp.svelte');
- });
+ it('should extract component (.svelte at the end, no relative path', async () => {
+ await shouldExtractComponent('NewComp.svelte');
+ });
- it('should extract component (.svelte at the end, relative path)', async () => {
- await shouldExtractComponent('./NewComp.svelte');
- });
+ it('should extract component (.svelte at the end, relative path)', async () => {
+ await shouldExtractComponent('./NewComp.svelte');
+ });
- it('should return "Invalid selection range"', async () => {
- const range = Range.create(Position.create(6, 8), Position.create(6, 25));
- const result = await extractComponent('Bla', range);
- assert.deepStrictEqual(result, 'Invalid selection range');
- });
+ it('should return "Invalid selection range"', async () => {
+ const range = Range.create(Position.create(6, 8), Position.create(6, 25));
+ const result = await extractComponent('Bla', range);
+ assert.deepStrictEqual(result, 'Invalid selection range');
+ });
- it('should update relative imports', async () => {
- const content = `
@@ -347,48 +347,48 @@ describe('SveltePlugin#getCodeAction', () => {
`;
- const existingFileUri = pathToUrl('C:/path/File.svelte');
- const doc = new SvelteDocument(new Document(existingFileUri, content));
- const range = Range.create(Position.create(4, 12), Position.create(4, 21));
- const result = await executeRefactoringCommand(doc, extractComponentCommand, [
- '',
- {
- filePath: '../NewComp',
- range,
- uri: ''
- }
- ]);
+ const existingFileUri = pathToUrl('C:/path/File.svelte');
+ const doc = new SvelteDocument(new Document(existingFileUri, content));
+ const range = Range.create(Position.create(4, 12), Position.create(4, 21));
+ const result = await executeRefactoringCommand(doc, extractComponentCommand, [
+ '',
+ {
+ filePath: '../NewComp',
+ range,
+ uri: ''
+ }
+ ]);
- const newFileUri = pathToUrl('C:/NewComp.svelte');
- assert.deepStrictEqual(result, {
- documentChanges: [
- TextDocumentEdit.create(
- OptionalVersionedTextDocumentIdentifier.create(existingFileUri, null),
- [
- TextEdit.replace(range, ''),
- TextEdit.insert(
- doc.script?.startPos || Position.create(0, 0),
- "\n import NewComp from '../NewComp.svelte';\n"
- )
- ]
- ),
- CreateFile.create(newFileUri, { overwrite: true }),
- TextDocumentEdit.create(
- OptionalVersionedTextDocumentIdentifier.create(newFileUri, null),
- [
- TextEdit.insert(
- Position.create(0, 0),
- `\n\ntoExtract\n\n\n\n`
- )
- ]
- )
- ]
- });
- });
- });
+ )
+ ]
+ )
+ ]
+ });
+ });
+ });
});
diff --git a/packages/language-server/test/plugins/svelte/features/getCompletions.test.ts b/packages/language-server/test/plugins/svelte/features/getCompletions.test.ts
index f7a26230f..9f282256d 100644
--- a/packages/language-server/test/plugins/svelte/features/getCompletions.test.ts
+++ b/packages/language-server/test/plugins/svelte/features/getCompletions.test.ts
@@ -6,125 +6,125 @@ import { SvelteDocument } from '../../../../src/plugins/svelte/SvelteDocument';
import { Document } from '../../../../src/lib/documents';
describe('SveltePlugin#getCompletions', () => {
- function expectCompletionsFor(
- content: string,
- position: Position = Position.create(0, content.length)
- ) {
- const svelteDoc = new SvelteDocument(new Document('url', content));
- const completions = getCompletions(svelteDoc, position);
- return {
- toEqual: (expectedLabels: string[] | null) =>
- assert.deepStrictEqual(
- completions?.items.map((item) => item.label) ?? null,
- expectedLabels
- )
- };
- }
-
- describe('should return null', () => {
- it('if position inside style', () => {
- expectCompletionsFor(
- 'test
',
- Position.create(0, 10)
- ).toEqual(null);
- });
-
- it('if position inside script', () => {
- expectCompletionsFor(
- 'test
',
- Position.create(0, 10)
- ).toEqual(null);
- });
-
- it('if not preceeded by valid content #1', () => {
- expectCompletionsFor('{nope').toEqual(null);
- });
-
- it('if not preceeded by valid content #2', () => {
- expectCompletionsFor('not really').toEqual(null);
- });
-
- it('if not preceeded by valid content #3', () => {
- expectCompletionsFor('{#awa.').toEqual(null);
- });
- });
-
- it('should return completions for #', () => {
- expectCompletionsFor('{#').toEqual(['if', 'each', 'await :then', 'await then', 'key']);
- });
-
- it('should return completions for @', () => {
- expectCompletionsFor('{@').toEqual(['html', 'debug']);
- });
-
- describe('should return no completions for :', () => {
- it(' when no open tag before that', () => {
- expectCompletionsFor('{:').toEqual(null);
- });
-
- it(' when only completed tag before that', () => {
- expectCompletionsFor('{#if}{/if}{:').toEqual(null);
- });
- });
-
- describe('should return no completions for /', () => {
- it('when no open tag before that', () => {
- expectCompletionsFor('{/').toEqual(null);
- });
-
- it('when only completed tag before that', () => {
- expectCompletionsFor('{#if}{/if}{/').toEqual(null);
- });
-
- it('when the only completed tag before it has white space before close symbol', () => {
- expectCompletionsFor('{#if}{ /if}{/').toEqual(null);
- });
- });
-
- describe('should return completion for :', () => {
- it('for if', () => {
- expectCompletionsFor('{#if}{:').toEqual(['else', 'else if']);
- });
-
- it('for each', () => {
- expectCompletionsFor('{#each}{:').toEqual(['else']);
- });
-
- it('for await', () => {
- expectCompletionsFor('{#await}{:').toEqual(['then', 'catch']);
- });
-
- it('for last open tag', () => {
- expectCompletionsFor('{#if}{/if}{#if}{#await}{:').toEqual(['then', 'catch']);
- });
- });
-
- describe('should return completion for /', () => {
- it('for if', () => {
- expectCompletionsFor('{#if}{/').toEqual(['if']);
- });
-
- it('for each', () => {
- expectCompletionsFor('{#each}{/').toEqual(['each']);
- });
-
- it('for await', () => {
- expectCompletionsFor('{#await}{/').toEqual(['await']);
- });
-
- it('for key', () => {
- expectCompletionsFor('{#key}{/').toEqual(['key']);
- });
-
- it('for last open tag', () => {
- expectCompletionsFor('{#if}{/if}{#if}{#await}{/').toEqual(['await']);
- });
- });
-
- it('should return completion for component documentation comment', () => {
- const content = '"]
- },
- "brackets": [
- [""],
- ["<", ">"],
- ["{", "}"],
- ["(", ")"],
- ["[", "]"]
- ],
- "autoClosingPairs": [
- { "open": "{", "close": "}" },
- { "open": "[", "close": "]" },
- { "open": "(", "close": ")" },
- { "open": "'", "close": "'" },
- { "open": "\"", "close": "\"" },
- { "open": "", "notIn": ["comment", "string"] },
- { "open": "/**", "close": "*/", "notIn": ["string"] }
- ],
- "surroundingPairs": [
- { "open": "'", "close": "'" },
- { "open": "\"", "close": "\"" },
- { "open": "`", "close": "`" },
- { "open": "{", "close": "}" },
- { "open": "[", "close": "]" },
- { "open": "(", "close": ")" },
- { "open": "<", "close": ">" }
- ],
- "folding": {
- "markers": {
- "start": "^\\s*//\\s*#?region\\b|^<(template|style|script)[^>]*>",
- "end": "^\\s*//\\s*#?endregion\\b|^(template|style|script)>"
- }
- }
+ "comments": {
+ "blockComment": [""]
+ },
+ "brackets": [
+ [""],
+ ["<", ">"],
+ ["{", "}"],
+ ["(", ")"],
+ ["[", "]"]
+ ],
+ "autoClosingPairs": [
+ { "open": "{", "close": "}" },
+ { "open": "[", "close": "]" },
+ { "open": "(", "close": ")" },
+ { "open": "'", "close": "'" },
+ { "open": "\"", "close": "\"" },
+ { "open": "", "notIn": ["comment", "string"] },
+ { "open": "/**", "close": "*/", "notIn": ["string"] }
+ ],
+ "surroundingPairs": [
+ { "open": "'", "close": "'" },
+ { "open": "\"", "close": "\"" },
+ { "open": "`", "close": "`" },
+ { "open": "{", "close": "}" },
+ { "open": "[", "close": "]" },
+ { "open": "(", "close": ")" },
+ { "open": "<", "close": ">" }
+ ],
+ "folding": {
+ "markers": {
+ "start": "^\\s*//\\s*#?region\\b|^<(template|style|script)[^>]*>",
+ "end": "^\\s*//\\s*#?endregion\\b|^(template|style|script)>"
+ }
+ }
}
diff --git a/packages/svelte-vscode/package-json-schema.json b/packages/svelte-vscode/package-json-schema.json
index 713c292bb..837d89d33 100644
--- a/packages/svelte-vscode/package-json-schema.json
+++ b/packages/svelte-vscode/package-json-schema.json
@@ -1,9 +1,9 @@
{
- "$schema": "http://json-schema.org/draft-07/schema",
- "properties": {
- "prettier": {
- "description": "Prettier-Plugin-Svelte configuration",
- "$ref": "./prettier-options-schema.json"
- }
- }
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "properties": {
+ "prettier": {
+ "description": "Prettier-Plugin-Svelte configuration",
+ "$ref": "./prettier-options-schema.json"
+ }
+ }
}
diff --git a/packages/svelte-vscode/package.json b/packages/svelte-vscode/package.json
index f4b002ad2..fef8180e3 100644
--- a/packages/svelte-vscode/package.json
+++ b/packages/svelte-vscode/package.json
@@ -1,518 +1,518 @@
{
- "name": "svelte-vscode",
- "version": "0.5.0",
- "description": "Svelte language support for VS Code",
- "main": "dist/src/extension.js",
- "scripts": {
- "build:grammar": "npx js-yaml syntaxes/svelte.tmLanguage.src.yaml > syntaxes/svelte.tmLanguage.json",
- "build:ts": "tsc -p ./",
- "build": "npm run build:ts && npm run build:grammar",
- "vscode:prepublish": "npm run build && npm prune --production",
- "watch": "npm run build:grammar && tsc -w -p ./",
- "test": "echo 'NOOP'"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/sveltejs/language-tools.git"
- },
- "keywords": [
- "svelte",
- "vscode"
- ],
- "author": "James Birtles & the Svelte Core Team",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/sveltejs/language-tools/issues"
- },
- "homepage": "https://github.com/sveltejs/language-tools#readme",
- "displayName": "Svelte for VS Code",
- "publisher": "svelte",
- "icon": "icons/logo.png",
- "galleryBanner": {
- "color": "#FF3E00",
- "theme": "dark"
- },
- "categories": [
- "Programming Languages",
- "Formatters"
- ],
- "engines": {
- "vscode": "^1.52.0"
- },
- "activationEvents": [
- "onLanguage:svelte",
- "onCommand:svelte.restartLanguageServer"
- ],
- "contributes": {
- "configuration": {
- "type": "object",
- "title": "Svelte",
- "properties": {
- "svelte.language-server.runtime": {
- "scope": "application",
- "type": "string",
- "title": "Language Server Runtime",
- "description": "- You normally don't need this - Path to the node executable to use to spawn the language server. This is useful when you depend on native modules such as node-sass as without this they will run in the context of vscode, meaning node version mismatch is likely. Minimum required node version is 12.17. This setting can only be changed in user settings for security reasons."
- },
- "svelte.language-server.ls-path": {
- "scope": "application",
- "type": "string",
- "title": "Language Server Path",
- "description": "- You normally don't set this - Path to the language server executable. If you installed the \"svelte-language-server\" npm package, it's within there at \"bin/server.js\". Path can be either relative to your workspace root or absolute. Set this only if you want to use a custom version of the language server. This setting can only be changed in user settings for security reasons."
- },
- "svelte.language-server.port": {
- "type": "number",
- "title": "Language Server Port",
- "description": "- You normally don't set this - At which port to spawn the language server. Can be used for attaching to the process for debugging / profiling. If you experience crashes due to \"port already in use\", try setting the port. -1 = default port is used.",
- "default": -1
- },
- "svelte.trace.server": {
- "type": "string",
- "enum": [
- "off",
- "messages",
- "verbose"
- ],
- "default": "off",
- "description": "Traces the communication between VS Code and the Svelte Language Server."
- },
- "svelte.plugin.typescript.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript",
- "description": "Enable the TypeScript plugin"
- },
- "svelte.plugin.typescript.diagnostics.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Diagnostics",
- "description": "Enable diagnostic messages for TypeScript"
- },
- "svelte.plugin.typescript.hover.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Hover Info",
- "description": "Enable hover info for TypeScript"
- },
- "svelte.plugin.typescript.documentSymbols.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Symbols in Outline",
- "description": "Enable document symbols for TypeScript"
- },
- "svelte.plugin.typescript.completions.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Completions",
- "description": "Enable completions for TypeScript"
- },
- "svelte.plugin.typescript.findReferences.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Find References",
- "description": "Enable find-references for TypeScript"
- },
- "svelte.plugin.typescript.definitions.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Go to Definition",
- "description": "Enable go to definition for TypeScript"
- },
- "svelte.plugin.typescript.codeActions.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Code Actions",
- "description": "Enable code actions for TypeScript"
- },
- "svelte.plugin.typescript.selectionRange.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Selection Range",
- "description": "Enable selection range for TypeScript"
- },
- "svelte.plugin.typescript.signatureHelp.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Signature Help",
- "description": "Enable signature help (parameter hints) for TypeScript"
- },
- "svelte.plugin.typescript.rename.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Rename",
- "description": "Enable rename functionality for JS/TS variables inside Svelte files"
- },
- "svelte.plugin.typescript.semanticTokens.enable": {
- "type": "boolean",
- "default": true,
- "title": "TypeScript: Semantic Tokens",
- "description": "Enable semantic tokens (semantic highlight) for TypeScript. Doesn't apply to JavaScript"
- },
- "svelte.plugin.css.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS",
- "description": "Enable the CSS plugin"
- },
- "svelte.plugin.css.globals": {
- "type": "string",
- "default": "",
- "title": "CSS: Global Files",
- "description": "Which css files should be checked for global variables (`--global-var: value;`). These variables are added to the css completions. String of comma-separated file paths or globs relative to workspace root."
- },
- "svelte.plugin.css.diagnostics.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Diagnostics",
- "description": "Enable diagnostic messages for CSS"
- },
- "svelte.plugin.css.hover.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Hover Info",
- "description": "Enable hover info for CSS"
- },
- "svelte.plugin.css.completions.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Auto Complete",
- "description": "Enable auto completions for CSS"
- },
- "svelte.plugin.css.completions.emmet": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Include Emmet Completions",
- "description": "Enable emmet auto completions for CSS"
- },
- "svelte.plugin.css.documentColors.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Document Colors",
- "description": "Enable document colors for CSS"
- },
- "svelte.plugin.css.colorPresentations.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Color Picker",
- "description": "Enable color picker for CSS"
- },
- "svelte.plugin.css.documentSymbols.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: Symbols in Outline",
- "description": "Enable document symbols for CSS"
- },
- "svelte.plugin.css.selectionRange.enable": {
- "type": "boolean",
- "default": true,
- "title": "CSS: SelectionRange",
- "description": "Enable selection range for CSS"
- },
- "svelte.plugin.html.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML",
- "description": "Enable the HTML plugin"
- },
- "svelte.plugin.html.hover.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Hover Info",
- "description": "Enable hover info for HTML"
- },
- "svelte.plugin.html.completions.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Auto Complete",
- "description": "Enable auto completions for HTML"
- },
- "svelte.plugin.html.completions.emmet": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Include Emmet Completions",
- "description": "Enable emmet auto completions for HTML"
- },
- "svelte.plugin.html.tagComplete.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Tag Auto Closing",
- "description": "Enable HTML tag auto closing"
- },
- "svelte.plugin.html.documentSymbols.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Symbols in Outline",
- "description": "Enable document symbols for HTML"
- },
- "svelte.plugin.html.linkedEditing.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Linked Editing",
- "description": "Enable Linked Editing for HTML"
- },
- "svelte.plugin.html.renameTags.enable": {
- "type": "boolean",
- "default": true,
- "title": "HTML: Rename tags",
- "description": "Enable rename for the opening/closing tag pairs in HTML"
- },
- "svelte.plugin.svelte.enable": {
- "type": "boolean",
- "default": true,
- "title": "Svelte",
- "description": "Enable the Svelte plugin"
- },
- "svelte.plugin.svelte.diagnostics.enable": {
- "type": "boolean",
- "default": true,
- "title": "Svelte: Diagnostics",
- "description": "Enable diagnostic messages for Svelte"
- },
- "svelte.plugin.svelte.compilerWarnings": {
- "type": "object",
- "additionalProperties": {
- "type": "string",
- "enum": [
- "ignore",
- "error"
- ]
- },
- "default": {},
- "title": "Svelte: Compiler Warnings Settings",
- "description": "Svelte compiler warning codes to ignore or to treat as errors. Example: { 'css-unused-selector': 'ignore', 'unused-export-let': 'error'}"
- },
- "svelte.plugin.svelte.format.enable": {
- "type": "boolean",
- "default": true,
- "title": "Svelte: Format",
- "description": "Enable formatting for Svelte (includes css & js). You can set some formatting options through this extension. They will be ignored if there's any kind of configuration file, for example a `.prettierrc` file."
- },
- "svelte.plugin.svelte.format.config.svelteSortOrder": {
- "type": "string",
- "default": "options-scripts-markup-styles",
- "title": "Svelte Format: Sort Order",
- "description": "Format: join the keys `options`, `scripts`, `markup`, `styles` with a - in the order you want. This option is ignored if there's any kind of configuration file, for example a `.prettierrc` file."
- },
- "svelte.plugin.svelte.format.config.svelteStrictMode": {
- "type": "boolean",
- "default": false,
- "title": "Svelte Format: Strict Mode",
- "description": "More strict HTML syntax. This option is ignored if there's any kind of configuration file, for example a `.prettierrc` file."
- },
- "svelte.plugin.svelte.format.config.svelteAllowShorthand": {
- "type": "boolean",
- "default": true,
- "title": "Svelte Format: Allow Shorthand",
- "description": "Option to enable/disable component attribute shorthand if attribute name and expression are the same. This option is ignored if there's any kind of configuration file, for example a `.prettierrc` file."
- },
- "svelte.plugin.svelte.format.config.svelteBracketNewLine": {
- "type": "boolean",
- "default": true,
- "title": "Svelte Format: Bracket New Line",
- "description": "Put the `>` of a multiline element on a new line. This option is ignored if there's any kind of configuration file, for example a `.prettierrc` file."
- },
- "svelte.plugin.svelte.format.config.svelteIndentScriptAndStyle": {
- "type": "boolean",
- "default": true,
- "title": "Svelte Format: Indent Script And Style",
- "description": "Whether or not to indent code inside `` + ``)
- );
- assert(duration <= 1000, `Parsing took ${duration} ms, which was longer than 1000ms`);
- });
+ it('parses in a reasonable time', () => {
+ let random = '';
+ let str = '';
+ for (let i = 0; i !== 17; i++) random += Math.random().toString(26).slice(2);
+ for (let i = 0; i !== 1137; i++) str += `${random} - line\t${i}\n`;
+ const duration = benchmark(
+ htmlx2jsx.bind(null, `` + ``)
+ );
+ assert(duration <= 1000, `Parsing took ${duration} ms, which was longer than 1000ms`);
+ });
});
diff --git a/packages/svelte2tsx/test/sourcemaps/composer.ts b/packages/svelte2tsx/test/sourcemaps/composer.ts
index 22561f6bf..17e820312 100644
--- a/packages/svelte2tsx/test/sourcemaps/composer.ts
+++ b/packages/svelte2tsx/test/sourcemaps/composer.ts
@@ -7,36 +7,36 @@ type comment = [cmap, string] | readonly [cmap, string];
type Section = HorizontalRule | Comment | Line | string;
class Comment {
- readonly content: [string, string][];
+ readonly content: [string, string][];
- constructor(gen: Iterable, readonly options: CommentOptions = {}) {
- this.content = Array.from(gen, ([cmap, message]): [string, string] => [
- typeof cmap === 'string' ? cmap : ' '.repeat(cmap.start) + cmap.text,
- message
- ]);
- }
+ constructor(gen: Iterable, readonly options: CommentOptions = {}) {
+ this.content = Array.from(gen, ([cmap, message]): [string, string] => [
+ typeof cmap === 'string' ? cmap : ' '.repeat(cmap.start) + cmap.text,
+ message
+ ]);
+ }
- render(indent: number, col0_width: number, width: number) {
- col0_width = Math.max(col0_width, ...this.content.map(([map]) => map.length));
- if ('indent' in this.options) indent = this.options.indent;
- return this.content
- .map(([map, comment]) =>
- (' '.repeat(indent * 4) + map.padEnd(col0_width) + ' ' + comment).padEnd(width)
- )
- .join('\n');
- }
+ render(indent: number, col0_width: number, width: number) {
+ col0_width = Math.max(col0_width, ...this.content.map(([map]) => map.length));
+ if ('indent' in this.options) indent = this.options.indent;
+ return this.content
+ .map(([map, comment]) =>
+ (' '.repeat(indent * 4) + map.padEnd(col0_width) + ' ' + comment).padEnd(width)
+ )
+ .join('\n');
+ }
}
class HorizontalRule {
- constructor(readonly content?: string, readonly _fill: string = '-') {}
+ constructor(readonly content?: string, readonly _fill: string = '-') {}
- fill(width: number) {
- return this.content
- ? this.content
- .padStart(Math.floor((width + this.content.length) / 2), this._fill)
- .padEnd(width, this._fill)
- : this._fill.repeat(width);
- }
+ fill(width: number) {
+ return this.content
+ ? this.content
+ .padStart(Math.floor((width + this.content.length) / 2), this._fill)
+ .padEnd(width, this._fill)
+ : this._fill.repeat(width);
+ }
}
/**
@@ -44,74 +44,74 @@ class HorizontalRule {
* width around it with the given fill.
*/
function rule(content?: string, fill?: string): HorizontalRule {
- return new HorizontalRule(content, fill);
+ return new HorizontalRule(content, fill);
}
/**
* Prints given line(s) in a multi-line comment block. (succeeding comments are joined together)
*/
function comment(lines: comment | Iterable, opts?: CommentOptions) {
- return new Comment(
- lines instanceof Array && lines.length === 2 && !(lines[0] instanceof Array)
- ? [lines]
- : (lines as Iterable),
- opts
- );
+ return new Comment(
+ lines instanceof Array && lines.length === 2 && !(lines[0] instanceof Array)
+ ? [lines]
+ : (lines as Iterable),
+ opts
+ );
}
function is_inside_comment(section: Section) {
- return section instanceof HorizontalRule || section instanceof Comment;
+ return section instanceof HorizontalRule || section instanceof Comment;
}
export type ComposeHelper = { rule: typeof rule; comment: typeof comment };
export function compose_file(
- fn: (composer: ComposeHelper) => Iterable,
- opts: { width?: number; indent?: number; match_first_column_width?: boolean } = {}
+ fn: (composer: ComposeHelper) => Iterable,
+ opts: { width?: number; indent?: number; match_first_column_width?: boolean } = {}
) {
- const sections = [...fn({ rule, comment })];
- const width = opts.width ?? 150;
- const min_col0_width = opts.match_first_column_width
- ? Math.max(
- ...sections.map((section) =>
- section instanceof Comment
- ? Math.max(...section.content.map((line) => line[0].length))
- : 0
- )
- )
- : 0;
+ const sections = [...fn({ rule, comment })];
+ const width = opts.width ?? 150;
+ const min_col0_width = opts.match_first_column_width
+ ? Math.max(
+ ...sections.map((section) =>
+ section instanceof Comment
+ ? Math.max(...section.content.map((line) => line[0].length))
+ : 0
+ )
+ )
+ : 0;
- const content: string[] = [];
- if (sections[0] instanceof HorizontalRule || sections[0] instanceof Comment) {
- sections.unshift('');
- }
+ const content: string[] = [];
+ if (sections[0] instanceof HorizontalRule || sections[0] instanceof Comment) {
+ sections.unshift('');
+ }
- for (let i = 0; i < sections.length; i++) {
- const { [i]: current, [i + 1]: next } = sections;
- let str = '';
- if (current instanceof HorizontalRule) {
- if (next instanceof HorizontalRule) continue;
- str = current.fill(width);
- if (!is_inside_comment(next)) {
- if (content[content.length - 1].includes('//')) {
- str = '//' + current.fill(width - 2);
- } else {
- str += comment_end;
- }
- }
- } else if (current instanceof Comment) {
- str = current.render(opts.indent ?? 0, min_col0_width, width);
- if (!(next === undefined || is_inside_comment(next))) str += comment_end;
- } else {
- str = ('' + current).trimRight().replace(/\t/g, ' ');
- if (is_inside_comment(next) && !str.includes('//')) {
- str = str.padEnd(width - get_extra_indent(str)) + comment_start;
- }
- }
- content.push(str);
- }
+ for (let i = 0; i < sections.length; i++) {
+ const { [i]: current, [i + 1]: next } = sections;
+ let str = '';
+ if (current instanceof HorizontalRule) {
+ if (next instanceof HorizontalRule) continue;
+ str = current.fill(width);
+ if (!is_inside_comment(next)) {
+ if (content[content.length - 1].includes('//')) {
+ str = '//' + current.fill(width - 2);
+ } else {
+ str += comment_end;
+ }
+ }
+ } else if (current instanceof Comment) {
+ str = current.render(opts.indent ?? 0, min_col0_width, width);
+ if (!(next === undefined || is_inside_comment(next))) str += comment_end;
+ } else {
+ str = ('' + current).trimRight().replace(/\t/g, ' ');
+ if (is_inside_comment(next) && !str.includes('//')) {
+ str = str.padEnd(width - get_extra_indent(str)) + comment_start;
+ }
+ }
+ content.push(str);
+ }
- return content.join('\n');
+ return content.join('\n');
}
const comment_start = '{/**';
diff --git a/packages/svelte2tsx/test/sourcemaps/helpers.ts b/packages/svelte2tsx/test/sourcemaps/helpers.ts
index e925cd45f..5d1382baa 100644
--- a/packages/svelte2tsx/test/sourcemaps/helpers.ts
+++ b/packages/svelte2tsx/test/sourcemaps/helpers.ts
@@ -1,10 +1,10 @@
import { GeneratedLine, Line } from './parser';
export type CharMap4 = [
- generated_charIndex: number,
- original_fileIndex: number,
- original_lineIndex: number,
- original_charIndex: number
+ generated_charIndex: number,
+ original_fileIndex: number,
+ original_lineIndex: number,
+ original_charIndex: number
];
export type LineMap = CharMap4[];
@@ -16,132 +16,132 @@ export type MappedRange = { start: MappedPosition; end: MappedPosition };
export const MappedKeys: (keyof MappedPosition)[] = ['generated', 'original'];
export interface Position {
- line: Line;
- character: number;
+ line: Line;
+ character: number;
}
export interface GeneratedPosition extends Position {
- line: GeneratedLine;
+ line: GeneratedLine;
}
export function print_string(str: string) {
- return ('' + str)
- .replace(/ /g, '•')
- .replace(/[\r\n]/g, '↲')
- .replace(/\t/g, '╚');
+ return ('' + str)
+ .replace(/ /g, '•')
+ .replace(/[\r\n]/g, '↲')
+ .replace(/\t/g, '╚');
}
function edit_string(str: string, { start, text }: Segment, insert: boolean) {
- if (str.length === start) return str + text;
- else if (str.length < start) return str.padEnd(start) + text;
- else return str.slice(0, start) + text + str.slice(start + (insert ? 0 : text.length));
+ if (str.length === start) return str + text;
+ else if (str.length < start) return str.padEnd(start) + text;
+ else return str.slice(0, start) + text + str.slice(start + (insert ? 0 : text.length));
}
/**
* Reduces segments into one big string
*/
export function reduce_segments(
- gen: Iterable,
- fn: (value: T, index: number) => Segment | void,
- initial = ''
+ gen: Iterable,
+ fn: (value: T, index: number) => Segment | void,
+ initial = ''
) {
- let str = initial;
- let i = 0;
- for (const value of gen) {
- const segment = fn(value, i++);
- if (segment) str = edit_string(str, segment, false);
- }
- return str;
+ let str = initial;
+ let i = 0;
+ for (const value of gen) {
+ const segment = fn(value, i++);
+ if (segment) str = edit_string(str, segment, false);
+ }
+ return str;
}
/**
* Inserts each segment in the given text
*/
export function insert_segments(text: string, segments: Iterable) {
- let str = '';
- let prev_start: number = undefined;
- // sort descending
- for (const segment of [...segments].sort((a, b) => b.start - a.start)) {
- str = segment.text + text.slice(segment.start, prev_start) + str;
- prev_start = segment.start;
- }
- return text.slice(0, prev_start) + str;
+ let str = '';
+ let prev_start: number = undefined;
+ // sort descending
+ for (const segment of [...segments].sort((a, b) => b.start - a.start)) {
+ str = segment.text + text.slice(segment.start, prev_start) + str;
+ prev_start = segment.start;
+ }
+ return text.slice(0, prev_start) + str;
}
export function fromLineCharToOffset({ line, character }: { line: Line; character: number }) {
- return line.start + character;
+ return line.start + character;
}
/**
* Returns a text span starting with head, ending with tail, and repeating body in the middle.
*/
export function span(length: number, [head, body, tail]: string = '#==') {
- if (length <= 1) return length < 1 ? '' : body === tail ? head : tail;
- return head + body.repeat(length - 2) + tail;
+ if (length <= 1) return length < 1 ? '' : body === tail ? head : tail;
+ return head + body.repeat(length - 2) + tail;
}
class Underline {
- constructor(readonly start: number, readonly text: string) {}
+ constructor(readonly start: number, readonly text: string) {}
- toString() {
- return ' '.repeat(this.start) + this.text;
- }
+ toString() {
+ return ' '.repeat(this.start) + this.text;
+ }
}
export function underline(start: number, end: number, style?: string) {
- return new Underline(start, span(end - start + 1, style));
+ return new Underline(start, span(end - start + 1, style));
}
export function* each_subset(lineMap: LineMap) {
- let char = lineMap[0];
- for (let i = 1; i < lineMap.length; i++) {
- if (char[2] !== lineMap[i][2]) {
- yield { line: char[2], start: char[0], end: (char = lineMap[i])[0] };
- }
- }
- yield { line: char[2], start: char[0], end: undefined };
+ let char = lineMap[0];
+ for (let i = 1; i < lineMap.length; i++) {
+ if (char[2] !== lineMap[i][2]) {
+ yield { line: char[2], start: char[0], end: (char = lineMap[i])[0] };
+ }
+ }
+ yield { line: char[2], start: char[0], end: undefined };
}
export function* each_exec(str: string, re: RegExp) {
- let arr: RegExpExecArray;
- while ((arr = re.exec(str))) yield { match: arr[0], index: arr.index };
+ let arr: RegExpExecArray;
+ while ((arr = re.exec(str))) yield { match: arr[0], index: arr.index };
}
/**
* Returns offset of character at index after accounting for extra space taken by tabs
*/
export function tab_aware_index(str: string, index: number) {
- return index + get_extra_indent(str.slice(0, index + 1));
+ return index + get_extra_indent(str.slice(0, index + 1));
}
/**
* Returns all extra space taken by tabs in given string
*/
export function get_extra_indent(str: string) {
- return (str.match(/\t/g)?.length ?? 0) * 3;
+ return (str.match(/\t/g)?.length ?? 0) * 3;
}
export function range_for(key: K, range: MappedRange) {
- return { start: range.start[key], end: range.end[key] };
+ return { start: range.start[key], end: range.end[key] };
}
export function hash(str: string): string {
- str = str.replace(/\r/g, '');
- let hash = 5381;
- let i = str.length;
- while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
- return (hash >>> 0).toString(36);
+ str = str.replace(/\r/g, '');
+ let hash = 5381;
+ let i = str.length;
+ while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
+ return (hash >>> 0).toString(36);
}
export function debug_print(start: Position, end: Position) {
- const underline_length =
- Math.min(
- fromLineCharToOffset(end) - fromLineCharToOffset(start),
- start.line.length - start.character
- ) + 1;
- const info = `${start.line.index + 1}`;
- const fill = ' '.repeat(info.length);
- return (
- `> ${info} | ${start.line.print()}\n` +
- ` ${fill} ${' '.repeat(start.character)}${'^'.repeat(underline_length)}\n`
- );
+ const underline_length =
+ Math.min(
+ fromLineCharToOffset(end) - fromLineCharToOffset(start),
+ start.line.length - start.character
+ ) + 1;
+ const info = `${start.line.index + 1}`;
+ const fill = ' '.repeat(info.length);
+ return (
+ `> ${info} | ${start.line.print()}\n` +
+ ` ${fill} ${' '.repeat(start.character)}${'^'.repeat(underline_length)}\n`
+ );
}
diff --git a/packages/svelte2tsx/test/sourcemaps/index.ts b/packages/svelte2tsx/test/sourcemaps/index.ts
index 3da87b751..2355da495 100644
--- a/packages/svelte2tsx/test/sourcemaps/index.ts
+++ b/packages/svelte2tsx/test/sourcemaps/index.ts
@@ -4,156 +4,156 @@ import { decode } from 'sourcemap-codec';
import { each_sample, GenerateFn, get_svelte2tsx_config, Sample } from '../helpers';
import { print_string } from './helpers';
import {
- process_transformed_text,
- is_edit_changed,
- is_edit_empty,
- is_edit_from_same_generated,
- is_test_empty,
- is_test_from_same_input,
- validate_edit_file,
- validate_test_file
+ process_transformed_text,
+ is_edit_changed,
+ is_edit_empty,
+ is_edit_from_same_generated,
+ is_test_empty,
+ is_test_from_same_input,
+ validate_edit_file,
+ validate_test_file
} from './process';
describe('sourcemaps', function () {
- for (const sample of each_sample(__dirname)) {
- if (process.env.CI) {
- sample.checkDirectory({ required: ['*.svelte', 'mappings.jsx', 'test.jsx'] });
- } else {
- sample.checkDirectory({
- required: ['*.svelte'],
- allowed: ['mappings.jsx', 'test.jsx', 'test.edit.jsx', 'output.tsx']
- });
- maybe_generate(sample, regenerate);
- sample.onError(function (generate, err) {
- const skip = (err as Error).message.includes('SourceMapping changed');
- regenerate(generate, skip);
- });
- }
-
- sample.it(function () {
- const parsed = parse(sample);
-
- parsed.each_test_range(
- sample.get('test.jsx'),
- function (actual, expected) {
- assert.strictEqual(actual, expected);
- },
- function () {
- throw new Error(`Invalid test file format`);
- },
- function (ranges) {
- throw new Error(
- `Could not find the following snippets in generated output\n` +
- ranges.map((range) => `\t"${print_string(range[2])}"`).join('\n') +
- (process.env.CI
- ? ''
- : `\nTo edit ranges : ${sample.cmd('test.edit.jsx')}`)
- );
- }
- );
-
- assert.strictEqual(
- parsed.print_mappings(),
- sample.get('mappings.jsx'),
- `SourceMapping changed, run tests with --auto to update them`
- );
- });
-
- function regenerate(generate: GenerateFn, skip = false) {
- const parsed = parse(sample);
- generate_output_and_mappings_file(generate, parsed, skip);
- if (!sample.has('test.jsx')) generate('test.jsx', parsed.generate_test(), skip);
- generate('test.edit.jsx', parsed.generate_test_edit(sample.get('test.jsx')), false);
- }
- }
+ for (const sample of each_sample(__dirname)) {
+ if (process.env.CI) {
+ sample.checkDirectory({ required: ['*.svelte', 'mappings.jsx', 'test.jsx'] });
+ } else {
+ sample.checkDirectory({
+ required: ['*.svelte'],
+ allowed: ['mappings.jsx', 'test.jsx', 'test.edit.jsx', 'output.tsx']
+ });
+ maybe_generate(sample, regenerate);
+ sample.onError(function (generate, err) {
+ const skip = (err as Error).message.includes('SourceMapping changed');
+ regenerate(generate, skip);
+ });
+ }
+
+ sample.it(function () {
+ const parsed = parse(sample);
+
+ parsed.each_test_range(
+ sample.get('test.jsx'),
+ function (actual, expected) {
+ assert.strictEqual(actual, expected);
+ },
+ function () {
+ throw new Error(`Invalid test file format`);
+ },
+ function (ranges) {
+ throw new Error(
+ `Could not find the following snippets in generated output\n` +
+ ranges.map((range) => `\t"${print_string(range[2])}"`).join('\n') +
+ (process.env.CI
+ ? ''
+ : `\nTo edit ranges : ${sample.cmd('test.edit.jsx')}`)
+ );
+ }
+ );
+
+ assert.strictEqual(
+ parsed.print_mappings(),
+ sample.get('mappings.jsx'),
+ `SourceMapping changed, run tests with --auto to update them`
+ );
+ });
+
+ function regenerate(generate: GenerateFn, skip = false) {
+ const parsed = parse(sample);
+ generate_output_and_mappings_file(generate, parsed, skip);
+ if (!sample.has('test.jsx')) generate('test.jsx', parsed.generate_test(), skip);
+ generate('test.edit.jsx', parsed.generate_test_edit(sample.get('test.jsx')), false);
+ }
+ }
});
/**
* Maybe generates test result files depending on the currently existing files.
*/
function maybe_generate(sample: Sample, regenerate: (generate: GenerateFn) => void) {
- const svelteFile = sample.find_file('*.svelte');
-
- if (sample.hasOnly(svelteFile)) {
- return sample.generateDeps(regenerate);
- }
-
- if (sample.has('test.edit.jsx')) {
- const edit = sample.get('test.edit.jsx');
-
- try {
- validate_edit_file(edit);
- } catch (err) {
- return sample.generateDeps(function (generate) {
- generate_output_and_mappings_file(generate, parse(sample));
- throw err;
- });
- }
-
- const edit_changed = is_edit_changed(edit);
-
- if (edit_changed || !sample.has('test.jsx')) {
- return sample.generateDeps(function (generate) {
- const parsed = parse(sample);
- if (is_edit_empty(edit)) {
- generate('test.jsx', parsed.generate_test());
- generate('test.edit.jsx', parsed.generate_test_edit());
- generate_output_and_mappings_file(generate, parsed);
- return;
- }
- if (is_edit_from_same_generated(edit, parsed.generated)) {
- const new_test = parsed.generate_test(edit);
- generate('test.jsx', new_test);
- generate('test.edit.jsx', parsed.generate_test_edit(new_test));
- generate_output_and_mappings_file(generate, parsed);
- return;
- }
- const err = edit_changed ? 'apply changes made to' : 'generate "test.jsx" from';
- throw new Error(
- '' +
- `Failed to ${err} "test.edit.jsx" as it is based on a stale output.\n` +
- `\tEither reverse output changes or delete "test.edit.jsx" manually before running tests again\n` +
- `\tcmd-click : ${sample.cmd('test.edit.jsx')}\n`
- );
- });
- }
- }
-
- if (!sample.has('mappings.jsx') || (!sample.has('test.jsx') && !sample.has('test.edit.jsx'))) {
- return sample.generateDeps(regenerate);
- }
-
- const test = sample.get('test.jsx');
- try {
- validate_test_file(test);
- } catch (err) {
- return sample.generateDeps(function (generate) {
- generate_output_and_mappings_file(generate, parse(sample));
- throw err;
- });
- }
- if (!is_test_from_same_input(test, sample.get(svelteFile))) {
- return sample.generateDeps(function (generate) {
- const parsed = parse(sample);
- generate_output_and_mappings_file(generate, parsed);
- generate('test.edit.jsx', parsed.generate_test_edit());
- if (is_test_empty(test)) {
- generate('test.jsx', parsed.generate_test());
- return;
- }
- throw new Error(
- '' +
- `Test input at "${svelteFile}" changed, thus making "test.jsx" invalid.\n` +
- `\tEither manually re-select all tested ranges in the newly generated "test.edit.jsx", delete "test.jsx" or undo input changes.\n` +
- `\tcmd-click : ${sample.cmd('test.edit.jsx')}\n`
- );
- });
- }
+ const svelteFile = sample.find_file('*.svelte');
+
+ if (sample.hasOnly(svelteFile)) {
+ return sample.generateDeps(regenerate);
+ }
+
+ if (sample.has('test.edit.jsx')) {
+ const edit = sample.get('test.edit.jsx');
+
+ try {
+ validate_edit_file(edit);
+ } catch (err) {
+ return sample.generateDeps(function (generate) {
+ generate_output_and_mappings_file(generate, parse(sample));
+ throw err;
+ });
+ }
+
+ const edit_changed = is_edit_changed(edit);
+
+ if (edit_changed || !sample.has('test.jsx')) {
+ return sample.generateDeps(function (generate) {
+ const parsed = parse(sample);
+ if (is_edit_empty(edit)) {
+ generate('test.jsx', parsed.generate_test());
+ generate('test.edit.jsx', parsed.generate_test_edit());
+ generate_output_and_mappings_file(generate, parsed);
+ return;
+ }
+ if (is_edit_from_same_generated(edit, parsed.generated)) {
+ const new_test = parsed.generate_test(edit);
+ generate('test.jsx', new_test);
+ generate('test.edit.jsx', parsed.generate_test_edit(new_test));
+ generate_output_and_mappings_file(generate, parsed);
+ return;
+ }
+ const err = edit_changed ? 'apply changes made to' : 'generate "test.jsx" from';
+ throw new Error(
+ '' +
+ `Failed to ${err} "test.edit.jsx" as it is based on a stale output.\n` +
+ `\tEither reverse output changes or delete "test.edit.jsx" manually before running tests again\n` +
+ `\tcmd-click : ${sample.cmd('test.edit.jsx')}\n`
+ );
+ });
+ }
+ }
+
+ if (!sample.has('mappings.jsx') || (!sample.has('test.jsx') && !sample.has('test.edit.jsx'))) {
+ return sample.generateDeps(regenerate);
+ }
+
+ const test = sample.get('test.jsx');
+ try {
+ validate_test_file(test);
+ } catch (err) {
+ return sample.generateDeps(function (generate) {
+ generate_output_and_mappings_file(generate, parse(sample));
+ throw err;
+ });
+ }
+ if (!is_test_from_same_input(test, sample.get(svelteFile))) {
+ return sample.generateDeps(function (generate) {
+ const parsed = parse(sample);
+ generate_output_and_mappings_file(generate, parsed);
+ generate('test.edit.jsx', parsed.generate_test_edit());
+ if (is_test_empty(test)) {
+ generate('test.jsx', parsed.generate_test());
+ return;
+ }
+ throw new Error(
+ '' +
+ `Test input at "${svelteFile}" changed, thus making "test.jsx" invalid.\n` +
+ `\tEither manually re-select all tested ranges in the newly generated "test.edit.jsx", delete "test.jsx" or undo input changes.\n` +
+ `\tcmd-click : ${sample.cmd('test.edit.jsx')}\n`
+ );
+ });
+ }
}
function generate_output_and_mappings_file(generate: GenerateFn, parsed: Parsed, skip = false) {
- generate('output.tsx', parsed.inline, false);
- generate('mappings.jsx', parsed.print_mappings(), skip);
+ generate('output.tsx', parsed.inline, false);
+ generate('mappings.jsx', parsed.print_mappings(), skip);
}
type Parsed = ReturnType & { generated: string; inline: string };
@@ -164,24 +164,24 @@ const cache = new WeakMap();
* generating further test output files.
*/
function parse(sample: Sample): Parsed {
- if (!cache.has(sample)) {
- const filename = sample.find_file('*.svelte');
- const original = sample.get(filename);
- const { code, map } = svelte2tsx(
- original,
- get_svelte2tsx_config({ filename }, sample.name)
- );
-
- map.file = 'output.tsx';
- map.sources = [filename];
- map.sourcesContent = [original];
-
- const mapped = process_transformed_text(original, code, decode(map.mappings) as any);
- cache.set(sample, {
- ...mapped,
- generated: code,
- inline: code + `\n//# sourceMappingURL=${map.toUrl()}`
- });
- }
- return cache.get(sample);
+ if (!cache.has(sample)) {
+ const filename = sample.find_file('*.svelte');
+ const original = sample.get(filename);
+ const { code, map } = svelte2tsx(
+ original,
+ get_svelte2tsx_config({ filename }, sample.name)
+ );
+
+ map.file = 'output.tsx';
+ map.sources = [filename];
+ map.sourcesContent = [original];
+
+ const mapped = process_transformed_text(original, code, decode(map.mappings) as any);
+ cache.set(sample, {
+ ...mapped,
+ generated: code,
+ inline: code + `\n//# sourceMappingURL=${map.toUrl()}`
+ });
+ }
+ return cache.get(sample);
}
diff --git a/packages/svelte2tsx/test/sourcemaps/parser.ts b/packages/svelte2tsx/test/sourcemaps/parser.ts
index dd55f06d6..a5157eb1d 100644
--- a/packages/svelte2tsx/test/sourcemaps/parser.ts
+++ b/packages/svelte2tsx/test/sourcemaps/parser.ts
@@ -1,246 +1,246 @@
import {
- CharMap4,
- each_subset,
- GeneratedPosition,
- LineMap,
- MappedPosition,
- Mappings,
- print_string,
- reduce_segments,
- span,
- underline
+ CharMap4,
+ each_subset,
+ GeneratedPosition,
+ LineMap,
+ MappedPosition,
+ Mappings,
+ print_string,
+ reduce_segments,
+ span,
+ underline
} from './helpers';
type LineContext = { index: number; start: number; length: number };
export class SourceText {
- readonly lines: L[] = [];
+ readonly lines: L[] = [];
- constructor(readonly text: string, line?: (ctx: LineContext) => L) {
- this.lines = Array.from(
- (function* (text: string): Generator {
- const line = { index: 0, start: 0, length: 0 };
- for (let i = 0; i < text.length; i++)
- switch (text.charCodeAt(i)) {
- case 13: // "\r"
- if (10 === text.charCodeAt(i + 1)) i++;
- case 10: // "\n"
- line.length = 1 + i - line.start;
- yield line;
- line.start += line.length;
- line.index++;
- }
- if (line.start === text.length) return;
- line.length = text.length - line.start;
- yield line;
- })(text),
- line ? line.bind(this) : (ctx) => new Line(this, ctx)
- );
- }
+ constructor(readonly text: string, line?: (ctx: LineContext) => L) {
+ this.lines = Array.from(
+ (function* (text: string): Generator {
+ const line = { index: 0, start: 0, length: 0 };
+ for (let i = 0; i < text.length; i++)
+ switch (text.charCodeAt(i)) {
+ case 13: // "\r"
+ if (10 === text.charCodeAt(i + 1)) i++;
+ case 10: // "\n"
+ line.length = 1 + i - line.start;
+ yield line;
+ line.start += line.length;
+ line.index++;
+ }
+ if (line.start === text.length) return;
+ line.length = text.length - line.start;
+ yield line;
+ })(text),
+ line ? line.bind(this) : (ctx) => new Line(this, ctx)
+ );
+ }
- toLineChar(index: number) {
- let i = this.lines.length - 1;
- while (index < this.lines[i].start) i--;
- return { line: this.lines[i], character: index - this.lines[i].start };
- }
+ toLineChar(index: number) {
+ let i = this.lines.length - 1;
+ while (index < this.lines[i].start) i--;
+ return { line: this.lines[i], character: index - this.lines[i].start };
+ }
- print_slice(start: number, end?: number) {
- return print_string(this.text.slice(start, end));
- }
+ print_slice(start: number, end?: number) {
+ return print_string(this.text.slice(start, end));
+ }
}
/**
* Wrapper around text that was compiled from another
*/
export class GeneratedSourceText extends SourceText {
- firstMapped: number;
- lastMapped: number;
- readonly original: SourceText;
- readonly mappings: Mappings;
- private readonly references: Map;
+ firstMapped: number;
+ lastMapped: number;
+ readonly original: SourceText;
+ readonly mappings: Mappings;
+ private readonly references: Map;
- constructor(text: string, original: SourceText, mappings: Mappings) {
- const references = new Map(original.lines.map((line) => [line, []]));
- super(text, function (this: GeneratedSourceText, line) {
- if (mappings.length > line.index && mappings[line.index].length > 0) {
- this.firstMapped ??= line.index;
- this.lastMapped = line.index;
- const lineMap = mappings[line.index];
- const genLine = new GeneratedLine(
- this,
- line,
- lineMap,
- [...new Set(lineMap.map((c) => c[2]))].sort().map((i) => original.lines[i])
- );
- for (const ogLine of genLine.ogLines) references.get(ogLine).push(genLine);
- return genLine;
- }
- return new GeneratedLine(this, line);
- });
- this.references = references;
- this.original = original;
- this.mappings = mappings;
- }
+ constructor(text: string, original: SourceText, mappings: Mappings) {
+ const references = new Map(original.lines.map((line) => [line, []]));
+ super(text, function (this: GeneratedSourceText, line) {
+ if (mappings.length > line.index && mappings[line.index].length > 0) {
+ this.firstMapped ??= line.index;
+ this.lastMapped = line.index;
+ const lineMap = mappings[line.index];
+ const genLine = new GeneratedLine(
+ this,
+ line,
+ lineMap,
+ [...new Set(lineMap.map((c) => c[2]))].sort().map((i) => original.lines[i])
+ );
+ for (const ogLine of genLine.ogLines) references.get(ogLine).push(genLine);
+ return genLine;
+ }
+ return new GeneratedLine(this, line);
+ });
+ this.references = references;
+ this.original = original;
+ this.mappings = mappings;
+ }
- at(genCharIndex: number): MappedPosition {
- const { line, character } = super.toLineChar(genCharIndex);
- return { generated: { line, character }, original: line.getOriginalPosition(character) };
- }
+ at(genCharIndex: number): MappedPosition {
+ const { line, character } = super.toLineChar(genCharIndex);
+ return { generated: { line, character }, original: line.getOriginalPosition(character) };
+ }
- from(ogCharIndex: number): MappedPosition[] {
- const original = this.original.toLineChar(ogCharIndex);
- const { line: ogLine, character: ogIndex } = original;
- const matches: GeneratedPosition[] = [];
- for (const line of this.for(ogLine)) {
- for (const char of line.lineMap) {
- if (char[2] === ogLine.index && char[3] === ogIndex) {
- matches.push({ line, character: char[0] });
- }
- }
- }
- return matches.map((generated) => ({ generated, original }));
- }
+ from(ogCharIndex: number): MappedPosition[] {
+ const original = this.original.toLineChar(ogCharIndex);
+ const { line: ogLine, character: ogIndex } = original;
+ const matches: GeneratedPosition[] = [];
+ for (const line of this.for(ogLine)) {
+ for (const char of line.lineMap) {
+ if (char[2] === ogLine.index && char[3] === ogIndex) {
+ matches.push({ line, character: char[0] });
+ }
+ }
+ }
+ return matches.map((generated) => ({ generated, original }));
+ }
- for(ogLine: Line) {
- return this.references.get(ogLine);
- }
+ for(ogLine: Line) {
+ return this.references.get(ogLine);
+ }
}
/**
* Wrapper around each line in a SourceText
*/
export class Line {
- readonly index: number;
- readonly start: number;
- readonly length: number;
+ readonly index: number;
+ readonly start: number;
+ readonly length: number;
- get end() {
- return this.start + this.length - 1;
- }
+ get end() {
+ return this.start + this.length - 1;
+ }
- constructor(readonly source: SourceText, ctx: LineContext) {
- ({ index: this.index, start: this.start, length: this.length } = ctx);
- }
+ constructor(readonly source: SourceText, ctx: LineContext) {
+ ({ index: this.index, start: this.start, length: this.length } = ctx);
+ }
- print_charAt(charIndex: number) {
- return print_string(this.source.text.charAt(this.start + charIndex));
- }
+ print_charAt(charIndex: number) {
+ return print_string(this.source.text.charAt(this.start + charIndex));
+ }
- print_slice(start: number, end?: number) {
- return print_string(
- start >= 0 && (end === undefined || (start <= end && end <= this.length))
- ? this.source.text.slice(this.start + start, this.start + (end ?? this.length))
- : this.toString().slice(start, end)
- );
- }
+ print_slice(start: number, end?: number) {
+ return print_string(
+ start >= 0 && (end === undefined || (start <= end && end <= this.length))
+ ? this.source.text.slice(this.start + start, this.start + (end ?? this.length))
+ : this.toString().slice(start, end)
+ );
+ }
- print() {
- return this.print_slice(0);
- }
+ print() {
+ return this.print_slice(0);
+ }
- toString() {
- return this.source.text.slice(this.start, this.start + this.length);
- }
+ toString() {
+ return this.source.text.slice(this.start, this.start + this.length);
+ }
}
/**
* Wrapper around each line in a GeneratedSourceText
*/
export class GeneratedLine extends Line {
- readonly source: GeneratedSourceText;
- readonly hasOrigin = this.lineMap.length !== 0;
- readonly hasStartOrigin = this.hasOrigin && this.lineMap[0][0] === 0;
- readonly isSingleOrigin = this.hasOrigin && this.ogLines.length === 1;
+ readonly source: GeneratedSourceText;
+ readonly hasOrigin = this.lineMap.length !== 0;
+ readonly hasStartOrigin = this.hasOrigin && this.lineMap[0][0] === 0;
+ readonly isSingleOrigin = this.hasOrigin && this.ogLines.length === 1;
- constructor(
- source: GeneratedSourceText,
- ctx: LineContext,
- readonly lineMap: LineMap = [],
- readonly ogLines: Line[] = []
- ) {
- super(source, ctx);
- }
+ constructor(
+ source: GeneratedSourceText,
+ ctx: LineContext,
+ readonly lineMap: LineMap = [],
+ readonly ogLines: Line[] = []
+ ) {
+ super(source, ctx);
+ }
- isExact() {
- return (
- this.hasOrigin &&
- this.hasStartOrigin &&
- this.isSingleOrigin &&
- this.ogLines[0].print() === this.print() &&
- this.source.for(this.ogLines[0]).length === 1 &&
- this.lineMap.every((char) => char[0] === char[3])
- );
- }
+ isExact() {
+ return (
+ this.hasOrigin &&
+ this.hasStartOrigin &&
+ this.isSingleOrigin &&
+ this.ogLines[0].print() === this.print() &&
+ this.source.for(this.ogLines[0]).length === 1 &&
+ this.lineMap.every((char) => char[0] === char[3])
+ );
+ }
- getOrderBreaking(ogLine: Line) {
- let prev: CharMap4 = this.lineMap.find((char) => char[2] === ogLine.index);
- return reduce_segments(this.lineMap, function (char) {
- if (char[2] === ogLine.index) {
- if (prev[3] > char[3]) {
- return underline(prev[0], (prev = char)[0] - 1, '#==');
- }
- prev = char;
- }
- });
- }
+ getOrderBreaking(ogLine: Line) {
+ let prev: CharMap4 = this.lineMap.find((char) => char[2] === ogLine.index);
+ return reduce_segments(this.lineMap, function (char) {
+ if (char[2] === ogLine.index) {
+ if (prev[3] > char[3]) {
+ return underline(prev[0], (prev = char)[0] - 1, '#==');
+ }
+ prev = char;
+ }
+ });
+ }
- getUnmappedStart() {
- return span(this.lineMap[0]?.[0] ?? this.length, '==#');
- }
+ getUnmappedStart() {
+ return span(this.lineMap[0]?.[0] ?? this.length, '==#');
+ }
- getGeneratedMappingResult(ogLine: Line) {
- return reduce_segments(this.lineMap, function (char) {
- if (char[2] === ogLine.index)
- return { start: char[0], text: ogLine.print_charAt(char[3]) };
- });
- }
+ getGeneratedMappingResult(ogLine: Line) {
+ return reduce_segments(this.lineMap, function (char) {
+ if (char[2] === ogLine.index)
+ return { start: char[0], text: ogLine.print_charAt(char[3]) };
+ });
+ }
- getOriginalMappingResult(ogLine: Line) {
- return reduce_segments(this.lineMap, function (char) {
- if (char[2] === ogLine.index)
- return { start: char[3], text: ogLine.print_charAt(char[3]) };
- });
- }
+ getOriginalMappingResult(ogLine: Line) {
+ return reduce_segments(this.lineMap, function (char) {
+ if (char[2] === ogLine.index)
+ return { start: char[3], text: ogLine.print_charAt(char[3]) };
+ });
+ }
- *subsets() {
- if (!this.hasOrigin) return;
- if (this.isSingleOrigin)
- return yield {
- ogLine: this.ogLines[0],
- text: this.print_slice(this.lineMap[0][0]),
- index: 0
- };
- const text: { [ogLineIndex: number]: string } = {};
- for (const { line, start, end } of each_subset(this.lineMap))
- text[line] = (text[line] ?? '').padEnd(start) + this.print_slice(start, end);
- for (let index = 0; index < this.ogLines.length; index++) {
- const ogLine = this.ogLines[index];
- yield { ogLine, text: text[ogLine.index], index };
- }
- }
+ *subsets() {
+ if (!this.hasOrigin) return;
+ if (this.isSingleOrigin)
+ return yield {
+ ogLine: this.ogLines[0],
+ text: this.print_slice(this.lineMap[0][0]),
+ index: 0
+ };
+ const text: { [ogLineIndex: number]: string } = {};
+ for (const { line, start, end } of each_subset(this.lineMap))
+ text[line] = (text[line] ?? '').padEnd(start) + this.print_slice(start, end);
+ for (let index = 0; index < this.ogLines.length; index++) {
+ const ogLine = this.ogLines[index];
+ yield { ogLine, text: text[ogLine.index], index };
+ }
+ }
- getMappingFor(charIndex: number) {
- if (!this.hasOrigin || (!this.hasStartOrigin && charIndex < this.lineMap[0][0])) return;
- let i = this.lineMap.length - 1;
- while (this.lineMap[i][0] > charIndex) i--;
- return this.lineMap[i];
- }
+ getMappingFor(charIndex: number) {
+ if (!this.hasOrigin || (!this.hasStartOrigin && charIndex < this.lineMap[0][0])) return;
+ let i = this.lineMap.length - 1;
+ while (this.lineMap[i][0] > charIndex) i--;
+ return this.lineMap[i];
+ }
- hasExactMappingFor(charIndex: number) {
- return this.getMappingFor(charIndex)?.[0] === charIndex;
- }
+ hasExactMappingFor(charIndex: number) {
+ return this.getMappingFor(charIndex)?.[0] === charIndex;
+ }
- getOriginalPosition(charIndex: number) {
- const char = this.getMappingFor(charIndex);
- if (!char) return { line: null, character: -1 };
- const { 2: line, 3: character } = char;
- return { line: this.source.original.lines[line], character };
- }
+ getOriginalPosition(charIndex: number) {
+ const char = this.getMappingFor(charIndex);
+ if (!char) return { line: null, character: -1 };
+ const { 2: line, 3: character } = char;
+ return { line: this.source.original.lines[line], character };
+ }
}
export type ParsedSource = {
- original: SourceText;
- generated: GeneratedSourceText;
+ original: SourceText;
+ generated: GeneratedSourceText;
};
/**
@@ -250,10 +250,10 @@ export type ParsedSource = {
* @param mappings mappings from transformed to original
*/
export function parse(
- original_text: string,
- generated_text: string,
- mappings: Mappings
+ original_text: string,
+ generated_text: string,
+ mappings: Mappings
): ParsedSource {
- const original = new SourceText(original_text);
- return { original, generated: new GeneratedSourceText(generated_text, original, mappings) };
+ const original = new SourceText(original_text);
+ return { original, generated: new GeneratedSourceText(generated_text, original, mappings) };
}
diff --git a/packages/svelte2tsx/test/sourcemaps/process.ts b/packages/svelte2tsx/test/sourcemaps/process.ts
index 78f2ea6c4..3cfe704ab 100644
--- a/packages/svelte2tsx/test/sourcemaps/process.ts
+++ b/packages/svelte2tsx/test/sourcemaps/process.ts
@@ -1,29 +1,29 @@
import { ComposeHelper, compose_file } from './composer';
import {
- debug_print,
- each_exec,
- fromLineCharToOffset,
- get_extra_indent,
- hash,
- insert_segments,
- MappedKeys,
- MappedPosition,
- MappedRange,
- Mappings,
- Position,
- Range,
- range_for,
- reduce_segments,
- tab_aware_index,
- underline
+ debug_print,
+ each_exec,
+ fromLineCharToOffset,
+ get_extra_indent,
+ hash,
+ insert_segments,
+ MappedKeys,
+ MappedPosition,
+ MappedRange,
+ Mappings,
+ Position,
+ Range,
+ range_for,
+ reduce_segments,
+ tab_aware_index,
+ underline
} from './helpers';
import {
- GeneratedLine,
- GeneratedSourceText,
- Line,
- parse,
- ParsedSource,
- SourceText
+ GeneratedLine,
+ GeneratedSourceText,
+ Line,
+ parse,
+ ParsedSource,
+ SourceText
} from './parser';
/**
@@ -53,105 +53,105 @@ type SourceMappingTest = { actual: Range; expected: Range; range: MappedRange };
// inject/retrieve info from raw file
namespace raw {
- // test.edit.jsx
- const EDIT_FILE_START = `/** Surround [[[text]]] with brackets & run tests to add it to this sample's tested ranges */\n`;
- const EDIT_FILE_END = `\n/** content-hash: $ */`.split('$'); // Hash of own content (used to check if ranges were edited)
-
- // test.jsx
- const TEST_FILE_START = '/** tested-ranges: $ */'.split('$'); // RawTestRange[] (what tests are evaluated from)
- const TEST_FILE_END = '\n/** origin-hash: $ */'.split('$'); // Hash of input.svelte
-
- /**
- * Return raw ranges and the hash from a test.jsx input string.
- */
- export function fromTestFile(file: string) {
- if (!file.startsWith(TEST_FILE_START[0]) || !file.includes(TEST_FILE_END[0]))
- throw new Error('Invalid test file');
- const length = TEST_FILE_START[0].length;
- const ranges = JSON.parse(file.slice(length, file.indexOf(TEST_FILE_START[1], length)));
- const hash = file.slice(
- file.lastIndexOf(TEST_FILE_END[0]) + TEST_FILE_END[0].length,
- -TEST_FILE_END[1].length
- );
- return { ranges: ranges as RawTestRange[], hash };
- }
-
- /**
- * Returns a string for a test.jsx file
- */
- export function toTestFile(origin: string, content: string, ranges: RawTestRange[]) {
- const raw = JSON.stringify(ranges);
- if (raw.includes(TEST_FILE_START[1]))
- throw new Error(`Tested range cannot include "${TEST_FILE_START[1]}"`);
- let header = TEST_FILE_START[0] + raw + TEST_FILE_START[1];
- if (ranges.length && /^\s*{\/\*\*/.test(content)) {
- const width = content.indexOf('{');
- content = content.slice(Math.min(width, header.length));
- }
-
- return header + content + TEST_FILE_END[0] + hash(origin) + TEST_FILE_END[1];
- }
-
- export function fromEditFile(file: string) {
- const start = file.lastIndexOf(EDIT_FILE_START);
- const end = file.lastIndexOf(EDIT_FILE_END[0]);
- if (start > 0) throw new Error('Test Edit file invalid start');
- if (end === -1) throw new Error('Test Edit file is missing its content-hash');
- return {
- content: file.slice(start === -1 ? 0 : EDIT_FILE_START.length, end),
- hash: file.slice(end + EDIT_FILE_END[0].length, file.indexOf(EDIT_FILE_END[1], end))
- };
- }
-
- export function toEditFile(content: string) {
- return EDIT_FILE_START + content + EDIT_FILE_END[0] + hash(content) + EDIT_FILE_END[1];
- }
+ // test.edit.jsx
+ const EDIT_FILE_START = `/** Surround [[[text]]] with brackets & run tests to add it to this sample's tested ranges */\n`;
+ const EDIT_FILE_END = `\n/** content-hash: $ */`.split('$'); // Hash of own content (used to check if ranges were edited)
+
+ // test.jsx
+ const TEST_FILE_START = '/** tested-ranges: $ */'.split('$'); // RawTestRange[] (what tests are evaluated from)
+ const TEST_FILE_END = '\n/** origin-hash: $ */'.split('$'); // Hash of input.svelte
+
+ /**
+ * Return raw ranges and the hash from a test.jsx input string.
+ */
+ export function fromTestFile(file: string) {
+ if (!file.startsWith(TEST_FILE_START[0]) || !file.includes(TEST_FILE_END[0]))
+ throw new Error('Invalid test file');
+ const length = TEST_FILE_START[0].length;
+ const ranges = JSON.parse(file.slice(length, file.indexOf(TEST_FILE_START[1], length)));
+ const hash = file.slice(
+ file.lastIndexOf(TEST_FILE_END[0]) + TEST_FILE_END[0].length,
+ -TEST_FILE_END[1].length
+ );
+ return { ranges: ranges as RawTestRange[], hash };
+ }
+
+ /**
+ * Returns a string for a test.jsx file
+ */
+ export function toTestFile(origin: string, content: string, ranges: RawTestRange[]) {
+ const raw = JSON.stringify(ranges);
+ if (raw.includes(TEST_FILE_START[1]))
+ throw new Error(`Tested range cannot include "${TEST_FILE_START[1]}"`);
+ let header = TEST_FILE_START[0] + raw + TEST_FILE_START[1];
+ if (ranges.length && /^\s*{\/\*\*/.test(content)) {
+ const width = content.indexOf('{');
+ content = content.slice(Math.min(width, header.length));
+ }
+
+ return header + content + TEST_FILE_END[0] + hash(origin) + TEST_FILE_END[1];
+ }
+
+ export function fromEditFile(file: string) {
+ const start = file.lastIndexOf(EDIT_FILE_START);
+ const end = file.lastIndexOf(EDIT_FILE_END[0]);
+ if (start > 0) throw new Error('Test Edit file invalid start');
+ if (end === -1) throw new Error('Test Edit file is missing its content-hash');
+ return {
+ content: file.slice(start === -1 ? 0 : EDIT_FILE_START.length, end),
+ hash: file.slice(end + EDIT_FILE_END[0].length, file.indexOf(EDIT_FILE_END[1], end))
+ };
+ }
+
+ export function toEditFile(content: string) {
+ return EDIT_FILE_START + content + EDIT_FILE_END[0] + hash(content) + EDIT_FILE_END[1];
+ }
}
namespace print {
- /**
- * Return string for mappings.jsx
- */
- export function mappings({ generated }: ParsedSource): string {
- return compose_file(function* (composer) {
- for (const line of generated.lines) {
- if (
- line.index < generated.firstMapped ||
- line.index > generated.lastMapped ||
- line.isExact()
- ) {
- yield line;
- } else {
- yield composer.rule('', '-');
- yield line;
- yield composer.comment(comment_for(line), { indent: 0 });
- yield composer.rule('', '-');
- }
- }
- });
-
- function* comment_for(line: GeneratedLine) {
- const text_generated = line.print();
- for (const { ogLine, text: text_og_subset, index } of line.subsets()) {
- const mapping_rel_generated = line.getGeneratedMappingResult(ogLine);
- const mapping_rel_original = line.getOriginalMappingResult(ogLine);
- const mapping_unordered = line.getOrderBreaking(ogLine);
- const text_original = ogLine.print();
- const show_gen_mapping =
- mapping_rel_generated !== text_generated &&
- mapping_rel_generated !== text_og_subset &&
- mapping_rel_generated !== mapping_rel_original;
-
- let rest = '';
- const others = line.source.for(ogLine).filter((l) => l !== line);
- if (others.length !== 0) {
- const lines = others.map((line) => line.index + 1).join(', ');
- rest = `(rest generated at line${others.length === 1 ? '' : 's'} ${lines})`;
- }
- const offset = line.toString().match(/^\t*/)[0].length * 3;
-
- // prettier-ignore
- yield* [
+ /**
+ * Return string for mappings.jsx
+ */
+ export function mappings({ generated }: ParsedSource): string {
+ return compose_file(function* (composer) {
+ for (const line of generated.lines) {
+ if (
+ line.index < generated.firstMapped ||
+ line.index > generated.lastMapped ||
+ line.isExact()
+ ) {
+ yield line;
+ } else {
+ yield composer.rule('', '-');
+ yield line;
+ yield composer.comment(comment_for(line), { indent: 0 });
+ yield composer.rule('', '-');
+ }
+ }
+ });
+
+ function* comment_for(line: GeneratedLine) {
+ const text_generated = line.print();
+ for (const { ogLine, text: text_og_subset, index } of line.subsets()) {
+ const mapping_rel_generated = line.getGeneratedMappingResult(ogLine);
+ const mapping_rel_original = line.getOriginalMappingResult(ogLine);
+ const mapping_unordered = line.getOrderBreaking(ogLine);
+ const text_original = ogLine.print();
+ const show_gen_mapping =
+ mapping_rel_generated !== text_generated &&
+ mapping_rel_generated !== text_og_subset &&
+ mapping_rel_generated !== mapping_rel_original;
+
+ let rest = '';
+ const others = line.source.for(ogLine).filter((l) => l !== line);
+ if (others.length !== 0) {
+ const lines = others.map((line) => line.index + 1).join(', ');
+ rest = `(rest generated at line${others.length === 1 ? '' : 's'} ${lines})`;
+ }
+ const offset = line.toString().match(/^\t*/)[0].length * 3;
+
+ // prettier-ignore
+ yield* [
index !== 0 && [``, `` ],
index === 0 && !line.hasStartOrigin && [line.getUnmappedStart(), `Originless mappings` ],
true && [text_generated, `[generated] line ${line.index + 1}` ],
@@ -161,357 +161,357 @@ namespace print {
mapping_rel_original !== text_original && [mapping_rel_original, `` ],
true && [text_original, `[original] line ${ogLine.index + 1} ${rest}` ]
].filter(Boolean).map(([map,comment])=>[" ".repeat(offset)+map,comment]) as [string, string][];
- }
- }
- }
-
- /**
- * Print string for test.jsx
- */
- export function test(test_ranges: RawTestRange[], source: ParsedSource): string {
- return raw.toTestFile(
- source.original.text,
- compose_file(compose_test, { match_first_column_width: true }),
- test_ranges
- );
-
- function* compose_test(composer: ComposeHelper) {
- const ranges = test_ranges.map((range) => tryEvalTestRange(range, source).range);
- for (let i = 0; i < ranges.length; i++) {
- yield composer.rule('', '-');
- if (is_same_line(ranges[i].start, ranges[i].end)) {
- const j = i;
- // print ranges that map from same gen line to same og line together
- while (i < ranges.length - 1 && can_merge(ranges[i], ranges[i + 1])) i++;
- const target = ranges.slice(j, i + 1);
- const is_single = j === i;
- for (const key of MappedKeys) {
- const { line } = target[0].start[key];
- if (!line) continue;
- yield line;
- yield composer.comment([
- reduce_segments(
- target.map((range) => range_for(key, range)),
- (range, i) =>
- underline(
- tab_aware_index(line.toString(), range.start.character),
- tab_aware_index(line.toString(), range.end.character),
- (is_single ? '#' : i + 1) + '=='
- )
- ).padEnd(line.length + get_extra_indent(line.toString()) - 3),
- `[${key}] line ${line.index + 1}${
- key === 'generated' && !target[0].start.original.line
- ? ' => No Mappings !'
- : ''
- }`
- ]);
- }
- } else {
- for (const key of MappedKeys) {
- const p0 = ranges[i].start[key];
- const p1 = ranges[i].end[key];
-
- const lines = source[key].lines.slice(p0.line.index, p1.line.index + 1);
-
- yield* lines;
- const length = p1.line.start - p0.line.start + p1.character;
- const full_underline = underline(p0.character, length, '#=#').toString();
-
- yield composer.comment(
- (function* (): Generator<[string, string]> {
- let off = 0;
- const r = lines.map((line: Line) => ({
- start: { line, character: 0 },
- end: { line, character: line.length - 1 }
- }));
- const l = r.length - 1;
- r[0].start.character = p0.character;
- r[l].end.character = p1.character;
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- yield [
- ' '.repeat(off) + line.print(),
- `[${key}] line ${line.index + 1}`
- ];
- yield [full_underline.slice(off, off + line.length), ''];
- off += line.length;
- }
- })(),
- { indent: 2 }
- );
- }
- }
-
- yield composer.rule('---');
- }
- }
-
- function can_merge(r1: MappedRange, r2: MappedRange) {
- return (
- is_same_line(r1.start, r2.end) &&
- r2.start.generated.character > r1.end.generated.character &&
- r2.start.original.character > r1.end.original.character
- );
- }
-
- function is_same_line(p1: MappedPosition, p2: MappedPosition) {
- return p1.generated.line === p2.generated.line && p1.original.line === p2.original.line;
- }
- }
-
- /**
- * Print string for test.edit.jsx
- */
- export function test_edit(parsed_tests: SourceMappingTest[], source: ParsedSource) {
- return raw.toEditFile(
- insert_segments(
- source.generated.text,
- (function* () {
- for (const test of parsed_tests) {
- const { start, end } = range_for('generated', test.range);
- yield { start: fromLineCharToOffset(start), text: '[[[' };
- yield { start: fromLineCharToOffset(end) + 1, text: ']]]' };
- }
- })()
- )
- );
- }
+ }
+ }
+ }
+
+ /**
+ * Print string for test.jsx
+ */
+ export function test(test_ranges: RawTestRange[], source: ParsedSource): string {
+ return raw.toTestFile(
+ source.original.text,
+ compose_file(compose_test, { match_first_column_width: true }),
+ test_ranges
+ );
+
+ function* compose_test(composer: ComposeHelper) {
+ const ranges = test_ranges.map((range) => tryEvalTestRange(range, source).range);
+ for (let i = 0; i < ranges.length; i++) {
+ yield composer.rule('', '-');
+ if (is_same_line(ranges[i].start, ranges[i].end)) {
+ const j = i;
+ // print ranges that map from same gen line to same og line together
+ while (i < ranges.length - 1 && can_merge(ranges[i], ranges[i + 1])) i++;
+ const target = ranges.slice(j, i + 1);
+ const is_single = j === i;
+ for (const key of MappedKeys) {
+ const { line } = target[0].start[key];
+ if (!line) continue;
+ yield line;
+ yield composer.comment([
+ reduce_segments(
+ target.map((range) => range_for(key, range)),
+ (range, i) =>
+ underline(
+ tab_aware_index(line.toString(), range.start.character),
+ tab_aware_index(line.toString(), range.end.character),
+ (is_single ? '#' : i + 1) + '=='
+ )
+ ).padEnd(line.length + get_extra_indent(line.toString()) - 3),
+ `[${key}] line ${line.index + 1}${
+ key === 'generated' && !target[0].start.original.line
+ ? ' => No Mappings !'
+ : ''
+ }`
+ ]);
+ }
+ } else {
+ for (const key of MappedKeys) {
+ const p0 = ranges[i].start[key];
+ const p1 = ranges[i].end[key];
+
+ const lines = source[key].lines.slice(p0.line.index, p1.line.index + 1);
+
+ yield* lines;
+ const length = p1.line.start - p0.line.start + p1.character;
+ const full_underline = underline(p0.character, length, '#=#').toString();
+
+ yield composer.comment(
+ (function* (): Generator<[string, string]> {
+ let off = 0;
+ const r = lines.map((line: Line) => ({
+ start: { line, character: 0 },
+ end: { line, character: line.length - 1 }
+ }));
+ const l = r.length - 1;
+ r[0].start.character = p0.character;
+ r[l].end.character = p1.character;
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+ yield [
+ ' '.repeat(off) + line.print(),
+ `[${key}] line ${line.index + 1}`
+ ];
+ yield [full_underline.slice(off, off + line.length), ''];
+ off += line.length;
+ }
+ })(),
+ { indent: 2 }
+ );
+ }
+ }
+
+ yield composer.rule('---');
+ }
+ }
+
+ function can_merge(r1: MappedRange, r2: MappedRange) {
+ return (
+ is_same_line(r1.start, r2.end) &&
+ r2.start.generated.character > r1.end.generated.character &&
+ r2.start.original.character > r1.end.original.character
+ );
+ }
+
+ function is_same_line(p1: MappedPosition, p2: MappedPosition) {
+ return p1.generated.line === p2.generated.line && p1.original.line === p2.original.line;
+ }
+ }
+
+ /**
+ * Print string for test.edit.jsx
+ */
+ export function test_edit(parsed_tests: SourceMappingTest[], source: ParsedSource) {
+ return raw.toEditFile(
+ insert_segments(
+ source.generated.text,
+ (function* () {
+ for (const test of parsed_tests) {
+ const { start, end } = range_for('generated', test.range);
+ yield { start: fromLineCharToOffset(start), text: '[[[' };
+ yield { start: fromLineCharToOffset(end) + 1, text: ']]]' };
+ }
+ })()
+ )
+ );
+ }
}
function tryEvalTestRange(
- tested_range: RawTestRange,
- source: ParsedSource
+ tested_range: RawTestRange,
+ source: ParsedSource
): SourceMappingTest | null {
- const { generated, original } = source;
- const [ogStart, ogLength, genText] = tested_range;
- if (generated.text.includes(genText)) {
- const index = tryFindGenPosition(generated, genText, ogStart);
- const range = { start: generated.at(index), end: generated.at(index + genText.length - 1) };
- return {
- range,
- actual: range_for('original', range),
- expected: {
- start: original.toLineChar(ogStart),
- end: original.toLineChar(ogStart + ogLength - 1)
- }
- };
- }
+ const { generated, original } = source;
+ const [ogStart, ogLength, genText] = tested_range;
+ if (generated.text.includes(genText)) {
+ const index = tryFindGenPosition(generated, genText, ogStart);
+ const range = { start: generated.at(index), end: generated.at(index + genText.length - 1) };
+ return {
+ range,
+ actual: range_for('original', range),
+ expected: {
+ start: original.toLineChar(ogStart),
+ end: original.toLineChar(ogStart + ogLength - 1)
+ }
+ };
+ }
}
function tryFindGenPosition(
- generated: GeneratedSourceText,
- generated_subset: string,
- ogStart: number
+ generated: GeneratedSourceText,
+ generated_subset: string,
+ ogStart: number
) {
- const matches = generated.from(ogStart);
- const { generated: cue } = matches.length === 1 ? matches[0] : tryPickMatch(matches);
- const forward = generated.text.indexOf(generated_subset, fromLineCharToOffset(cue));
- const backward = generated.text.lastIndexOf(generated_subset, fromLineCharToOffset(cue));
- const target = forward === backward || forward === -1 ? backward : forward;
- return target;
-
- function tryPickMatch(matches: MappedPosition[]) {
- const exact = matches.filter((match) =>
- match.generated.line.source.text
- .slice(fromLineCharToOffset(match.generated))
- .startsWith(generated_subset)
- );
- if (exact.length === 1) return exact[0];
- const l = exact.length;
- const m = matches.length;
- const m_of_them = l === m ? 'all of them' : l === 0 ? 'none' : `${l} out of ${m}`;
- throw new Error(
- `Could not find TestRange: Generated text includes ` +
- `${m} characters mapping back to origin's ${toString(matches[0].original)} and ` +
- `${m_of_them} start with the tested text "${generated_subset}"` +
- `\n Matching : ${matches.map((match) => toString(match.generated)).join(',\n')}`
- );
- }
-
- function toString(pos: Position) {
- return `[${pos.line.index + 1}:${pos.character + 1}]`;
- }
+ const matches = generated.from(ogStart);
+ const { generated: cue } = matches.length === 1 ? matches[0] : tryPickMatch(matches);
+ const forward = generated.text.indexOf(generated_subset, fromLineCharToOffset(cue));
+ const backward = generated.text.lastIndexOf(generated_subset, fromLineCharToOffset(cue));
+ const target = forward === backward || forward === -1 ? backward : forward;
+ return target;
+
+ function tryPickMatch(matches: MappedPosition[]) {
+ const exact = matches.filter((match) =>
+ match.generated.line.source.text
+ .slice(fromLineCharToOffset(match.generated))
+ .startsWith(generated_subset)
+ );
+ if (exact.length === 1) return exact[0];
+ const l = exact.length;
+ const m = matches.length;
+ const m_of_them = l === m ? 'all of them' : l === 0 ? 'none' : `${l} out of ${m}`;
+ throw new Error(
+ `Could not find TestRange: Generated text includes ` +
+ `${m} characters mapping back to origin's ${toString(matches[0].original)} and ` +
+ `${m_of_them} start with the tested text "${generated_subset}"` +
+ `\n Matching : ${matches.map((match) => toString(match.generated)).join(',\n')}`
+ );
+ }
+
+ function toString(pos: Position) {
+ return `[${pos.line.index + 1}:${pos.character + 1}]`;
+ }
}
export function validate_edit_file(text_with_ranges: string) {
- for (const raw of parse_edit_ranges(text_with_ranges, false)) {
- if (raw.start === -1 || raw.end === -1) {
- const missing_start = raw.start === -1;
- const end = missing_start ? 'start' : 'end';
- const start = missing_start ? 'end' : 'start';
- const index = missing_start ? raw.end : raw.start;
- const { line, character } = new SourceText(text_with_ranges).toLineChar(index);
- throw new Error(
- `Line ${line.index + 1} ${start}s a range that has no corresponding ${end}\n\n` +
- `\t${line.print()}\n` +
- `\t${' '.repeat(character) + '^^^'}\n`
- );
- }
- }
+ for (const raw of parse_edit_ranges(text_with_ranges, false)) {
+ if (raw.start === -1 || raw.end === -1) {
+ const missing_start = raw.start === -1;
+ const end = missing_start ? 'start' : 'end';
+ const start = missing_start ? 'end' : 'start';
+ const index = missing_start ? raw.end : raw.start;
+ const { line, character } = new SourceText(text_with_ranges).toLineChar(index);
+ throw new Error(
+ `Line ${line.index + 1} ${start}s a range that has no corresponding ${end}\n\n` +
+ `\t${line.print()}\n` +
+ `\t${' '.repeat(character) + '^^^'}\n`
+ );
+ }
+ }
}
export function validate_test_file(test: string) {
- raw.fromTestFile(test);
+ raw.fromTestFile(test);
}
export function is_edit_changed(edit_file: string) {
- try {
- const { content, hash: prev } = raw.fromEditFile(edit_file);
- return hash(content) !== prev;
- } catch {
- return true;
- }
+ try {
+ const { content, hash: prev } = raw.fromEditFile(edit_file);
+ return hash(content) !== prev;
+ } catch {
+ return true;
+ }
}
export function is_test_from_same_input(test: string, input: string) {
- return hash(input) === raw.fromTestFile(test).hash;
+ return hash(input) === raw.fromTestFile(test).hash;
}
export function is_test_empty(test: string) {
- return raw.fromTestFile(test).ranges.length === 0;
+ return raw.fromTestFile(test).ranges.length === 0;
}
export function is_edit_from_same_generated(test_edit: string, generated: string) {
- return raw.fromEditFile(test_edit).content.replace(/\[\[\[|\]\]\]/g, '') === generated;
+ return raw.fromEditFile(test_edit).content.replace(/\[\[\[|\]\]\]/g, '') === generated;
}
export function is_edit_empty(test_edit: string) {
- return !/\[\[\[[^\]]*\]\]\]/.test(raw.fromEditFile(test_edit).content);
+ return !/\[\[\[[^\]]*\]\]\]/.test(raw.fromEditFile(test_edit).content);
}
export function process_transformed_text(
- original_text: string,
- generated_text: string,
- mappings: Mappings
+ original_text: string,
+ generated_text: string,
+ mappings: Mappings
) {
- const source = parse(original_text, generated_text, mappings);
- return {
- print_mappings: () => print.mappings(source),
-
- generate_test_edit(test_file: string = '') {
- return print.test_edit(parse_test_file(test_file, source), source);
- },
-
- generate_test(test_edit_file: string = '') {
- if (test_edit_file) validate_edit_file(test_edit_file);
- return print.test(parse_edit_file(test_edit_file, source), source);
- },
-
- each_test_range(
- test_file: string,
- assertStrictEqual: (actual: string, expected: string) => void,
- invalid_file: () => void,
- invalid_range: (arr: RawTestRange[]) => void
- ) {
- const tested_ranges = parse_test_file(test_file, source, invalid_file, invalid_range);
- for (const { actual, expected, range } of tested_ranges) {
- const { start, end } = range_for('generated', range);
- let gen = '';
- if (start.line === end.line) {
- gen += start.line.print() + '\n';
- gen += underline(start.character, end.character);
- } else {
- gen +=
- source.generated.print_slice(
- start.line.start,
- end.line.start + end.line.length
- ) + '\n';
- gen += underline(start.character, end.line.start + end.character);
- }
- const og = source.original.print_slice(
- Math.min(actual.start.line.start, expected.start.line.start),
- Math.max(actual.end.line.end + 1, expected.start.line.end + 1)
- );
- assertStrictEqual(
- gen + '\n' + og + '\n' + underline_offset(actual, expected),
- gen + '\n' + og + '\n' + underline_offset(expected, actual)
- );
- }
- }
- };
-
- function underline_offset(r1: Range, r2: Range) {
- return underline(
- r1.start.character + (r1.start.line.start - r2.start.line.start),
- r1.end.character + (r1.end.line.start - r2.end.line.start),
- '#=='
- );
- }
+ const source = parse(original_text, generated_text, mappings);
+ return {
+ print_mappings: () => print.mappings(source),
+
+ generate_test_edit(test_file: string = '') {
+ return print.test_edit(parse_test_file(test_file, source), source);
+ },
+
+ generate_test(test_edit_file: string = '') {
+ if (test_edit_file) validate_edit_file(test_edit_file);
+ return print.test(parse_edit_file(test_edit_file, source), source);
+ },
+
+ each_test_range(
+ test_file: string,
+ assertStrictEqual: (actual: string, expected: string) => void,
+ invalid_file: () => void,
+ invalid_range: (arr: RawTestRange[]) => void
+ ) {
+ const tested_ranges = parse_test_file(test_file, source, invalid_file, invalid_range);
+ for (const { actual, expected, range } of tested_ranges) {
+ const { start, end } = range_for('generated', range);
+ let gen = '';
+ if (start.line === end.line) {
+ gen += start.line.print() + '\n';
+ gen += underline(start.character, end.character);
+ } else {
+ gen +=
+ source.generated.print_slice(
+ start.line.start,
+ end.line.start + end.line.length
+ ) + '\n';
+ gen += underline(start.character, end.line.start + end.character);
+ }
+ const og = source.original.print_slice(
+ Math.min(actual.start.line.start, expected.start.line.start),
+ Math.max(actual.end.line.end + 1, expected.start.line.end + 1)
+ );
+ assertStrictEqual(
+ gen + '\n' + og + '\n' + underline_offset(actual, expected),
+ gen + '\n' + og + '\n' + underline_offset(expected, actual)
+ );
+ }
+ }
+ };
+
+ function underline_offset(r1: Range, r2: Range) {
+ return underline(
+ r1.start.character + (r1.start.line.start - r2.start.line.start),
+ r1.end.character + (r1.end.line.start - r2.end.line.start),
+ '#=='
+ );
+ }
}
function parse_test_file(
- test_file: string,
- source: ParsedSource,
- on_invalid_file?: () => void,
- on_invalid_range?: (ranges: RawTestRange[]) => void
+ test_file: string,
+ source: ParsedSource,
+ on_invalid_file?: () => void,
+ on_invalid_range?: (ranges: RawTestRange[]) => void
) {
- const parsed: SourceMappingTest[] = [];
- const invalid: RawTestRange[] = [];
- const test_ranges = (function () {
- try {
- return raw.fromTestFile(test_file).ranges;
- } catch {
- return on_invalid_file?.(), [];
- }
- })();
- for (const test_range of test_ranges) {
- const range = tryEvalTestRange(test_range, source);
- if (range) parsed.push(range);
- else invalid.push(test_range);
- }
- if (invalid.length) on_invalid_range?.(invalid);
- return parsed;
+ const parsed: SourceMappingTest[] = [];
+ const invalid: RawTestRange[] = [];
+ const test_ranges = (function () {
+ try {
+ return raw.fromTestFile(test_file).ranges;
+ } catch {
+ return on_invalid_file?.(), [];
+ }
+ })();
+ for (const test_range of test_ranges) {
+ const range = tryEvalTestRange(test_range, source);
+ if (range) parsed.push(range);
+ else invalid.push(test_range);
+ }
+ if (invalid.length) on_invalid_range?.(invalid);
+ return parsed;
}
function parse_edit_file(edit_file: string, { generated }: ParsedSource) {
- if (!edit_file) return [];
- return parse_edit_ranges(edit_file, true).map(function (raw) {
- const range = { start: generated.at(raw.start), end: generated.at(raw.end) };
- const original = range_for('original', range);
- const { start, end } = range_for('generated', range);
- const text = generated.text.slice(
- fromLineCharToOffset(start),
- fromLineCharToOffset(end) + 1
- );
-
- if (
- !original.start.line ||
- !original.end.line ||
- (original.start.line === original.end.line &&
- original.start.character === original.end.character &&
- !start.line.hasExactMappingFor(start.character))
- ) {
- throw new Error(
- `Failed to generate mapping test, selected range has no mappings.\n\n` +
- debug_print(start, end)
- );
- }
-
- const ogStart = fromLineCharToOffset(original.start);
- const ogLength = fromLineCharToOffset(original.end) - ogStart + 1;
- return [ogStart, ogLength, text];
- });
+ if (!edit_file) return [];
+ return parse_edit_ranges(edit_file, true).map(function (raw) {
+ const range = { start: generated.at(raw.start), end: generated.at(raw.end) };
+ const original = range_for('original', range);
+ const { start, end } = range_for('generated', range);
+ const text = generated.text.slice(
+ fromLineCharToOffset(start),
+ fromLineCharToOffset(end) + 1
+ );
+
+ if (
+ !original.start.line ||
+ !original.end.line ||
+ (original.start.line === original.end.line &&
+ original.start.character === original.end.character &&
+ !start.line.hasExactMappingFor(start.character))
+ ) {
+ throw new Error(
+ `Failed to generate mapping test, selected range has no mappings.\n\n` +
+ debug_print(start, end)
+ );
+ }
+
+ const ogStart = fromLineCharToOffset(original.start);
+ const ogLength = fromLineCharToOffset(original.end) - ogStart + 1;
+ return [ogStart, ogLength, text];
+ });
}
function parse_edit_ranges(text_with_ranges: string, index_relative: boolean) {
- const ranges: { start: number; end: number }[] = [];
- const pending: { start: number; end: number }[] = [];
- const { content } = raw.fromEditFile(text_with_ranges);
- let offset = 0;
- for (const { match, index } of each_exec(content, /\[\[\[|\]\]\]/g)) {
- if (match === '[[[') {
- const range = { start: index - offset, end: -1 };
- pending.push(range);
- ranges.push(range);
- } else {
- if (pending.length === 0) {
- const range = { start: -1, end: -1 }; // error for later
- ranges.push(range);
- pending.push(range);
- }
- pending.pop().end = index - offset - 1;
- }
- if (index_relative) offset += 3;
- }
- return ranges;
+ const ranges: { start: number; end: number }[] = [];
+ const pending: { start: number; end: number }[] = [];
+ const { content } = raw.fromEditFile(text_with_ranges);
+ let offset = 0;
+ for (const { match, index } of each_exec(content, /\[\[\[|\]\]\]/g)) {
+ if (match === '[[[') {
+ const range = { start: index - offset, end: -1 };
+ pending.push(range);
+ ranges.push(range);
+ } else {
+ if (pending.length === 0) {
+ const range = { start: -1, end: -1 }; // error for later
+ ranges.push(range);
+ pending.push(range);
+ }
+ pending.pop().end = index - offset - 1;
+ }
+ if (index_relative) offset += 3;
+ }
+ return ranges;
}
diff --git a/packages/svelte2tsx/test/svelte2tsx/index.ts b/packages/svelte2tsx/test/svelte2tsx/index.ts
index 8a3252b32..4c54f3a33 100644
--- a/packages/svelte2tsx/test/svelte2tsx/index.ts
+++ b/packages/svelte2tsx/test/svelte2tsx/index.ts
@@ -2,11 +2,11 @@ import { svelte2tsx } from '../build';
import { get_svelte2tsx_config, test_samples } from '../helpers';
describe('svelte2tsx', () => {
- test_samples(
- __dirname,
- (input, config) => {
- return svelte2tsx(input, get_svelte2tsx_config(config, config.sampleName));
- },
- 'tsx'
- );
+ test_samples(
+ __dirname,
+ (input, config) => {
+ return svelte2tsx(input, get_svelte2tsx_config(config, config.sampleName));
+ },
+ 'tsx'
+ );
});
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-constant/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-constant/expected.js
index fe421a93c..42f1dd373 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-constant/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-constant/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'a', type: 'boolean', doc: '\nSome doc\n' },
- { name: 'b', type: 'string', doc: undefined },
- { name: 'c', type: 'Event', doc: undefined }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'a', type: 'boolean', doc: '\nSome doc\n' },
+ { name: 'b', type: 'string', doc: undefined },
+ { name: 'c', type: 'Event', doc: undefined }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-string-literals/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-string-literals/expected.js
index 4a3b0487e..cf4ce6859 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-string-literals/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface-string-literals/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'a-b', type: 'boolean', doc: '\nSome doc\n' },
- { name: 'b', type: 'string', doc: undefined },
- { name: 'c', type: 'Event', doc: undefined }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'a-b', type: 'boolean', doc: '\nSome doc\n' },
+ { name: 'b', type: 'string', doc: undefined },
+ { name: 'c', type: 'Event', doc: undefined }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface/expected.js
index ebece35b0..b45e5d91e 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/component-events-interface/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'a', type: 'boolean', doc: '\nSome *doc*\n' },
- { name: 'b', type: 'string', doc: undefined },
- { name: 'c', type: 'Event', doc: undefined }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'a', type: 'boolean', doc: '\nSome *doc*\n' },
+ { name: 'b', type: 'string', doc: undefined },
+ { name: 'c', type: 'Event', doc: undefined }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/editing-mustache/expected.error.json b/packages/svelte2tsx/test/svelte2tsx/samples/editing-mustache/expected.error.json
index 95cf71155..da48446f4 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/editing-mustache/expected.error.json
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/editing-mustache/expected.error.json
@@ -1,16 +1,16 @@
{
- "name": "ParseError",
- "code": "parse-error",
- "start": {
- "line": 1,
- "column": 4,
- "character": 4
- },
- "end": {
- "line": 1,
- "column": 4,
- "character": 4
- },
- "pos": 4,
- "frame": "1: {a?.}\n ^"
+ "name": "ParseError",
+ "code": "parse-error",
+ "start": {
+ "line": 1,
+ "column": 4,
+ "character": 4
+ },
+ "end": {
+ "line": 1,
+ "column": 4,
+ "character": 4
+ },
+ "pos": 4,
+ "frame": "1: {a?.}\n ^"
}
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events-alias/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events-alias/expected.js
index 997b066d3..392da7b1f 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events-alias/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events-alias/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'btn', type: 'CustomEvent' },
- { name: 'hi', type: 'CustomEvent' },
- { name: 'bye', type: 'CustomEvent' }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'btn', type: 'CustomEvent' },
+ { name: 'hi', type: 'CustomEvent' },
+ { name: 'bye', type: 'CustomEvent' }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events/expected.js
index 997b066d3..392da7b1f 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatcher-events/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'btn', type: 'CustomEvent' },
- { name: 'hi', type: 'CustomEvent' },
- { name: 'bye', type: 'CustomEvent' }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'btn', type: 'CustomEvent' },
+ { name: 'hi', type: 'CustomEvent' },
+ { name: 'bye', type: 'CustomEvent' }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatchers/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatchers/expected.js
index ef47078ef..e1efb759c 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatchers/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/event-dispatchers/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'click', type: 'Event' },
- { name: 'hi', type: 'CustomEvent' },
- { name: 'bye', type: 'CustomEvent' }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'click', type: 'Event' },
+ { name: 'hi', type: 'CustomEvent' },
+ { name: 'bye', type: 'CustomEvent' }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatcher-typed/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatcher-typed/expected.js
index ae849edbc..a69a81c1b 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatcher-typed/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatcher-typed/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'hi', type: 'CustomEvent', doc: '\nA DOC\n' },
- { name: 'bye', type: 'CustomEvent', doc: '\nANOTHER DOC\n' },
- { name: 'btn', type: 'CustomEvent', doc: undefined }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'hi', type: 'CustomEvent', doc: '\nA DOC\n' },
+ { name: 'bye', type: 'CustomEvent', doc: '\nANOTHER DOC\n' },
+ { name: 'btn', type: 'CustomEvent', doc: undefined }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers-same-event/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers-same-event/expected.js
index ef47078ef..e1efb759c 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers-same-event/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers-same-event/expected.js
@@ -1,9 +1,9 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'click', type: 'Event' },
- { name: 'hi', type: 'CustomEvent' },
- { name: 'bye', type: 'CustomEvent' }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'click', type: 'Event' },
+ { name: 'hi', type: 'CustomEvent' },
+ { name: 'bye', type: 'CustomEvent' }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers/expected.js b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers/expected.js
index d8d4451bb..e292dce86 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers/expected.js
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-event-dispatchers/expected.js
@@ -1,10 +1,10 @@
let assert = require('assert');
module.exports = function ({ events }) {
- assert.deepEqual(events.getAll(), [
- { name: 'click', type: 'Event' },
- { name: 'hi', type: 'CustomEvent', doc: '\nA DOC\n' },
- { name: 'btn', type: 'CustomEvent', doc: undefined },
- { name: 'bye', type: 'CustomEvent' }
- ]);
+ assert.deepEqual(events.getAll(), [
+ { name: 'click', type: 'Event' },
+ { name: 'hi', type: 'CustomEvent', doc: '\nA DOC\n' },
+ { name: 'btn', type: 'CustomEvent', doc: undefined },
+ { name: 'bye', type: 'CustomEvent' }
+ ]);
};
diff --git a/packages/svelte2tsx/test/svelte2tsx/tsconfig.json b/packages/svelte2tsx/test/svelte2tsx/tsconfig.json
index e3011b9b9..da455eb67 100644
--- a/packages/svelte2tsx/test/svelte2tsx/tsconfig.json
+++ b/packages/svelte2tsx/test/svelte2tsx/tsconfig.json
@@ -1,16 +1,16 @@
{
- "compilerOptions": {
- "module": "ES6",
- "noImplicitAny": true,
- "noImplicitThis": true,
- "noImplicitReturns": true,
- "sourceMap": true,
- "noEmit": true,
- "allowJs": true,
- "jsxFactory": "h",
- "jsx": "preserve"
- },
- "files": ["../../svelte-shims.d.ts", "../../svelte-jsx.d.ts"],
- "include": ["/samples/**/*.tsx", "../../*.d.ts"],
- "exclude": ["node_modules"]
+ "compilerOptions": {
+ "module": "ES6",
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "noImplicitReturns": true,
+ "sourceMap": true,
+ "noEmit": true,
+ "allowJs": true,
+ "jsxFactory": "h",
+ "jsx": "preserve"
+ },
+ "files": ["../../svelte-shims.d.ts", "../../svelte-jsx.d.ts"],
+ "include": ["/samples/**/*.tsx", "../../*.d.ts"],
+ "exclude": ["node_modules"]
}
diff --git a/packages/svelte2tsx/test/test.ts b/packages/svelte2tsx/test/test.ts
index df10cacbf..3fc2b18a4 100644
--- a/packages/svelte2tsx/test/test.ts
+++ b/packages/svelte2tsx/test/test.ts
@@ -1,6 +1,6 @@
require('ts-node').register({
- project: 'test/tsconfig.json',
- transpileOnly: true
+ project: 'test/tsconfig.json',
+ transpileOnly: true
});
require('source-map-support').install();
const glob = require('tiny-glob/sync');
@@ -8,15 +8,15 @@ const glob = require('tiny-glob/sync');
//console.clear();
if (process.env.CI) {
- const arr = glob('**/*.solo', { cwd: 'test' });
- if (arr.length) throw new Error(`Forgot to remove ".solo" from test(s) ${arr}`);
+ const arr = glob('**/*.solo', { cwd: 'test' });
+ if (arr.length) throw new Error(`Forgot to remove ".solo" from test(s) ${arr}`);
}
const test_folders = glob('*/index.ts', { cwd: 'test' });
const solo_folders = test_folders.filter((folder) => /\.solo$/.test(folder));
if (solo_folders.length) {
- solo_folders.forEach((name) => require('./' + name));
+ solo_folders.forEach((name) => require('./' + name));
} else {
- test_folders.forEach((name) => require('./' + name));
+ test_folders.forEach((name) => require('./' + name));
}
diff --git a/packages/svelte2tsx/test/tsconfig.json b/packages/svelte2tsx/test/tsconfig.json
index 1d4d62082..ec5f7fc35 100644
--- a/packages/svelte2tsx/test/tsconfig.json
+++ b/packages/svelte2tsx/test/tsconfig.json
@@ -1,11 +1,11 @@
{
- "compilerOptions": {
- "types": ["@types/node", "@types/mocha"],
- "target": "es6",
- "module": "commonjs",
- "moduleResolution": "node",
- "esModuleInterop": true
- },
- "exclude": ["samples/**"],
- "include": ["*.ts"]
+ "compilerOptions": {
+ "types": ["@types/node", "@types/mocha"],
+ "target": "es6",
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "esModuleInterop": true
+ },
+ "exclude": ["samples/**"],
+ "include": ["*.ts"]
}
diff --git a/packages/svelte2tsx/tsconfig.json b/packages/svelte2tsx/tsconfig.json
index c0cf75bcd..b01fd6175 100644
--- a/packages/svelte2tsx/tsconfig.json
+++ b/packages/svelte2tsx/tsconfig.json
@@ -1,27 +1,27 @@
{
- "compilerOptions": {
- "target": "es2018",
- "lib": ["ES2018"],
- "rootDir": "src",
+ "compilerOptions": {
+ "target": "es2018",
+ "lib": ["ES2018"],
+ "rootDir": "src",
- "sourceMap": true,
+ "sourceMap": true,
- "noEmitOnError": true,
- "noErrorTruncation": true,
+ "noEmitOnError": true,
+ "noErrorTruncation": true,
- //let rollup handle these
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "allowSyntheticDefaultImports": true,
+ //let rollup handle these
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "allowSyntheticDefaultImports": true,
- "noImplicitThis": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true
- },
- "paths": {
- "@/*": ["src/*"]
- },
- // "include" is set in rollup.config(.test).js
- "exclude": ["node_modules", "repl"]
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true
+ },
+ "paths": {
+ "@/*": ["src/*"]
+ },
+ // "include" is set in rollup.config(.test).js
+ "exclude": ["node_modules", "repl"]
}
diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json
index 42bde7f25..0763edbeb 100644
--- a/packages/typescript-plugin/package.json
+++ b/packages/typescript-plugin/package.json
@@ -1,23 +1,23 @@
{
- "name": "typescript-svelte-plugin",
- "version": "0.1.0",
- "description": "A TypeScript Plugin providing Svelte intellisense",
- "main": "src/index.js",
- "scripts": {
- "build": "tsc -p ./",
- "test": "echo 'NOOP'"
- },
- "keywords": [
- "svelte",
- "typescript",
- "javascript",
- "plugin"
- ],
- "author": "The Svelte Community",
- "license": "MIT",
- "devDependencies": {
- "@tsconfig/node12": "^1.0.0",
- "@types/node": "^13.9.0",
- "typescript": "*"
- }
+ "name": "typescript-svelte-plugin",
+ "version": "0.1.0",
+ "description": "A TypeScript Plugin providing Svelte intellisense",
+ "main": "src/index.js",
+ "scripts": {
+ "build": "tsc -p ./",
+ "test": "echo 'NOOP'"
+ },
+ "keywords": [
+ "svelte",
+ "typescript",
+ "javascript",
+ "plugin"
+ ],
+ "author": "The Svelte Community",
+ "license": "MIT",
+ "devDependencies": {
+ "@tsconfig/node12": "^1.0.0",
+ "@types/node": "^13.9.0",
+ "typescript": "*"
+ }
}
diff --git a/packages/typescript-plugin/src/index.ts b/packages/typescript-plugin/src/index.ts
index 98c183a61..54d2a0dd0 100644
--- a/packages/typescript-plugin/src/index.ts
+++ b/packages/typescript-plugin/src/index.ts
@@ -1,13 +1,13 @@
function init(modules: { typescript: typeof import('typescript/lib/tsserverlibrary') }) {
- function create(info: ts.server.PluginCreateInfo) {
- // TODO
- }
+ function create(info: ts.server.PluginCreateInfo) {
+ // TODO
+ }
- function getExternalFiles(project: ts.server.ConfiguredProject) {
- // TODO
- }
+ function getExternalFiles(project: ts.server.ConfiguredProject) {
+ // TODO
+ }
- return { create, getExternalFiles };
+ return { create, getExternalFiles };
}
export = init;
diff --git a/packages/typescript-plugin/tsconfig.json b/packages/typescript-plugin/tsconfig.json
index 651378bd6..ff09ccc23 100644
--- a/packages/typescript-plugin/tsconfig.json
+++ b/packages/typescript-plugin/tsconfig.json
@@ -1,14 +1,14 @@
{
- "extends": "@tsconfig/node12/tsconfig.json",
- "compilerOptions": {
- "moduleResolution": "node",
- "esModuleInterop": true,
- "strict": true,
- "declaration": true,
- "outDir": ".",
- "sourceMap": false,
- "composite": true
- },
- "include": ["./src/**/*"],
- "exclude": ["./node_modules"]
+ "extends": "@tsconfig/node12/tsconfig.json",
+ "compilerOptions": {
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "strict": true,
+ "declaration": true,
+ "outDir": ".",
+ "sourceMap": false,
+ "composite": true
+ },
+ "include": ["./src/**/*"],
+ "exclude": ["./node_modules"]
}
diff --git a/tsconfig.json b/tsconfig.json
index 5a99332ab..9911a26cc 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,9 +1,9 @@
{
- "references": [
- { "path": "./packages/language-server" },
- { "path": "./packages/svelte-vscode" }
- ],
- "files": [],
- "include": [],
- "exclude": ["**/node_modules"]
+ "references": [
+ { "path": "./packages/language-server" },
+ { "path": "./packages/svelte-vscode" }
+ ],
+ "files": [],
+ "include": [],
+ "exclude": ["**/node_modules"]
}