feat(language-tools): Match monorepo coding style and cleanup

This commit is contained in:
Princesseuh
2025-10-27 22:08:43 +01:00
parent 85b833d804
commit 372b7c357f
86 changed files with 584 additions and 2410 deletions

View File

@@ -1,50 +0,0 @@
name: "\U0001F4A1 Feature Request"
description: 'Submit an RFC or suggest an idea for this project'
title: "\U0001F4A1 RFC: "
labels: ['feature']
assignees: []
body:
- type: markdown
attributes:
value: Thanks for taking the time to suggest a new feature! Please fill out this form as completely as possible.
- type: textarea
attributes:
label: Background & Motivation
description: |
A quick, clear and concise description of what the problem is.
**Please include links to relevant issues, Discord convos, and anything else.**
placeholder: I want to be able to...
validations:
required: true
- type: textarea
attributes:
label: Proposed Solution
description: Your take on one (or more) possible solution(s) to problem.
value: |
### Possible solutions
### Alternatives considered
### Risks, downsides, and/or tradeoffs
### Open Questions
validations:
required: true
- type: textarea
attributes:
label: Detailed Design
description: |
🛑 **Just looking for feedback on an idea? Leave this section blank.**
Otherwise, explain the exact steps required to implement this change.
Include specific details that would help someone implement this feature.
- type: checkboxes
attributes:
label: Help make it happen!
description: 'Tip: RFCs with contributing authors are much more likely to get done!'
options:
- label: I am willing to submit a PR to implement this change.
- label: I am willing to submit a PR to implement this change, but would need some guidance.
- label: I am not willing to submit a PR to implement this change.
validations:
required: true

View File

@@ -1,7 +0,0 @@
---
name: "\U0001F4D8 Documentation"
about: Report a bug or suggest improvement related to the documentation of this project
title: "\U0001F4D8 DOC: "
labels: ''
assignees: ''
---

View File

@@ -154,6 +154,55 @@ jobs:
- name: Test ${{ matrix.TEST_SUITE.name }}
run: ${{ matrix.TEST_SUITE.script }}
test-language-tools:
runs-on: ${{ matrix.os }}
timeout-minutes: 30
needs: build
strategy:
matrix:
os: [ubuntu-latest]
node_version: [20.9.0, 22]
include:
- os: windows-latest
node_version: 20.9.0
- os: macos-latest
node_version: 20.9.0
fail-fast: false
name: 'Test (language-tools): node-${{ matrix.node_version }}, ${{ matrix.os }}'
steps:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Setup PNPM
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Setup node@${{ matrix.node_version }}
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ matrix.node_version }}
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build the packages
run: pnpm build
- name: Test (Linux)
if: runner.os == 'Linux'
run: |
pnpm run test:language-tools:no-vs
cd packages/language-tools/vscode
xvfb-run -a pnpm test
# TODO: Figure out why the vscode tests are fine, but the ts-plugin ones are super flaky
# cd ../ts-plugin
# xvfb-run -a pnpm test
- name: Test
run: pnpm test:language-tools
if: runner.os != 'Linux'
e2e:
name: "Test (E2E): ${{ matrix.os }} (node@${{ matrix.NODE_VERSION }})"
runs-on: ${{ matrix.os }}

1
.gitignore vendored
View File

@@ -16,6 +16,7 @@ package-lock.json
.turbo/
.eslintcache
.pnpm-store
.vscode-test/
# do not commit .env files or any files that end with `.env`
*.env

View File

@@ -7,8 +7,10 @@ benchmark/results/
**/smoke
**/node_modules
**/fixtures
**/fixture
**/vendor
**/.vercel
**/.vscode-test
# Short-term need to format
!packages/db/test/fixtures

View File

@@ -1,56 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
"files": {
"ignore": [
"**/dist/**/*",
"**/node_modules/**/*",
"**/fixture/**/*",
"**/fixtures/**/*",
"**/.vscode-test/**/*",
"packages/vscode/syntaxes/*.json",
".github",
".changeset",
".idea/"
],
"ignoreUnknown": true
},
"formatter": {
"indentStyle": "tab",
"indentWidth": 2,
"lineWidth": 100,
"ignore": [".changeset", "pnpm-lock.yaml", "*.astro"]
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": false
},
"javascript": {
"formatter": {
"trailingCommas": "all",
"quoteStyle": "single",
"semicolons": "always"
}
},
"json": {
"parser": {
"allowComments": true,
"allowTrailingCommas": true
},
"formatter": {
"indentStyle": "space",
"trailingCommas": "none"
}
},
"overrides": [
{
"include": ["package.json"],
"json": {
"formatter": {
"lineWidth": 1
}
}
}
]
}

View File

@@ -1,7 +1,16 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.6/schema.json",
"files": {
"includes": ["**", "!**/smoke/**", "!**/fixtures/**", "!**/_temp-fixtures/**", "!**/vendor/**"]
"includes": [
"**",
"!**/smoke/**",
"!**/fixtures/**",
"!**/fixture/**",
"!**/_temp-fixtures/**",
"!**/vendor/**",
"packages/language-tools/vscode/syntaxes/*.json",
"!**/.vscode-test/**"
]
},
"vcs": {
"enabled": true,

View File

@@ -143,4 +143,17 @@ export default [
],
},
},
{
files: [
'packages/language-tools/ts-plugin/**/*',
'packages/language-tools/vscode/**/*',
// The language server is distributed as CJS in the VS Code extension, despite being written as ESM.
// As such, sometimes require are required.
'packages/language-tools/language-server/**/*',
],
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
},
];

View File

