Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ node_modules
*.vsix

extensions/vscode/out
extensions/vscode/tests/embeddedGrammars/*.tmLanguage.json
packages/*/*.d.ts
packages/*/*.js
packages/*/*.map
Expand Down
119 changes: 119 additions & 0 deletions extensions/vscode/scripts/grammars-sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { createHash } from 'node:crypto';
import * as fs from 'node:fs';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';

interface LockItem {
file: string;
url: string;
checksum?: string;
}

const CHECKSUM_PREFIX = 'sha256-';

function computeChecksum(content: string | Buffer): string {
const buffer = typeof content === 'string' ? Buffer.from(content) : content;
return CHECKSUM_PREFIX + createHash('sha256').update(buffer).digest('hex');
}

async function fetchWithChecksum(url: string) {
console.log(`Downloading ${url}...`);
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
}
const content = await res.text();
return { content, checksum: computeChecksum(content) };
}

async function fileChecksum(filePath: string): Promise<string | null> {
if (!fs.existsSync(filePath)) {
return null;
}
const content = await readFile(filePath);
return computeChecksum(content);
}

async function safeWriteFile(filePath: string, content: string | Buffer) {
await mkdir(path.dirname(filePath), { recursive: true });
await writeFile(filePath, content);
}

async function processItem(dirPath: string, item: LockItem, update: boolean): Promise<boolean> {
if (!item.file || !item.url) {
throw new Error('Lock item must include "file" and "url".');
}

const filePath = path.resolve(dirPath, item.file);

if (update || !item.checksum) {
const { content, checksum } = await fetchWithChecksum(item.url);
await safeWriteFile(filePath, content);
const changed = item.checksum !== checksum;
item.checksum = checksum;
return changed || update;
}

const expected = item.checksum;
const localChecksum = await fileChecksum(filePath);
if (localChecksum === expected) {
return false;
}

const { content, checksum } = await fetchWithChecksum(item.url);
if (checksum !== expected) {
throw new Error(
`Checksum mismatch for ${item.file}. Expected ${expected}, got ${checksum}.
Please run "pnpm test:prepare -u" to update the lock hash.`,
);
}

if (checksum !== localChecksum) {
await safeWriteFile(filePath, content);
}

return false;
}

const dir = path.dirname(fileURLToPath(import.meta.url));
const dirPath = path.resolve(dir, '../tests/embeddedGrammars');
const lockPath = path.resolve(dirPath, '_lock.json');
const update = !fs.existsSync(lockPath);
const lock: LockItem[] = update
? [
{
'file': 'css.tmLanguage.json',
'url': 'https://raw.githubusercontent.com/microsoft/vscode/main/extensions/css/syntaxes/css.tmLanguage.json',
'checksum': 'sha256-bcc97d1a3a6bf112f72d8bdb58bc438eb68aa0e070b94d00c6064b75f5cab69b',
},
{
'file': 'html.tmLanguage.json',
'url': 'https://raw.githubusercontent.com/microsoft/vscode/main/extensions/html/syntaxes/html.tmLanguage.json',
'checksum': 'sha256-80dedf4fb27e88889ac8fb72763954a6d2660502c686f4415208d8c8d00352cd',
},
{
'file': 'javascript.tmLanguage.json',
'url':
'https://raw.githubusercontent.com/microsoft/vscode/main/extensions/javascript/syntaxes/JavaScript.tmLanguage.json',
'checksum': 'sha256-db6f17f15bc4f5e860a3b8fa6055a69720a53df845c8d5121cdc4f128c16291f',
},
{
'file': 'scss.tmLanguage.json',
'url': 'https://raw.githubusercontent.com/microsoft/vscode/main/extensions/scss/syntaxes/scss.tmLanguage.json',
'checksum': 'sha256-8f2824a80a7c6fd558fc538ec52d0a7a42a4d7ecb7ddf20d79f0d1f00fa6602b',
},
{
'file': 'typescript.tmLanguage.json',
'url':
'https://raw.githubusercontent.com/microsoft/vscode/main/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json',
'checksum': 'sha256-4e92e0d7de560217d6c8d3236d85e6e17a5d77825b15729a230c761743122661',
},
]
: JSON.parse(await readFile(lockPath, 'utf8'));
if (!Array.isArray(lock)) {
throw new Error('_lock.json must contain an array of lock items.');
}
await Promise.all(lock.map(item => processItem(dirPath, item, update)));
await mkdir(dirPath, { recursive: true });
await writeFile(lockPath, JSON.stringify(lock, null, '\t') + '\n', 'utf8');
802 changes: 802 additions & 0 deletions extensions/vscode/tests/__snapshots__/grammar.spec.ts.snap

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script setup lang="ts">
type a = 1;
</script>

