🎉 initiate project *astro_rewrite*
This commit is contained in:
parent
ffd4d5e86c
commit
2ba37bfbe3
8658 changed files with 2268794 additions and 2538 deletions
17
node_modules/@astrojs/language-server/dist/plugins/astro/AstroPlugin.d.ts
generated
vendored
Normal file
17
node_modules/@astrojs/language-server/dist/plugins/astro/AstroPlugin.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { CompletionContext, Diagnostic, FoldingRange, FormattingOptions, Position, TextEdit } from 'vscode-languageserver';
|
||||
import type { ConfigManager } from '../../core/config';
|
||||
import type { AstroDocument } from '../../core/documents';
|
||||
import type { AppCompletionList, Plugin } from '../interfaces';
|
||||
import type { LanguageServiceManager } from '../typescript/LanguageServiceManager';
|
||||
export declare class AstroPlugin implements Plugin {
|
||||
__name: string;
|
||||
private configManager;
|
||||
private readonly languageServiceManager;
|
||||
private readonly completionProvider;
|
||||
private readonly diagnosticsProvider;
|
||||
constructor(configManager: ConfigManager, languageServiceManager: LanguageServiceManager);
|
||||
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<AppCompletionList | null>;
|
||||
getDiagnostics(document: AstroDocument): Promise<Diagnostic[]>;
|
||||
formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
|
||||
getFoldingRanges(document: AstroDocument): FoldingRange[];
|
||||
}
|
||||
90
node_modules/@astrojs/language-server/dist/plugins/astro/AstroPlugin.js
generated
vendored
Normal file
90
node_modules/@astrojs/language-server/dist/plugins/astro/AstroPlugin.js
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AstroPlugin = void 0;
|
||||
const vscode_languageserver_1 = require("vscode-languageserver");
|
||||
const importPackage_1 = require("../../importPackage");
|
||||
const CompletionsProvider_1 = require("./features/CompletionsProvider");
|
||||
const DiagnosticsProvider_1 = require("./features/DiagnosticsProvider");
|
||||
class AstroPlugin {
|
||||
constructor(configManager, languageServiceManager) {
|
||||
this.__name = 'astro';
|
||||
this.configManager = configManager;
|
||||
this.languageServiceManager = languageServiceManager;
|
||||
this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(this.languageServiceManager);
|
||||
this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.languageServiceManager);
|
||||
}
|
||||
async getCompletions(document, position, completionContext) {
|
||||
const completions = this.completionProvider.getCompletions(document, position, completionContext);
|
||||
return completions;
|
||||
}
|
||||
async getDiagnostics(document) {
|
||||
return await this.diagnosticsProvider.getDiagnostics(document);
|
||||
}
|
||||
async formatDocument(document, options) {
|
||||
const filePath = document.getFilePath();
|
||||
if (!filePath) {
|
||||
return [];
|
||||
}
|
||||
const prettier = (0, importPackage_1.importPrettier)(filePath);
|
||||
const prettierConfig = (await prettier.resolveConfig(filePath, { editorconfig: true, useCache: false })) ?? {};
|
||||
const prettierVSConfig = await this.configManager.getPrettierVSConfig(document);
|
||||
const editorFormatConfig = options !== undefined // We need to check for options existing here because some editors might not have it
|
||||
? {
|
||||
tabWidth: options.tabSize,
|
||||
useTabs: !options.insertSpaces,
|
||||
}
|
||||
: {};
|
||||
// Return a config with the following cascade:
|
||||
// - Prettier config file should always win if it exists, if it doesn't:
|
||||
// - Prettier config from the VS Code extension is used, if it doesn't exist:
|
||||
// - Use the editor's basic configuration settings
|
||||
const resultConfig = returnObjectIfHasKeys(prettierConfig) || returnObjectIfHasKeys(prettierVSConfig) || editorFormatConfig;
|
||||
const fileInfo = await prettier.getFileInfo(filePath, { ignorePath: '.prettierignore' });
|
||||
if (fileInfo.ignored) {
|
||||
return [];
|
||||
}
|
||||
const result = prettier.format(document.getText(), {
|
||||
...resultConfig,
|
||||
plugins: [...getAstroPrettierPlugin(), ...(resultConfig.plugins ?? [])],
|
||||
parser: 'astro',
|
||||
});
|
||||
return document.getText() === result
|
||||
? []
|
||||
: [vscode_languageserver_1.TextEdit.replace(vscode_languageserver_1.Range.create(document.positionAt(0), document.positionAt(document.getTextLength())), result)];
|
||||
function getAstroPrettierPlugin() {
|
||||
const hasPluginLoadedAlready = prettier.getSupportInfo().languages.some((l) => l.name === 'astro');
|
||||
return hasPluginLoadedAlready ? [] : [(0, importPackage_1.getPrettierPluginPath)(filePath)];
|
||||
}
|
||||
}
|
||||
getFoldingRanges(document) {
|
||||
const foldingRanges = [];
|
||||
const { frontmatter } = document.astroMeta;
|
||||
// Currently editing frontmatter, don't fold
|
||||
if (frontmatter.state !== 'closed')
|
||||
return foldingRanges;
|
||||
// The way folding ranges work is by folding anything between the starting position and the ending one, as such
|
||||
// the start in this case should be after the frontmatter start (after the starting ---) until the last character
|
||||
// of the last line of the frontmatter before its ending (before the closing ---)
|
||||
// ---
|
||||
// ^ -- start
|
||||
// console.log("Astro")
|
||||
// --- ^ -- end
|
||||
const start = document.positionAt(frontmatter.startOffset + 3);
|
||||
const end = document.positionAt(frontmatter.endOffset - 1);
|
||||
return [
|
||||
{
|
||||
startLine: start.line,
|
||||
startCharacter: start.character,
|
||||
endLine: end.line,
|
||||
endCharacter: end.character,
|
||||
kind: vscode_languageserver_1.FoldingRangeKind.Imports,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
exports.AstroPlugin = AstroPlugin;
|
||||
function returnObjectIfHasKeys(obj) {
|
||||
if (Object.keys(obj || {}).length > 0) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
17
node_modules/@astrojs/language-server/dist/plugins/astro/features/CompletionsProvider.d.ts
generated
vendored
Normal file
17
node_modules/@astrojs/language-server/dist/plugins/astro/features/CompletionsProvider.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { CompletionContext, Position } from 'vscode-languageserver';
|
||||
import type { AstroDocument } from '../../../core/documents';
|
||||
import type { AppCompletionList, CompletionsProvider } from '../../interfaces';
|
||||
import type { LanguageServiceManager } from '../../typescript/LanguageServiceManager';
|
||||
export declare class CompletionsProviderImpl implements CompletionsProvider {
|
||||
private readonly languageServiceManager;
|
||||
private readonly ts;
|
||||
private lastCompletion;
|
||||
directivesHTMLLang: import("vscode-html-languageservice").LanguageService;
|
||||
constructor(languageServiceManager: LanguageServiceManager);
|
||||
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<AppCompletionList | null>;
|
||||
private getComponentScriptCompletion;
|
||||
private getPropCompletionsAndFilePath;
|
||||
private getImportedSymbol;
|
||||
private getPropType;
|
||||
private getCompletionItemForProperty;
|
||||
}
|
||||
242
node_modules/@astrojs/language-server/dist/plugins/astro/features/CompletionsProvider.js
generated
vendored
Normal file
242
node_modules/@astrojs/language-server/dist/plugins/astro/features/CompletionsProvider.js
generated
vendored
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CompletionsProviderImpl = void 0;
|
||||
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
|
||||
const vscode_languageserver_1 = require("vscode-languageserver");
|
||||
const utils_1 = require("../../../core/documents/utils");
|
||||
const astro_attributes_1 = require("../../html/features/astro-attributes");
|
||||
const utils_2 = require("../../html/utils");
|
||||
const utils_3 = require("../../typescript/utils");
|
||||
class CompletionsProviderImpl {
|
||||
constructor(languageServiceManager) {
|
||||
this.lastCompletion = null;
|
||||
this.directivesHTMLLang = (0, vscode_html_languageservice_1.getLanguageService)({
|
||||
customDataProviders: [astro_attributes_1.astroDirectives],
|
||||
useDefaultDataProvider: false,
|
||||
});
|
||||
this.languageServiceManager = languageServiceManager;
|
||||
this.ts = languageServiceManager.docContext.ts;
|
||||
}
|
||||
async getCompletions(document, position, completionContext) {
|
||||
let items = [];
|
||||
const html = document.html;
|
||||
const offset = document.offsetAt(position);
|
||||
const node = html.findNodeAt(offset);
|
||||
const insideExpression = (0, utils_1.isInsideExpression)(document.getText(), node.start, offset);
|
||||
if (completionContext?.triggerCharacter === '-' && node.parent === undefined && !insideExpression) {
|
||||
const frontmatter = this.getComponentScriptCompletion(document, position);
|
||||
if (frontmatter)
|
||||
items.push(frontmatter);
|
||||
}
|
||||
if ((0, utils_1.isInComponentStartTag)(html, offset) && !insideExpression) {
|
||||
const { completions: props, componentFilePath } = await this.getPropCompletionsAndFilePath(document, position, completionContext);
|
||||
if (props.length) {
|
||||
items.push(...props);
|
||||
}
|
||||
const isAstro = componentFilePath?.endsWith('.astro');
|
||||
if (!isAstro && node.tag !== 'Fragment') {
|
||||
const directives = (0, utils_2.removeDataAttrCompletion)(this.directivesHTMLLang.doComplete(document, position, html).items);
|
||||
items.push(...directives);
|
||||
}
|
||||
}
|
||||
return vscode_languageserver_1.CompletionList.create(items, true);
|
||||
}
|
||||
getComponentScriptCompletion(document, position) {
|
||||
const base = {
|
||||
kind: vscode_languageserver_1.CompletionItemKind.Snippet,
|
||||
label: '---',
|
||||
sortText: '\0',
|
||||
preselect: true,
|
||||
detail: 'Create component script block',
|
||||
insertTextFormat: vscode_languageserver_1.InsertTextFormat.Snippet,
|
||||
commitCharacters: [],
|
||||
};
|
||||
const prefix = document.getLineUntilOffset(document.offsetAt(position));
|
||||
if (document.astroMeta.frontmatter.state === null) {
|
||||
return {
|
||||
...base,
|
||||
insertText: '---\n$0\n---',
|
||||
textEdit: prefix.match(/^\s*\-+/)
|
||||
? vscode_languageserver_1.TextEdit.replace({ start: { ...position, character: 0 }, end: position }, '---\n$0\n---')
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
if (document.astroMeta.frontmatter.state === 'open') {
|
||||
let insertText = '---';
|
||||
// If the current line is a full component script starter/ender, the user expects a full frontmatter
|
||||
// completion and not just a completion for "---" on the same line (which result in, well, nothing)
|
||||
if (prefix === '---') {
|
||||
insertText = '---\n$0\n---';
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
insertText,
|
||||
detail: insertText === '---' ? 'Close component script block' : 'Create component script block',
|
||||
textEdit: prefix.match(/^\s*\-+/)
|
||||
? vscode_languageserver_1.TextEdit.replace({ start: { ...position, character: 0 }, end: position }, insertText)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async getPropCompletionsAndFilePath(document, position, completionContext) {
|
||||
const offset = document.offsetAt(position);
|
||||
const html = document.html;
|
||||
const node = html.findNodeAt(offset);
|
||||
if (!(0, utils_1.isPossibleComponent)(node)) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
const inAttribute = node.start + node.tag.length < offset;
|
||||
if (!inAttribute) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
if (completionContext?.triggerCharacter === '/' || completionContext?.triggerCharacter === '>') {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
// If inside of attribute value, skip.
|
||||
if (completionContext &&
|
||||
completionContext.triggerKind === vscode_languageserver_1.CompletionTriggerKind.TriggerCharacter &&
|
||||
completionContext.triggerCharacter === '"') {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
const componentName = node.tag;
|
||||
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
||||
// Get the source file
|
||||
const tsFilePath = tsDoc.filePath;
|
||||
const program = lang.getProgram();
|
||||
const sourceFile = program?.getSourceFile(tsFilePath);
|
||||
const typeChecker = program?.getTypeChecker();
|
||||
if (!sourceFile || !typeChecker) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
// Get the import statement
|
||||
const imp = this.getImportedSymbol(sourceFile, componentName);
|
||||
const importType = imp && typeChecker.getTypeAtLocation(imp);
|
||||
if (!importType) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
const symbol = importType.getSymbol();
|
||||
if (!symbol) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
const symbolDeclaration = symbol.declarations;
|
||||
if (!symbolDeclaration) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
const filePath = symbolDeclaration[0].getSourceFile().fileName;
|
||||
const componentSnapshot = await this.languageServiceManager.getSnapshot(filePath);
|
||||
if (this.lastCompletion) {
|
||||
if (this.lastCompletion.tag === componentName &&
|
||||
this.lastCompletion.documentVersion == componentSnapshot.version) {
|
||||
return { completions: this.lastCompletion.completions, componentFilePath: filePath };
|
||||
}
|
||||
}
|
||||
// Get the component's props type
|
||||
const componentType = this.getPropType(symbolDeclaration, typeChecker);
|
||||
if (!componentType) {
|
||||
return { completions: [], componentFilePath: null };
|
||||
}
|
||||
let completionItems = [];
|
||||
// Add completions for this component's props type properties
|
||||
const properties = componentType.getProperties().filter((property) => property.name !== 'children') || [];
|
||||
properties.forEach((property) => {
|
||||
const type = typeChecker.getTypeOfSymbolAtLocation(property, imp);
|
||||
let completionItem = this.getCompletionItemForProperty(property, typeChecker, type);
|
||||
completionItems.push(completionItem);
|
||||
});
|
||||
this.lastCompletion = {
|
||||
tag: componentName,
|
||||
documentVersion: componentSnapshot.version,
|
||||
completions: completionItems,
|
||||
};
|
||||
return { completions: completionItems, componentFilePath: filePath };
|
||||
}
|
||||
getImportedSymbol(sourceFile, identifier) {
|
||||
for (let list of sourceFile.getChildren()) {
|
||||
for (let node of list.getChildren()) {
|
||||
if (this.ts.isImportDeclaration(node)) {
|
||||
let clauses = node.importClause;
|
||||
if (!clauses)
|
||||
continue;
|
||||
let namedImport = clauses.getChildAt(0);
|
||||
if (this.ts.isNamedImports(namedImport)) {
|
||||
for (let imp of namedImport.elements) {
|
||||
// Iterate the named imports
|
||||
if (imp.name.getText() === identifier) {
|
||||
return imp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.ts.isIdentifier(namedImport)) {
|
||||
if (namedImport.getText() === identifier) {
|
||||
return namedImport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getPropType(declarations, typeChecker) {
|
||||
for (const decl of declarations) {
|
||||
const fileName = (0, utils_3.toVirtualFilePath)(decl.getSourceFile().fileName);
|
||||
if (fileName.endsWith('.tsx') || fileName.endsWith('.jsx') || fileName.endsWith('.d.ts')) {
|
||||
if (!this.ts.isFunctionDeclaration(decl) && !this.ts.isFunctionTypeNode(decl)) {
|
||||
console.error(`We only support functions declarations at the moment`);
|
||||
continue;
|
||||
}
|
||||
const fn = decl;
|
||||
if (!fn.parameters.length)
|
||||
continue;
|
||||
const param1 = fn.parameters[0];
|
||||
const propType = typeChecker.getTypeAtLocation(param1);
|
||||
return propType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getCompletionItemForProperty(mem, typeChecker, type) {
|
||||
const typeString = typeChecker.typeToString(type);
|
||||
let insertText = mem.name;
|
||||
switch (typeString) {
|
||||
case 'string':
|
||||
insertText = `${mem.name}="$1"`;
|
||||
break;
|
||||
case 'boolean':
|
||||
insertText = mem.name;
|
||||
break;
|
||||
default:
|
||||
insertText = `${mem.name}={$1}`;
|
||||
break;
|
||||
}
|
||||
let item = {
|
||||
label: mem.name,
|
||||
detail: typeString,
|
||||
insertText: insertText,
|
||||
insertTextFormat: vscode_languageserver_1.InsertTextFormat.Snippet,
|
||||
commitCharacters: [],
|
||||
// Ensure that props shows up first as a completion, despite this plugin being ran after the HTML one
|
||||
sortText: '\0',
|
||||
};
|
||||
if (mem.flags & this.ts.SymbolFlags.Optional) {
|
||||
item.filterText = item.label;
|
||||
item.label += '?';
|
||||
// Put optional props at a lower priority
|
||||
item.sortText = '_';
|
||||
}
|
||||
mem.getDocumentationComment(typeChecker);
|
||||
let description = mem
|
||||
.getDocumentationComment(typeChecker)
|
||||
.map((val) => val.text)
|
||||
.join('\n');
|
||||
if (description) {
|
||||
let docs = {
|
||||
kind: vscode_languageserver_1.MarkupKind.Markdown,
|
||||
value: description,
|
||||
};
|
||||
item.documentation = docs;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
exports.CompletionsProviderImpl = CompletionsProviderImpl;
|
||||
10
node_modules/@astrojs/language-server/dist/plugins/astro/features/DiagnosticsProvider.d.ts
generated
vendored
Normal file
10
node_modules/@astrojs/language-server/dist/plugins/astro/features/DiagnosticsProvider.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Diagnostic } from 'vscode-languageserver-types';
|
||||
import { AstroDocument } from '../../../core/documents';
|
||||
import { DiagnosticsProvider } from '../../interfaces';
|
||||
import { LanguageServiceManager } from '../../typescript/LanguageServiceManager';
|
||||
export declare class DiagnosticsProviderImpl implements DiagnosticsProvider {
|
||||
private languageServiceManager;
|
||||
constructor(languageServiceManager: LanguageServiceManager);
|
||||
getDiagnostics(document: AstroDocument): Promise<Diagnostic[]>;
|
||||
private compilerMessageToDiagnostic;
|
||||
}
|
||||
23
node_modules/@astrojs/language-server/dist/plugins/astro/features/DiagnosticsProvider.js
generated
vendored
Normal file
23
node_modules/@astrojs/language-server/dist/plugins/astro/features/DiagnosticsProvider.js
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.DiagnosticsProviderImpl = void 0;
|
||||
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
|
||||
class DiagnosticsProviderImpl {
|
||||
constructor(languageServiceManager) {
|
||||
this.languageServiceManager = languageServiceManager;
|
||||
}
|
||||
async getDiagnostics(document) {
|
||||
const { tsDoc } = (await this.languageServiceManager.getLSAndTSDoc(document));
|
||||
return tsDoc.compilerDiagnostics.map(this.compilerMessageToDiagnostic);
|
||||
}
|
||||
compilerMessageToDiagnostic(message) {
|
||||
return {
|
||||
message: message.text + '\n\n' + message.hint,
|
||||
range: vscode_languageserver_types_1.Range.create(message.location.line - 1, message.location.column - 1, message.location.line, message.location.length),
|
||||
code: message.code,
|
||||
severity: message.severity,
|
||||
source: 'astro',
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.DiagnosticsProviderImpl = DiagnosticsProviderImpl;
|
||||
Loading…
Add table
Add a link
Reference in a new issue