@astrojs/language-server 0.12.1 → 0.13.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @astrojs/language-server
2
2
 
3
+ ## 0.13.2
4
+
5
+ ### Patch Changes
6
+
7
+ - aff8b76: Fix error caused by malformed Svelte components
8
+ - Updated dependencies [aff8b76]
9
+ - @astrojs/svelte-language-integration@0.1.2
10
+
11
+ ## 0.13.1
12
+
13
+ ### Patch Changes
14
+
15
+ - ea74fdb: Publish failed
16
+
17
+ ## 0.13.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 82b8891: Add HTML hover info, fix Astro directives producing errors, fix missing children property for JSX based frameworks
22
+
23
+ ### Patch Changes
24
+
25
+ - 9f4f907: Add CSS hover info
26
+ - c09116f: Add support for Document Symbols (Outline tab, breadcrumb navigation)
27
+
3
28
  ## 0.12.1
4
29
 
5
30
  ### Patch Changes
@@ -1,4 +1,4 @@
1
- import { HTMLDocument } from 'vscode-html-languageservice';
1
+ import { HTMLDocument, Range } from 'vscode-html-languageservice';
2
2
  import { WritableDocument } from './DocumentBase';
3
3
  import { AstroMetadata } from './parseAstro';
4
4
  import { TagInformation } from './utils';
@@ -12,7 +12,7 @@ export declare class AstroDocument extends WritableDocument {
12
12
  constructor(url: string, content: string);
13
13
  private updateDocInfo;
14
14
  setText(text: string): void;
15
- getText(): string;
15
+ getText(range?: Range | undefined): string;
16
16
  getURL(): string;
17
17
  getFilePath(): string | null;
18
18
  }
@@ -24,7 +24,12 @@ class AstroDocument extends DocumentBase_1.WritableDocument {
24
24
  this.version++;
25
25
  this.updateDocInfo();
26
26
  }
