@astrojs/language-server 0.21.1 → 0.22.0

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,16 @@
1
1
  # @astrojs/language-server
2
2
 
3
+ ## 0.22.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d5aafc0: Formatting is now powered by Prettier and our Prettier plugin. Going forward, this should result in a more stable and complete way of formatting Astro files
8
+
9
+ ### Patch Changes
10
+
11
+ - 61620f1: Add support for Go To Type Definition
12
+ - 9337f00: Fix language server not working when no initlizationOptions were passed
13
+
3
14
  ## 0.21.1
4
15
 
5
16
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import { VSCodeEmmetConfig } from '@vscode/emmet-helper';
2
- import { LSConfig, LSCSSConfig, LSFormatConfig, LSHTMLConfig, LSTypescriptConfig } from './interfaces';
2
+ import { LSConfig, LSCSSConfig, LSHTMLConfig, LSTypescriptConfig } from './interfaces';
3
3
  import { Connection, FormattingOptions } from 'vscode-languageserver';
4
4
  import { TextDocument } from 'vscode-languageserver-textdocument';
5
5
  import { FormatCodeSettings, InlayHintsOptions, UserPreferences } from 'typescript';
@@ -23,7 +23,6 @@ export declare class ConfigManager {
23
23
  removeDocument(scopeUri: string): void;
24
24
  getConfig<T>(section: string, scopeUri: string): Promise<T | Record<string, any>>;
25
25
  getEmmetConfig(document: TextDocument): Promise<VSCodeEmmetConfig>;
26
- getAstroFormatConfig(document: TextDocument): Promise<LSFormatConfig>;
27
26
  getTSFormatConfig(document: TextDocument, vscodeOptions?: FormattingOptions): Promise<FormatCodeSettings>;
28
27
  getTSPreferences(document: TextDocument): Promise<UserPreferences>;
29
28
  getTSInlayHintsPreferences(document: TextDocument): Promise<InlayHintsOptions>;
@@ -90,13 +90,6 @@ class ConfigManager {
90
90
  showSuggestionsAsSnippets: emmetConfig.showSuggestionsAsSnippets ?? false,
91
91
  };
92
92
  }
