Skip to content

Commit

Permalink
feat: do hybrid ts / json
Browse files Browse the repository at this point in the history
  • Loading branch information
Princesseuh committed Aug 6, 2024
1 parent 7c75c14 commit f673235
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 420 deletions.
13 changes: 4 additions & 9 deletions packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@
},
"type": "commonjs",
"main": "dist/index.js",
"files": [
"bin",
"dist/**/*.js",
"dist/**/*.d.ts",
"types/**/*.d.ts"
],
"files": ["bin", "dist/**/*.js", "dist/**/*.d.ts", "types/**/*.d.ts"],
"bin": {
"astro-ls": "./bin/nodeServer.js"
},
Expand All @@ -27,13 +22,13 @@
},
"dependencies": {
"@astrojs/compiler": "^2.10.2",
"@astrojs/yaml2ts": "^0.1.0",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@volar/kit": "~2.4.0-alpha.15",
"@volar/language-core": "~2.4.0-alpha.15",
"@volar/language-server": "~2.4.0-alpha.15",
"@volar/language-service": "~2.4.0-alpha.15",
"@volar/typescript": "~2.4.0-alpha.15",
"devalue": "^5.0.0",
"fast-glob": "^3.2.12",
"muggle-string": "^0.4.1",
"volar-service-css": "0.0.59",
Expand All @@ -42,9 +37,9 @@
"volar-service-prettier": "0.0.59",
"volar-service-typescript": "0.0.59",
"volar-service-typescript-twoslash-queries": "0.0.59",
"volar-service-yaml": "0.0.59",
"vscode-html-languageservice": "^5.2.0",
"vscode-uri": "^3.0.8",
"yaml": "^2.4.5"
"vscode-uri": "^3.0.8"
},
"devDependencies": {
"@astrojs/svelte": "^5.0.3",
Expand Down
135 changes: 135 additions & 0 deletions packages/language-server/src/core/frontmatterHolders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
forEachEmbeddedCode,
type CodeMapping,
type LanguagePlugin,
type VirtualCode,
} from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';
import { FRONTMATTER_OFFSET } from './utils.js';
import { yaml2ts } from '@astrojs/yaml2ts';

export function getFrontmatterLanguagePlugin(): LanguagePlugin<URI, FrontmatterHolder> {
return {
getLanguageId(scriptId) {
if (scriptId.path.endsWith('.md')) {
return 'frontmatter-ts';
}
},
createVirtualCode(scriptId, languageId, snapshot) {
if (languageId === 'markdown') {
const fileName = scriptId.fsPath.replace(/\\/g, '/');
return new FrontmatterHolder(fileName, snapshot, 'blog');
}
},
updateVirtualCode(scriptId, virtualCode, newSnapshot, ctx) {
return virtualCode.updateSnapshot(newSnapshot);
},
typescript: {
extraFileExtensions: [
{ extension: 'md', isMixedContent: true, scriptKind: 7 },
{ extension: 'mdx', isMixedContent: true, scriptKind: 7 },
],
getServiceScript(astroCode) {
for (const code of forEachEmbeddedCode(astroCode)) {
if (code.id === 'frontmatter-ts') {
return {
code,
extension: '.ts',
scriptKind: 3 satisfies ts.ScriptKind.TS,
};
}
}
return undefined;
},
},
};
}

export class FrontmatterHolder implements VirtualCode {
id: string = 'frontmatter-holder';
languageId: string = 'frontmatter';
mappings!: CodeMapping[];
embeddedCodes!: VirtualCode[];
public hasFrontmatter: boolean = false;

lastValidContent: {
source: string;
generated: string;
mappings: CodeMapping[];
} = {
source: '',
generated: '',
mappings: [],
};

constructor(
public fileName: string,
public snapshot: ts.IScriptSnapshot,
public collection: string
) {
this.updateSnapshot(snapshot);
}

updateSnapshot(snapshot: ts.IScriptSnapshot) {
this.mappings = [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [this.snapshot.getLength()],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: true,
},
},
];

this.embeddedCodes = [];
this.snapshot = snapshot;

// TODO: More robust frontmatter detection
this.hasFrontmatter = this.snapshot.getText(0, 10).startsWith('---');

const frontmatter = this.hasFrontmatter
? this.snapshot
.getText(0, this.snapshot.getText(0, this.snapshot.getLength()).indexOf('---', 3) + 3)
.replaceAll('---', ' ')
: ''; // Generate an empty frontmatter so that we can map an error for a missing frontmatter

this.embeddedCodes.push({
id: `yaml_frontmatter_${this.collection}`,
languageId: 'yaml',
snapshot: {
getText: (start, end) => frontmatter.substring(start, end),
getLength: () => frontmatter.length,
getChangeRange: () => undefined,
},
mappings: [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [frontmatter.length],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
},
],
});

if (this.hasFrontmatter) {
const yaml2tsResult = yaml2ts(frontmatter, this.snapshot, this.collection);
this.embeddedCodes.push(yaml2tsResult.virtualCode);
}

return this;
}
}
2 changes: 2 additions & 0 deletions packages/language-server/src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { VirtualCode } from '@volar/language-core';
import { URI, Utils } from 'vscode-uri';
import { importSvelteIntegration, importVueIntegration } from '../importPackage';

export const FRONTMATTER_OFFSET = 4;

export function framework2tsx(
filePath: string,
sourceCode: string,
Expand Down
Loading

0 comments on commit f673235

Please sign in to comment.