27
- getText() {
27
+ getText(range) {
28
+ if (range) {
29
+ const start = this.offsetAt(range.start);
30
+ const end = this.offsetAt(range.end);
31
+ return this.content.substring(start, end);
32
+ }
28
33
  return this.content;
29
34
  }
30
35
  getURL() {
@@ -1,4 +1,4 @@
1
- import { CancellationToken, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FoldingRange, Hover, Position, Range, Location, SignatureHelp, SignatureHelpContext, TextDocumentContentChangeEvent, TextDocumentIdentifier, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CancellationToken, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FoldingRange, Hover, Position, Range, Location, SignatureHelp, SignatureHelpContext, TextDocumentContentChangeEvent, TextDocumentIdentifier, WorkspaceEdit, SymbolInformation } from 'vscode-languageserver';
2
2
  import type { AppCompletionItem, Plugin } from './interfaces';
3
3
  import { DocumentManager } from '../core/documents/DocumentManager';
4
4
  interface PluginHostConfig {
@@ -18,6 +18,7 @@ export declare class PluginHost {
18
18
  doHover(textDocument: TextDocumentIdentifier, position: Position): Promise<Hover | null>;
19
19
  doTagComplete(textDocument: TextDocumentIdentifier, position: Position): Promise<string | null>;
20
20
  getFoldingRanges(textDocument: TextDocumentIdentifier): Promise<FoldingRange[] | null>;
21
+ getDocumentSymbols(textDocument: TextDocumentIdentifier, cancellationToken: CancellationToken): Promise<SymbolInformation[]>;
21
22
  getDefinitions(textDocument: TextDocumentIdentifier, position: Position): Promise<DefinitionLink[] | Location[]>;
22
23
  rename(textDocument: TextDocumentIdentifier, position: Position, newName: string): Promise<WorkspaceEdit | null>;
23
24
  getDocumentColors(textDocument: TextDocumentIdentifier): Promise<ColorInformation[]>;
@@ -53,6 +53,10 @@ class PluginHost {
53
53
  const foldingRanges = (0, lodash_1.flatten)(await this.execute('getFoldingRanges', [document], ExecuteMode.Collect)).filter((completion) => completion != null);
54
54
  return foldingRanges;
55
55
  }
56
+ async getDocumentSymbols(textDocument, cancellationToken) {
57
+ const document = this.getDocument(textDocument.uri);
58
+ return (0, lodash_1.flatten)(await this.execute('getDocumentSymbols', [document, cancellationToken], ExecuteMode.Collect));
59
+ }
56
60
  async getDefinitions(textDocument, position) {
57
61
  const document = this.getDocument(textDocument.uri);
58
62
  const definitions = (0, lodash_1.flatten)(await this.execute('getDefinitions', [document, position], ExecuteMode.Collect));
@@ -1,4 +1,4 @@
1
- import { Color, ColorInformation, ColorPresentation, CompletionContext, CompletionList, Position, Range } from 'vscode-languageserver';
1
+ import { Color, ColorInformation, ColorPresentation, CompletionContext, CompletionList, Hover, Position, Range, SymbolInformation } from 'vscode-languageserver';
2
2
  import { ConfigManager } from '../../core/config/ConfigManager';
3
3
  import { AstroDocument } from '../../core/documents';
4
4
  import type { Plugin } from '../interfaces';
@@ -8,16 +8,25 @@ export declare class CSSPlugin implements Plugin {
8
8
  private cssDocuments;
9
9
  private triggerCharacters;
10
10
  constructor(configManager: ConfigManager);
11
+ doHover(document: AstroDocument, position: Position): Hover | null;
12
+ private doHoverInternal;
11
13
  getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): CompletionList | null;
12
14
  private getCompletionsInternal;
13
15
  getDocumentColors(document: AstroDocument): ColorInformation[];
14
16
  getColorPresentations(document: AstroDocument, range: Range, color: Color): ColorPresentation[];
17
+ getDocumentSymbols(document: AstroDocument): SymbolInformation[];
15
18
  private inStyleAttributeWithoutInterpolation;
16
19
  /**
17
20
  * Get the associated CSS Document for a style tag
18
21
  */
19
22
  private getCSSDocumentForStyleTag;
23
+ /**
24
+ * Get all the CSSDocuments in a document
25
+ */
20
26
  private getCSSDocumentsForDocument;
27
+ /**
28
+ * Get all the stylesheets (Stylesheet type) in a document
29
+ */
21
30
  private getStylesheetsForDocument;
22
31
  /**
23
32
  * Get style tag at position for a document
@@ -17,6 +17,35 @@ class CSSPlugin {
17
17
  this.triggerCharacters = new Set(['.', ':', '-', '/']);
18
18
  this.configManager = configManager;
19
19
  }
20
+ doHover(document, position) {
21
+ if (!this.featureEnabled('hover')) {
22
+ return null;
23
+ }
24
+ if ((0, documents_1.isInsideFrontmatter)(document.getText(), document.offsetAt(position))) {
25
+ return null;
26
+ }
27
+ const styleTag = this.getStyleTagForPosition(document, position);
28
+ if (!styleTag) {
29
+ const attributeContext = (0, parseHtml_1.getAttributeContextAtPosition)(document, position);
30
+ if (!attributeContext) {
31
+ return null;
32
+ }
33
+ if (this.inStyleAttributeWithoutInterpolation(attributeContext, document.getText())) {
34
+ const [start, end] = attributeContext.valueRange;
35
+ return this.doHoverInternal(new StyleAttributeDocument_1.StyleAttributeDocument(document, start, end), position);
36
+ }
37
+ return null;
38
+ }
39
+ const cssDocument = this.getCSSDocumentForStyleTag(styleTag, document);
40
+ if (shouldExcludeHover(cssDocument)) {
41
+ return null;
42
+ }
43
+ return this.doHoverInternal(cssDocument, position);
44
+ }
45
+ doHoverInternal(cssDocument, position) {
46
+ const hoverInfo = (0, language_service_1.getLanguageService)(extractLanguage(cssDocument)).doHover(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
47
+ return hoverInfo ? (0, documents_1.mapHoverToParent)(cssDocument, hoverInfo) : hoverInfo;
48
+ }
20
49
  getCompletions(document, position, completionContext) {
21
50
  if (!this.featureEnabled('completions')) {
22
51
  return null;
@@ -100,6 +129,17 @@ class CSSPlugin {
100
129
  });
101
130
  return (0, lodash_1.flatten)(allColorPres);
102
131
  }
132
+ getDocumentSymbols(document) {
133
+ if (!this.featureEnabled('documentSymbols')) {
134
+ return [];
135
+ }
136
+ const allDocumentSymbols = this.getCSSDocumentsForDocument(document).map((cssDoc) => {
137
+ return (0, language_service_1.getLanguageService)(extractLanguage(cssDoc))
138
+ .findDocumentSymbols(cssDoc, cssDoc.stylesheet)
139
+ .map((symbol) => (0, documents_1.mapSymbolInformationToOriginal)(cssDoc, symbol));
140
+ });
141
+ return (0, lodash_1.flatten)(allDocumentSymbols);
142
+ }
103
143
  inStyleAttributeWithoutInterpolation(attrContext, text) {
104
144
  return (attrContext.name === 'style' &&
105
145
  !!attrContext.valueRange &&
@@ -116,9 +156,15 @@ class CSSPlugin {
116
156
  }
117
157
  return cssDoc;
118
158
  }
159
+ /**
160
+ * Get all the CSSDocuments in a document
161
+ */
119
162
  getCSSDocumentsForDocument(document) {
120
163
  return document.styleTags.map((tag) => this.getCSSDocumentForStyleTag(tag, document));
121
164
  }
165
+ /**
166
+ * Get all the stylesheets (Stylesheet type) in a document
167
+ */
122
168
  getStylesheetsForDocument(document) {
123
169
  return this.getCSSDocumentsForDocument(document).map((cssDoc) => cssDoc.stylesheet);
124
170
  }
@@ -135,6 +181,22 @@ class CSSPlugin {
135
181
  }
136
182
  }
137
183
  exports.CSSPlugin = CSSPlugin;
184
+ /**
185
+ * Exclude certain language when getting hover info
186
+ * The CSS language service only supports CSS, LESS and SCSS,
187
+ * which mean that we cannot support hover info in other languages
188
+ */
189
+ function shouldExcludeHover(document) {
190
+ const language = typeof document === 'string' ? document : extractLanguage(document);
191
+ switch (language) {
192
+ case 'sass':
193
+ case 'stylus':
194
+ case 'styl':
195
+ return true;
196
+ default:
197
+ return false;
198
+ }
199
+ }
138
200
  /**
139
201
  * Exclude certain language when getting colors
140
202
  * The CSS language service only supports CSS, LESS and SCSS,
@@ -5,10 +5,10 @@ exports.pseudoClass = [
5
5
  {
6
6
  name: ':global()',
7
7
  description: `[astro] :global modifier
8
- Applying styles to a selector globally`,
8
+ Apply styles to a selector globally`,
9
9
  references: [
10
10
  {
11
- name: 'Astro Docs',
11
+ name: 'Astro documentation',
12
12
  url: 'https://docs.astro.build/en/guides/styling/#global-styles-within-style-tag',
13
13
  },
14
14
  ],
@@ -1,19 +1,22 @@
1
- import { CompletionList, Position, FoldingRange } from 'vscode-languageserver';
1
+ import { CompletionList, Position, FoldingRange, Hover, SymbolInformation } from 'vscode-languageserver';
2
2
  import type { Plugin } from '../interfaces';
3
3
  import { ConfigManager } from '../../core/config/ConfigManager';
4
4
  import { AstroDocument } from '../../core/documents/AstroDocument';
5
5
  export declare class HTMLPlugin implements Plugin {
6
6
  __name: string;
7
7
  private lang;
8
+ private componentLang;
8
9
  private styleScriptTemplate;
9
10
  private configManager;
10
11
  constructor(configManager: ConfigManager);
12
+ doHover(document: AstroDocument, position: Position): Hover | null;
11
13
  /**
12
14
  * Get HTML completions
13
15
  */
14
16
  getCompletions(document: AstroDocument, position: Position): CompletionList | null;
15
17
  getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
16
18
  doTagComplete(document: AstroDocument, position: Position): string | null;
19
+ getDocumentSymbols(document: AstroDocument): SymbolInformation[];
17
20
  /**
18
21
  * Get lang completions for style tags (ex: `<style lang="scss">`)
19
22
  */
@@ -5,13 +5,39 @@ const vscode_languageserver_1 = require("vscode-languageserver");
5
5
  const emmet_helper_1 = require("@vscode/emmet-helper");
6
6
  const vscode_html_languageservice_1 = require("vscode-html-languageservice");
7
7
  const utils_1 = require("../../core/documents/utils");
8
+ const utils_2 = require("../../utils");
9
+ const astro_attributes_1 = require("./features/astro-attributes");
8
10
  class HTMLPlugin {
9
11
  constructor(configManager) {
10
12
  this.__name = 'html';
11
- this.lang = (0, vscode_html_languageservice_1.getLanguageService)();
13
+ this.lang = (0, vscode_html_languageservice_1.getLanguageService)({
14
+ customDataProviders: [astro_attributes_1.astroAttributes],
15
+ });
16
+ this.componentLang = (0, vscode_html_languageservice_1.getLanguageService)({
17
+ customDataProviders: [astro_attributes_1.astroAttributes, astro_attributes_1.astroDirectives],
18
+ useDefaultDataProvider: false,
19
+ });
12
20
  this.styleScriptTemplate = new Set(['style']);
13
21
  this.configManager = configManager;
14
22
  }
23
+ doHover(document, position) {
24
+ if (!this.featureEnabled('hover')) {
25
+ return null;
26
+ }
27
+ const html = document.html;
28
+ if (!html) {
29
+ return null;
30
+ }
31
+ const node = html.findNodeAt(document.offsetAt(position));
32
+ if (!node) {
33
+ return null;
34
+ }
35
+ // If the node we're hovering on is a component, instead only provide astro-specific hover info
36
+ if ((0, utils_2.isPossibleComponent)(node)) {
37
+ return this.componentLang.doHover(document, position, html);
38
+ }
39
+ return this.lang.doHover(document, position, html);
40
+ }
15
41
  /**
16
42
  * Get HTML completions
17
43
  */
@@ -66,6 +92,16 @@ class HTMLPlugin {
66
92
  }
67
93
  return this.lang.doTagComplete(document, position, html);
68
94
  }
95
+ getDocumentSymbols(document) {
96
+ if (!this.featureEnabled('documentSymbols')) {
97
+ return [];
98
+ }
99
+ const html = document.html;
100
+ if (!html) {
101
+ return [];
102
+ }
103
+ return this.lang.findDocumentSymbols(document, html);
104
+ }
69
105
  /**
70
106
  * Get lang completions for style tags (ex: `<style lang="scss">`)
71
107
  */
@@ -0,0 +1,2 @@
1
+ export declare const astroAttributes: import("vscode-html-languageservice").IHTMLDataProvider;
2
+ export declare const astroDirectives: import("vscode-html-languageservice").IHTMLDataProvider;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.astroDirectives = exports.astroAttributes = void 0;
4
+ const vscode_html_languageservice_1 = require("vscode-html-languageservice");
5
+ exports.astroAttributes = (0, vscode_html_languageservice_1.newHTMLDataProvider)('astro-attributes', {
6
+ version: 1,
7
+ globalAttributes: [
8
+ {
9
+ name: 'class:list',
10
+ description: 'Utility to provide a list of class',
11
+ },
12
+ {
13
+ name: 'set:html',
14
+ description: 'Inject unescaped HTML into this tag',
15
+ references: [
16
+ {
17
+ name: 'Astro documentation',
18
+ url: 'https://docs.astro.build/en/migrate/#deprecated-unescaped-html',
19
+ },
20
+ ],
21
+ },
22
+ {
23
+ name: 'set:text',
24
+ description: 'Inject escaped text into this tag',
25
+ references: [
26
+ {
27
+ name: 'Astro documentation',
28
+ url: 'https://docs.astro.build/en/migrate/#deprecated-unescaped-html',
29
+ },
30
+ ],
31
+ },
32
+ ],
33
+ tags: [
34
+ {
35
+ name: 'script',
36
+ attributes: [
37
+ {
38
+ // The VS Code tag definitions does not provide a description for the deprecated `charset` attribute on script tags
39
+ // Which mean that since we get no hover info for this, we instead get JSX hover info. So we'll just specify a description ourselves for this specific case
40
+ name: 'charset',
41
+ description: "(Deprecated) It's unnecessary to specify the charset attribute, because documents must use UTF-8, and the script element inherits its character encoding from the document.",
42
+ },
43
+ {
44
+ name: 'define:vars',
45
+ description: 'Passes serializable server-side variables into a client-side script element',
46
+ references: [
47
+ {
48
+ name: 'Astro documentation',
49
+ url: 'https://docs.astro.build/en/guides/styling/#variables-in-scripts--styles',
50
+ },
51
+ ],
52
+ },
53
+ ],
54
+ },
55
+ {
56
+ name: 'style',
57
+ attributes: [
58
+ {
59
+ name: 'define:vars',
60
+ description: 'Passes serializable server-side variables into a client-side style element',
61
+ references: [
62
+ {
63
+ name: 'Astro documentation',
64
+ url: 'https://docs.astro.build/en/guides/styling/#variables-in-scripts--styles',
65
+ },
66
+ ],
67
+ },
68
+ ],
69
+ },
70
+ ],
71
+ });
72
+ exports.astroDirectives = (0, vscode_html_languageservice_1.newHTMLDataProvider)('astro-directives', {
73
+ version: 1,
74
+ globalAttributes: [
75
+ {
76
+ name: 'client:load',
77
+ description: 'Start importing the component JS at page load. Hydrate the component when import completes.',
78
+ references: [
79
+ {
80
+ name: 'Astro documentation',
81
+ url: 'https://docs.astro.build/en/core-concepts/component-hydration/#hydrate-interactive-components',
82
+ },
83
+ ],
84
+ },
85
+ {
86
+ name: 'client:idle',
87
+ description: 'Start importing the component JS as soon as main thread is free (uses requestIdleCallback()). Hydrate the component when import completes.',
88
+ references: [
89
+ {
90
+ name: 'Astro documentation',
91
+ url: 'https://docs.astro.build/en/core-concepts/component-hydration/#hydrate-interactive-components',
92
+ },
93
+ ],
94
+ },
95
+ {
96
+ name: 'client:visible',
97
+ description: 'Start importing the component JS as soon as the element enters the viewport (uses IntersectionObserver). Hydrate the component when import completes. Useful for content lower down on the page.',
98
+ references: [
99
+ {
100
+ name: 'Astro documentation',
101
+ url: 'https://docs.astro.build/en/core-concepts/component-hydration/#hydrate-interactive-components',
102
+ },
103
+ ],
104
+ },
105
+ {
106
+ name: 'client:media',
107
+ description: 'Start importing the component JS as soon as the browser matches the given media query (uses matchMedia). Hydrate the component when import completes. Useful for sidebar toggles, or other elements that should only display on mobile or desktop devices.',
108
+ references: [
109
+ {
110
+ name: 'Astro documentation',
111
+ url: 'https://docs.astro.build/en/core-concepts/component-hydration/#hydrate-interactive-components',
112
+ },
113
+ ],
114
+ },
115
+ {
116
+ name: 'client:only',
117
+ description: 'Start importing the component JS at page load and hydrate when the import completes, similar to client:load. The component will be skipped at build time, useful for components that are entirely dependent on client-side APIs. This is best avoided unless absolutely needed, in most cases it is best to render placeholder content on the server and delay any browser API calls until the component hydrates in the browser.',
118
+ references: [
119
+ {
120
+ name: 'Astro documentation',
121
+ url: 'https://docs.astro.build/en/core-concepts/component-hydration/#hydrate-interactive-components',
122
+ },
123
+ ],
124
+ },
125
+ ],
126
+ });
@@ -1,4 +1,4 @@
1
- import { CancellationToken, CompletionContext, DefinitionLink, Diagnostic, Hover, Position, SignatureHelp, SignatureHelpContext, TextDocumentContentChangeEvent, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CancellationToken, CompletionContext, DefinitionLink, Diagnostic, Hover, Position, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, WorkspaceEdit } from 'vscode-languageserver';
2
2
  import { ConfigManager } from '../../core/config';
3
3
  import { AstroDocument, DocumentManager } from '../../core/documents';
4
4
  import { AppCompletionItem, AppCompletionList, OnWatchFileChangesParam, Plugin } from '../interfaces';
@@ -11,9 +11,11 @@ export declare class TypeScriptPlugin implements Plugin {
11
11
  private readonly hoverProvider;
12
12
  private readonly signatureHelpProvider;
13
13
  private readonly diagnosticsProvider;
14
+ private readonly documentSymbolsProvider;
14
15
  constructor(docManager: DocumentManager, configManager: ConfigManager, workspaceUris: string[]);
15
16
  doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
16
17
  rename(document: AstroDocument, position: Position, newName: string): Promise<WorkspaceEdit | null>;
18
+ getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
17
19
  getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<AppCompletionList<CompletionEntryWithIdentifer> | null>;
18
20
  resolveCompletion(document: AstroDocument, completionItem: AppCompletionItem<CompletionEntryWithIdentifer>): Promise<AppCompletionItem<CompletionEntryWithIdentifer>>;
19
21
  getDefinitions(document: AstroDocument, position: Position): Promise<DefinitionLink[]>;
@@ -35,6 +35,7 @@ const SignatureHelpProvider_1 = require("./features/SignatureHelpProvider");
35
35
  const utils_2 = require("./features/utils");
36
36
  const LanguageServiceManager_1 = require("./LanguageServiceManager");
37
37
  const utils_3 = require("./utils");
38
+ const DocumentSymbolsProvider_1 = require("./features/DocumentSymbolsProvider");
38
39
  class TypeScriptPlugin {
39
40
  constructor(docManager, configManager, workspaceUris) {
40
41
  this.__name = 'typescript';
@@ -44,8 +45,12 @@ class TypeScriptPlugin {
44
45
  this.hoverProvider = new HoverProvider_1.HoverProviderImpl(this.languageServiceManager);
45
46
  this.signatureHelpProvider = new SignatureHelpProvider_1.SignatureHelpProviderImpl(this.languageServiceManager);
46
47
  this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.languageServiceManager);
48
+ this.documentSymbolsProvider = new DocumentSymbolsProvider_1.DocumentSymbolsProviderImpl(this.languageServiceManager);
47
49
  }
48
50
  async doHover(document, position) {
51
+ if (!this.featureEnabled('hover')) {
52
+ return null;
53
+ }
49
54
  return this.hoverProvider.doHover(document, position);
50
55
  }
51
56
  async rename(document, position, newName) {
@@ -71,7 +76,17 @@ class TypeScriptPlugin {
71
76
  });
72
77
  return edit;
73
78
  }
79
+ async getDocumentSymbols(document) {
80
+ if (!this.featureEnabled('documentSymbols')) {
81
+ return [];
82
+ }
83
+ const symbols = await this.documentSymbolsProvider.getDocumentSymbols(document);
84
+ return symbols;
85
+ }
74
86
  async getCompletions(document, position, completionContext) {
87
+ if (!this.featureEnabled('completions')) {
88
+ return null;
89
+ }
75
90
  const completions = await this.completionProvider.getCompletions(document, position, completionContext);
76
91
  return completions;
77
92
  }
@@ -19,7 +19,7 @@ class CompletionsProviderImpl {
19
19
  }
20
20
  async getCompletions(document, position, _completionContext) {
21
21
  var _a;
22
- // TODO: handle inside expression
22
+ // TODO: handle inside expression and script tags
23
23
  if (!(0, utils_1.isInsideFrontmatter)(document.getText(), document.offsetAt(position))) {
24
24
  return null;
25
25
  }
@@ -188,35 +188,14 @@ function isNoMarkdownBlockQuoteWithinMarkdown(sourceFile, boundaries, diagnostic
188
188
  * Some diagnostics have JSX-specific nomenclature. Enhance them for more clarity.
189
189
  */
190
190
  function enhanceIfNecessary(diagnostic) {
191
- if (diagnostic.code === 2786) {
192
- return {
193
- ...diagnostic,
194
- message: 'Type definitions are missing for this Svelte Component. ' +
195
- // eslint-disable-next-line max-len
196
- "It needs a class definition with at least the property '$$prop_def' which should contain a map of input property definitions.\n" +
197
- 'Example:\n' +
198
- ' class ComponentName { $$prop_def: { propertyName: string; } }\n' +
199
- 'If you are using Svelte 3.31+, use SvelteComponentTyped:\n' +
200
- ' import type { SvelteComponentTyped } from "svelte";\n' +
201
- ' class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}\n\n' +
202
- 'Underlying error:\n' +
203
- diagnostic.message,
204
- };
205
- }
206
- if (diagnostic.code === 2607) {
207
- return {
208
- ...diagnostic,
209
- message: 'Element does not support attributes because ' +
210
- 'type definitions are missing for this Svelte Component or element cannot be used as such.\n\n' +
211
- 'Underlying error:\n' +
212
- diagnostic.message,
213
- };
214
- }
215
- if (diagnostic.code === 1184) {
216
- return {
217
- ...diagnostic,
218
- message: diagnostic.message + '\nIf this is a declare statement, move it into <script context="module">..</script>',
219
- };
191
+ if (diagnostic.code === 2322) {
192
+ // For the rare case where an user might try to put a client directive on something that is not a component
193
+ if (diagnostic.message.includes("Property 'client:") && diagnostic.message.includes("to type 'HTMLProps")) {
194
+ return {
195
+ ...diagnostic,
196
+ message: 'Client directives are only available on framework components',
197
+ };
198
+ }
220
199
  }
221
200
  return diagnostic;
222
201
  }
@@ -0,0 +1,10 @@
1
+ import { SymbolInformation } from 'vscode-languageserver-types';
2
+ import { AstroDocument } from '../../../core/documents';
3
+ import { DocumentSymbolsProvider } from '../../interfaces';
4
+ import { LanguageServiceManager } from '../LanguageServiceManager';
5
+ export declare class DocumentSymbolsProviderImpl implements DocumentSymbolsProvider {
6
+ private languageServiceManager;
7
+ constructor(languageServiceManager: LanguageServiceManager);
8
+ getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
9
+ private collectSymbols;
10
+ }
@@ -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;