@@ -1,126 +0,0 @@
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import tseslint from 'typescript-eslint';
// plugins
import regexpEslint from 'eslint-plugin-regexp';
const typescriptEslint = tseslint.plugin;
// parsers
const typescriptParser = tseslint.parser;
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default [
// If ignores is used without any other keys in the configuration object, then the patterns act as global ignores.
// ref: https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores
{
ignores: [
'**/dist',
'**/node_modules',
'**/fixtures',
'**/fixture',
'**/.vscode-test',
'.github',
'.changeset',
],
},
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
regexpEslint.configs['flat/recommended'],
{
languageOptions: {
parser: typescriptParser,
parserOptions: {
project: ['./tsconfig.eslint.json'],
tsconfigRootDir: __dirname,
},
},
plugins: {
'@typescript-eslint': typescriptEslint,
regexp: regexpEslint,
},
rules: {
// These off/configured-differently-by-default rules fit well for us
'@typescript-eslint/switch-exhaustiveness-check': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
'@typescript-eslint/no-shadow': 'error',
'no-console': ['warn', { allow: ['warn', 'error', 'info', 'debug'] }],
// Todo: do we want these?
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/class-literal-property-style': 'off',
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/no-base-to-string': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-misused-promises': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/only-throw-error': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'@typescript-eslint/prefer-optional-chain': 'off',
'@typescript-eslint/prefer-promise-reject-errors': 'off',
'@typescript-eslint/prefer-string-starts-ends-with': 'off',
'@typescript-eslint/require-await': 'off',
'@typescript-eslint/restrict-plus-operands': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/sort-type-constituents': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/no-explicit-any': 'off',
// Enforce separate type imports for type-only imports to avoid bundling unneeded code
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
fixStyle: 'separate-type-imports',
disallowTypeAnnotations: false,
},
],
// These rules enabled by the preset configs don't work well for us
'@typescript-eslint/await-thenable': 'off',
'prefer-const': 'off',
// In some cases, using explicit letter-casing is more performant than the `i` flag
'regexp/use-ignore-case': 'off',
'regexp/prefer-regexp-exec': 'warn',
'regexp/prefer-regexp-test': 'warn',
},
},
{
files: [
'packages/ts-plugin/**/*',
'packages/vscode/**/*',
// The language server is distributed as CJS in the VS Code extension, despite being written as ESM.
// As such, sometimes require are required.
'packages/language-server/**/*',
],
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
},
];

View File

@@ -9,6 +9,7 @@ export default {
'examples/**',
'**/{test,e2e}/**/{fixtures,_temp-fixtures}/**',
'benchmark/**',
'packages/language-tools/**/*',
],
workspaces: {
'.': {

View File

@@ -9,7 +9,7 @@
},
"scripts": {
"release": "pnpm run build && changeset publish",
"build": "turbo run build --filter=astro --filter=create-astro --filter=\"@astrojs/*\" --filter=\"@benchmark/*\"",
"build": "turbo run build --filter=astro --filter=create-astro --filter=\"@astrojs/*\" --filter=\"astro-vscode\" --filter=\"@benchmark/*\"",
"build:ci": "turbo run build:ci --filter=astro --filter=create-astro --filter=\"@astrojs/*\" --filter=\"@benchmark/*\"",
"build:ci:no-cache": "pnpm -r --filter=astro --filter=create-astro --filter=\"@astrojs/*\" --filter=\"@benchmark/*\" build:ci",
"build:examples": "turbo run build --filter=\"@example/*\"",
@@ -20,9 +20,11 @@
"format:code:ci": "biome format && prettier -w \"**/*\" --ignore-unknown --cache --check",
"format:imports": "biome check --formatter-enabled=false --write",
"format:imports:ci": "biome ci --formatter-enabled=false",
"test": "pnpm run test:astro && pnpm run test:integrations",
"test": "pnpm run test:astro && pnpm run test:integrations && pnpm run test:language-tools",
"test:astro": "turbo run test --concurrency=1 --filter=astro --only",
"test:integrations": "turbo run test --concurrency=1 --filter=create-astro --filter=\"@astrojs/*\" --only",
"test:integrations": "turbo run test --concurrency=1 --filter=create-astro --filter=\"@astrojs/*\" --filter=\"!./packages/language-tools/**/*\" --only",
"test:language-tools": "turbo run test --concurrency=1 --filter=\"./packages/language-tools/**/*\" --filter=\"!./packages/language-tools/ts-plugin\" --only",
"test:language-tools:no-vs": "turbo run test --filter=\"@astrojs/language-server\" --filter=\"@astrojs/check\" --only",
"test:citgm": "pnpm -r --filter=astro test",
"test:match": "cd packages/astro && pnpm run test:match",
"test:cli": "cd packages/astro && pnpm run test:cli",

View File

@@ -91,7 +91,7 @@
],
"scripts": {
"prebuild": "astro-scripts prebuild --to-string \"src/runtime/server/astro-island.ts\" \"src/runtime/client/{idle,load,media,only,visible}.ts\"",
"build": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" --copy-wasm && tsc && astro-check --root ./components",
"build": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" --copy-wasm && tsc",
"build:ci": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" --copy-wasm",
"dev": "astro-scripts dev --copy-wasm --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.{ts,js}\"",
"test": "pnpm run test:unit && pnpm run test:integration && pnpm run test:types",
@@ -173,7 +173,7 @@
"sharp": "^0.34.0"
},
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/check": "workspace:*",
"@playwright/test": "1.51.1",
"@types/aria-query": "^5.0.4",
"@types/common-ancestor-path": "^1.0.2",

View File

@@ -10,6 +10,7 @@ export async function check(flags: Flags) {
skipAsk: !!flags.yes || !!flags.y,
cwd: flags.root,
};
// @ts-ignore For some unknown reason, in CI TS isn't able to get the type here even though it works locally.
const checkPackage = await getPackage<typeof import('@astrojs/check')>(
'@astrojs/check',
logger,

View File

@@ -200,7 +200,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
if (flags.watch) {
return await new Promise(() => {}); // lives forever
} else {
return process.exit(checkServer ? 1 : 0);
return process.exit(typeof checkServer === 'boolean' && checkServer ? 1 : 0);
}
}
}