<script setup lang="ts">
type a = 1
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script
setup
>
const a = 0;
</script>

<script
setup
lang="ts"
>
type a = 0;
</script>

<style
scoped
>
:root {
color: red;
}
</style>

<style
scoped
lang="scss"
>
$color: red;
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@
if (false
< true
) { }
(
<br />
);
</script>

<script lang="js">
if (false
< true
) {}
(
<br />
);
</script>

<script lang="jsx">
Expand Down
21 changes: 21 additions & 0 deletions extensions/vscode/tests/embeddedGrammarFixtures/basic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup>
const a = 0;
</script>

<script setup lang="ts">
type a = 0;
</script>

<template>
<div />
</template>

<style scoped>
:root {
color: red;
}
</style>

<style scoped lang="scss">
$color: red;
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script setup lang="ts">const a = 1;</script>
27 changes: 27 additions & 0 deletions extensions/vscode/tests/embeddedGrammars/_lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"file": "css.tmLanguage.json",
"url": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/css/syntaxes/css.tmLanguage.json",
"checksum": "sha256-bcc97d1a3a6bf112f72d8bdb58bc438eb68aa0e070b94d00c6064b75f5cab69b"
},
{
"file": "html.tmLanguage.json",
"url": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/html/syntaxes/html.tmLanguage.json",
"checksum": "sha256-80dedf4fb27e88889ac8fb72763954a6d2660502c686f4415208d8c8d00352cd"
},
{
"file": "javascript.tmLanguage.json",
"url": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/javascript/syntaxes/JavaScript.tmLanguage.json",
"checksum": "sha256-db6f17f15bc4f5e860a3b8fa6055a69720a53df845c8d5121cdc4f128c16291f"
},
{
"file": "scss.tmLanguage.json",
"url": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/scss/syntaxes/scss.tmLanguage.json",
"checksum": "sha256-8f2824a80a7c6fd558fc538ec52d0a7a42a4d7ecb7ddf20d79f0d1f00fa6602b"
},
{
"file": "typescript.tmLanguage.json",
"url": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json",
"checksum": "sha256-4e92e0d7de560217d6c8d3236d85e6e17a5d77825b15729a230c761743122661"
}
]
26 changes: 26 additions & 0 deletions extensions/vscode/tests/grammar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import * as path from 'node:path';
import { describe, expect, it } from 'vitest';
import { createGrammarSnapshot } from 'vscode-tmlanguage-snapshot';

const grammarsSync = import('../scripts/grammars-sync');
const fixturesDir = path.resolve(__dirname, './grammarFixtures');
const embeddedFixturesDir = path.resolve(__dirname, './embeddedGrammarFixtures');
const packageJsonPath = path.resolve(__dirname, '../package.json');

describe('grammar', async () => {
await grammarsSync;
const snapshot = await createGrammarSnapshot(packageJsonPath);
const fixtures = fs.readdirSync(fixturesDir);

Expand All @@ -18,3 +21,26 @@ describe('grammar', async () => {
});
}
});

describe('embedded grammar', async () => {
await grammarsSync;
const embeddedGrammarsDir = path.resolve(__dirname, './embeddedGrammars');
const snapshot = await createGrammarSnapshot(packageJsonPath, {
extraGrammarPaths: [
path.resolve(embeddedGrammarsDir, './typescript.tmLanguage.json'),
path.resolve(embeddedGrammarsDir, './javascript.tmLanguage.json'),
path.resolve(embeddedGrammarsDir, './css.tmLanguage.json'),
path.resolve(embeddedGrammarsDir, './scss.tmLanguage.json'),
path.resolve(embeddedGrammarsDir, './html.tmLanguage.json'),
],
});
const fixtures = fs.readdirSync(embeddedFixturesDir);

for (const fixture of fixtures) {
it(fixture, async () => {
const result = await snapshot(`tests/embeddedGrammarFixtures/${fixture}`);

expect(result).toMatchSnapshot();
});
}
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"build": "tsgo -b",
"watch": "tsgo -b -w",
"test": "npm run build && vitest run",
"test:update": "npm run build && vitest run --update",
"test:grammar": "vitest run extensions/vscode/tests/grammar.spec.ts",
"format": "dprint fmt",
"lint": "tsslint --project {tsconfig.json,packages/*/tsconfig.json,extensions/*/tsconfig.json}",
"lint:fix": "npm run lint -- --fix"
Expand Down
10 changes: 3 additions & 7 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
testTimeout: 60_000,
poolOptions: {
forks: {
singleFork: true,
isolate: false,
},
},
testTimeout: 20_000,
fileParallelism: false,
isolate: false,
},
});