93
- async getAstroFormatConfig(document) {
94
- const astroFormatConfig = (await this.getConfig('astro.format', document.uri)) ?? {};
95
- return {
96
- indentFrontmatter: astroFormatConfig.indentFrontmatter ?? exports.defaultLSConfig.format.indentFrontmatter,
97
- newLineAfterFrontmatter: astroFormatConfig.newLineAfterFrontmatter ?? exports.defaultLSConfig.format.newLineAfterFrontmatter,
98
- };
99
- }
100
93
  async getTSFormatConfig(document, vscodeOptions) {
101
94
  const formatConfig = (await this.getConfig('typescript.format', document.uri)) ?? {};
102
95
  return {
@@ -1,6 +1,9 @@
1
1
  import type * as svelte from '@astrojs/svelte/dist/editor.cjs';
2
2
  import type * as vue from '@astrojs/svelte/dist/editor.cjs';
3
+ import type * as prettier from 'prettier';
3
4
  export declare function setIsTrusted(_isTrusted: boolean): void;
4
5
  export declare function getPackagePath(packageName: string, fromPath: string[]): string | undefined;
5
6
  export declare function importSvelteIntegration(fromPath: string): typeof svelte | undefined;
6
7
  export declare function importVueIntegration(fromPath: string): typeof vue | undefined;
8
+ export declare function importPrettier(fromPath: string): typeof prettier;
9
+ export declare function getPrettierPluginPath(fromPath: string): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.importVueIntegration = exports.importSvelteIntegration = exports.getPackagePath = exports.setIsTrusted = void 0;
3
+ exports.getPrettierPluginPath = exports.importPrettier = exports.importVueIntegration = exports.importSvelteIntegration = exports.getPackagePath = exports.setIsTrusted = void 0;
4
4
  const path_1 = require("path");
5
5
  let isTrusted = true;
6
6
  function setIsTrusted(_isTrusted) {
@@ -42,3 +42,13 @@ function importVueIntegration(fromPath) {
42
42
  return importEditorIntegration('@astrojs/vue', fromPath);
43
43
  }
44
44
  exports.importVueIntegration = importVueIntegration;
45
+ function importPrettier(fromPath) {
46
+ // This shouldn't ever fail, because we bundle Prettier in the extension itself
47
+ const prettierPkg = getPackagePath('prettier', [fromPath, __dirname]);
48
+ return require(prettierPkg);
49
+ }
50
+ exports.importPrettier = importPrettier;
51
+ function getPrettierPluginPath(fromPath) {
52
+ return getPackagePath('prettier-plugin-astro', [fromPath, __dirname]);
53
+ }
54
+ exports.getPrettierPluginPath = getPrettierPluginPath;
@@ -24,6 +24,7 @@ export declare class PluginHost {
24
24
  getSemanticTokens(textDocument: TextDocumentIdentifier, range?: Range, cancellationToken?: CancellationToken): Promise<SemanticTokens | null>;
25
25
  getLinkedEditingRanges(textDocument: TextDocumentIdentifier, position: Position): Promise<LinkedEditingRanges | null>;
26
26
  getDefinitions(textDocument: TextDocumentIdentifier, position: Position): Promise<DefinitionLink[] | Location[]>;
27
+ getTypeDefinition(textDocument: TextDocumentIdentifier, position: Position): Promise<Location[] | null>;
27
28
  rename(textDocument: TextDocumentIdentifier, position: Position, newName: string): Promise<WorkspaceEdit | null>;
28
29
  getDocumentColors(textDocument: TextDocumentIdentifier): Promise<ColorInformation[]>;
29
30
  getColorPresentations(textDocument: TextDocumentIdentifier, range: Range, color: Color): Promise<ColorPresentation[]>;
@@ -115,6 +115,10 @@ class PluginHost {
115
115
  return definitions.map((def) => ({ range: def.targetSelectionRange, uri: def.targetUri }));
116
116
  }
117
117
  }
118
+ getTypeDefinition(textDocument, position) {
119
+ const document = this.getDocument(textDocument.uri);
120
+ return this.execute('getTypeDefinitions', [document, position], ExecuteMode.FirstNonNull);
121
+ }
118
122
  async rename(textDocument, position, newName) {
119
123
  const document = this.getDocument(textDocument.uri);
120
124
  return this.execute('rename', [document, position, newName], ExecuteMode.FirstNonNull);
@@ -1,4 +1,4 @@
1
- import { CompletionContext, FoldingRange, Position } from 'vscode-languageserver';
1
+ import { CompletionContext, FoldingRange, Position, TextEdit, FormattingOptions } from 'vscode-languageserver';
2
2
  import { ConfigManager } from '../../core/config';
3
3
  import { AstroDocument } from '../../core/documents';
4
4
  import { AppCompletionList, Plugin } from '../interfaces';
@@ -10,5 +10,6 @@ export declare class AstroPlugin implements Plugin {
10
10
  private readonly completionProvider;
11
11
  constructor(configManager: ConfigManager, languageServiceManager: LanguageServiceManager);
12
12
  getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<AppCompletionList | null>;
13
+ formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
13
14
  getFoldingRanges(document: AstroDocument): FoldingRange[];
14
15
  }
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AstroPlugin = void 0;
4
4
  const vscode_languageserver_1 = require("vscode-languageserver");
5
+ const importPackage_1 = require("../../importPackage");
6
+ const utils_1 = require("../../utils");
5
7
  const CompletionsProvider_1 = require("./features/CompletionsProvider");
6
8
  class AstroPlugin {
7
9
  constructor(configManager, languageServiceManager) {
@@ -14,6 +16,37 @@ class AstroPlugin {
14
16
  const completions = this.completionProvider.getCompletions(document, position, completionContext);
15
17
  return completions;
16
18
  }
19
+ async formatDocument(document, options) {
20
+ const filePath = document.getFilePath();
21
+ if (!filePath) {
22
+ return [];
23
+ }
24
+ const prettier = (0, importPackage_1.importPrettier)(filePath);
25
+ const prettierConfig = await prettier.resolveConfig(filePath, { editorconfig: true, useCache: false });
26
+ const editorFormatConfig = options !== undefined
27
+ ? {
28
+ tabWidth: prettierConfig?.tabWidth ?? options.tabSize,
29
+ useTabs: prettierConfig?.useTabs ?? !options.insertSpaces,
30
+ }
31
+ : {};
32
+ const resultConfig = (0, utils_1.mergeDeep)(prettierConfig ?? {}, editorFormatConfig);
33
+ const fileInfo = await prettier.getFileInfo(filePath, { ignorePath: '.prettierignore' });
34
+ if (fileInfo.ignored) {
35
+ return [];
36
+ }
37
+ const result = prettier.format(document.getText(), {
38
+ ...resultConfig,
39
+ plugins: getAstroPrettierPlugin(),
40
+ parser: 'astro',
41
+ });
42
+ return document.getText() === result
43
+ ? []
44
+ : [vscode_languageserver_1.TextEdit.replace(vscode_languageserver_1.Range.create(document.positionAt(0), document.positionAt(document.getTextLength())), result)];
45
+ function getAstroPrettierPlugin() {
46
+ const hasPluginLoadedAlready = prettier.getSupportInfo().languages.some((l) => l.name === 'astro');
47
+ return hasPluginLoadedAlready ? [] : [(0, importPackage_1.getPrettierPluginPath)(filePath)];
48
+ }
49
+ }
17
50
  getFoldingRanges(document) {
18
51
  const foldingRanges = [];
19
52
  const { frontmatter } = document.astroMeta;
@@ -1,3 +1,3 @@
1
1
  import { LanguageService } from 'vscode-css-languageservice';
2
- export declare function getLanguage(kind?: string): "css" | "scss" | "less";
2
+ export declare function getLanguage(kind?: string): "css" | "less" | "scss";
3
3
  export declare function getLanguageService(kind?: string): LanguageService;
@@ -1,4 +1,4 @@
1
- import { CompletionList, Position, TextEdit, FoldingRange, Hover, SymbolInformation, FormattingOptions, LinkedEditingRanges } from 'vscode-languageserver';
1
+ import { CompletionList, Position, FoldingRange, Hover, SymbolInformation, LinkedEditingRanges } 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';
@@ -15,7 +15,6 @@ export declare class HTMLPlugin implements Plugin {
15
15
  * Get HTML completions
16
16
  */
17
17
  getCompletions(document: AstroDocument, position: Position): Promise<CompletionList | null>;
18
- formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
19
18
  getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
20
19
  getLinkedEditingRanges(document: AstroDocument, position: Position): LinkedEditingRanges | null;
21
20
  doTagComplete(document: AstroDocument, position: Position): Promise<string | null>;
@@ -83,24 +83,6 @@ class HTMLPlugin {
83
83
  // Emmet completions change on every keystroke, so they are never complete
84
84
  emmetResults.items.length > 0);
85
85
  }
86
- async formatDocument(document, options) {
87
- const start = document.positionAt(document.astroMeta.frontmatter.state === 'closed' ? document.astroMeta.frontmatter.endOffset + 3 : 0);
88
- if (document.astroMeta.frontmatter.state === 'closed') {
89
- start.line += 1;
90
- start.character = 0;
91
- }
92
- const end = document.positionAt(document.getTextLength());
93
- const htmlFormatConfig = (await this.configManager.getConfig('html.format', document.uri)) ?? {};
94
- // The HTML plugin can't format script tags properly, we'll handle those inside the TypeScript plugin
95
- if (htmlFormatConfig.contentUnformatted) {
96
- htmlFormatConfig.contentUnformatted = htmlFormatConfig.contentUnformatted + ',script';
97
- }
98
- else {
99
- htmlFormatConfig.contentUnformatted = 'script';
100
- }
101
- const edits = this.lang.format(document, vscode_languageserver_1.Range.create(start, end), { ...htmlFormatConfig, ...options });
102
- return edits;
103
- }
104
86
  getFoldingRanges(document) {
105
87
  const html = document.html;
106
88
  if (!html) {
@@ -1,4 +1,4 @@
1
- import { CodeAction, CodeActionContext, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FileChangeType, FoldingRange, FormattingOptions, Hover, InlayHint, LinkedEditingRanges, Position, Range, ReferenceContext, SelectionRange, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextDocumentIdentifier, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CodeAction, CodeActionContext, Color, Location, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FileChangeType, FoldingRange, FormattingOptions, Hover, InlayHint, LinkedEditingRanges, Position, Range, ReferenceContext, SelectionRange, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextDocumentIdentifier, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
2
2
  import { TextDocument } from 'vscode-languageserver-textdocument';
3
3
  export declare type Resolvable<T> = T | Promise<T>;
4
4
  export interface AppCompletionItem<T extends TextDocumentIdentifier = any> extends CompletionItem {
@@ -74,6 +74,9 @@ export interface SemanticTokensProvider {
74
74
  export interface LinkedEditingRangesProvider {
75
75
  getLinkedEditingRanges(document: TextDocument, position: Position): Resolvable<LinkedEditingRanges | null>;
76
76
  }
77
+ export interface TypeDefinitionProvider {
78
+ getTypeDefinitions(document: TextDocument, position: Position): Resolvable<Location[] | null>;
79
+ }
77
80
  export interface OnWatchFileChangesParam {
78
81
  fileName: string;
79
82
  changeType: FileChangeType;
@@ -84,7 +87,7 @@ export interface OnWatchFileChangesProvider {
84
87
  export interface UpdateNonAstroFile {
85
88
  updateNonAstroFile(fileName: string, changes: TextDocumentContentChangeEvent[]): void;
86
89
  }
87
- declare type ProviderBase = DiagnosticsProvider & HoverProvider & CompletionsProvider & DefinitionsProvider & FormattingProvider & FoldingRangesProvider & TagCompleteProvider & DocumentColorsProvider & ColorPresentationsProvider & DocumentSymbolsProvider & UpdateImportsProvider & CodeActionsProvider & FindReferencesProvider & RenameProvider & SignatureHelpProvider & SemanticTokensProvider & SelectionRangeProvider & OnWatchFileChangesProvider & LinkedEditingRangesProvider & InlayHintsProvider & UpdateNonAstroFile;
90
+ declare type ProviderBase = DiagnosticsProvider & HoverProvider & CompletionsProvider & DefinitionsProvider & TypeDefinitionProvider & FormattingProvider & FoldingRangesProvider & TagCompleteProvider & DocumentColorsProvider & ColorPresentationsProvider & DocumentSymbolsProvider & UpdateImportsProvider & CodeActionsProvider & FindReferencesProvider & RenameProvider & SignatureHelpProvider & SemanticTokensProvider & SelectionRangeProvider & OnWatchFileChangesProvider & LinkedEditingRangesProvider & InlayHintsProvider & UpdateNonAstroFile;
88
91
  export declare type LSProvider = ProviderBase;
89
92
  export declare type Plugin = Partial<ProviderBase> & {
90
93
  __name: string;
@@ -1,4 +1,4 @@
1
- import { CancellationToken, CodeAction, CodeActionContext, CompletionContext, DefinitionLink, Diagnostic, FoldingRange, FormattingOptions, Hover, InlayHint, Position, Range, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CancellationToken, CodeAction, CodeActionContext, CompletionContext, DefinitionLink, Location, Diagnostic, FoldingRange, Hover, InlayHint, Position, Range, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, WorkspaceEdit } from 'vscode-languageserver';
2
2
  import { ConfigManager } from '../../core/config';
3
3
  import { AstroDocument } from '../../core/documents';
4
4
  import { AppCompletionItem, AppCompletionList, OnWatchFileChangesParam, Plugin } from '../interfaces';
@@ -13,17 +13,16 @@ export declare class TypeScriptPlugin implements Plugin {
13
13
  private readonly completionProvider;
14
14
  private readonly hoverProvider;
15
15
  private readonly definitionsProvider;
16
+ private readonly typeDefinitionsProvider;
16
17
  private readonly signatureHelpProvider;
17
18
  private readonly diagnosticsProvider;
18
19
  private readonly documentSymbolsProvider;
19
20
  private readonly inlayHintsProvider;
20
21
  private readonly semanticTokensProvider;
21
22
  private readonly foldingRangesProvider;
22
- private readonly formattingProvider;
23
23
  constructor(configManager: ConfigManager, languageServiceManager: LanguageServiceManager);
24
24
  doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
25
25
  rename(document: AstroDocument, position: Position, newName: string): Promise<WorkspaceEdit | null>;
26
- formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
27
26
  getFoldingRanges(document: AstroDocument): Promise<FoldingRange[] | null>;
28
27
  getSemanticTokens(document: AstroDocument, range?: Range, cancellationToken?: CancellationToken): Promise<SemanticTokens | null>;
29
28
  getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
@@ -32,6 +31,7 @@ export declare class TypeScriptPlugin implements Plugin {
32
31
  resolveCompletion(document: AstroDocument, completionItem: AppCompletionItem<CompletionItemData>, cancellationToken?: CancellationToken): Promise<AppCompletionItem<CompletionItemData>>;
33
32
  getInlayHints(document: AstroDocument, range: Range): Promise<InlayHint[]>;
34
33
  getDefinitions(document: AstroDocument, position: Position): Promise<DefinitionLink[]>;
34
+ getTypeDefinition(document: AstroDocument, position: Position): Promise<Location[] | null>;
35
35
  getDiagnostics(document: AstroDocument, cancellationToken?: CancellationToken): Promise<Diagnostic[]>;
36
36
  onWatchFileChanges(onWatchFileChangesParas: OnWatchFileChangesParam[]): Promise<void>;
37
37
  updateNonAstroFile(fileName: string, changes: TextDocumentContentChangeEvent[]): Promise<void>;
@@ -17,9 +17,9 @@ const FoldingRangesProvider_1 = require("./features/FoldingRangesProvider");
17
17
  const CodeActionsProvider_1 = require("./features/CodeActionsProvider");
18
18
  const DefinitionsProvider_1 = require("./features/DefinitionsProvider");
19
19
  const InlayHintsProvider_1 = require("./features/InlayHintsProvider");
20
- const FormattingProvider_1 = require("./features/FormattingProvider");
21
20
  const astro2tsx_1 = __importDefault(require("./astro2tsx"));
22
21
  const utils_2 = require("./snapshots/utils");
22
+ const TypeDefinitionsProvider_1 = require("./features/TypeDefinitionsProvider");
23
23
  class TypeScriptPlugin {
24
24
  constructor(configManager, languageServiceManager) {
25
25
  this.__name = 'typescript';
@@ -29,13 +29,13 @@ class TypeScriptPlugin {
29
29
  this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(this.languageServiceManager, this.configManager);
30
30
  this.hoverProvider = new HoverProvider_1.HoverProviderImpl(this.languageServiceManager);
31
31
  this.definitionsProvider = new DefinitionsProvider_1.DefinitionsProviderImpl(this.languageServiceManager);
32
+ this.typeDefinitionsProvider = new TypeDefinitionsProvider_1.TypeDefinitionsProviderImpl(this.languageServiceManager);
32
33
  this.signatureHelpProvider = new SignatureHelpProvider_1.SignatureHelpProviderImpl(this.languageServiceManager);
33
34
  this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.languageServiceManager);
34
35
  this.documentSymbolsProvider = new DocumentSymbolsProvider_1.DocumentSymbolsProviderImpl(this.languageServiceManager);
35
36
  this.semanticTokensProvider = new SemanticTokenProvider_1.SemanticTokensProviderImpl(this.languageServiceManager);
36
37
  this.inlayHintsProvider = new InlayHintsProvider_1.InlayHintsProviderImpl(this.languageServiceManager, this.configManager);
37
38
  this.foldingRangesProvider = new FoldingRangesProvider_1.FoldingRangesProviderImpl(this.languageServiceManager);
38
- this.formattingProvider = new FormattingProvider_1.FormattingProviderImpl(this.languageServiceManager, this.configManager);
39
39
  }
40
40
  async doHover(document, position) {
41
41
  if (!(await this.featureEnabled(document, 'hover'))) {
@@ -66,9 +66,6 @@ class TypeScriptPlugin {
66
66
  });
67
67
  return edit;
68
68
  }
69
- async formatDocument(document, options) {
70
- return this.formattingProvider.formatDocument(document, options);
71
- }
72
69
  async getFoldingRanges(document) {
73
70
  return this.foldingRangesProvider.getFoldingRanges(document);
74
71
  }
@@ -107,6 +104,9 @@ class TypeScriptPlugin {
107
104
  async getDefinitions(document, position) {
108
105
  return this.definitionsProvider.getDefinitions(document, position);
109
106
  }
107
+ async getTypeDefinition(document, position) {
108
+ return this.typeDefinitionsProvider.getTypeDefinitions(document, position);
109
+ }
110
110
  async getDiagnostics(document, cancellationToken) {
111
111
  if (!(await this.featureEnabled(document, 'diagnostics'))) {
112
112
  return [];
@@ -0,0 +1,9 @@
1
+ import { Position, Location } from 'vscode-languageserver-protocol';
2
+ import { AstroDocument } from '../../../core/documents';
3
+ import { TypeDefinitionProvider } from '../../interfaces';
4
+ import { LanguageServiceManager } from '../LanguageServiceManager';
5
+ export declare class TypeDefinitionsProviderImpl implements TypeDefinitionProvider {
6
+ private languageServiceManager;
7
+ constructor(languageServiceManager: LanguageServiceManager);
8
+ getTypeDefinitions(document: AstroDocument, position: Position): Promise<Location[]>;
9
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TypeDefinitionsProviderImpl = void 0;
4
+ const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
5
+ const documents_1 = require("../../../core/documents");
6
+ const utils_1 = require("../../../utils");
7
+ const utils_2 = require("../utils");
8
+ const utils_3 = require("./utils");
9
+ class TypeDefinitionsProviderImpl {
10
+ constructor(languageServiceManager) {
11
+ this.languageServiceManager = languageServiceManager;
12
+ }
13
+ async getTypeDefinitions(document, position) {
14
+ const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
15
+ const mainFragment = await tsDoc.createFragment();
16
+ const fragmentOffset = mainFragment.offsetAt(mainFragment.getGeneratedPosition(position));
17
+ const tsFilePath = (0, utils_2.toVirtualAstroFilePath)(tsDoc.filePath);
18
+ const html = document.html;
19
+ const offset = document.offsetAt(position);
20
+ const node = html.findNodeAt(offset);
21
+ let typeDefs;
22
+ if (node.tag === 'script') {
23
+ const { snapshot: scriptTagSnapshot, filePath: scriptFilePath, offset: scriptOffset, } = (0, utils_2.getScriptTagSnapshot)(tsDoc, document, node, position);
24
+ typeDefs = lang.getTypeDefinitionAtPosition(scriptFilePath, scriptOffset);
25
+ if (typeDefs) {
26
+ typeDefs = typeDefs.map((def) => {
27
+ const isInSameFile = def.fileName === scriptFilePath;
28
+ def.fileName = isInSameFile ? tsFilePath : def.fileName;
29
+ if (isInSameFile) {
30
+ def.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(def.textSpan.start)));
31
+ }
32
+ return def;
33
+ });
34
+ }
35
+ }
36
+ else {
37
+ typeDefs = lang.getTypeDefinitionAtPosition(tsFilePath, fragmentOffset);
38
+ }
39
+ const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
40
+ docs.set(tsFilePath, { fragment: mainFragment, snapshot: tsDoc });
41
+ if (!typeDefs) {
42
+ return [];
43
+ }
44
+ const result = await Promise.all(typeDefs.map(async (typeDef) => {
45
+ const { fragment } = await docs.retrieve(typeDef.fileName);
46
+ const fileName = (0, utils_2.ensureRealFilePath)(typeDef.fileName);
47
+ const range = (0, documents_1.mapRangeToOriginal)(fragment, (0, utils_2.convertRange)(fragment, typeDef.textSpan));
48
+ if (range.start.line >= 0 && range.end.line >= 0) {
49
+ return vscode_languageserver_protocol_1.Location.create((0, utils_1.pathToUrl)(fileName), range);
50
+ }
51
+ }));
52
+ return result.filter(utils_1.isNotNullOrUndefined);
53
+ }
54
+ }
55
+ exports.TypeDefinitionsProviderImpl = TypeDefinitionsProviderImpl;
package/dist/server.js CHANGED
@@ -48,6 +48,7 @@ function startLanguageServer(connection) {
48
48
  let typescriptPlugin = undefined;
49
49
  let hasConfigurationCapability = false;
50
50
  connection.onInitialize((params) => {
51
+ const environment = params.initializationOptions?.environment ?? 'node';
51
52
  const workspaceUris = params.workspaceFolders?.map((folder) => folder.uri.toString()) ?? [params.rootUri ?? ''];
52
53
  workspaceUris.forEach((uri) => {
53
54
  uri = (0, utils_1.urlToPath)(uri);
@@ -73,7 +74,7 @@ function startLanguageServer(connection) {
73
74
  pluginHost.registerPlugin(new HTMLPlugin_1.HTMLPlugin(configManager));
74
75
  pluginHost.registerPlugin(new CSSPlugin_1.CSSPlugin(configManager));
75
76
  // We don't currently support running the TypeScript and Astro plugin in the browser
76
- if (params.initializationOptions.environment !== 'browser') {
77
+ if (environment === 'node') {
77
78
  const languageServiceManager = new LanguageServiceManager_1.LanguageServiceManager(documentManager, workspaceUris.map(utils_1.normalizeUri), configManager);
78
79
  typescriptPlugin = new plugins_1.TypeScriptPlugin(configManager, languageServiceManager);
79
80
  pluginHost.registerPlugin(new AstroPlugin_1.AstroPlugin(configManager, languageServiceManager));
@@ -90,6 +91,7 @@ function startLanguageServer(connection) {
90
91
  },
91
92
  foldingRangeProvider: true,
92
93
  definitionProvider: true,
94
+ typeDefinitionProvider: true,
93
95
  renameProvider: true,
94
96
  documentFormattingProvider: true,
95
97
  codeActionProvider: {
@@ -184,6 +186,7 @@ function startLanguageServer(connection) {
184
186
  // Features
185
187
  connection.onHover((params) => pluginHost.doHover(params.textDocument, params.position));
186
188
  connection.onDefinition((evt) => pluginHost.getDefinitions(evt.textDocument, evt.position));
189
+ connection.onTypeDefinition((evt) => pluginHost.getTypeDefinition(evt.textDocument, evt.position));
187
190
  connection.onFoldingRanges((evt) => pluginHost.getFoldingRanges(evt.textDocument));
188
191
  connection.onCodeAction((evt, cancellationToken) => pluginHost.getCodeActions(evt.textDocument, evt.range, evt.context, cancellationToken));
189
192
  connection.onCompletion(async (evt) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/language-server",
3
- "version": "0.21.1",
3
+ "version": "0.22.0",
4
4
  "author": "withastro",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -20,6 +20,8 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@vscode/emmet-helper": "^2.8.4",
23
+ "prettier": "^2.7.1",
24
+ "prettier-plugin-astro": "^0.5.0",
23
25
  "source-map": "^0.7.3",
24
26
  "typescript": "~4.6.4",
25
27
  "vscode-css-languageservice": "^6.0.1",
@@ -35,6 +37,7 @@
35
37
  "@astrojs/vue": "^0.5.0",
36
38
  "@types/chai": "^4.3.0",
37
39
  "@types/mocha": "^9.1.0",
40
+ "@types/prettier": "^2.7.0",
38
41
  "@types/sinon": "^10.0.11",
39
42
  "astro": "^1.0.0-beta.72",
40
43
  "astro-scripts": "0.0.1",
@@ -1,11 +0,0 @@
1
- import { FormattingOptions, TextEdit } from 'vscode-languageserver-types';
2
- import { ConfigManager } from '../../../core/config';
3
- import { AstroDocument } from '../../../core/documents';
4
- import { FormattingProvider } from '../../interfaces';
5
- import { LanguageServiceManager } from '../LanguageServiceManager';
6
- export declare class FormattingProviderImpl implements FormattingProvider {
7
- private languageServiceManager;
8
- private configManager;
9
- constructor(languageServiceManager: LanguageServiceManager, configManager: ConfigManager);
10
- formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
11
- }
@@ -1,132 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FormattingProviderImpl = void 0;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- const vscode_languageserver_types_1 = require("vscode-languageserver-types");
9
- const utils_1 = require("../utils");
10
- class FormattingProviderImpl {
11
- constructor(languageServiceManager, configManager) {
12
- this.languageServiceManager = languageServiceManager;
13
- this.configManager = configManager;
14
- }
15
- async formatDocument(document, options) {
16
- const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
17
- const filePath = (0, utils_1.toVirtualAstroFilePath)(tsDoc.filePath);
18
- const formatConfig = await this.configManager.getTSFormatConfig(document, options);
19
- let frontmatterEdits = [];
20
- let scriptTagsEdits = [];
21
- if (document.astroMeta.frontmatter.state === 'closed') {
22
- const start = document.positionAt(document.astroMeta.frontmatter.startOffset + 3);
23
- start.line += 1;
24
- start.character = 0;
25
- const startOffset = document.offsetAt(start);
26
- const endOffset = document.astroMeta.frontmatter.endOffset;
27
- const astroFormatConfig = await this.configManager.getAstroFormatConfig(document);
28
- const settings = {
29
- ...formatConfig,
30
- baseIndentSize: astroFormatConfig.indentFrontmatter ? formatConfig.tabSize ?? 0 : undefined,
31
- };
32
- frontmatterEdits = lang.getFormattingEditsForRange(filePath, startOffset, endOffset, settings);
33
- if (astroFormatConfig.newLineAfterFrontmatter) {
34
- const templateStart = document.positionAt(endOffset + 3);
35
- templateStart.line += 1;
36
- templateStart.character = 0;
37
- frontmatterEdits.push({
38
- span: { start: document.offsetAt(templateStart), length: 0 },
39
- newText: '\n',
40
- });
41
- }
42
- }
43
- document.scriptTags.forEach((scriptTag) => {
44
- const { filePath: scriptFilePath, snapshot: scriptTagSnapshot } = (0, utils_1.getScriptTagSnapshot)(tsDoc, document, scriptTag.container);
45
- const startLine = document.offsetAt(vscode_languageserver_types_1.Position.create(scriptTag.startPos.line, 0));
46
- const initialIndentLevel = computeInitialIndent(document, startLine, options);
47
- const baseIndent = (formatConfig.tabSize ?? 0) * (initialIndentLevel + 1);
48
- const formatSettings = {
49
- baseIndentSize: baseIndent,
50
- indentStyle: typescript_1.default.IndentStyle.Smart,
51
- ...formatConfig,
52
- };
53
- let edits = lang.getFormattingEditsForDocument(scriptFilePath, formatSettings);
54
- if (edits) {
55
- edits = edits
56
- .map((edit) => {
57
- edit.span.start = document.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(edit.span.start)));
58
- return edit;
59
- })
60
- .filter((edit) => {
61
- return (scriptTagSnapshot.isInGenerated(document.positionAt(edit.span.start)) &&
62
- scriptTag.end !== edit.span.start &&
63
- // Don't format the last line of the file as it's in most case the indentation
64
- scriptTag.endPos.line !== document.positionAt(edit.span.start).line);
65
- });
66
- const endLine = document.getLineUntilOffset(document.offsetAt(scriptTag.endPos));
67
- if (isWhitespaceOnly(endLine)) {
68
- const endLineStartOffset = document.offsetAt(vscode_languageserver_types_1.Position.create(scriptTag.endPos.line, 0));
69
- const lastLineIndentRange = vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(scriptTag.endPos.line, 0), scriptTag.endPos);
70
- const newText = generateIndent(initialIndentLevel, options);
71
- if (endLine !== newText) {
72
- edits.push({
73
- span: {
74
- start: endLineStartOffset,
75
- length: lastLineIndentRange.end.character,
76
- },
77
- newText,
78
- });
79
- }
80
- }
81
- }
82
- scriptTagsEdits.push(...edits);
83
- });
84
- return [...frontmatterEdits, ...scriptTagsEdits].map((edit) => ({
85
- range: (0, utils_1.convertRange)(document, edit.span),
86
- newText: edit.newText,
87
- }));
88
- }
89
- }
90
- exports.FormattingProviderImpl = FormattingProviderImpl;
91
- function computeInitialIndent(document, lineStart, options) {
92
- let content = document.getText();
93
- let i = lineStart;
94
- let nChars = 0;
95
- let tabSize = options.tabSize || 4;
96
- while (i < content.length) {
97
- let ch = content.charAt(i);
98
- if (ch === ' ') {
99
- nChars++;
100
- }
101
- else if (ch === '\t') {
102
- nChars += tabSize;
103
- }
104
- else {
105
- break;
106
- }
107
- i++;
108
- }
109
- return Math.floor(nChars / tabSize);
110
- }
111
- function generateIndent(level, options) {
112
- if (options.insertSpaces) {
113
- return repeat(' ', level * options.tabSize);
114
- }
115
- else {
116
- return repeat('\t', level);
117
- }
118
- }
119
- function repeat(value, count) {
120
- let s = '';
121
- while (count > 0) {
122
- if ((count & 1) === 1) {
123
- s += value;
124
- }
125
- value += value;
126
- count = count >>> 1;
127
- }
128
- return s;
129
- }
130
- function isWhitespaceOnly(str) {
131
- return /^\s*$/.test(str);
132
- }