View File

@@ -3,6 +3,8 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
"astro": "workspace:*",
"@astrojs/check": "^0.9.4",
"typescript": "^5.9.2"
}
}

View File

@@ -3,6 +3,8 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
"astro": "workspace:*",
"@astrojs/check": "^0.9.4",
"typescript": "^5.9.2"
}
}

View File

@@ -7,8 +7,8 @@
"homepage": "https://github.com/withastro/language-tools/tree/main/packages/astro-check",
"repository": {
"type": "git",
"url": "https://github.com/withastro/language-tools",
"directory": "packages/astro-check"
"url": "https://github.com/withastro/astro.git",
"directory": "packages/language-tools/astro-check"
},
"type": "module",
"main": "dist/index.js",
@@ -24,8 +24,7 @@
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"test": "tsx ./test/script.ts \"**/*.test.ts\"",
"test:match": "pnpm run test --test-name-pattern"
"test": "astro-scripts test \"**/*.test.ts\" --tsx true"
},
"dependencies": {
"@astrojs/language-server": "^2.15.0",
@@ -35,9 +34,10 @@
},
"devDependencies": {
"@types/node": "^20.9.0",
"@types/yargs": "^17.0.24",
"tinyglobby": "^0.2.15",
"tsx": "^3.12.7"
"@types/yargs": "^17.0.33",
"tsx": "^4.20.6",
"astro-scripts": "workspace:*"
},
"peerDependencies": {
"typescript": "^5.0.0"

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env node
import path from 'node:path';
import { check, parseArgsAsCheckConfig } from './index.js';
const args = parseArgsAsCheckConfig(process.argv);
const args = parseArgsAsCheckConfig(process.argv.slice(2));
console.info(`Getting diagnostics for Astro files in ${path.resolve(args.root)}...`);

View File

@@ -109,6 +109,7 @@ export async function check(flags: Partial<Flags>): Promise<boolean | void> {
return result.errors + result.warnings > 0;
case 'hint':
return result.errors + result.warnings + result.hints > 0;
case undefined:
default:
return result.errors > 0;
}

View File

@@ -1,5 +1,5 @@
import { spawnSync } from 'child_process';
import assert from 'node:assert';
import { spawnSync } from 'node:child_process';
import { describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';

View File

@@ -1,6 +1,6 @@
import assert from 'node:assert';
import path from 'node:path';
import { describe, it } from 'node:test';
import path from 'path';
import { check } from '../dist/index.js';
describe('astro-check - js api', async () => {

View File

@@ -1,92 +0,0 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { run } from 'node:test';
import { spec } from 'node:test/reporters';
import { pathToFileURL } from 'node:url';
import { parseArgs } from 'node:util';
import { glob } from 'tinyglobby';
const isCI = !!process.env.CI;
const defaultTimeout = isCI ? 1400000 : 600000;
export default async function test() {
const args = parseArgs({
allowPositionals: true,
options: {
// aka --test-name-pattern: https://nodejs.org/api/test.html#filtering-tests-by-name
match: { type: 'string', alias: 'm' },
// aka --test-only: https://nodejs.org/api/test.html#only-tests
only: { type: 'boolean', alias: 'o' },
// aka --test-concurrency: https://nodejs.org/api/test.html#test-runner-execution-model
parallel: { type: 'boolean', alias: 'p' },
// experimental: https://nodejs.org/api/test.html#watch-mode
watch: { type: 'boolean', alias: 'w' },
// Test timeout in milliseconds (default: 30000ms)
timeout: { type: 'string', alias: 't' },
// Test setup file
setup: { type: 'string', alias: 's' },
// Test teardown file
teardown: { type: 'string' },
},
});
const pattern = args.positionals[0];
if (!pattern) throw new Error('Missing test glob pattern');
const files = await glob(pattern, {
onlyFiles: true,
absolute: true,
ignore: ['**/node_modules/**'],
});
// For some reason, the `only` option does not work and we need to explicitly set the CLI flag instead.
// Node.js requires opt-in to run .only tests :(
// https://nodejs.org/api/test.html#only-tests
if (args.values.only) {
process.env.NODE_OPTIONS ??= '';
process.env.NODE_OPTIONS += ' --test-only';
}
if (!args.values.parallel) {
// If not parallel, we create a temporary file that imports all the test files
// so that it all runs in a single process.
const tempTestFile = path.resolve('./node_modules/.astro/test.mjs');
await fs.mkdir(path.dirname(tempTestFile), { recursive: true });
await fs.writeFile(
tempTestFile,
files.map((f) => `import ${JSON.stringify(pathToFileURL(f).toString())};`).join('\n'),
);
files.length = 0;
files.push(tempTestFile);
}
const teardownModule = args.values.teardown
? await import(pathToFileURL(path.resolve(args.values.teardown)).toString())
: undefined;
// https://nodejs.org/api/test.html#runoptions
run({
files,
testNamePatterns: args.values.match ? [args.values.match, 'Teardown'] : undefined,
concurrency: args.values.parallel,
only: args.values.only,
setup: args.values.setup,
watch: args.values.watch,
timeout: args.values.timeout ? Number(args.values.timeout) : defaultTimeout, // Node.js defaults to Infinity, so set better fallback
})
.on('test:fail', () => {
// For some reason, a test fail using the JS API does not set an exit code of 1,
// so we set it here manually
process.exitCode = 1;
})
.on('end', () => {
const testPassed = process.exitCode === 0 || process.exitCode === undefined;
teardownModule?.default(testPassed);
})
.pipe(new spec())
.pipe(process.stdout);
}
test();

View File

@@ -1,8 +1,9 @@
{
"extends": "../../../tsconfig.base.json",
"extends": "../../tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"module": "ESNext"
"module": "ESNext",
"allowImportingTsExtensions": true
}
}

View File

@@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",

View File

@@ -5,8 +5,8 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/withastro/language-tools",
"directory": "packages/language-server"
"url": "https://github.com/withastro/astro.git",
"directory": "packages/language-tools/language-server"
},
"type": "commonjs",
"main": "dist/index.js",
@@ -23,7 +23,7 @@
"build": "tsc",
"dev": "tsc --watch",
"sync-fixture": "pnpm --dir ./test/fixture sync",
"test": "pnpm run sync-fixture && tsx ./test/script.ts \"**/*.test.ts\"",
"test": "pnpm sync-fixture && astro-scripts test \"**/*.test.ts\" --teardown-test ./test/misc/teardown.ts --tsx true",
"test:match": "pnpm run test --match"
},
"dependencies": {
@@ -47,17 +47,14 @@
"vscode-uri": "^3.1.0"
},
"devDependencies": {
"@astrojs/svelte": "^5.0.3",
"@astrojs/vue": "^4.0.8",
"@types/node": "^20.9.0",
"@volar/test-utils": "~2.4.23",
"@volar/typescript": "~2.4.23",
"astro": "^4.14.0",
"svelte": "^4.2.10",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11"
"vscode-languageserver-textdocument": "^1.0.11",
"astro-scripts": "workspace:*"
},
"peerDependencies": {
"prettier": "^3.0.0",

View File

@@ -9,10 +9,9 @@ import { URI } from 'vscode-uri';
import { addAstroTypes, getAstroLanguagePlugin } from './core/index.js';
import { getSvelteLanguagePlugin } from './core/svelte.js';
import { getVueLanguagePlugin } from './core/vue.js';
import { getAstroInstall } from './utils.js';
import { create as createAstroService } from './plugins/astro.js';
import { create as createTypeScriptServices } from './plugins/typescript/index.js';
import { getAstroInstall } from './utils.js';
// Export those for downstream consumers
export { Diagnostic, DiagnosticSeverity };

View File

@@ -1,9 +1,9 @@
import { VIRTUAL_CODE_ID, yaml2ts } from '@astrojs/yaml2ts';
import {
type CodeMapping,
forEachEmbeddedCode,
type LanguagePlugin,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';

View File

@@ -2,9 +2,9 @@ import * as path from 'node:path';
import type { DiagnosticMessage, DiagnosticSeverity } from '@astrojs/compiler/types';
import {
type CodeMapping,
forEachEmbeddedCode,
type LanguagePlugin,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type { TypeScriptExtraServiceScript } from '@volar/typescript';
import type ts from 'typescript';

View File

@@ -1,9 +1,9 @@
import {
type CodeInformation,
forEachEmbeddedCode,
type LanguagePlugin,
type Mapping,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';

View File

@@ -44,7 +44,7 @@ function toPascalCase(string: string) {
.replace(new RegExp(/[^\w\s]/, 'g'), '')
.replace(
new RegExp(/\s+(.)(\w*)/, 'g'),
($1, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}`,
(_, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}`,
)
.replace(new RegExp(/\w/), (s) => s.toUpperCase());
}

View File

@@ -1,9 +1,9 @@
import {
type CodeInformation,
forEachEmbeddedCode,
type LanguagePlugin,
type Mapping,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';

View File

@@ -1,8 +1,13 @@
import { dirname, resolve } from 'node:path';
// Those three imports needs to always be `type` imports, as we always want to import them dynamically
// TODO: Consider maybe somehow moving those integrations to a separate package to avoid circular dependencies?
// @ts-ignore - Due to a circular dependency, we can't have those as dependencies
import type * as svelte from '@astrojs/svelte/dist/editor.cjs';
// @ts-ignore - Due to a circular dependency, we can't have those as dependencies
import type * as vue from '@astrojs/vue/dist/editor.cjs';
import type * as prettier from 'prettier';
type PackageVersion = {

View File

@@ -4,23 +4,21 @@ import {
MessageType,
ShowMessageNotification,
} from '@volar/language-server/node';
import { URI } from 'vscode-uri';
import { getAstroLanguagePlugin } from './core';
import { getSvelteLanguagePlugin } from './core/svelte.js';
import { getVueLanguagePlugin } from './core/vue.js';
import { getPrettierPluginPath, importPrettier } from './importPackage.js';
// Services
import { create as createCssService } from 'volar-service-css';
import { create as createEmmetService } from 'volar-service-emmet';
import { create as createPrettierService } from 'volar-service-prettier';
import { create as createTypeScriptTwoSlashService } from 'volar-service-typescript-twoslash-queries';
import { URI } from 'vscode-uri';
import { getAstroLanguagePlugin } from './core';
import { type CollectionConfig, getFrontmatterLanguagePlugin } from './core/frontmatterHolders.js';
import { getSvelteLanguagePlugin } from './core/svelte.js';
import { getVueLanguagePlugin } from './core/vue.js';
import { getPrettierPluginPath, importPrettier } from './importPackage.js';
import { create as createAstroService } from './plugins/astro.js';
import { create as createHtmlService } from './plugins/html.js';
import { create as createTypescriptAddonsService } from './plugins/typescript-addons/index.js';
import { create as createTypeScriptServices } from './plugins/typescript/index.js';
import { create as createTypescriptAddonsService } from './plugins/typescript-addons/index.js';
import { create as createYAMLService } from './plugins/yaml.js';
export function getLanguagePlugins(collectionConfig: CollectionConfig) {

View File

@@ -1,11 +1,11 @@
import {
MessageType,
ShowMessageNotification,
type WorkspaceFolder,
createConnection,
createServer,
createTypeScriptProject,
loadTsdkByPath,
MessageType,
ShowMessageNotification,
type WorkspaceFolder,
} from '@volar/language-server/node';
import { URI, Utils } from 'vscode-uri';
import {

View File

@@ -1,8 +1,8 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import * as _ from '@volar/language-server/node';
import type { LanguageServer } from '../server.js';
import { getLanguageServer } from '../server.js';
import * as _ from '@volar/language-server/node.js';
import type { LanguageServer } from '../server.ts';
import { getLanguageServer } from '../server.ts';
describe('Astro - Code Lens', () => {
let languageServer: LanguageServer;

View File

@@ -4,8 +4,8 @@ import path from 'node:path';
import { after, before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { URI } from 'vscode-uri';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
const contentSchemaPath = path.resolve(fixtureDir, '.astro', 'collections', 'caching.schema.json');

View File

@@ -2,8 +2,8 @@ import assert from 'node:assert';
import path from 'node:path';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('Content Intellisense - Completions', async () => {
let languageServer: LanguageServer;

View File

@@ -3,8 +3,8 @@ import path from 'node:path';
import { before, describe, it } from 'node:test';
import type { LocationLink } from '@volar/language-server';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('Content Intellisense - Go To Everywhere', async () => {
let languageServer: LanguageServer;
@@ -32,7 +32,7 @@ describe('Content Intellisense - Go To Everywhere', async () => {
assert.deepStrictEqual(targetRange, {
start: { line: 5, character: 2 },
end: { line: 5, character: 54 },
end: { line: 5, character: 65 },
});
assert.deepStrictEqual(targetSelectionRange, {

View File

@@ -3,10 +3,11 @@ import path from 'node:path';
import { before, describe, it } from 'node:test';
import type { FullDocumentDiagnosticReport } from '@volar/language-server';
import { DiagnosticSeverity, Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('Content Intellisense - Diagnostics', async () => {
// TODO: We can't sync the fixture with these mistakes at all, as such we can't run these tests.
describe.skip('Content Intellisense - Diagnostics', async () => {
let languageServer: LanguageServer;
before(async () => (languageServer = await getLanguageServer()));

View File

@@ -2,8 +2,8 @@ import assert from 'node:assert';
import path from 'node:path';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('Content Intellisense - Hover', async () => {
let languageServer: LanguageServer;

View File

@@ -1,8 +1,8 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import type { LanguageServer } from '../server.js';
import { getLanguageServer } from '../server.js';
import type { LanguageServer } from '../server.ts';
import { getLanguageServer } from '../server.ts';
describe('CSS - Completions', () => {
let languageServer: LanguageServer;

View File

@@ -1,8 +1,8 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import type { LanguageServer } from '../server.js';
import { getLanguageServer } from '../server.js';
import type { LanguageServer } from '../server.ts';
import { getLanguageServer } from '../server.ts';
describe('CSS - Hover', () => {
let languageServer: LanguageServer;

View File

@@ -1,10 +1,10 @@
{
"name": "astro-language-server-test",
"private": true,
"devDependencies": {
"astro": "^4.14.0"
},
"scripts": {
"sync": "astro sync"
}
"name": "astro-language-server-test",
"private": true,
"devDependencies": {
"astro": "workspace:*"
},
"scripts": {
"sync": "astro sync"
}
}

View File

@@ -3,17 +3,17 @@ import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string().describe("The blog post's title."),
description: z.string(),
title: z.string().describe("The blog post's title.").optional(),
description: z.string().optional(),
tags: z.array(z.string()).optional(),
type: z.enum(['blog']).optional(),
type: z.enum(['blog']).or(z.null()).optional(),
}),
});
const caching = defineCollection({
type: 'content',
schema: z.object({
title: z.string().describe("I will be changed"),
title: z.string().describe('I will be changed'),
}),
});

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('HTML - Completions', () => {
let languageServer: LanguageServer;

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('HTML - Custom Data', () => {
let languageServer: LanguageServer;

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('HTML - Hover', () => {
let languageServer: LanguageServer;

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import type { InitializeResult, ServerCapabilities } from '@volar/language-server';
import { getLanguageServer } from '../server.js';
import { getLanguageServer } from '../server.ts';
describe('Initialize', async () => {
let initializeResult: InitializeResult;

View File

@@ -2,8 +2,8 @@ import assert from 'node:assert';
import * as path from 'node:path';
import { before, describe, it } from 'node:test';
import { Range } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('Formatting - Prettier', () => {
let languageServer: LanguageServer;

View File

@@ -1,5 +1,5 @@
import { describe, it } from 'node:test';
import { getLanguageServer } from '../server.js';
import { getLanguageServer } from '../server.ts';
describe('Teardown', () => {
it('Can teardown', async () => {

View File

@@ -2,6 +2,12 @@
"name": "language-server-tests",
"private": true,
"type": "module",
"dependencies": {
"@astrojs/svelte": "workspace:*",
"@astrojs/vue": "workspace:*",
"astro": "workspace:*",
"svelte": "^4.2.10"
},
"devDependencies": {
"tinyglobby": "^0.2.15"
}

View File

@@ -1,95 +0,0 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { run } from 'node:test';
import { spec } from 'node:test/reporters';
import { pathToFileURL } from 'node:url';
import { parseArgs } from 'node:util';
import { glob } from 'tinyglobby';
const isCI = !!process.env.CI;
const defaultTimeout = isCI ? 1400000 : 600000;
export default async function test() {
const args = parseArgs({
allowPositionals: true,
options: {
// aka --test-name-pattern: https://nodejs.org/api/test.html#filtering-tests-by-name
match: { type: 'string', alias: 'm' },
// aka --test-only: https://nodejs.org/api/test.html#only-tests
only: { type: 'boolean', alias: 'o' },
// aka --test-concurrency: https://nodejs.org/api/test.html#test-runner-execution-model
parallel: { type: 'boolean', alias: 'p' },
// experimental: https://nodejs.org/api/test.html#watch-mode
watch: { type: 'boolean', alias: 'w' },
// Test timeout in milliseconds (default: 30000ms)
timeout: { type: 'string', alias: 't' },
// Test setup file
setup: { type: 'string', alias: 's' },
// Test teardown file
teardown: { type: 'string' },
},
});
const pattern = args.positionals[0];
if (!pattern) throw new Error('Missing test glob pattern');
const files = await glob(pattern, {
onlyFiles: true,
absolute: true,
ignore: ['**/node_modules/**'],
});
files.push(path.resolve('./test/misc/teardown.ts'));
// For some reason, the `only` option does not work and we need to explicitly set the CLI flag instead.
// Node.js requires opt-in to run .only tests :(
// https://nodejs.org/api/test.html#only-tests
if (args.values.only) {
process.env.NODE_OPTIONS ??= '';
process.env.NODE_OPTIONS += ' --test-only';
}
if (!args.values.parallel) {
// If not parallel, we create a temporary file that imports all the test files
// so that it all runs in a single process.
const tempTestFile = path.resolve('./node_modules/.astro/test.mjs');
await fs.mkdir(path.dirname(tempTestFile), { recursive: true });
await fs.writeFile(
tempTestFile,
files.map((f) => `import ${JSON.stringify(pathToFileURL(f).toString())};`).join('\n'),
);
files.length = 0;
files.push(tempTestFile);
}
const teardownModule = args.values.teardown
? await import(pathToFileURL(path.resolve(args.values.teardown)).toString())
: undefined;
// https://nodejs.org/api/test.html#runoptions
run({
files,
testNamePatterns: args.values.match ? [args.values.match, 'Teardown'] : undefined,
concurrency: args.values.parallel,
only: args.values.only,
setup: args.values.setup,
watch: args.values.watch,
forceExit: true,
timeout: args.values.timeout ? Number(args.values.timeout) : defaultTimeout, // Node.js defaults to Infinity, so set better fallback
})
.on('test:fail', () => {
// For some reason, a test fail using the JS API does not set an exit code of 1,
// so we set it here manually
process.exitCode = 1;
})
.on('end', () => {
const testPassed = process.exitCode === 0 || process.exitCode === undefined;
teardownModule?.default(testPassed);
})
.pipe(new spec())
.pipe(process.stdout);
}
test();

View File

@@ -3,7 +3,7 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { LanguageServerHandle } from '@volar/test-utils';
import { startLanguageServer } from '@volar/test-utils';
import * as protocol from 'vscode-languageserver-protocol/node';
import * as protocol from 'vscode-languageserver-protocol/node.js';
import type { TextDocument } from 'vscode-languageserver-textdocument';
import { URI } from 'vscode-uri';

View File

@@ -1,6 +0,0 @@
import { getLanguageServer } from './server.js';
export async function mochaGlobalTeardown() {
const languageServer = await getLanguageServer();
languageServer.handle.connection.dispose();
}

View File

@@ -1,8 +1,9 @@
{
"extends": "../../../tsconfig.base.json",
"extends": "../../tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"module": "ESNext"
"module": "ESNext",
"allowImportingTsExtensions": true
}
}

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('TypeScript Addons - Completions', async () => {
let languageServer: LanguageServer;

View File

@@ -1,5 +1,5 @@
import assert from 'node:assert';
import { readdir } from 'node:fs/promises';
import { mkdir, readdir, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { after, before, describe, it } from 'node:test';
import {
@@ -7,10 +7,9 @@ import {
type FullDocumentDiagnosticReport,
type MarkupContent,
} from '@volar/language-server';
import { mkdir, rm, writeFile } from 'fs/promises';
import { URI } from 'vscode-uri';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('TypeScript - Cache invalidation', async () => {
let languageServer: LanguageServer;

View File

@@ -2,8 +2,8 @@ import assert from 'node:assert';
import path from 'node:path';
import { before, describe, it } from 'node:test';
import { Position } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('TypeScript - Completions', async () => {
let languageServer: LanguageServer;

View File

@@ -3,8 +3,8 @@ import * as path from 'node:path';
import { before, describe, it } from 'node:test';
import type { FullDocumentDiagnosticReport } from '@volar/language-server';
import { type Diagnostic, DiagnosticSeverity, Range } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('TypeScript - Diagnostics', async () => {
let languageServer: LanguageServer;

View File

@@ -2,7 +2,7 @@ import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { Range } from '@volar/language-server';
import { URI } from 'vscode-uri';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('TypeScript - Organize & Sort Imports', () => {
let languageServer: LanguageServer;

View File

@@ -3,8 +3,8 @@ import path from 'node:path';
import { before, describe, it } from 'node:test';
import type { RenameFilesParams } from 'vscode-languageserver-protocol';
import { WillRenameFilesRequest } from 'vscode-languageserver-protocol';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { fixtureDir } from '../utils.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
import { fixtureDir } from '../utils.ts';
describe('TypeScript - Renaming', async () => {
let languageServer: LanguageServer;

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { before, describe, it } from 'node:test';
import { type FullDocumentDiagnosticReport, Position, Range } from '@volar/language-server';
import { type LanguageServer, getLanguageServer } from '../server.js';
import { getLanguageServer, type LanguageServer } from '../server.ts';
describe('TypeScript - Diagnostics', async () => {
let languageServer: LanguageServer;

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { getAstroMetadata } from '../../dist/core/parseAstro.js';
import { createCompilerPoint, createCompilerPosition } from '../utils.js';
import { createCompilerPoint, createCompilerPosition } from '../utils.ts';
describe('parseAstro - Can parse astro files', () => {
it('Can parse files', () => {

View File

@@ -6,8 +6,8 @@
"type": "commonjs",
"repository": {
"type": "git",
"url": "https://github.com/withastro/language-tools",
"directory": "packages/ts-plugin"
"url": "https://github.com/withastro/astro.git",
"directory": "packages/language-tools/ts-plugin"
},
"keywords": [
"astro",

View File

@@ -2,9 +2,9 @@ import { pathToFileURL } from 'node:url';
import { VIRTUAL_CODE_ID, yaml2ts } from '@astrojs/yaml2ts';
import {
type CodeMapping,
forEachEmbeddedCode,
type LanguagePlugin,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';

View File

@@ -2,9 +2,9 @@
import {
type CodeMapping,
forEachEmbeddedCode,
type LanguagePlugin,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import { astro2tsx } from './astro2tsx.js';

View File

@@ -1,48 +0,0 @@
const path = require('path');
const { runTests } = require('@vscode/test-electron');
const { downloadDirToExecutablePath } = require('./utils');
const { existsSync, readdirSync } = require('fs');
async function main() {
// NOTE: Those tests are very flaky on Windows and macOS, so we'll skip them for now
if (process.platform === 'win32' || process.platform === 'darwin') {
process.exit(0);
}
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../vscode');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index.js');
// If there's already a downloaded version of VS Code, let's use it
const vscodeTestPath = path.resolve(__dirname, '../../vscode/.vscode-test');
let vsPath = undefined;
if (existsSync(vscodeTestPath)) {
const files = readdirSync(vscodeTestPath);
files.forEach((file) => {
if (file.startsWith('vscode-')) {
vsPath = downloadDirToExecutablePath(
path.resolve(__dirname, '../../vscode/.vscode-test/', file),
);
return;
}
});
}
await runTests({
extensionDevelopmentPath,
extensionTestsPath,
vscodeExecutablePath: vsPath,
launchArgs: ['./fixtures/fixtures.code-workspace'],
});
} catch {
console.error('Failed to run tests');
process.exit(1);
}
}
main();

View File

@@ -7,7 +7,7 @@ suite('Extension Test Suite', () => {
// TypeScript takes a while to wake up and there's unfortunately no good way to wait for it
async function waitForTS(command, commandArgs, condition) {
for (let i = 0; i < 1000; i++) {
for (let i = 0; i < 2000; i++) {
const commandResult = await vscode.commands.executeCommand(command, ...commandArgs);
if (condition(commandResult)) {
return commandResult;
@@ -32,7 +32,7 @@ suite('Extension Test Suite', () => {
const hasAstroRef = references.some((ref) => ref.uri.path.includes('MyAstroComponent.astro'));
assert.strictEqual(hasAstroRef, true, 'Should find Astro reference');
}).timeout(22000);
}).timeout(50000);
test('can get completions for Astro components', async () => {
const doc = await vscode.workspace.openTextDocument(
@@ -49,7 +49,7 @@ suite('Extension Test Suite', () => {
return item.insertText === 'MyAstroComponent';
});
assert.strictEqual(hasAstroCompletion, true, 'Should find Astro component completion');
}).timeout(12000);
}).timeout(50000);
test('can get implementations inside Astro files', async () => {
const doc = await vscode.workspace.openTextDocument(
@@ -66,5 +66,5 @@ suite('Extension Test Suite', () => {
impl.uri.path.includes('MyAstroComponent'),
);
assert.strictEqual(hasAstroImplementation, true, 'Should find Astro implementation');
}).timeout(12000);
}).timeout(50000);
});

View File

@@ -1,38 +0,0 @@
const path = require('path');
const Mocha = require('mocha');
const glob = require('glob');
exports.run = function () {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true,
});
const testsRoot = path.resolve(__dirname, '..');
return new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
// Add files to the test suite
files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
try {
// Run the mocha test
mocha.run((failures) => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
// eslint-disable-next-line @typescript-eslint/no-shadow
} catch (err) {
e(err);
}
});
});
};

View File

@@ -1,14 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"module": "ES2020",
"target": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"checkJs": false,
"rootDir": ".",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": ["**/*.js"]
}

View File

@@ -1,69 +0,0 @@
/* MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE */
// @vscode/test-electron doesn't export this, so copying it here
// https://github.com/microsoft/vscode-test/blob/c6092b087a9c795c6d2097e864ab13e89d825226/lib/util.ts
const path = require('path');
/**
* @type {string}
*/
let systemDefaultPlatform;
const windowsPlatforms = new Set(['win32-archive', 'win32-x64-archive', 'win32-arm64-archive']);
const darwinPlatforms = new Set(['darwin-arm64', 'darwin']);
switch (process.platform) {
case 'darwin':
systemDefaultPlatform = process.arch === 'arm64' ? 'darwin-arm64' : 'darwin';
break;
case 'win32':
systemDefaultPlatform =
process.arch === 'arm64'
? 'win32-arm64-archive'
: process.arch === 'ia32'
? 'win32-archive'
: 'win32-x64-archive';
break;
default:
systemDefaultPlatform =
process.arch === 'arm64'
? 'linux-arm64'
: process.arch === 'arm'
? 'linux-armhf'
: 'linux-x64';
}
/**
* @param {string} dir
*/
function downloadDirToExecutablePath(dir) {
if (windowsPlatforms.has(systemDefaultPlatform)) {
return path.resolve(dir, 'Code.exe');
} else if (darwinPlatforms.has(systemDefaultPlatform)) {
return path.resolve(dir, 'Visual Studio Code.app/Contents/MacOS/Electron');
} else {
return path.resolve(dir, 'code');
}
}
module.exports = { downloadDirToExecutablePath };

View File

@@ -37,8 +37,8 @@
"main": "./dist/node/client.js",
"repository": {
"type": "git",
"url": "https://github.com/withastro/language-tools.git",
"directory": "packages/vscode"
"url": "https://github.com/withastro/astro.git",
"directory": "packages/language-tools/vscode"
},
"contributes": {
"snippets": [
@@ -253,7 +253,6 @@
"@vscode/vsce": "2.30.0",
"esbuild": "^0.17.19",
"esbuild-plugin-copy": "^2.1.1",
"glob": "^8.0.3",
"js-yaml": "^4.1.0",
"kleur": "^4.1.5",
"mocha": "^10.2.0",

View File

@@ -1,4 +1,4 @@
const assert = require('assert');
const assert = require('node:assert');
const vscode = require('vscode');
suite('Extension Test Suite', () => {

View File

@@ -1,7 +1,7 @@
import { spawn } from 'child_process';
import { readdirSync } from 'fs';
import { dirname, join, resolve } from 'path';
import { fileURLToPath } from 'url';
import { spawn } from 'node:child_process';
import { readdirSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));

View File

@@ -1,27 +0,0 @@
const path = require('path');
const { runTests } = require('@vscode/test-electron');
async function main() {
// NOTE: Those tests are very flaky on Windows and macOS, so we'll skip them for now
if (process.platform === 'win32' || process.platform === 'darwin') {
process.exit(0);
}
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index.js');
// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
} catch {
console.error('Failed to run tests');
process.exit(1);
}
}
main();

View File

@@ -1,15 +0,0 @@
const assert = require('assert');
const vscode = require('vscode');
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('can activate the extension', async function () {
// This can be slow in CI.
this.timeout(10000);
const ext = vscode.extensions.getExtension('astro-build.astro-vscode');
const activate = await ext?.activate();
assert.notStrictEqual(activate, undefined);
});
});

View File

@@ -1,40 +0,0 @@
const path = require('path');
const Mocha = require('mocha');
const glob = require('glob');
exports.run = function () {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true,
});
const testsRoot = path.resolve(__dirname, '..');
return /** @type {Promise<void>} */ (
new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
// Add files to the test suite
files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
try {
// Run the mocha test
mocha.run((failures) => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
// eslint-disable-next-line @typescript-eslint/no-shadow
} catch (err) {
e(err);
}
});
})
);
};

View File

@@ -1,14 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"module": "ES2020",
"target": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"checkJs": true,
"rootDir": ".",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": ["**/*.js", "grammar/test.mjs"]
}

View File

@@ -6,6 +6,11 @@
"build": "tsc",
"dev": "tsc --watch"
},
"repository": {
"type": "git",
"url": "https://github.com/withastro/astro.git",
"directory": "packages/language-tools/yaml2ts"
},
"type": "commonjs",
"main": "dist/index.js",
"files": [

View File

@@ -1 +1 @@
export { yaml2ts, VIRTUAL_CODE_ID, type YAML2TSResult } from './yaml2ts';
export { VIRTUAL_CODE_ID, type YAML2TSResult, yaml2ts } from './yaml2ts';

1927
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
/** @type {import("prettier").Config} */
export default {
printWidth: 100,
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'all',
useTabs: true,
overrides: [
{
files: ['*.md', '*.toml', '*.yml'],
options: {
useTabs: false,
},
},
],
};

View File

@@ -27,6 +27,10 @@ export default async function test() {
setup: { type: 'string', alias: 's' },
// Test teardown file
teardown: { type: 'string' },
// Use tsx to run the tests,
tsx: { type: 'boolean' },
// Test teardown file to include in the test files list
'teardown-test': { type: 'string' },
},
});
@@ -39,6 +43,10 @@ export default async function test() {
ignore: ['**/node_modules/**'],
});
if (args.values['teardown-test']) {
files.push(path.resolve(args.values['teardown-test']));
}
// For some reason, the `only` option does not work and we need to explicitly set the CLI flag instead.
// Node.js requires opt-in to run .only tests :(
// https://nodejs.org/api/test.html#only-tests
@@ -47,6 +55,11 @@ export default async function test() {
process.env.NODE_OPTIONS += ' --test-only';
}
if (args.values.tsx) {
process.env.NODE_OPTIONS ??= '';
process.env.NODE_OPTIONS += ' --import tsx';
}
if (!args.values.parallel) {
// If not parallel, we create a temporary file that imports all the test files
// so that it all runs in a single process.
@@ -68,7 +81,11 @@ export default async function test() {
// https://nodejs.org/api/test.html#runoptions
run({
files,
testNamePatterns: args.values.match,
testNamePatterns: args.values.match
? args.values['teardown-test']
? [args.values.match, 'Teardown']
: args.values.match
: undefined,
concurrency: args.values.parallel,
only: args.values.only,
setup: args.values.setup,