@astrojs/language-server 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DocumentSymbolsProviderImpl = void 0;
4
+ const typescript_1 = require("typescript");
5
+ const vscode_languageserver_types_1 = require("vscode-languageserver-types");
6
+ const documents_1 = require("../../../core/documents");
7
+ const utils_1 = require("../utils");
8
+ const vscode_languageserver_types_2 = require("vscode-languageserver-types");
9
+ class DocumentSymbolsProviderImpl {
10
+ constructor(languageServiceManager) {
11
+ this.languageServiceManager = languageServiceManager;
12
+ }
13
+ async getDocumentSymbols(document) {
14
+ var _a, _b, _c;
15
+ const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
16
+ const fragment = await tsDoc.createFragment();
17
+ const navTree = lang.getNavigationTree(tsDoc.filePath);
18
+ if (!navTree) {
19
+ return [];
20
+ }
21
+ const symbols = [];
22
+ this.collectSymbols(navTree, fragment, undefined, (symbol) => symbols.push(symbol));
23
+ const result = [];
24
+ // Add a "Frontmatter" namespace for the frontmatter if we have a closed one
25
+ if (document.astroMeta.frontmatter.state === 'closed') {
26
+ result.push(vscode_languageserver_types_1.SymbolInformation.create('Frontmatter', vscode_languageserver_types_1.SymbolKind.Namespace, vscode_languageserver_types_1.Range.create(document.positionAt(document.astroMeta.frontmatter.startOffset), document.positionAt(document.astroMeta.frontmatter.endOffset))));
27
+ }
28
+ // Add a "Template" namespace for everything under the frontmatter
29
+ result.push(vscode_languageserver_types_1.SymbolInformation.create('Template', vscode_languageserver_types_1.SymbolKind.Namespace, vscode_languageserver_types_1.Range.create(document.positionAt((_a = document.astroMeta.frontmatter.endOffset) !== null && _a !== void 0 ? _a : 0), document.positionAt(document.getTextLength()))));
30
+ for (let symbol of symbols.splice(1)) {
31
+ symbol = (0, documents_1.mapSymbolInformationToOriginal)(fragment, symbol);
32
+ if (document.offsetAt(symbol.location.range.end) >= ((_b = document.astroMeta.content.firstNonWhitespaceOffset) !== null && _b !== void 0 ? _b : 0)) {
33
+ symbol.containerName = 'Template';
34
+ // For some reason, it seems like TypeScript thinks that the "class" attribute is a real class, weird
35
+ if (symbol.kind === vscode_languageserver_types_1.SymbolKind.Class && symbol.name === '<class>') {
36
+ const node = document.html.findNodeAt(document.offsetAt(symbol.location.range.start));
37
+ if ((_c = node.attributes) === null || _c === void 0 ? void 0 : _c.class) {
38
+ continue;
39
+ }
40
+ }
41
+ }
42
+ // Remove the default function detected in our TSX output
43
+ if (symbol.kind === vscode_languageserver_types_1.SymbolKind.Function && symbol.name == 'default') {
44
+ continue;
45
+ }
46
+ result.push(symbol);
47
+ }
48
+ return result;
49
+ }
50
+ collectSymbols(item, fragment, container, cb) {
51
+ for (const span of item.spans) {
52
+ const symbol = vscode_languageserver_types_1.SymbolInformation.create(item.text, (0, utils_1.symbolKindFromString)(item.kind), vscode_languageserver_types_1.Range.create(fragment.positionAt(span.start), fragment.positionAt(span.start + span.length)), fragment.getURL(), container);
53
+ // TypeScript gives us kind modifiers as a string instead of an array
54
+ const kindModifiers = new Set(item.kindModifiers.split(/,|\s+/g));
55
+ if (kindModifiers.has(typescript_1.ScriptElementKindModifier.deprecatedModifier)) {
56
+ if (!symbol.tags)
57
+ symbol.tags = [];
58
+ symbol.tags.push(vscode_languageserver_types_2.SymbolTag.Deprecated);
59
+ }
60
+ cb(symbol);
61
+ }
62
+ if (item.childItems) {
63
+ for (const child of item.childItems) {
64
+ this.collectSymbols(child, fragment, item.text, cb);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ exports.DocumentSymbolsProviderImpl = DocumentSymbolsProviderImpl;
@@ -70,6 +70,14 @@ async function createLanguageService(tsconfigPath, docContext) {
70
70
  let projectVersion = 0;
71
71
  const snapshotManager = new SnapshotManager_1.SnapshotManager(docContext.globalSnapshotManager, files, fullConfig, workspaceRoot || process.cwd());
72
72
  const astroModuleLoader = (0, module_loader_1.createAstroModuleLoader)(getScriptSnapshot, compilerOptions);
73
+ let languageServerDirectory;
74
+ try {
75
+ languageServerDirectory = (0, path_1.dirname)(require.resolve('@astrojs/language-server'));
76
+ }
77
+ catch (e) {
78
+ languageServerDirectory = __dirname;
79
+ }
80
+ const astroTSXFile = typescript_1.default.sys.resolvePath((0, path_1.resolve)(languageServerDirectory, '../types/astro-jsx.d.ts'));
73
81
  const host = {
74
82
  getNewLine: () => typescript_1.default.sys.newLine,
75
83
  useCaseSensitiveFileNames: () => typescript_1.default.sys.useCaseSensitiveFileNames,
@@ -82,7 +90,7 @@ async function createLanguageService(tsconfigPath, docContext) {
82
90
  getCurrentDirectory: () => workspaceRoot,
83
91
  getDefaultLibFileName: typescript_1.default.getDefaultLibFilePath,
84
92
  getProjectVersion: () => projectVersion.toString(),
85
- getScriptFileNames: () => Array.from(new Set([...snapshotManager.getProjectFileNames(), ...snapshotManager.getFileNames()])),
93
+ getScriptFileNames: () => Array.from(new Set([...snapshotManager.getProjectFileNames(), ...snapshotManager.getFileNames(), astroTSXFile])),
86
94
  getScriptSnapshot,
87
95
  getScriptVersion: (fileName) => getScriptSnapshot(fileName).version.toString(),
88
96
  };
@@ -168,31 +176,26 @@ async function createLanguageService(tsconfigPath, docContext) {
168
176
  snapshotManager.updateNonAstroFile(fileName, changes);
169
177
  }
170
178
  function getParsedTSConfig() {
171
- var _a, _b, _c, _d;
179
+ var _a, _b, _c;
172
180
  let configJson = (tsconfigPath && typescript_1.default.readConfigFile(tsconfigPath, typescript_1.default.sys.readFile).config) || {};
173
181
  // If our user has types in their config but it doesn't include the types needed for Astro, add them to the config
174
182
  if (((_a = configJson.compilerOptions) === null || _a === void 0 ? void 0 : _a.types) && !((_b = configJson.compilerOptions) === null || _b === void 0 ? void 0 : _b.types.includes('astro/env'))) {
175
183
  configJson.compilerOptions.types.push('astro/env');
176
184
  }
177
185
  configJson.compilerOptions = Object.assign(getDefaultCompilerOptions(), configJson.compilerOptions);
178
- // If the user supplied exclude, let's use theirs
179
- (_c = configJson.exclude) !== null && _c !== void 0 ? _c : (configJson.exclude = getDefaultExclude());
180
186
  // Delete include so that .astro files don't get mistakenly excluded by the user
181
187
  delete configJson.include;
182
188
  // If the user supplied exclude, let's use theirs otherwise, use ours
183
- (_d = configJson.exclude) !== null && _d !== void 0 ? _d : (configJson.exclude = getDefaultExclude());
189
+ (_c = configJson.exclude) !== null && _c !== void 0 ? _c : (configJson.exclude = getDefaultExclude());
184
190
  // Everything here will always, unconditionally, be in the resulting config
185
191
  const forcedCompilerOptions = {
186
- // Our TSX is currently not typed, which unfortunately means that we can't support `noImplicitAny`
187
- noImplicitAny: false,
188
- // Most of the code people write in an .astro file is in the frontmatter which is executed server side
189
- // Thus, we don't want the DOM lib. We'll need to overwrite this for script tags however
190
- lib: ['ESNext'],
191
192
  noEmit: true,
192
193
  declaration: false,
193
194
  allowNonTsExtensions: true,
194
195
  allowJs: true,
195
196
  jsx: typescript_1.default.JsxEmit.Preserve,
197
+ jsxImportSource: undefined,
198
+ jsxFactory: 'astroHTML',
196
199
  module: typescript_1.default.ModuleKind.ESNext,
197
200
  target: typescript_1.default.ScriptTarget.ESNext,
198
201
  moduleResolution: typescript_1.default.ModuleResolutionKind.NodeJs,
@@ -77,7 +77,7 @@ function createFromFrameworkFilePath(filePath, framework) {
77
77
  code = (0, svelte_language_integration_1.toTSX)(originalText);
78
78
  }
79
79
  else {
80
- code = 'export default function() {}';
80
+ code = 'export default function(props: Record<string, any>): any {<div></div>}';
81
81
  }
82
82
  return new DocumentSnapshot_1.TypeScriptDocumentSnapshot(0, filePath, code, typescript_1.default.ScriptKind.TSX);
83
83
  }
@@ -1,6 +1,7 @@
1
1
  import ts from 'typescript';
2
- import { CompletionItemKind, DiagnosticSeverity, Position, Range } from 'vscode-languageserver';
2
+ import { CompletionItemKind, DiagnosticSeverity, Position, Range, SymbolKind } from 'vscode-languageserver';
3
3
  import { SnapshotFragment } from './snapshots/DocumentSnapshot';
4
+ export declare function symbolKindFromString(kind: string): SymbolKind;
4
5
  export declare function scriptElementKindToCompletionItemKind(kind: ts.ScriptElementKind): CompletionItemKind;
5
6
  export declare function getCommitCharactersForScriptElement(kind: ts.ScriptElementKind): string[] | undefined;
6
7
  export declare function getExtensionFromScriptKind(kind: ts.ScriptKind | undefined): ts.Extension;
@@ -3,12 +3,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ensureRealFilePath = exports.ensureRealAstroFilePath = exports.toRealAstroFilePath = exports.toVirtualFilePath = exports.toVirtualAstroFilePath = exports.isVirtualFilePath = exports.isVirtualSvelteFilePath = exports.isVirtualVueFilePath = exports.isVirtualAstroFilePath = exports.isFrameworkFilePath = exports.isAstroFilePath = exports.isVirtualFrameworkFilePath = exports.getFrameworkFromFilePath = exports.convertToLocationRange = exports.convertRange = exports.mapSeverity = exports.getScriptKindFromFileName = exports.isSubPath = exports.findTsConfigPath = exports.getExtensionFromScriptKind = exports.getCommitCharactersForScriptElement = exports.scriptElementKindToCompletionItemKind = void 0;
6
+ exports.ensureRealFilePath = exports.ensureRealAstroFilePath = exports.toRealAstroFilePath = exports.toVirtualFilePath = exports.toVirtualAstroFilePath = exports.isVirtualFilePath = exports.isVirtualSvelteFilePath = exports.isVirtualVueFilePath = exports.isVirtualAstroFilePath = exports.isFrameworkFilePath = exports.isAstroFilePath = exports.isVirtualFrameworkFilePath = exports.getFrameworkFromFilePath = exports.convertToLocationRange = exports.convertRange = exports.mapSeverity = exports.getScriptKindFromFileName = exports.isSubPath = exports.findTsConfigPath = exports.getExtensionFromScriptKind = exports.getCommitCharactersForScriptElement = exports.scriptElementKindToCompletionItemKind = exports.symbolKindFromString = void 0;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const path_1 = require("path");
9
9
  const utils_1 = require("../../utils");
10
10
  const vscode_languageserver_1 = require("vscode-languageserver");
11
11
  const documents_1 = require("../../core/documents");
12
+ function symbolKindFromString(kind) {
13
+ switch (kind) {
14
+ case 'module':
15
+ return vscode_languageserver_1.SymbolKind.Module;
16
+ case 'class':
17
+ return vscode_languageserver_1.SymbolKind.Class;
18
+ case 'local class':
19
+ return vscode_languageserver_1.SymbolKind.Class;
20
+ case 'interface':
21
+ return vscode_languageserver_1.SymbolKind.Interface;
22
+ case 'enum':
23
+ return vscode_languageserver_1.SymbolKind.Enum;
24
+ case 'enum member':
25
+ return vscode_languageserver_1.SymbolKind.Constant;
26
+ case 'var':
27
+ return vscode_languageserver_1.SymbolKind.Variable;
28
+ case 'local var':
29
+ return vscode_languageserver_1.SymbolKind.Variable;
30
+ case 'function':
31
+ return vscode_languageserver_1.SymbolKind.Function;
32
+ case 'local function':
33
+ return vscode_languageserver_1.SymbolKind.Function;
34
+ case 'method':
35
+ return vscode_languageserver_1.SymbolKind.Method;
36
+ case 'getter':
37
+ return vscode_languageserver_1.SymbolKind.Method;
38
+ case 'setter':
39
+ return vscode_languageserver_1.SymbolKind.Method;
40
+ case 'property':
41
+ return vscode_languageserver_1.SymbolKind.Property;
42
+ case 'constructor':
43
+ return vscode_languageserver_1.SymbolKind.Constructor;
44
+ case 'parameter':
45
+ return vscode_languageserver_1.SymbolKind.Variable;
46
+ case 'type parameter':
47
+ return vscode_languageserver_1.SymbolKind.Variable;
48
+ case 'alias':
49
+ return vscode_languageserver_1.SymbolKind.Variable;
50
+ case 'let':
51
+ return vscode_languageserver_1.SymbolKind.Variable;
52
+ case 'const':
53
+ return vscode_languageserver_1.SymbolKind.Constant;
54
+ case 'JSX attribute':
55
+ return vscode_languageserver_1.SymbolKind.Property;
56
+ default:
57
+ return vscode_languageserver_1.SymbolKind.Variable;
58
+ }
59
+ }
60
+ exports.symbolKindFromString = symbolKindFromString;
12
61
  function scriptElementKindToCompletionItemKind(kind) {
13
62
  switch (kind) {
14
63
  case typescript_1.default.ScriptElementKind.primitiveType:
package/dist/server.js CHANGED
@@ -94,7 +94,9 @@ function startLanguageServer(connection) {
94
94
  ':',
95
95
  ],
96
96
  },
97
+ colorProvider: true,
97
98
  hoverProvider: true,
99
+ documentSymbolProvider: true,
98
100
  signatureHelpProvider: {
99
101
  triggerCharacters: ['(', ',', '<'],
100
102
  retriggerCharacters: [')'],
@@ -143,6 +145,9 @@ function startLanguageServer(connection) {
143
145
  }
144
146
  return pluginHost.resolveCompletion(data, completionItem);
145
147
  });
148
+ connection.onDocumentSymbol((params, cancellationToken) => pluginHost.getDocumentSymbols(params.textDocument, cancellationToken));
149
+ connection.onDocumentColor((params) => pluginHost.getDocumentColors(params.textDocument));
150
+ connection.onColorPresentation((params) => pluginHost.getColorPresentations(params.textDocument, params.range, params.color));
146
151
  connection.onRequest(TagCloseRequest, (evt) => pluginHost.doTagComplete(evt.textDocument, evt.position));
147
152
  connection.onSignatureHelp((evt, cancellationToken) => pluginHost.getSignatureHelp(evt.textDocument, evt.position, evt.context, cancellationToken));
148
153
  connection.onRenameRequest((evt) => pluginHost.rename(evt.textDocument, evt.position, evt.newName));
package/dist/utils.d.ts CHANGED
@@ -17,17 +17,13 @@ export declare function pathToUrl(path: string): string;
17
17
  */
18
18
  export declare function getLastPartOfPath(path: string): string;
19
19
  /**
20
- *
21
- * The language service is case insensitive, and would provide
22
- * hover info for Svelte components like `Option` which have
23
- * the same name like a html tag.
20
+ * Return true if a specific node could be a component.
21
+ * This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
24
22
  */
25
23
  export declare function isPossibleComponent(node: Node): boolean;
26
24
  /**
27
- *
28
- * The language service is case insensitive, and would provide
29
- * hover info for Svelte components like `Option` which have
30
- * the same name like a html tag.
25
+ * Return true if a specific node could be a component with a client directive on it.
26
+ * This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
31
27
  */
32
28
  export declare function isPossibleClientComponent(node: Node): boolean;
33
29
  /** Flattens an array */
package/dist/utils.js CHANGED
@@ -38,21 +38,17 @@ function getLastPartOfPath(path) {
38
38
  }
39
39
  exports.getLastPartOfPath = getLastPartOfPath;
40
40
  /**
41
- *
42
- * The language service is case insensitive, and would provide
43
- * hover info for Svelte components like `Option` which have
44
- * the same name like a html tag.
41
+ * Return true if a specific node could be a component.
42
+ * This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
45
43
  */
46
44
  function isPossibleComponent(node) {
47
- var _a;
48
- return !!((_a = node.tag) === null || _a === void 0 ? void 0 : _a[0].match(/[A-Z]/));
45
+ var _a, _b;
46
+ return !!((_a = node.tag) === null || _a === void 0 ? void 0 : _a[0].match(/[A-Z]/)) || !!((_b = node.tag) === null || _b === void 0 ? void 0 : _b.match(/.+[.][A-Z]/));
49
47
  }
50
48
  exports.isPossibleComponent = isPossibleComponent;
51
49
  /**
52
- *
53
- * The language service is case insensitive, and would provide
54
- * hover info for Svelte components like `Option` which have
55
- * the same name like a html tag.
50
+ * Return true if a specific node could be a component with a client directive on it.
51
+ * This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
56
52
  */
57
53
  function isPossibleClientComponent(node) {
58
54
  if (isPossibleComponent(node) && node.attributes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/language-server",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "author": "withastro",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",