summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/astro-languageserver/src/core/documents/Document.ts2
-rw-r--r--tools/astro-languageserver/src/core/documents/DocumentBase.ts237
-rw-r--r--tools/astro-languageserver/src/core/documents/DocumentMapper.ts316
-rw-r--r--tools/astro-languageserver/src/core/documents/index.ts2
-rw-r--r--tools/astro-languageserver/src/core/documents/utils.ts84
-rw-r--r--tools/astro-languageserver/src/plugins/css/CSSDocument.ts144
-rw-r--r--tools/astro-languageserver/src/plugins/css/CSSPlugin.ts127
-rw-r--r--tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts110
-rw-r--r--tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts81
-rw-r--r--tools/astro-languageserver/src/plugins/css/service.ts50
-rw-r--r--tools/astro-languageserver/src/plugins/index.ts2
11 files changed, 515 insertions, 640 deletions
diff --git a/tools/astro-languageserver/src/core/documents/Document.ts b/tools/astro-languageserver/src/core/documents/Document.ts
index 5ee080fdf..04a460a08 100644
--- a/tools/astro-languageserver/src/core/documents/Document.ts
+++ b/tools/astro-languageserver/src/core/documents/Document.ts
@@ -26,7 +26,7 @@ export class Document implements TextDocument {
this.html = parseHtml(this.content);
this.astro = parseAstro(this.content);
this.styleInfo = extractStyleTag(this.content, this.html);
- if(this.styleInfo) {
+ if (this.styleInfo) {
this.styleInfo.attributes.lang = 'css';
}
}
diff --git a/tools/astro-languageserver/src/core/documents/DocumentBase.ts b/tools/astro-languageserver/src/core/documents/DocumentBase.ts
index 19120f1c0..299feeb62 100644
--- a/tools/astro-languageserver/src/core/documents/DocumentBase.ts
+++ b/tools/astro-languageserver/src/core/documents/DocumentBase.ts
@@ -5,140 +5,137 @@ import { Position, TextDocument } from 'vscode-languageserver';
* Represents a textual document.
*/
export abstract class ReadableDocument implements TextDocument {
- /**
- * Get the text content of the document
- */
- abstract getText(): string;
-
- /**
- * Returns the url of the document
- */
- abstract getURL(): string;
-
- /**
- * Returns the file path if the url scheme is file
- */
- abstract getFilePath(): string | null;
-
- /**
- * Current version of the document.
- */
- public version = 0;
-
- /**
- * Get the length of the document's content
- */
- getTextLength(): number {
- return this.getText().length;
+ /**
+ * Get the text content of the document
+ */
+ abstract getText(): string;
+
+ /**
+ * Returns the url of the document
+ */
+ abstract getURL(): string;
+
+ /**
+ * Returns the file path if the url scheme is file
+ */
+ abstract getFilePath(): string | null;
+
+ /**
+ * Current version of the document.
+ */
+ public version = 0;
+
+ /**
+ * Get the length of the document's content
+ */
+ getTextLength(): number {
+ return this.getText().length;
+ }
+
+ /**
+ * Get the line and character based on the offset
+ * @param offset The index of the position
+ */
+ positionAt(offset: number): Position {
+ offset = clamp(offset, 0, this.getTextLength());
+
+ const lineOffsets = this.getLineOffsets();
+ let low = 0;
+ let high = lineOffsets.length;
+ if (high === 0) {
+ return Position.create(0, offset);
}
- /**
- * Get the line and character based on the offset
- * @param offset The index of the position
- */
- positionAt(offset: number): Position {
- offset = clamp(offset, 0, this.getTextLength());
-
- const lineOffsets = this.getLineOffsets();
- let low = 0;
- let high = lineOffsets.length;
- if (high === 0) {
- return Position.create(0, offset);
- }
-
- while (low < high) {
- const mid = Math.floor((low + high) / 2);
- if (lineOffsets[mid] > offset) {
- high = mid;
- } else {
- low = mid + 1;
- }
- }
-
- // low is the least x for which the line offset is larger than the current offset
- // or array.length if no line offset is larger than the current offset
- const line = low - 1;
- return Position.create(line, offset - lineOffsets[line]);
+ while (low < high) {
+ const mid = Math.floor((low + high) / 2);
+ if (lineOffsets[mid] > offset) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
}
- /**
- * Get the index of the line and character position
- * @param position Line and character position
- */
- offsetAt(position: Position): number {
- const lineOffsets = this.getLineOffsets();
-
- if (position.line >= lineOffsets.length) {
- return this.getTextLength();
- } else if (position.line < 0) {
- return 0;
- }
-
- const lineOffset = lineOffsets[position.line];
- const nextLineOffset =
- position.line + 1 < lineOffsets.length
- ? lineOffsets[position.line + 1]
- : this.getTextLength();
-
- return clamp(nextLineOffset, lineOffset, lineOffset + position.character);
+ // low is the least x for which the line offset is larger than the current offset
+ // or array.length if no line offset is larger than the current offset
+ const line = low - 1;
+ return Position.create(line, offset - lineOffsets[line]);
+ }
+
+ /**
+ * Get the index of the line and character position
+ * @param position Line and character position
+ */
+ offsetAt(position: Position): number {
+ const lineOffsets = this.getLineOffsets();
+
+ if (position.line >= lineOffsets.length) {
+ return this.getTextLength();
+ } else if (position.line < 0) {
+ return 0;
}
- private getLineOffsets() {
- const lineOffsets = [];
- const text = this.getText();
- let isLineStart = true;
-
- for (let i = 0; i < text.length; i++) {
- if (isLineStart) {
- lineOffsets.push(i);
- isLineStart = false;
- }
- const ch = text.charAt(i);
- isLineStart = ch === '\r' || ch === '\n';
- if (ch === '\r' && i + 1 < text.length && text.charAt(i + 1) === '\n') {
- i++;
- }
- }
-
- if (isLineStart && text.length > 0) {
- lineOffsets.push(text.length);
- }
-
- return lineOffsets;
+ const lineOffset = lineOffsets[position.line];
+ const nextLineOffset = position.line + 1 < lineOffsets.length ? lineOffsets[position.line + 1] : this.getTextLength();
+
+ return clamp(nextLineOffset, lineOffset, lineOffset + position.character);
+ }
+
+ private getLineOffsets() {
+ const lineOffsets = [];
+ const text = this.getText();
+ let isLineStart = true;
+
+ for (let i = 0; i < text.length; i++) {
+ if (isLineStart) {
+ lineOffsets.push(i);
+ isLineStart = false;
+ }
+ const ch = text.charAt(i);
+ isLineStart = ch === '\r' || ch === '\n';
+ if (ch === '\r' && i + 1 < text.length && text.charAt(i + 1) === '\n') {
+ i++;
+ }
}
- /**
- * Implements TextDocument
- */
- get uri(): string {
- return this.getURL();
+ if (isLineStart && text.length > 0) {
+ lineOffsets.push(text.length);
}
- get lineCount(): number {
- return this.getText().split(/\r?\n/).length;
- }
+ return lineOffsets;
+ }
+
+ /**
+ * Implements TextDocument
+ */
+ get uri(): string {
+ return this.getURL();
+ }
+
+ get lineCount(): number {
+ return this.getText().split(/\r?\n/).length;
+ }
- abstract languageId: string;
+ abstract languageId: string;
}
/**
* Represents a textual document that can be manipulated.
*/
export abstract class WritableDocument extends ReadableDocument {
- /**
- * Set the text content of the document
- * @param text The new text content
- */
- abstract setText(text: string): void;
-
- /**
- * Update the text between two positions.
- * @param text The new text slice
- * @param start Start offset of the new text
- * @param end End offset of the new text
- */
- update(text: string, start: number, end: number): void {
- const content = this.getText();
- this.setText(content.slice(0, start) + text + content.slice(end));
- }
-} \ No newline at end of file
+ /**
+ * Set the text content of the document
+ * @param text The new text content
+ */
+ abstract setText(text: string): void;
+
+ /**
+ * Update the text between two positions.
+ * @param text The new text slice
+ * @param start Start offset of the new text
+ * @param end End offset of the new text
+ */
+ update(text: string, start: number, end: number): void {
+ const content = this.getText();
+ this.setText(content.slice(0, start) + text + content.slice(end));
+ }
+}
diff --git a/tools/astro-languageserver/src/core/documents/DocumentMapper.ts b/tools/astro-languageserver/src/core/documents/DocumentMapper.ts
index 815ce06ff..8a6a6ef29 100644
--- a/tools/astro-languageserver/src/core/documents/DocumentMapper.ts
+++ b/tools/astro-languageserver/src/core/documents/DocumentMapper.ts
@@ -11,7 +11,7 @@ import {
CodeAction,
SelectionRange,
TextEdit,
- InsertReplaceEdit
+ InsertReplaceEdit,
} from 'vscode-languageserver';
import { TagInformation, offsetAt, positionAt } from './utils';
import { SourceMapConsumer } from 'source-map';
@@ -47,331 +47,271 @@ export interface DocumentMapper {
}
/**
-* Does not map, returns positions as is.
-*/
+ * Does not map, returns positions as is.
+ */
export class IdentityMapper implements DocumentMapper {
constructor(private url: string, private parent?: DocumentMapper) {}
getOriginalPosition(generatedPosition: Position): Position {
- if (this.parent) {
- generatedPosition = this.getOriginalPosition(generatedPosition);
- }
+ if (this.parent) {
+ generatedPosition = this.getOriginalPosition(generatedPosition);
+ }
- return generatedPosition;
+ return generatedPosition;
}
getGeneratedPosition(originalPosition: Position): Position {
- if (this.parent) {
- originalPosition = this.getGeneratedPosition(originalPosition);
- }
+ if (this.parent) {
+ originalPosition = this.getGeneratedPosition(originalPosition);
+ }
- return originalPosition;
+ return originalPosition;
}
isInGenerated(position: Position): boolean {
- if (this.parent && !this.parent.isInGenerated(position)) {
- return false;
- }
+ if (this.parent && !this.parent.isInGenerated(position)) {
+ return false;
+ }
- return true;
+ return true;
}
getURL(): string {
- return this.url;
+ return this.url;
}
destroy() {
- this.parent?.destroy?.();
+ this.parent?.destroy?.();
}
}
/**
-* Maps positions in a fragment relative to a parent.
-*/
+ * Maps positions in a fragment relative to a parent.
+ */
export class FragmentMapper implements DocumentMapper {
- constructor(
- private originalText: string,
- private tagInfo: TagInformation,
- private url: string
- ) {}
+ constructor(private originalText: string, private tagInfo: TagInformation, private url: string) {}
getOriginalPosition(generatedPosition: Position): Position {
- const parentOffset = this.offsetInParent(offsetAt(generatedPosition, this.tagInfo.content));
- return positionAt(parentOffset, this.originalText);
+ const parentOffset = this.offsetInParent(offsetAt(generatedPosition, this.tagInfo.content));
+ return positionAt(parentOffset, this.originalText);
}
private offsetInParent(offset: number): number {
- return this.tagInfo.start + offset;
+ return this.tagInfo.start + offset;
}
getGeneratedPosition(originalPosition: Position): Position {
- const fragmentOffset = offsetAt(originalPosition, this.originalText) - this.tagInfo.start;
- return positionAt(fragmentOffset, this.tagInfo.content);
+ const fragmentOffset = offsetAt(originalPosition, this.originalText) - this.tagInfo.start;
+ return positionAt(fragmentOffset, this.tagInfo.content);
}
isInGenerated(pos: Position): boolean {
- const offset = offsetAt(pos, this.originalText);
- return offset >= this.tagInfo.start && offset <= this.tagInfo.end;
+ const offset = offsetAt(pos, this.originalText);
+ return offset >= this.tagInfo.start && offset <= this.tagInfo.end;
}
getURL(): string {
- return this.url;
+ return this.url;
}
}
export class SourceMapDocumentMapper implements DocumentMapper {
- constructor(
- protected consumer: SourceMapConsumer,
- protected sourceUri: string,
- private parent?: DocumentMapper
- ) {}
+ constructor(protected consumer: SourceMapConsumer, protected sourceUri: string, private parent?: DocumentMapper) {}
getOriginalPosition(generatedPosition: Position): Position {
- if (this.parent) {
- generatedPosition = this.parent.getOriginalPosition(generatedPosition);
- }
-
- if (generatedPosition.line < 0) {
- return { line: -1, character: -1 };
- }
-
- const mapped = this.consumer.originalPositionFor({
- line: generatedPosition.line + 1,
- column: generatedPosition.character
- });
-
- if (!mapped) {
- return { line: -1, character: -1 };
- }
-
- if (mapped.line === 0) {
- console.log('Got 0 mapped line from', generatedPosition, 'col was', mapped.column);
- }
-
- return {
- line: (mapped.line || 0) - 1,
- character: mapped.column || 0
- };
+ if (this.parent) {
+ generatedPosition = this.parent.getOriginalPosition(generatedPosition);
+ }
+
+ if (generatedPosition.line < 0) {
+ return { line: -1, character: -1 };
+ }
+
+ const mapped = this.consumer.originalPositionFor({
+ line: generatedPosition.line + 1,
+ column: generatedPosition.character,
+ });
+
+ if (!mapped) {
+ return { line: -1, character: -1 };
+ }
+
+ if (mapped.line === 0) {
+ console.log('Got 0 mapped line from', generatedPosition, 'col was', mapped.column);
+ }
+
+ return {
+ line: (mapped.line || 0) - 1,
+ character: mapped.column || 0,
+ };
}
getGeneratedPosition(originalPosition: Position): Position {
- if (this.parent) {
- originalPosition = this.parent.getGeneratedPosition(originalPosition);
- }
-
- const mapped = this.consumer.generatedPositionFor({
- line: originalPosition.line + 1,
- column: originalPosition.character,
- source: this.sourceUri
- });
-
- if (!mapped) {
- return { line: -1, character: -1 };
- }
-
- const result = {
- line: (mapped.line || 0) - 1,
- character: mapped.column || 0
- };
-
- if (result.line < 0) {
- return result;
- }
-
+ if (this.parent) {
+ originalPosition = this.parent.getGeneratedPosition(originalPosition);
+ }
+
+ const mapped = this.consumer.generatedPositionFor({
+ line: originalPosition.line + 1,
+ column: originalPosition.character,
+ source: this.sourceUri,
+ });
+
+ if (!mapped) {
+ return { line: -1, character: -1 };
+ }
+
+ const result = {
+ line: (mapped.line || 0) - 1,
+ character: mapped.column || 0,
+ };
+
+ if (result.line < 0) {
return result;
+ }
+
+ return result;
}
isInGenerated(position: Position): boolean {
- if (this.parent && !this.isInGenerated(position)) {
- return false;
- }
+ if (this.parent && !this.isInGenerated(position)) {
+ return false;
+ }
- const generated = this.getGeneratedPosition(position);
- return generated.line >= 0;
+ const generated = this.getGeneratedPosition(position);
+ return generated.line >= 0;
}
getURL(): string {
- return this.sourceUri;
+ return this.sourceUri;
}
/**
* Needs to be called when source mapper is no longer needed in order to prevent memory leaks.
*/
destroy() {
- this.parent?.destroy?.();
- this.consumer.destroy();
+ this.parent?.destroy?.();
+ this.consumer.destroy();
}
}
-export function mapRangeToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- range: Range
-): Range {
+export function mapRangeToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, range: Range): Range {
// DON'T use Range.create here! Positions might not be mapped
// and therefore return negative numbers, which makes Range.create throw.
// These invalid position need to be handled
// on a case-by-case basis in the calling functions.
const originalRange = {
- start: fragment.getOriginalPosition(range.start),
- end: fragment.getOriginalPosition(range.end)
+ start: fragment.getOriginalPosition(range.start),
+ end: fragment.getOriginalPosition(range.end),
};
// Range may be mapped one character short - reverse that for "in the same line" cases
if (
- originalRange.start.line === originalRange.end.line &&
- range.start.line === range.end.line &&
- originalRange.end.character - originalRange.start.character ===
- range.end.character - range.start.character - 1
+ originalRange.start.line === originalRange.end.line &&
+ range.start.line === range.end.line &&
+ originalRange.end.character - originalRange.start.character === range.end.character - range.start.character - 1
) {
- originalRange.end.character += 1;
+ originalRange.end.character += 1;
}
return originalRange;
}
export function mapRangeToGenerated(fragment: DocumentMapper, range: Range): Range {
- return Range.create(
- fragment.getGeneratedPosition(range.start),
- fragment.getGeneratedPosition(range.end)
- );
+ return Range.create(fragment.getGeneratedPosition(range.start), fragment.getGeneratedPosition(range.end));
}
-export function mapCompletionItemToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- item: CompletionItem
-): CompletionItem {
+export function mapCompletionItemToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, item: CompletionItem): CompletionItem {
if (!item.textEdit) {
- return item;
+ return item;
}
return {
- ...item,
- textEdit: mapEditToOriginal(fragment, item.textEdit)
+ ...item,
+ textEdit: mapEditToOriginal(fragment, item.textEdit),
};
}
-export function mapHoverToParent(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- hover: Hover
-): Hover {
+export function mapHoverToParent(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, hover: Hover): Hover {
if (!hover.range) {
- return hover;
+ return hover;
}
return { ...hover, range: mapRangeToOriginal(fragment, hover.range) };
}
-export function mapObjWithRangeToOriginal<T extends { range: Range }>(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- objWithRange: T
-): T {
+export function mapObjWithRangeToOriginal<T extends { range: Range }>(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, objWithRange: T): T {
return { ...objWithRange, range: mapRangeToOriginal(fragment, objWithRange.range) };
}
-export function mapInsertReplaceEditToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- edit: InsertReplaceEdit
-): InsertReplaceEdit {
+export function mapInsertReplaceEditToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, edit: InsertReplaceEdit): InsertReplaceEdit {
return {
- ...edit,
- insert: mapRangeToOriginal(fragment, edit.insert),
- replace: mapRangeToOriginal(fragment, edit.replace)
+ ...edit,
+ insert: mapRangeToOriginal(fragment, edit.insert),
+ replace: mapRangeToOriginal(fragment, edit.replace),
};
}
-export function mapEditToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- edit: TextEdit | InsertReplaceEdit
-): TextEdit | InsertReplaceEdit {
- return TextEdit.is(edit)
- ? mapObjWithRangeToOriginal(fragment, edit)
- : mapInsertReplaceEditToOriginal(fragment, edit);
+export function mapEditToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, edit: TextEdit | InsertReplaceEdit): TextEdit | InsertReplaceEdit {
+ return TextEdit.is(edit) ? mapObjWithRangeToOriginal(fragment, edit) : mapInsertReplaceEditToOriginal(fragment, edit);
}
-export function mapDiagnosticToGenerated(
- fragment: DocumentMapper,
- diagnostic: Diagnostic
-): Diagnostic {
+export function mapDiagnosticToGenerated(fragment: DocumentMapper, diagnostic: Diagnostic): Diagnostic {
return { ...diagnostic, range: mapRangeToGenerated(fragment, diagnostic.range) };
}
-export function mapColorPresentationToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- presentation: ColorPresentation
-): ColorPresentation {
+export function mapColorPresentationToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, presentation: ColorPresentation): ColorPresentation {
const item = {
- ...presentation
+ ...presentation,
};
if (item.textEdit) {
- item.textEdit = mapObjWithRangeToOriginal(fragment, item.textEdit);
+ item.textEdit = mapObjWithRangeToOriginal(fragment, item.textEdit);
}
if (item.additionalTextEdits) {
- item.additionalTextEdits = item.additionalTextEdits.map((edit) =>
- mapObjWithRangeToOriginal(fragment, edit)
- );
+ item.additionalTextEdits = item.additionalTextEdits.map((edit) => mapObjWithRangeToOriginal(fragment, edit));
}
return item;
}
-export function mapSymbolInformationToOriginal(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- info: SymbolInformation
-): SymbolInformation {
+export function mapSymbolInformationToOriginal(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, info: SymbolInformation): SymbolInformation {
return { ...info, location: mapObjWithRangeToOriginal(fragment, info.location) };
}
-export function mapLocationLinkToOriginal(
- fragment: DocumentMapper,
- def: LocationLink
-): LocationLink {
+export function mapLocationLinkToOriginal(fragment: DocumentMapper, def: LocationLink): LocationLink {
return LocationLink.create(
- def.targetUri,
- fragment.getURL() === def.targetUri
- ? mapRangeToOriginal(fragment, def.targetRange)
- : def.targetRange,
- fragment.getURL() === def.targetUri
- ? mapRangeToOriginal(fragment, def.targetSelectionRange)
- : def.targetSelectionRange,
- def.originSelectionRange
- ? mapRangeToOriginal(fragment, def.originSelectionRange)
- : undefined
+ def.targetUri,
+ fragment.getURL() === def.targetUri ? mapRangeToOriginal(fragment, def.targetRange) : def.targetRange,
+ fragment.getURL() === def.targetUri ? mapRangeToOriginal(fragment, def.targetSelectionRange) : def.targetSelectionRange,
+ def.originSelectionRange ? mapRangeToOriginal(fragment, def.originSelectionRange) : undefined
);
}
export function mapTextDocumentEditToOriginal(fragment: DocumentMapper, edit: TextDocumentEdit) {
if (edit.textDocument.uri !== fragment.getURL()) {
- return edit;
+ return edit;
}
return TextDocumentEdit.create(
- edit.textDocument,
- edit.edits.map((textEdit) => mapObjWithRangeToOriginal(fragment, textEdit))
+ edit.textDocument,
+ edit.edits.map((textEdit) => mapObjWithRangeToOriginal(fragment, textEdit))
);
}
export function mapCodeActionToOriginal(fragment: DocumentMapper, codeAction: CodeAction) {
return CodeAction.create(
- codeAction.title,
- {
- documentChanges: codeAction.edit!.documentChanges!.map((edit) =>
- mapTextDocumentEditToOriginal(fragment, edit as TextDocumentEdit)
- )
- },
- codeAction.kind
+ codeAction.title,
+ {
+ documentChanges: codeAction.edit!.documentChanges!.map((edit) => mapTextDocumentEditToOriginal(fragment, edit as TextDocumentEdit)),
+ },
+ codeAction.kind
);
}
-export function mapSelectionRangeToParent(
- fragment: Pick<DocumentMapper, 'getOriginalPosition'>,
- selectionRange: SelectionRange
-): SelectionRange {
+export function mapSelectionRangeToParent(fragment: Pick<DocumentMapper, 'getOriginalPosition'>, selectionRange: SelectionRange): SelectionRange {
const { range, parent } = selectionRange;
- return SelectionRange.create(
- mapRangeToOriginal(fragment, range),
- parent && mapSelectionRangeToParent(fragment, parent)
- );
-} \ No newline at end of file
+ return SelectionRange.create(mapRangeToOriginal(fragment, range), parent && mapSelectionRangeToParent(fragment, parent));
+}
diff --git a/tools/astro-languageserver/src/core/documents/index.ts b/tools/astro-languageserver/src/core/documents/index.ts
index 496107f3c..5dc0eb61f 100644
--- a/tools/astro-languageserver/src/core/documents/index.ts
+++ b/tools/astro-languageserver/src/core/documents/index.ts
@@ -2,4 +2,4 @@ export * from './Document';
export * from './DocumentBase';
export * from './DocumentManager';
export * from './DocumentMapper';
-export * from './utils'; \ No newline at end of file
+export * from './utils';
diff --git a/tools/astro-languageserver/src/core/documents/utils.ts b/tools/astro-languageserver/src/core/documents/utils.ts
index 220994f4c..227a76176 100644
--- a/tools/astro-languageserver/src/core/documents/utils.ts
+++ b/tools/astro-languageserver/src/core/documents/utils.ts
@@ -1,6 +1,6 @@
import { HTMLDocument, Node, Position } from 'vscode-html-languageservice';
import { clamp } from '../../utils';
-import {parseHtml} from './parseHtml';
+import { parseHtml } from './parseHtml';
export interface TagInformation {
content: string;
@@ -12,28 +12,23 @@ export interface TagInformation {
container: { start: number; end: number };
}
-function parseAttributes(
- rawAttrs: Record<string, string | null> | undefined
-): Record<string, string> {
+function parseAttributes(rawAttrs: Record<string, string | null> | undefined): Record<string, string> {
const attrs: Record<string, string> = {};
if (!rawAttrs) {
- return attrs;
+ return attrs;
}
Object.keys(rawAttrs).forEach((attrName) => {
- const attrValue = rawAttrs[attrName];
- attrs[attrName] = attrValue === null ? attrName : removeOuterQuotes(attrValue);
+ const attrValue = rawAttrs[attrName];
+ attrs[attrName] = attrValue === null ? attrName : removeOuterQuotes(attrValue);
});
return attrs;
function removeOuterQuotes(attrValue: string) {
- if (
- (attrValue.startsWith('"') && attrValue.endsWith('"')) ||
- (attrValue.startsWith("'") && attrValue.endsWith("'"))
- ) {
- return attrValue.slice(1, attrValue.length - 1);
- }
- return attrValue;
+ if ((attrValue.startsWith('"') && attrValue.endsWith('"')) || (attrValue.startsWith("'") && attrValue.endsWith("'"))) {
+ return attrValue.slice(1, attrValue.length - 1);
+ }
+ return attrValue;
}
}
@@ -163,8 +158,8 @@ function getLineOffsets(text: string) {
}
export function* walk(node: Node): Generator<Node, void, unknown> {
- for(let child of node.children) {
- yield * walk(child);
+ for (let child of node.children) {
+ yield* walk(child);
}
yield node;
}
@@ -202,18 +197,13 @@ export function* walk(node: Node, startIndex = 0) {
* @param source text content to extract tag from
* @param tag the tag to extract
*/
- function extractTags(
- text: string,
- tag: 'script' | 'style' | 'template',
- html?: HTMLDocument
-): TagInformation[] {
+function extractTags(text: string, tag: 'script' | 'style' | 'template', html?: HTMLDocument): TagInformation[] {
const rootNodes = html?.roots || parseHtml(text).roots;
- const matchedNodes = rootNodes
- .filter((node) => node.tag === tag);
+ const matchedNodes = rootNodes.filter((node) => node.tag === tag);
- if(tag === 'style' && !matchedNodes.length && rootNodes.length && rootNodes[0].tag === 'html') {
- for(let child of walk(rootNodes[0])) {
- if(child.tag === 'style') {
+ if (tag === 'style' && !matchedNodes.length && rootNodes.length && rootNodes[0].tag === 'html') {
+ for (let child of walk(rootNodes[0])) {
+ if (child.tag === 'style') {
matchedNodes.push(child);
}
}
@@ -222,34 +212,34 @@ export function* walk(node: Node, startIndex = 0) {
return matchedNodes.map(transformToTagInfo);
function transformToTagInfo(matchedNode: Node) {
- const start = matchedNode.startTagEnd ?? matchedNode.start;
- const end = matchedNode.endTagStart ?? matchedNode.end;
- const startPos = positionAt(start, text);
- const endPos = positionAt(end, text);
- const container = {
- start: matchedNode.start,
- end: matchedNode.end
- };
- const content = text.substring(start, end);
-
- return {
- content,
- attributes: parseAttributes(matchedNode.attributes),
- start,
- end,
- startPos,
- endPos,
- container
- };
+ const start = matchedNode.startTagEnd ?? matchedNode.start;
+ const end = matchedNode.endTagStart ?? matchedNode.end;
+ const startPos = positionAt(start, text);
+ const endPos = positionAt(end, text);
+ const container = {
+ start: matchedNode.start,
+ end: matchedNode.end,
+ };
+ const content = text.substring(start, end);
+
+ return {
+ content,
+ attributes: parseAttributes(matchedNode.attributes),
+ start,
+ end,
+ startPos,
+ endPos,
+ container,
+ };
}
}
export function extractStyleTag(source: string, html?: HTMLDocument): TagInformation | null {
const styles = extractTags(source, 'style', html);
if (!styles.length) {
- return null;
+ return null;
}
// There can only be one style tag
return styles[0];
-} \ No newline at end of file
+}
diff --git a/tools/astro-languageserver/src/plugins/css/CSSDocument.ts b/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
index 90b28352c..9f1839678 100644
--- a/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
+++ b/tools/astro-languageserver/src/plugins/css/CSSDocument.ts
@@ -4,92 +4,92 @@ import { getLanguageService } from './service';
import { Document, DocumentMapper, ReadableDocument, TagInformation } from '../../core/documents/index';
export interface CSSDocumentBase extends DocumentMapper, TextDocument {
- languageId: string;
- stylesheet: Stylesheet;
+ languageId: string;
+ stylesheet: Stylesheet;
}
export class CSSDocument extends ReadableDocument implements DocumentMapper {
- private styleInfo: Pick<TagInformation, 'attributes' | 'start' | 'end'>;
- readonly version = this.parent.version;
+ private styleInfo: Pick<TagInformation, 'attributes' | 'start' | 'end'>;
+ readonly version = this.parent.version;
- public stylesheet: Stylesheet;
- public languageId: string;
+ public stylesheet: Stylesheet;
+ public languageId: string;
- constructor(private parent: Document) {
- super();
+ constructor(private parent: Document) {
+ super();
- if (this.parent.styleInfo) {
- this.styleInfo = this.parent.styleInfo;
- } else {
- this.styleInfo = {
- attributes: {},
- start: -1,
- end: -1
- };
- }
-
- this.languageId = this.language;
- this.stylesheet = getLanguageService(this.language).parseStylesheet(this);
+ if (this.parent.styleInfo) {
+ this.styleInfo = this.parent.styleInfo;
+ } else {
+ this.styleInfo = {
+ attributes: {},
+ start: -1,
+ end: -1,
+ };
}
- /**
- * Get the fragment position relative to the parent
- * @param pos Position in fragment
- */
- getOriginalPosition(pos: Position): Position {
- const parentOffset = this.styleInfo.start + this.offsetAt(pos);
- return this.parent.positionAt(parentOffset);
- }
+ this.languageId = this.language;
+ this.stylesheet = getLanguageService(this.language).parseStylesheet(this);
+ }
- /**
- * Get the position relative to the start of the fragment
- * @param pos Position in parent
- */
- getGeneratedPosition(pos: Position): Position {
- const fragmentOffset = this.parent.offsetAt(pos) - this.styleInfo.start;
- return this.positionAt(fragmentOffset);
- }
+ /**
+ * Get the fragment position relative to the parent
+ * @param pos Position in fragment
+ */
+ getOriginalPosition(pos: Position): Position {
+ const parentOffset = this.styleInfo.start + this.offsetAt(pos);
+ return this.parent.positionAt(parentOffset);
+ }
- /**
- * Returns true if the given parent position is inside of this fragment
- * @param pos Position in parent
- */
- isInGenerated(pos: Position): boolean {
- const offset = this.parent.offsetAt(pos);
- return offset >= this.styleInfo.start && offset <= this.styleInfo.end;
- }
+ /**
+ * Get the position relative to the start of the fragment
+ * @param pos Position in parent
+ */
+ getGeneratedPosition(pos: Position): Position {
+ const fragmentOffset = this.parent.offsetAt(pos) - this.styleInfo.start;
+ return this.positionAt(fragmentOffset);
+ }
- /**
- * Get the fragment text from the parent
- */
- getText(): string {
- return this.parent.getText().slice(this.styleInfo.start, this.styleInfo.end);
- }
+ /**
+ * Returns true if the given parent position is inside of this fragment
+ * @param pos Position in parent
+ */
+ isInGenerated(pos: Position): boolean {
+ const offset = this.parent.offsetAt(pos);
+ return offset >= this.styleInfo.start && offset <= this.styleInfo.end;
+ }
- /**
- * Returns the length of the fragment as calculated from the start and end positon
- */
- getTextLength(): number {
- return this.styleInfo.end - this.styleInfo.start;
- }
+ /**
+ * Get the fragment text from the parent
+ */
+ getText(): string {
+ return this.parent.getText().slice(this.styleInfo.start, this.styleInfo.end);
+ }
- /**
- * Return the parent file path
- */
- getFilePath(): string | null {
- return this.parent.getFilePath();
- }
+ /**
+ * Returns the length of the fragment as calculated from the start and end positon
+ */
+ getTextLength(): number {
+ return this.styleInfo.end - this.styleInfo.start;
+ }
- getURL() {
- return this.parent.getURL();
- }
+ /**
+ * Return the parent file path
+ */
+ getFilePath(): string | null {
+ return this.parent.getFilePath();
+ }
- getAttributes() {
- return this.styleInfo.attributes;
- }
+ getURL() {
+ return this.parent.getURL();
+ }
- private get language() {
- const attrs = this.getAttributes();
- return attrs.lang || attrs.type || 'css';
- }
+ getAttributes() {
+ return this.styleInfo.attributes;
+ }
+
+ private get language() {
+ const attrs = this.getAttributes();
+ return attrs.lang || attrs.type || 'css';
+ }
}
diff --git a/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts b/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
index 4c0dcb949..26c90ac66 100644
--- a/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
+++ b/tools/astro-languageserver/src/plugins/css/CSSPlugin.ts
@@ -26,24 +26,16 @@ export class CSSPlugin implements CompletionsProvider {
});
}
- getCompletions(
- document: Document,
- position: Position,
- completionContext?: CompletionContext
- ): CompletionList | null {
+ getCompletions(document: Document, position: Position, completionContext?: CompletionContext): CompletionList | null {
const triggerCharacter = completionContext?.triggerCharacter;
const triggerKind = completionContext?.triggerKind;
const isCustomTriggerCharacter = triggerKind === CompletionTriggerKind.TriggerCharacter;
- if (
- isCustomTriggerCharacter &&
- triggerCharacter &&
- !this.triggerCharacters.has(triggerCharacter)
- ) {
- return null;
+ if (isCustomTriggerCharacter && triggerCharacter && !this.triggerCharacters.has(triggerCharacter)) {
+ return null;
}
- if(this.isInsideFrontmatter(document, position)) {
+ if (this.isInsideFrontmatter(document, position)) {
return null;
}
@@ -55,82 +47,55 @@ export class CSSPlugin implements CompletionsProvider {
const attributeContext = getAttributeContextAtPosition(document, position);
if (!attributeContext) {
- return null;
+ return null;
}
if (this.inStyleAttributeWithoutInterpolation(attributeContext, document.getText())) {
- const [start, end] = attributeContext.valueRange;
- return this.getCompletionsInternal(
- document,
- position,
- new StyleAttributeDocument(document, start, end)
- );
+ const [start, end] = attributeContext.valueRange;
+ return this.getCompletionsInternal(document, position, new StyleAttributeDocument(document, start, end));
} else {
- return getIdClassCompletion(cssDocument, attributeContext);
+ return getIdClassCompletion(cssDocument, attributeContext);
}
}
- private getCompletionsInternal(
- document: Document,
- position: Position,
- cssDocument: CSSDocumentBase
- ) {
- if (isSASS(cssDocument)) {
- // the css language service does not support sass, still we can use
- // the emmet helper directly to at least get emmet completions
- return doEmmetComplete(document, position, 'sass', this.configManager.getEmmetConfig());
- }
-
- const type = extractLanguage(cssDocument);
-
- const lang = getLanguageService(type);
- const emmetResults: CompletionList = {
- isIncomplete: true,
- items: []
- };
- if (false /* this.configManager.getConfig().css.completions.emmet */) {
- lang.setCompletionParticipants([
- getEmmetCompletionParticipants(
- cssDocument,
- cssDocument.getGeneratedPosition(position),
- getLanguage(type),
- this.configManager.getEmmetConfig(),
- emmetResults
- )
- ]);
- }
- const results = lang.doComplete(
- cssDocument,
- cssDocument.getGeneratedPosition(position),
- cssDocument.stylesheet
- );
- return CompletionList.create(
- [...(results ? results.items : []), ...emmetResults.items].map((completionItem) =>
- mapCompletionItemToOriginal(cssDocument, completionItem)
- ),
- // Emmet completions change on every keystroke, so they are never complete
- emmetResults.items.length > 0
- );
- }
+ private getCompletionsInternal(document: Document, position: Position, cssDocument: CSSDocumentBase) {
+ if (isSASS(cssDocument)) {
+ // the css language service does not support sass, still we can use
+ // the emmet helper directly to at least get emmet completions
+ return doEmmetComplete(document, position, 'sass', this.configManager.getEmmetConfig());
+ }
- private inStyleAttributeWithoutInterpolation(
- attrContext: AttributeContext,
- text: string
- ): attrContext is Required<AttributeContext> {
- return (
- attrContext.name === 'style' &&
- !!attrContext.valueRange &&
- !text.substring(attrContext.valueRange[0], attrContext.valueRange[1]).includes('{')
+ const type = extractLanguage(cssDocument);
+
+ const lang = getLanguageService(type);
+ const emmetResults: CompletionList = {
+ isIncomplete: true,
+ items: [],
+ };
+ if (false /* this.configManager.getConfig().css.completions.emmet */) {
+ lang.setCompletionParticipants([
+ getEmmetCompletionParticipants(cssDocument, cssDocument.getGeneratedPosition(position), getLanguage(type), this.configManager.getEmmetConfig(), emmetResults),
+ ]);
+ }
+ const results = lang.doComplete(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
+ return CompletionList.create(
+ [...(results ? results.items : []), ...emmetResults.items].map((completionItem) => mapCompletionItemToOriginal(cssDocument, completionItem)),
+ // Emmet completions change on every keystroke, so they are never complete
+ emmetResults.items.length > 0
);
}
+ private inStyleAttributeWithoutInterpolation(attrContext: AttributeContext, text: string): attrContext is Required<AttributeContext> {
+ return attrContext.name === 'style' && !!attrContext.valueRange && !text.substring(attrContext.valueRange[0], attrContext.valueRange[1]).includes('{');
+ }
+
private getCSSDoc(document: Document) {
- let cssDoc = this.documents.get(document);
- if (!cssDoc || cssDoc.version < document.version) {
- cssDoc = new CSSDocument(document);
- this.documents.set(document, cssDoc);
- }
- return cssDoc;
+ let cssDoc = this.documents.get(document);
+ if (!cssDoc || cssDoc.version < document.version) {
+ cssDoc = new CSSDocument(document);
+ this.documents.set(document, cssDoc);
+ }
+ return cssDoc;
}
private isInsideFrontmatter(document: Document, position: Position) {
@@ -140,14 +105,14 @@ export class CSSPlugin implements CompletionsProvider {
function isSASS(document: CSSDocumentBase) {
switch (extractLanguage(document)) {
- case 'sass':
- return true;
- default:
- return false;
+ case 'sass':
+ return true;
+ default:
+ return false;
}
}
function extractLanguage(document: CSSDocumentBase): string {
const lang = document.languageId;
return lang.replace(/^text\//, '');
-} \ No newline at end of file
+}
diff --git a/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts b/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
index 7b49d771d..e00398037 100644
--- a/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
+++ b/tools/astro-languageserver/src/plugins/css/StyleAttributeDocument.ts
@@ -7,70 +7,66 @@ const PREFIX = '__ {';
const SUFFIX = '}';
export class StyleAttributeDocument extends ReadableDocument implements DocumentMapper {
- readonly version = this.parent.version;
+ readonly version = this.parent.version;
- public stylesheet: Stylesheet;
- public languageId = 'css';
+ public stylesheet: Stylesheet;
+ public languageId = 'css';
- constructor(
- private readonly parent: Document,
- private readonly attrStart: number,
- private readonly attrEnd: number
- ) {
- super();
+ constructor(private readonly parent: Document, private readonly attrStart: number, private readonly attrEnd: number) {
+ super();
- this.stylesheet = getLanguageService(this.languageId).parseStylesheet(this);
- }
+ this.stylesheet = getLanguageService(this.languageId).parseStylesheet(this);
+ }
- /**
- * Get the fragment position relative to the parent
- * @param pos Position in fragment
- */
- getOriginalPosition(pos: Position): Position {
- const parentOffset = this.attrStart + this.offsetAt(pos) - PREFIX.length;
- return this.parent.positionAt(parentOffset);
- }
+ /**
+ * Get the fragment position relative to the parent
+ * @param pos Position in fragment
+ */
+ getOriginalPosition(pos: Position): Position {
+ const parentOffset = this.attrStart + this.offsetAt(pos) - PREFIX.length;
+ return this.parent.positionAt(parentOffset);
+ }
- /**
- * Get the position relative to the start of the fragment
- * @param pos Position in parent
- */
- getGeneratedPosition(pos: Position): Position {
- const fragmentOffset = this.parent.offsetAt(pos) - this.attrStart + PREFIX.length;
- return this.positionAt(fragmentOffset);
- }
+ /**
+ * Get the position relative to the start of the fragment
+ * @param pos Position in parent
+ */
+ getGeneratedPosition(pos: Position): Position {
+ const fragmentOffset = this.parent.offsetAt(pos) - this.attrStart + PREFIX.length;
+ return this.positionAt(fragmentOffset);
+ }
- /**
- * Returns true if the given parent position is inside of this fragment
- * @param pos Position in parent
- */
- isInGenerated(pos: Position): boolean {
- const offset = this.parent.offsetAt(pos);
- return offset >= this.attrStart && offset <= this.attrEnd;
- }
+ /**
+ * Returns true if the given parent position is inside of this fragment
+ * @param pos Position in parent
+ */
+ isInGenerated(pos: Position): boolean {
+ const offset = this.parent.offsetAt(pos);
+ return offset >= this.attrStart && offset <= this.attrEnd;
+ }
- /**
- * Get the fragment text from the parent
- */
- getText(): string {
- return PREFIX + this.parent.getText().slice(this.attrStart, this.attrEnd) + SUFFIX;
- }
+ /**
+ * Get the fragment text from the parent
+ */
+ getText(): string {
+ return PREFIX + this.parent.getText().slice(this.attrStart, this.attrEnd) + SUFFIX;
+ }
- /**
- * Returns the length of the fragment as calculated from the start and end position
- */
- getTextLength(): number {
- return PREFIX.length + this.attrEnd - this.attrStart + SUFFIX.length;
- }
+ /**
+ * Returns the length of the fragment as calculated from the start and end position
+ */
+ getTextLength(): number {
+ return PREFIX.length + this.attrEnd - this.attrStart + SUFFIX.length;
+ }
- /**
- * Return the parent file path
- */
- getFilePath(): string | null {
- return this.parent.getFilePath();
- }
+ /**
+ * Return the parent file path
+ */
+ getFilePath(): string | null {
+ return this.parent.getFilePath();
+ }
- getURL() {
- return this.parent.getURL();
- }
-} \ No newline at end of file
+ getURL() {
+ return this.parent.getURL();
+ }
+}
diff --git a/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts b/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
index 368359ac9..45acb5ad6 100644
--- a/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
+++ b/tools/astro-languageserver/src/plugins/css/features/getIdClassCompletion.ts
@@ -2,32 +2,29 @@ import { CompletionItem, CompletionItemKind, CompletionList } from 'vscode-langu
import { AttributeContext } from '../../../core/documents/parseHtml';
import { CSSDocument } from '../CSSDocument';
-export function getIdClassCompletion(
- cssDoc: CSSDocument,
- attributeContext: AttributeContext
-): CompletionList | null {
- const collectingType = getCollectingType(attributeContext);
+export function getIdClassCompletion(cssDoc: CSSDocument, attributeContext: AttributeContext): CompletionList | null {
+ const collectingType = getCollectingType(attributeContext);
- if (!collectingType) {
- return null;
- }
- const items = collectSelectors(cssDoc.stylesheet as CSSNode, collectingType);
+ if (!collectingType) {
+ return null;
+ }
+ const items = collectSelectors(cssDoc.stylesheet as CSSNode, collectingType);
- console.log("getIdClassCompletion items", items.length);
- return CompletionList.create(items);
+ console.log('getIdClassCompletion items', items.length);
+ return CompletionList.create(items);
}
function getCollectingType(attributeContext: AttributeContext): number | undefined {
- if (attributeContext.inValue) {
- if (attributeContext.name === 'class') {
- return NodeType.ClassSelector;
- }
- if (attributeContext.name === 'id') {
- return NodeType.IdentifierSelector;
- }
- } else if (attributeContext.name.startsWith('class:')) {
- return NodeType.ClassSelector;
+ if (attributeContext.inValue) {
+ if (attributeContext.name === 'class') {
+ return NodeType.ClassSelector;
+ }
+ if (attributeContext.name === 'id') {
+ return NodeType.IdentifierSelector;
}
+ } else if (attributeContext.name.startsWith('class:')) {
+ return NodeType.ClassSelector;
+ }
}
/**
@@ -36,35 +33,35 @@ function getCollectingType(attributeContext: AttributeContext): number | undefin
* The enum is not exported. we have to update this whenever it changes
*/
export enum NodeType {
- ClassSelector = 14,
- IdentifierSelector = 15
+ ClassSelector = 14,
+ IdentifierSelector = 15,
}
export type CSSNode = {
- type: number;
- children: CSSNode[] | undefined;
- getText(): string;
+ type: number;
+ children: CSSNode[] | undefined;
+ getText(): string;
};
export function collectSelectors(stylesheet: CSSNode, type: number) {
- const result: CSSNode[] = [];
- walk(stylesheet, (node) => {
- if (node.type === type) {
- result.push(node);
- }
- });
+ const result: CSSNode[] = [];
+ walk(stylesheet, (node) => {
+ if (node.type === type) {
+ result.push(node);
+ }
+ });
- return result.map(
- (node): CompletionItem => ({
- label: node.getText().substring(1),
- kind: CompletionItemKind.Keyword
- })
- );
+ return result.map(
+ (node): CompletionItem => ({
+ label: node.getText().substring(1),
+ kind: CompletionItemKind.Keyword,
+ })
+ );
}
function walk(node: CSSNode, callback: (node: CSSNode) => void) {
- callback(node);
- if (node.children) {
- node.children.forEach((node) => walk(node, callback));
- }
-} \ No newline at end of file
+ callback(node);
+ if (node.children) {
+ node.children.forEach((node) => walk(node, callback));
+ }
+}
diff --git a/tools/astro-languageserver/src/plugins/css/service.ts b/tools/astro-languageserver/src/plugins/css/service.ts
index e8ac86a65..78b11296e 100644
--- a/tools/astro-languageserver/src/plugins/css/service.ts
+++ b/tools/astro-languageserver/src/plugins/css/service.ts
@@ -1,58 +1,48 @@
-import {
- getCSSLanguageService,
- getSCSSLanguageService,
- getLESSLanguageService,
- LanguageService,
- ICSSDataProvider
-} from 'vscode-css-languageservice';
+import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageService, ICSSDataProvider } from 'vscode-css-languageservice';
const customDataProvider: ICSSDataProvider = {
providePseudoClasses() {
- return [];
+ return [];
},
provideProperties() {
- return [];
+ return [];
},
provideAtDirectives() {
- return [];
+ return [];
},
providePseudoElements() {
- return [];
- }
+ return [];
+ },
};
-const [css, scss, less] = [
- getCSSLanguageService,
- getSCSSLanguageService,
- getLESSLanguageService
-].map((getService) =>
+const [css, scss, less] = [getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService].map((getService) =>
getService({
- customDataProviders: [customDataProvider]
+ customDataProviders: [customDataProvider],
})
);
const langs = {
css,
scss,
- less
+ less,
};
export function getLanguage(kind?: string) {
switch (kind) {
- case 'scss':
- case 'text/scss':
- return 'scss' as const;
- case 'less':
- case 'text/less':
- return 'less' as const;
- case 'css':
- case 'text/css':
- default:
- return 'css' as const;
+ case 'scss':
+ case 'text/scss':
+ return 'scss' as const;
+ case 'less':
+ case 'text/less':
+ return 'less' as const;
+ case 'css':
+ case 'text/css':
+ default:
+ return 'css' as const;
}
}
export function getLanguageService(kind?: string): LanguageService {
const lang = getLanguage(kind);
return langs[lang];
-} \ No newline at end of file
+}
diff --git a/tools/astro-languageserver/src/plugins/index.ts b/tools/astro-languageserver/src/plugins/index.ts
index 368b339cb..bb73cbe5e 100644
--- a/tools/astro-languageserver/src/plugins/index.ts
+++ b/tools/astro-languageserver/src/plugins/index.ts
@@ -3,4 +3,4 @@ export * from './astro/AstroPlugin';
export * from './html/HTMLPlugin';
export * from './typescript/TypeScriptPlugin';
export * from './interfaces';
-export * from './css/CSSPlugin'; \ No newline at end of file
+export * from './css/CSSPlugin';