diff --git a/eslint.config.js b/eslint.config.js index d1c5736c..d6ae62c5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,3 +1,4 @@ +// @ts-expect-error import svelte_config from '@sveltejs/eslint-config'; /** @type {import('eslint').Linter.Config[]} */ diff --git a/package.json b/package.json index 46d4d22f..3ac0e6eb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "type": "module", "scripts": { - "check": "pnpm -r check", + "check": "tsc --noEmit", "lint": "pnpm -r lint && eslint --cache --cache-location node_modules/.eslintcache", "format": "pnpm -r format", "changeset:version": "changeset version && pnpm -r generate:version && git add --all", diff --git a/packages/cli/bin.ts b/packages/cli/bin.ts index bf364138..e8b607fb 100644 --- a/packages/cli/bin.ts +++ b/packages/cli/bin.ts @@ -7,6 +7,7 @@ import { create } from './index.js'; import { dist, package_manager } from './utils.js'; import { executeSvelteAdd } from './svelte-add.js'; import pkg from './package.json'; +import type { TemplateTypes, Types } from './types/internal.js'; run(); @@ -47,7 +48,8 @@ ${colors.grey(`create-svelte version ${version}`)} } } - const options = await p.group( + type A = { template: string | symbol, types: string | symbol | null } + const options = await p.group( { template: (_) => p.select({ @@ -89,8 +91,8 @@ ${colors.grey(`create-svelte version ${version}`)} await create(cwd, { name: path.basename(path.resolve(cwd)), - template: /** @type {'default' | 'skeleton' | 'skeletonlib'} */ options.template, - types: /** @type {'checkjs' | 'typescript' | null} */ options.types + template: options.template as TemplateTypes, + types: options.types as Types }); p.outro('Your project is ready!'); diff --git a/packages/cli/index.ts b/packages/cli/index.ts index ceb976ab..2beca489 100644 --- a/packages/cli/index.ts +++ b/packages/cli/index.ts @@ -1,31 +1,28 @@ import fs from 'node:fs'; import path from 'node:path'; import { mkdirp, copy, dist } from './utils.js'; +import type { Common, Condition, File, Options, Types } from './types/internal.js'; -/** @type {import('./types/index.js').create} */ // eslint-disable-next-line @typescript-eslint/require-await -export async function create(cwd, options) { +export async function create(cwd: string, options: Options) { mkdirp(cwd); write_template_files(options.template, options.types, options.name, cwd); write_common_files(cwd, options, options.name); } -/** - * @param {string} template - * @param {'typescript' | 'checkjs' | null} types - * @param {string} name - * @param {string} cwd - */ -function write_template_files(template, types, name, cwd) { +function write_template_files( + template: string, + types: Types, + name: string, + cwd: string +) { const dir = dist(`templates/${template}`); - copy(`${dir}/assets`, cwd, (name) => name.replace('DOT-', '.')); + copy(`${dir}/assets`, cwd, (name: string) => name.replace('DOT-', '.')); copy(`${dir}/package.json`, `${cwd}/package.json`); const manifest = `${dir}/files.types=${types}.json`; - const files = /** @type {import('./types/internal.js').File[]} */ JSON.parse( - fs.readFileSync(manifest, 'utf-8') - ); + const files = JSON.parse(fs.readFileSync(manifest, 'utf-8')) as File[]; files.forEach((file) => { const dest = path.join(cwd, file.name); @@ -35,17 +32,9 @@ function write_template_files(template, types, name, cwd) { }); } -/** - * - * @param {string} cwd - * @param {import('./types/internal.js').Options} options - * @param {string} name - */ -function write_common_files(cwd, options, name) { +function write_common_files(cwd: string, options: Options, name: string) { const shared = dist('shared.json'); - const { files } = /** @type {import('./types/internal.js').Common} */ JSON.parse( - fs.readFileSync(shared, 'utf-8') - ); + const { files } = JSON.parse(fs.readFileSync(shared, 'utf-8')) as Common; const pkg_file = path.join(cwd, 'package.json'); const pkg = /** @type {any} */ JSON.parse(fs.readFileSync(pkg_file, 'utf-8')); @@ -73,12 +62,7 @@ function write_common_files(cwd, options, name) { fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, '\t') + '\n'); } -/** - * @param {import('./types/internal.js').Condition} condition - * @param {import('./types/internal.js').Options} options - * @returns {boolean} - */ -function matches_condition(condition, options) { +function matches_condition(condition: Condition, options: Options) { if (condition === 'default' || condition === 'skeleton' || condition === 'skeletonlib') { return options.template === condition; } @@ -88,11 +72,7 @@ function matches_condition(condition, options) { return !!options[condition]; } -/** - * @param {any} target - * @param {any} source - */ -function merge(target, source) { +function merge(target: any, source: any) { for (const key in source) { if (key in target) { const target_value = target[key]; @@ -116,12 +96,10 @@ function merge(target, source) { } } -/** @param {Record} obj */ -function sort_keys(obj) { +function sort_keys(obj: Record) { if (!obj) return; - /** @type {Record} */ - const sorted = {}; + const sorted: Record = {}; Object.keys(obj) .sort() .forEach((key) => { @@ -137,7 +115,7 @@ function sort_keys(obj) { * * @param {import('./types/internal.js').Common['files']} files */ -function sort_files(files) { +function sort_files(files: Common['files']) { return files.sort((f1, f2) => { const f1_more_generic = f1.include.every((include) => f2.include.includes(include)) && @@ -151,8 +129,7 @@ function sort_files(files) { }); } -/** @param {string} name */ -function to_valid_package_name(name) { +function to_valid_package_name(name: string) { return name .trim() .toLowerCase() diff --git a/packages/cli/svelte-add.js b/packages/cli/svelte-add.ts similarity index 58% rename from packages/cli/svelte-add.js rename to packages/cli/svelte-add.ts index 5892b84a..a78ccc15 100644 --- a/packages/cli/svelte-add.js +++ b/packages/cli/svelte-add.ts @@ -1,27 +1,30 @@ #!/usr/bin/env node import { remoteControl, executeAdders, prompts } from '@svelte-cli/core/internal'; -import { adderCategories, categories, adderIds } from '@svelte-cli/config'; +import pkg from './package.json'; +import type { Question } from '@svelte-cli/core/adder/options'; +import type { + AdderDetails, + AddersToApplySelectorParams, + ExecutingAdderInfo +} from '@svelte-cli/core/adder/execute'; +import { adderCategories, categories, adderIds, type CategoryKeys } from '@svelte-cli/config'; import { getAdderDetails } from '@svelte-cli/adders'; -/** - * @param {string} cwd - */ -export async function executeSvelteAdd(cwd) { +export async function executeSvelteAdd(cwd: string) { remoteControl.enable(); - /** @type {import('@svelte-cli/core/internal').AdderDetails>[]} */ - const adderDetails = []; + const adderDetails: Array>> = []; for (const adderName of adderIds) { const adder = await getAdderDetails(adderName); + // @ts-expect-error adderDetails.push({ config: adder.config, checks: adder.checks }); } - /** @type {import('@svelte-cli/core/internal').ExecutingAdderInfo} */ - const executingAdderInfo = { - name: 'todo-package-name-svelte-cli', - version: 'todo-version' + const executingAdderInfo: ExecutingAdderInfo = { + name: pkg.name, + version: pkg.version }; await executeAdders(adderDetails, executingAdderInfo, undefined, selectAddersToApply, cwd); @@ -29,26 +32,13 @@ export async function executeSvelteAdd(cwd) { remoteControl.disable(); } -/** - * @typedef AdderOption - * @property {string} value - * @property {string} label - * @property {string} hint - */ - -/** - * @param {import('@svelte-cli/core/internal').AddersToApplySelectorParams} param0 - * @returns {Promise} - */ -async function selectAddersToApply({ projectType, addersMetadata }) { - /** @type {Record} */ - const promptOptions = {}; +type AdderOption = { value: string; label: string; hint: string }; +async function selectAddersToApply({ projectType, addersMetadata }: AddersToApplySelectorParams) { + const promptOptions: Record = {}; for (const [categoryId, adderIds] of Object.entries(adderCategories)) { - const typedCategoryId = /** @type {import('@svelte-cli/config').CategoryKeys} */ (categoryId); - const categoryDetails = categories[typedCategoryId]; - /** @type {AdderOption[]} */ - const options = []; + const categoryDetails = categories[categoryId as CategoryKeys]; + const options: AdderOption[] = []; const adders = addersMetadata.filter((x) => adderIds.includes(x.id)); for (const adder of adders) { diff --git a/packages/cli/test/check.js b/packages/cli/test/check.ts similarity index 89% rename from packages/cli/test/check.js rename to packages/cli/test/check.ts index 62ef1382..1bc52fdc 100644 --- a/packages/cli/test/check.js +++ b/packages/cli/test/check.ts @@ -5,13 +5,11 @@ import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; import glob from 'tiny-glob/sync.js'; import { beforeAll, describe, test } from 'vitest'; -import { create } from '../dist/index.js'; +import { create } from '../index.js'; +import type { TemplateTypes, Types } from '../types/internal.js'; -/** - * Resolve the given path relative to the current file - * @param {string} path - */ -const resolve_path = (path) => fileURLToPath(new URL(path, import.meta.url)); +// Resolve the given path relative to the current file +const resolve_path = (path: string) => fileURLToPath(new URL(path, import.meta.url)); // use a directory outside of packages to ensure it isn't added to the pnpm workspace const test_workspace_dir = resolve_path('../../../.test-tmp/create-svelte/'); @@ -57,8 +55,7 @@ beforeAll(async () => { }); }, 60000); -/** @param {any} pkg */ -function patch_package_json(pkg) { +function patch_package_json(pkg: any) { Object.entries(overrides).forEach(([key, value]) => { if (pkg.devDependencies?.[key]) { pkg.devDependencies[key] = value; @@ -88,14 +85,12 @@ function patch_package_json(pkg) { */ const script_test_map = new Map(); -const templates = /** @type {Array<'default' | 'skeleton' | 'skeletonlib'>} */ ( - fs.readdirSync('templates') -); +const templates = fs.readdirSync('templates') as TemplateTypes[]; for (const template of templates) { if (template[0] === '.') continue; - for (const types of /** @type {const} */ (['checkjs', 'typescript'])) { + for (const types of ['checkjs', 'typescript'] as Types[]) { const cwd = path.join(test_workspace_dir, `${template}-${types}`); fs.rmSync(cwd, { recursive: true, force: true }); diff --git a/packages/cli/types/internal.d.ts b/packages/cli/types/internal.d.ts index f0e86222..8a3d66a6 100644 --- a/packages/cli/types/internal.d.ts +++ b/packages/cli/types/internal.d.ts @@ -1,7 +1,10 @@ +export type TemplateTypes = 'default' | 'skeleton' | 'skeletonlib' +export type Types = 'typescript' | 'checkjs' | null + export type Options = { name: string; - template: 'default' | 'skeleton' | 'skeletonlib'; - types: 'typescript' | 'checkjs' | null; + template: TemplateTypes; + types: Types; }; export type File = { @@ -9,7 +12,7 @@ export type File = { contents: string; }; -export type Condition = 'typescript' | 'checkjs' | 'skeleton' | 'default' | 'skeletonlib'; +export type Condition = Exclude; export type Common = { files: Array<{ diff --git a/packages/cli/vitest.config.js b/packages/cli/vitest.config.js index 3f545141..33cdc9c7 100644 --- a/packages/cli/vitest.config.js +++ b/packages/cli/vitest.config.js @@ -1,5 +1,5 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ - test: { dir: './test', include: ['*.js'] } + test: { dir: './test', include: ['*.ts'] } }); diff --git a/tsconfig.json b/tsconfig.json index 26c62f05..f9f1c2cb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "exclude": ["**/dist/**", "**/temp/**"], + "exclude": [ "**/dist/**", "packages/cli/templates/**", "packages/cli/shared/**", "**/temp/**" ], "compilerOptions": { "checkJs": true, "module": "es2022", @@ -10,6 +10,6 @@ "strict": true, "esModuleInterop": true, "verbatimModuleSyntax": true, - "isolatedModules": true + "isolatedModules": true, } }