diff --git a/packages/svelte-check/package.json b/packages/svelte-check/package.json index 771bdaf91..c3f6e2fc3 100644 --- a/packages/svelte-check/package.json +++ b/packages/svelte-check/package.json @@ -23,14 +23,13 @@ }, "homepage": "https://github.com/sveltejs/language-tools#readme", "engines": { - "node": ">= 18.0.0" + "node": ">= 18.3.0" }, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", - "picocolors": "^1.0.0", - "sade": "^1.7.4" + "picocolors": "^1.0.0" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", @@ -47,7 +46,6 @@ "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "5.0.2", "@rollup/plugin-typescript": "^10.0.0", - "@types/sade": "^1.7.2", "builtin-modules": "^3.3.0", "rollup": "3.7.5", "rollup-plugin-cleanup": "^3.2.0", diff --git a/packages/svelte-check/src/options.ts b/packages/svelte-check/src/options.ts index faf3f6080..23096023e 100644 --- a/packages/svelte-check/src/options.ts +++ b/packages/svelte-check/src/options.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import sade from 'sade'; +import { parseArgs } from 'node:util'; import { URI } from 'vscode-uri'; export interface SvelteCheckCliOptions { @@ -17,82 +17,109 @@ export interface SvelteCheckCliOptions { } export function parseOptions(cb: (opts: SvelteCheckCliOptions) => any) { - const prog = sade('svelte-check', true) - .version(require('../../package.json').version) // ends up in dist/src, that's why we go two levels up - .option( - '--workspace', - 'Path to your workspace. All subdirectories except node_modules and those listed in `--ignore` are checked. Defaults to current working directory.' - ) - .option( - '--output', - 'What output format to use. Options are human, human-verbose, machine, machine-verbose.', - 'human-verbose' - ) - .option( - '--watch', - 'Will not exit after one pass but keep watching files for changes and rerun diagnostics', - false - ) - .option('--preserveWatchOutput', 'Do not clear the screen in watch mode', false) - .option( - '--tsconfig', - 'Pass a path to a tsconfig or jsconfig file. The path can be relative to the workspace path or absolute. Doing this means that only files matched by the files/include/exclude pattern of the config file are diagnosed. It also means that errors from TypeScript and JavaScript files are reported. When not given, searches for the next upper tsconfig/jsconfig in the workspace path.' - ) - .option( - '--no-tsconfig', - 'Use this if you only want to check the Svelte files found in the current directory and below and ignore any JS/TS files (they will not be type-checked)', - false - ) - .option( - '--ignore', - 'Only has an effect when using `--no-tsconfig` option. Files/folders to ignore - relative to workspace root, comma-separated, inside quotes. Example: `--ignore "dist,build"`' - ) - .option( - '--fail-on-warnings', - 'Will also exit with error code when there are warnings', - false - ) - .option( - '--compiler-warnings', - 'A list of Svelte compiler warning codes. Each entry defines whether that warning should be ignored or treated as an error. Warnings are comma-separated, between warning code and error level is a colon; all inside quotes. Example: `--compiler-warnings "css-unused-selector:ignore,unused-export-let:error"`' - ) - .option( - '--diagnostic-sources', - 'A list of diagnostic sources which should run diagnostics on your code. Possible values are `js` (includes TS), `svelte`, `css`. Comma-separated, inside quotes. By default all are active. Example: `--diagnostic-sources "js,svelte"`' - ) - .option( - '--threshold', - 'Filters the diagnostics to display. `error` will output only errors while `warning` will output warnings and errors.', - 'warning' - ) - // read by sade and preprocessor like sass - .option('--color', 'Force enabling of color output', false) - .option('--no-color', 'Force disabling of color output', false) - .action((opts) => { - const workspaceUri = getWorkspaceUri(opts); - const tsconfig = getTsconfig(opts, workspaceUri.fsPath); - - if (opts.ignore && tsconfig) { - throwError('`--ignore` only has an effect when using `--no-tsconfig`'); - } + const options = { + help: { type: 'boolean', short: 'h' }, + version: { type: 'boolean', short: 'v' }, + workspace: { type: 'string' }, + output: { type: 'string', default: 'human-verbose' }, + watch: { type: 'boolean' }, + preserveWatchOutput: { type: 'boolean' }, + tsconfig: { type: 'string' }, + 'no-tsconfig': { type: 'boolean' }, + ignore: { type: 'string' }, + 'fail-on-warnings': { type: 'boolean' }, + 'compiler-warnings': { type: 'string' }, + 'diagnostic-sources': { type: 'string' }, + threshold: { type: 'string', default: 'warning' }, + color: { type: 'boolean' }, + 'no-color': { type: 'boolean' } + } as const; - cb({ - workspaceUri, - outputFormat: getOutputFormat(opts), - watch: !!opts.watch, - preserveWatchOutput: !!opts.preserveWatchOutput, - tsconfig, - filePathsToIgnore: opts.ignore?.split(',') || [], - failOnWarnings: !!opts['fail-on-warnings'], - compilerWarnings: getCompilerWarnings(opts), - diagnosticSources: getDiagnosticSources(opts), - threshold: getThreshold(opts) - }); + try { + const { values } = parseArgs({ + args: process.argv.slice(2), + options, + strict: false }); - prog.parse(process.argv, { - unknown: (arg) => `Unknown option ${arg}` - }); + if (values.help) { + showHelp(); + process.exit(0); + } + + if (values.version) { + console.log(require('../../package.json').version); + process.exit(0); + } + + const workspaceUri = getWorkspaceUri(values); + const tsconfig = getTsconfig(values, workspaceUri.fsPath); + + if (values.ignore && tsconfig) { + throwError('`--ignore` only has an effect when using `--no-tsconfig`'); + } + + cb({ + workspaceUri, + outputFormat: getOutputFormat(values), + watch: !!values.watch, + preserveWatchOutput: !!values.preserveWatchOutput, + tsconfig, + filePathsToIgnore: typeof values.ignore === 'string' ? values.ignore.split(',') : [], + failOnWarnings: !!values['fail-on-warnings'], + compilerWarnings: getCompilerWarnings(values), + diagnosticSources: getDiagnosticSources(values), + threshold: getThreshold(values) + }); + } catch (error: any) { + console.error(`Error parsing arguments: ${error.message}`); + process.exit(1); + } +} + +function showHelp() { + const packageJson = require('../../package.json'); + console.log(`${packageJson.name} v${packageJson.version}`); + console.log(`${packageJson.description}`); + console.log(''); + console.log('Usage: svelte-check [options]'); + console.log(''); + console.log('Options:'); + console.log(' -h, --help Show help'); + console.log(' -v, --version Show version'); + console.log( + ' --workspace Path to your workspace. All subdirectories except node_modules and those listed in `--ignore` are checked. Defaults to current working directory.' + ); + console.log( + ' --output What output format to use. Options are human, human-verbose, machine, machine-verbose. (default: "human-verbose")' + ); + console.log( + ' --watch Will not exit after one pass but keep watching files for changes and rerun diagnostics' + ); + console.log(' --preserveWatchOutput Do not clear the screen in watch mode'); + console.log( + ' --tsconfig Pass a path to a tsconfig or jsconfig file. The path can be relative to the workspace path or absolute.' + ); + console.log( + ' --no-tsconfig Use this if you only want to check the Svelte files found in the current directory and below and ignore any JS/TS files' + ); + console.log( + ' --ignore Only has an effect when using `--no-tsconfig` option. Files/folders to ignore - relative to workspace root, comma-separated, inside quotes.' + ); + console.log( + ' --fail-on-warnings Will also exit with error code when there are warnings' + ); + console.log( + ' --compiler-warnings A list of Svelte compiler warning codes. Each entry defines whether that warning should be ignored or treated as an error.' + ); + console.log( + ' --diagnostic-sources A list of diagnostic sources which should run diagnostics on your code. Possible values are `js` (includes TS), `svelte`, `css`.' + ); + console.log( + ' --threshold Filters the diagnostics to display. `error` will output only errors while `warning` will output warnings and errors. (default: "warning")' + ); + console.log(' --color Force enabling of color output'); + console.log(' --no-color Force disabling of color output'); } const outputFormats = ['human', 'human-verbose', 'machine', 'machine-verbose'] as const; @@ -190,7 +217,7 @@ function getDiagnosticSources(opts: Record): DiagnosticSource[] { .split(',') ?.map((s: string) => s.trim()) .filter((s: any) => diagnosticSources.includes(s)) - : diagnosticSources; + : [...diagnosticSources]; } const thresholds = ['warning', 'error'] as const; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38c0cb205..4005424c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,9 +127,6 @@ importers: picocolors: specifier: ^1.0.0 version: 1.0.0 - sade: - specifier: ^1.7.4 - version: 1.8.1 devDependencies: '@rollup/plugin-commonjs': specifier: ^24.0.0 @@ -146,9 +143,6 @@ importers: '@rollup/plugin-typescript': specifier: ^10.0.0 version: 10.0.1(rollup@3.7.5)(tslib@2.5.2)(typescript@5.8.2) - '@types/sade': - specifier: ^1.7.2 - version: 1.7.4 builtin-modules: specifier: ^3.3.0 version: 3.3.0 @@ -765,18 +759,12 @@ packages: '@types/mocha@9.1.1': resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} - '@types/mri@1.1.1': - resolution: {integrity: sha512-nJOuiTlsvmClSr3+a/trTSx4DTuY/VURsWGKSf/eeavh0LRMqdsK60ti0TlwM5iHiGOK3/Ibkxsbr7i9rzGreA==} - '@types/node@18.19.46': resolution: {integrity: sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/sade@1.7.4': - resolution: {integrity: sha512-6ys13kmtlY0aIOz4KtMdeBD9BHs6vSE3aRcj4vAZqXjypT2el8WZt6799CMjElVgh1cbOH/t3vrpQ4IpwytcPA==} - '@types/semver@7.7.0': resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} @@ -1382,10 +1370,6 @@ packages: engines: {node: '>= 12.0.0'} hasBin: true - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -1558,10 +1542,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2229,18 +2209,12 @@ snapshots: '@types/mocha@9.1.1': {} - '@types/mri@1.1.1': {} - '@types/node@18.19.46': dependencies: undici-types: 5.26.5 '@types/resolve@1.20.2': {} - '@types/sade@1.7.4': - dependencies: - '@types/mri': 1.1.1 - '@types/semver@7.7.0': {} '@types/sinon@7.5.2': {} @@ -2863,8 +2837,6 @@ snapshots: yargs-parser: 20.2.4 yargs-unparser: 2.0.0 - mri@1.2.0: {} - ms@2.1.2: {} ms@2.1.3: {} @@ -3043,10 +3015,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - sade@1.8.1: - dependencies: - mri: 1.2.0 - safe-buffer@5.2.1: {} semver@7.5.1: