From 75ac1d536b084bce6c38230c3e9cd559bd6ec1db Mon Sep 17 00:00:00 2001 From: Oskar Lebuda Date: Tue, 7 Jul 2026 23:10:18 +0200 Subject: [PATCH 1/3] feat(typecheck): add golar support --- README.md | 2 +- packages/nuxi/src/commands/typecheck.ts | 251 ++++++++++++++++++++---- playground/package.json | 4 + pnpm-lock.yaml | 17 +- 4 files changed, 231 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index fbab95d0..f58dd8ae 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ COMMANDS preview Launches Nitro server for local testing after `nuxi build`. start Launches Nitro server for local testing after `nuxi build`. test Run tests - typecheck Runs `vue-tsc` to check types throughout your app. + typecheck Runs type-checking throughout your app using `vue-tsc` or Golar. upgrade Upgrade Nuxt complete Generate shell completion scripts diff --git a/packages/nuxi/src/commands/typecheck.ts b/packages/nuxi/src/commands/typecheck.ts index 4e8425e4..a83766ab 100644 --- a/packages/nuxi/src/commands/typecheck.ts +++ b/packages/nuxi/src/commands/typecheck.ts @@ -1,40 +1,76 @@ +import { existsSync } from 'node:fs' +import { writeFile } from 'node:fs/promises' import process from 'node:process' -import { cancel, confirm, isCancel, spinner } from '@clack/prompts' +import { cancel, confirm, isCancel, select, spinner } from '@clack/prompts' import { defineCommand } from 'citty' import { colors } from 'consola/utils' import { resolveModulePath } from 'exsolve' import { addDevDependency, detectPackageManager } from 'nypm' import { resolve } from 'pathe' -import { readTSConfig } from 'pkg-types' +import { readPackageJSON, readTSConfig } from 'pkg-types' import { hasTTY } from 'std-env' import { x } from 'tinyexec' import { loadKit } from '../utils/kit' import { logger } from '../utils/logger' +import { withNodePath } from '../utils/paths' import { cwdArgs, dotEnvArgs, extendsArgs, legacyRootDirArgs, logLevelArgs } from './_shared' -const REQUIRED_DEPS = { - 'typescript': 'typescript', - 'vue-tsc': 'vue-tsc/bin/vue-tsc.js', -} as const +type TypeChecker = 'vue-tsc' | 'golar' -type DepName = keyof typeof REQUIRED_DEPS +interface TypeCheckerSetup { + checker: TypeChecker + bin: string +} -function resolveDeps({ cache }: { cache?: boolean } = {}) { - const out = {} as Record - // trick to type `name` as `DepName` instead of `string` - let name: DepName - for (name in REQUIRED_DEPS) { - out[name] = resolveModulePath(REQUIRED_DEPS[name], { try: true, cache }) - } - return out +interface TypeCheckerMeta { + label: string + hint: string + packages: readonly string[] + docs?: string | undefined } +interface ResolvedTypeChecker { + missing: string[] + bin?: string +} + +const TYPE_CHECKERS = { + 'vue-tsc': { + label: 'vue-tsc', + hint: 'Vue\'s official TypeScript checker', + packages: ['typescript', 'vue-tsc'], + docs: undefined, + }, + 'golar': { + label: 'Golar', + hint: 'Native-speed type-checking powered by typescript-go', + packages: ['golar', '@golar/vue'], + docs: 'https://golar.dev/languages/vue/', + }, +} as const satisfies Record + +const CHECKER_PRIORITY: TypeChecker[] = ['vue-tsc', 'golar'] + +const GOLAR_CONFIG_FILES = [ + 'golar.config.ts', + 'golar.config.mts', + 'golar.config.mjs', + 'golar.config.cts', + 'golar.config.cjs', +] as const + +const GOLAR_CONFIG_TEMPLATE = `import { defineConfig } from 'golar/unstable' +import '@golar/vue' + +export default defineConfig({}) +` + export default defineCommand({ meta: { name: 'typecheck', - description: 'Runs `vue-tsc` to check types throughout your app.', + description: 'Runs type-checking throughout your app using `vue-tsc` or Golar.', }, args: { ...cwdArgs, @@ -48,22 +84,22 @@ export default defineCommand({ const cwd = resolve(ctx.args.cwd || ctx.args.rootDir) - const [supportsProjects, vueTsc] = await Promise.all([ - readTSConfig(cwd).then(r => !!(r.references?.length)), - ensureVueTsc(cwd, resolveDeps()), + const [supportsProjects, typechecker] = await Promise.all([ + readTSConfig(cwd).then(config => !!(config.references?.length)), + resolveTypeChecker(cwd), writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel as 'silent' | 'info' | 'verbose', { ...ctx.data?.overrides, ...(ctx.args.extends && { extends: ctx.args.extends }), }), ]) - if (!vueTsc) { + if (!typechecker) { process.exitCode = 1 return } const start = Date.now() - const result = await x(vueTsc, supportsProjects ? ['-b', '--noEmit'] : ['--noEmit'], { + const result = await x(typechecker.bin, getTypecheckArgs(typechecker.checker, supportsProjects), { nodeOptions: { stdio: 'inherit', cwd }, }) const duration = `${Date.now() - start}ms` @@ -82,27 +118,166 @@ export default defineCommand({ }, }) -async function ensureVueTsc(cwd: string, deps: Record): Promise { - const missing = (Object.keys(REQUIRED_DEPS) as DepName[]).filter(name => !deps[name]) - if (missing.length === 0) { - return deps['vue-tsc'] +function getTypecheckArgs(checker: TypeChecker, supportsProjects: boolean) { + if (checker === 'golar') { + return supportsProjects + ? ['tsc', '--build', '--noEmit'] + : ['tsc', '--noEmit'] + } + + return supportsProjects + ? ['-b', '--noEmit'] + : ['--noEmit'] +} + +async function resolveTypeChecker(cwd: string): Promise { + for (const checker of CHECKER_PRIORITY) { + const resolved = resolveChecker(checker, cwd) + if (resolved.missing.length === 0 && resolved.bin) { + if (checker === 'golar') { + await ensureGolarConfig(cwd) + } + return { checker, bin: resolved.bin } + } } + return await promptTypeCheckerInstall(cwd) +} + +function resolveChecker(checker: TypeChecker, cwd: string, { cache = true } = {}): ResolvedTypeChecker { + const from = withNodePath(cwd) + + if (checker === 'golar') { + const bin = resolveGolarBin(cwd) + const vuePlugin = resolveModulePath('@golar/vue', { from, try: true, cache }) + const missing = [ + ...(!bin ? ['golar'] : []), + ...(!vuePlugin ? ['@golar/vue'] : []), + ] + return { missing, bin } + } + + const typescript = resolveModulePath('typescript', { from, try: true, cache }) + const bin = resolveModulePath('vue-tsc/bin/vue-tsc.js', { from, try: true, cache }) + const missing = [ + ...(!typescript ? ['typescript'] : []), + ...(!bin ? ['vue-tsc'] : []), + ] + return { missing, bin } +} + +function resolveGolarBin(cwd: string) { + // golar restricts package exports, so resolve the CLI entry directly + let dir = cwd + while (true) { + const candidate = resolve(dir, 'node_modules/golar/dist/bin.js') + if (existsSync(candidate)) { + return candidate + } + const parent = resolve(dir, '..') + if (parent === dir) { + return undefined + } + dir = parent + } +} + +async function ensureGolarConfig(cwd: string) { + if (GOLAR_CONFIG_FILES.some(file => existsSync(resolve(cwd, file)))) { + return + } + + const pkg = await readPackageJSON(cwd).catch(() => null) + const filename = pkg?.type === 'module' ? 'golar.config.ts' : 'golar.config.mts' + await writeFile(resolve(cwd, filename), GOLAR_CONFIG_TEMPLATE) + logger.info(`Created ${colors.cyan(filename)}`) +} + +async function promptTypeCheckerInstall(cwd: string): Promise { const packageManager = await detectPackageManager(cwd, { includeParentDirs: true }) const pmName = packageManager?.name ?? 'npm' - const installCommand = `${packageManager?.command ?? pmName} add ${pmName === 'bun' ? '-d' : '-D'} ${missing.join(' ')}` - - const list = missing.map(name => colors.cyan(name)).join(' and ') - const plural = missing.length > 1 - const are = plural ? 'are' : 'is' - const devDependency = plural ? 'devDependencies' : 'a devDependency' + const devFlag = pmName === 'bun' ? '-d' : '-D' + const pmCommand = packageManager?.command ?? pmName if (!hasTTY) { - logger.error(`${list} ${are} required for ${colors.cyan('nuxt typecheck')}. Install ${plural ? 'them' : 'it'} as ${devDependency}:\n\n ${colors.bold(installCommand)}\n`) + printInstallInstructions(pmCommand, devFlag) + return + } + + logger.warn(`No type checker found for ${colors.cyan('nuxt typecheck')}.`) + + const selected = await select({ + message: 'Which type checker would you like to use?', + options: CHECKER_PRIORITY.map(name => ({ + value: name, + label: TYPE_CHECKERS[name].label, + hint: TYPE_CHECKERS[name].hint, + })), + initialValue: 'vue-tsc', + }) + + if (isCancel(selected)) { + cancel('Skipping installation.') return } - logger.warn(`${list} ${are} required for ${colors.cyan('nuxt typecheck')} but ${plural ? 'were' : 'was'} not found.`) + const installCommand = formatInstallCommand(selected, pmCommand, devFlag) + const { missing } = resolveChecker(selected, cwd) + + if (missing.length > 0) { + const installed = await installMissingPackages({ + cwd, + packageManager, + pmName, + packages: missing, + installCommand, + }) + if (!installed) { + return + } + } + + const resolved = resolveChecker(selected, cwd, { cache: false }) + if (!resolved.bin) { + logger.error(`Failed to resolve ${colors.cyan(selected)} after installation. Please check your installation.`) + return + } + + if (selected === 'golar') { + await ensureGolarConfig(cwd) + } + + return { checker: selected, bin: resolved.bin } +} + +function printInstallInstructions(pmCommand: string, devFlag: string) { + logger.error(`A type checker is required for ${colors.cyan('nuxt typecheck')}. Install one of the following:\n`) + + for (const checker of CHECKER_PRIORITY) { + const meta = TYPE_CHECKERS[checker] + const command = formatInstallCommand(checker, pmCommand, devFlag) + const docs = meta.docs ? ` (see ${colors.cyan(meta.docs)})` : '' + logger.info(`${colors.cyan(meta.label)}${docs}:\n\n ${colors.bold(command)}\n`) + } + + logger.info(`Golar also requires a ${colors.cyan('golar.config.ts')} file. One will be created automatically on the next interactive run.\n`) +} + +function formatInstallCommand(checker: TypeChecker, pmCommand: string, devFlag: string) { + return `${pmCommand} add ${devFlag} ${TYPE_CHECKERS[checker].packages.join(' ')}` +} + +async function installMissingPackages(options: { + cwd: string + packageManager: Awaited> + pmName: string + packages: string[] + installCommand: string +}): Promise { + const { cwd, packageManager, pmName, packages, installCommand } = options + const list = packages.map(name => colors.cyan(name)).join(' and ') + const plural = packages.length > 1 + const devDependency = plural ? 'devDependencies' : 'a devDependency' const shouldInstall = await confirm({ message: `Install ${list} as ${devDependency}?`, @@ -111,23 +286,22 @@ async function ensureVueTsc(cwd: string, deps: Record) { @@ -142,7 +316,6 @@ async function writeTypes(cwd: string, dotenv?: string, logLevel?: 'silent' | 'i }, }) - // Generate types and build Nuxt instance await writeTypes(nuxt) await buildNuxt(nuxt) await nuxt.close() diff --git a/playground/package.json b/playground/package.json index 78f76cd2..4411f91b 100644 --- a/playground/package.json +++ b/playground/package.json @@ -14,8 +14,12 @@ "vue-router": "^5.1.0" }, "devDependencies": { +<<<<<<< Updated upstream "@nuxt/test-utils": "^4.0.3", "typescript": "^6.0.3", "vue-tsc": "^3.3.5" +======= + "@nuxt/test-utils": "^4.0.3" +>>>>>>> Stashed changes } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a7b589e..2c1f62bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -404,6 +404,7 @@ importers: devDependencies: '@nuxt/test-utils': specifier: ^4.0.3 +<<<<<<< Updated upstream version: 4.0.3(crossws@0.4.5(srvx@0.11.17))(magicast@0.5.3)(typescript@6.0.3)(vite@7.3.3(@types/node@24.13.2)(jiti@2.7.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.9) typescript: specifier: ^6.0.3 @@ -411,6 +412,9 @@ importers: vue-tsc: specifier: ^3.3.5 version: 3.3.5(typescript@6.0.3) +======= + version: 4.0.3(crossws@0.4.5(srvx@0.11.16))(magicast@0.5.3)(typescript@6.0.3)(vite@7.3.3(@types/node@24.12.4)(jiti@2.7.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.8) +>>>>>>> Stashed changes packages: @@ -8686,14 +8690,17 @@ snapshots: '@volar/language-core@2.4.28': dependencies: '@volar/source-map': 2.4.28 + optional: true - '@volar/source-map@2.4.28': {} + '@volar/source-map@2.4.28': + optional: true '@volar/typescript@2.4.28': dependencies: '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 + optional: true '@vue-macros/common@3.1.2(vue@3.5.38(typescript@6.0.3))': dependencies: @@ -8792,6 +8799,7 @@ snapshots: muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.4 + optional: true '@vue/reactivity@3.5.38': dependencies: @@ -8842,7 +8850,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - alien-signals@3.2.1: {} + alien-signals@3.2.1: + optional: true ansi-regex@5.0.1: {} @@ -11436,7 +11445,8 @@ snapshots: parseurl@1.3.3: {} - path-browserify@1.0.1: {} + path-browserify@1.0.1: + optional: true path-exists@4.0.0: {} @@ -12576,6 +12586,7 @@ snapshots: '@volar/typescript': 2.4.28 '@vue/language-core': 3.3.5 typescript: 6.0.3 + optional: true vue@3.5.38(typescript@6.0.3): dependencies: From 3a63e5788c8fbe19c069d4575cf177b6d24b24e3 Mon Sep 17 00:00:00 2001 From: Oskar Lebuda Date: Tue, 7 Jul 2026 23:29:43 +0200 Subject: [PATCH 2/3] feat: add support for golar --- packages/nuxi/src/commands/typecheck.ts | 95 +++++++++++++++++-------- playground/package.json | 4 -- pnpm-lock.yaml | 17 +---- 3 files changed, 68 insertions(+), 48 deletions(-) diff --git a/packages/nuxi/src/commands/typecheck.ts b/packages/nuxi/src/commands/typecheck.ts index a83766ab..3a885ac0 100644 --- a/packages/nuxi/src/commands/typecheck.ts +++ b/packages/nuxi/src/commands/typecheck.ts @@ -28,7 +28,7 @@ interface TypeCheckerMeta { label: string hint: string packages: readonly string[] - docs?: string | undefined + docs?: string } interface ResolvedTypeChecker { @@ -36,12 +36,11 @@ interface ResolvedTypeChecker { bin?: string } -const TYPE_CHECKERS = { +const TYPE_CHECKERS: Record = { 'vue-tsc': { label: 'vue-tsc', hint: 'Vue\'s official TypeScript checker', packages: ['typescript', 'vue-tsc'], - docs: undefined, }, 'golar': { label: 'Golar', @@ -49,7 +48,7 @@ const TYPE_CHECKERS = { packages: ['golar', '@golar/vue'], docs: 'https://golar.dev/languages/vue/', }, -} as const satisfies Record +} const CHECKER_PRIORITY: TypeChecker[] = ['vue-tsc', 'golar'] @@ -78,15 +77,26 @@ export default defineCommand({ ...dotEnvArgs, ...extendsArgs, ...legacyRootDirArgs, + checker: { + type: 'string', + description: 'Type checker to use (`vue-tsc` or `golar`)', + }, }, async run(ctx) { process.env.NODE_ENV = process.env.NODE_ENV || 'production' const cwd = resolve(ctx.args.cwd || ctx.args.rootDir) + const checkerArg = ctx.args.checker + if (checkerArg && !(checkerArg in TYPE_CHECKERS)) { + logger.error(`Unknown type checker ${colors.cyan(checkerArg)}. Expected one of: ${CHECKER_PRIORITY.join(', ')}.`) + process.exitCode = 1 + return + } + const [supportsProjects, typechecker] = await Promise.all([ readTSConfig(cwd).then(config => !!(config.references?.length)), - resolveTypeChecker(cwd), + resolveTypeChecker(cwd, checkerArg as TypeChecker | undefined), writeTypes(cwd, ctx.args.dotenv, ctx.args.logLevel as 'silent' | 'info' | 'verbose', { ...ctx.data?.overrides, ...(ctx.args.extends && { extends: ctx.args.extends }), @@ -130,8 +140,14 @@ function getTypecheckArgs(checker: TypeChecker, supportsProjects: boolean) { : ['--noEmit'] } -async function resolveTypeChecker(cwd: string): Promise { - for (const checker of CHECKER_PRIORITY) { +async function resolveTypeChecker(cwd: string, preferred?: TypeChecker): Promise { + const priority = preferred + ? [preferred] + : hasGolarConfig(cwd) + ? (['golar', 'vue-tsc'] as TypeChecker[]) + : CHECKER_PRIORITY + + for (const checker of priority) { const resolved = resolveChecker(checker, cwd) if (resolved.missing.length === 0 && resolved.bin) { if (checker === 'golar') { @@ -141,7 +157,7 @@ async function resolveTypeChecker(cwd: string): Promise existsSync(resolve(cwd, file))) } async function ensureGolarConfig(cwd: string) { - if (GOLAR_CONFIG_FILES.some(file => existsSync(resolve(cwd, file)))) { + if (hasGolarConfig(cwd)) { return } @@ -193,32 +222,36 @@ async function ensureGolarConfig(cwd: string) { logger.info(`Created ${colors.cyan(filename)}`) } -async function promptTypeCheckerInstall(cwd: string): Promise { +async function promptTypeCheckerInstall(cwd: string, preferred?: TypeChecker): Promise { const packageManager = await detectPackageManager(cwd, { includeParentDirs: true }) const pmName = packageManager?.name ?? 'npm' const devFlag = pmName === 'bun' ? '-d' : '-D' const pmCommand = packageManager?.command ?? pmName if (!hasTTY) { - printInstallInstructions(pmCommand, devFlag) + printInstallInstructions(pmCommand, devFlag, preferred ? [preferred] : CHECKER_PRIORITY) return } - logger.warn(`No type checker found for ${colors.cyan('nuxt typecheck')}.`) - - const selected = await select({ - message: 'Which type checker would you like to use?', - options: CHECKER_PRIORITY.map(name => ({ - value: name, - label: TYPE_CHECKERS[name].label, - hint: TYPE_CHECKERS[name].hint, - })), - initialValue: 'vue-tsc', - }) + let selected = preferred + if (!selected) { + logger.warn(`No type checker found for ${colors.cyan('nuxt typecheck')}.`) + + const answer = await select({ + message: 'Which type checker would you like to use?', + options: CHECKER_PRIORITY.map(name => ({ + value: name, + label: TYPE_CHECKERS[name].label, + hint: TYPE_CHECKERS[name].hint, + })), + initialValue: 'vue-tsc', + }) - if (isCancel(selected)) { - cancel('Skipping installation.') - return + if (isCancel(answer)) { + cancel('Skipping installation.') + return + } + selected = answer } const installCommand = formatInstallCommand(selected, pmCommand, devFlag) @@ -250,17 +283,19 @@ async function promptTypeCheckerInstall(cwd: string): Promise 1 ? 'one of the following' : 'it as a devDependency'}:\n`) - for (const checker of CHECKER_PRIORITY) { + for (const checker of checkers) { const meta = TYPE_CHECKERS[checker] const command = formatInstallCommand(checker, pmCommand, devFlag) const docs = meta.docs ? ` (see ${colors.cyan(meta.docs)})` : '' logger.info(`${colors.cyan(meta.label)}${docs}:\n\n ${colors.bold(command)}\n`) } - logger.info(`Golar also requires a ${colors.cyan('golar.config.ts')} file. One will be created automatically on the next interactive run.\n`) + if (checkers.includes('golar')) { + logger.info(`Golar also requires a ${colors.cyan('golar.config.ts')} file. One will be created automatically the first time Golar is used.\n`) + } } function formatInstallCommand(checker: TypeChecker, pmCommand: string, devFlag: string) { diff --git a/playground/package.json b/playground/package.json index 4411f91b..78f76cd2 100644 --- a/playground/package.json +++ b/playground/package.json @@ -14,12 +14,8 @@ "vue-router": "^5.1.0" }, "devDependencies": { -<<<<<<< Updated upstream "@nuxt/test-utils": "^4.0.3", "typescript": "^6.0.3", "vue-tsc": "^3.3.5" -======= - "@nuxt/test-utils": "^4.0.3" ->>>>>>> Stashed changes } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c1f62bd..4a7b589e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -404,7 +404,6 @@ importers: devDependencies: '@nuxt/test-utils': specifier: ^4.0.3 -<<<<<<< Updated upstream version: 4.0.3(crossws@0.4.5(srvx@0.11.17))(magicast@0.5.3)(typescript@6.0.3)(vite@7.3.3(@types/node@24.13.2)(jiti@2.7.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.9) typescript: specifier: ^6.0.3 @@ -412,9 +411,6 @@ importers: vue-tsc: specifier: ^3.3.5 version: 3.3.5(typescript@6.0.3) -======= - version: 4.0.3(crossws@0.4.5(srvx@0.11.16))(magicast@0.5.3)(typescript@6.0.3)(vite@7.3.3(@types/node@24.12.4)(jiti@2.7.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.8) ->>>>>>> Stashed changes packages: @@ -8690,17 +8686,14 @@ snapshots: '@volar/language-core@2.4.28': dependencies: '@volar/source-map': 2.4.28 - optional: true - '@volar/source-map@2.4.28': - optional: true + '@volar/source-map@2.4.28': {} '@volar/typescript@2.4.28': dependencies: '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 - optional: true '@vue-macros/common@3.1.2(vue@3.5.38(typescript@6.0.3))': dependencies: @@ -8799,7 +8792,6 @@ snapshots: muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.4 - optional: true '@vue/reactivity@3.5.38': dependencies: @@ -8850,8 +8842,7 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - alien-signals@3.2.1: - optional: true + alien-signals@3.2.1: {} ansi-regex@5.0.1: {} @@ -11445,8 +11436,7 @@ snapshots: parseurl@1.3.3: {} - path-browserify@1.0.1: - optional: true + path-browserify@1.0.1: {} path-exists@4.0.0: {} @@ -12586,7 +12576,6 @@ snapshots: '@volar/typescript': 2.4.28 '@vue/language-core': 3.3.5 typescript: 6.0.3 - optional: true vue@3.5.38(typescript@6.0.3): dependencies: From 6f17a4cb20ed22ca6775d16901d01b09843b4847 Mon Sep 17 00:00:00 2001 From: Oskar Lebuda Date: Wed, 8 Jul 2026 15:14:33 +0200 Subject: [PATCH 3/3] feat: add support for golar --- packages/nuxi/src/commands/typecheck.ts | 5 +++-- packages/nuxi/src/utils/paths.ts | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nuxi/src/commands/typecheck.ts b/packages/nuxi/src/commands/typecheck.ts index 3a885ac0..b8cb7744 100644 --- a/packages/nuxi/src/commands/typecheck.ts +++ b/packages/nuxi/src/commands/typecheck.ts @@ -1,5 +1,6 @@ import { existsSync } from 'node:fs' import { writeFile } from 'node:fs/promises' +import { delimiter } from 'node:path' import process from 'node:process' import { cancel, confirm, isCancel, select, spinner } from '@clack/prompts' @@ -88,7 +89,7 @@ export default defineCommand({ const cwd = resolve(ctx.args.cwd || ctx.args.rootDir) const checkerArg = ctx.args.checker - if (checkerArg && !(checkerArg in TYPE_CHECKERS)) { + if (checkerArg && !Object.hasOwn(TYPE_CHECKERS, checkerArg)) { logger.error(`Unknown type checker ${colors.cyan(checkerArg)}. Expected one of: ${CHECKER_PRIORITY.join(', ')}.`) process.exitCode = 1 return @@ -197,7 +198,7 @@ function resolveGolarBin(cwd: string) { dir = parent } - for (const nodePath of process.env.NODE_PATH?.split(':') || []) { + for (const nodePath of process.env.NODE_PATH?.split(delimiter) || []) { const candidate = resolve(nodePath, 'golar/dist/bin.js') if (existsSync(candidate)) { return candidate diff --git a/packages/nuxi/src/utils/paths.ts b/packages/nuxi/src/utils/paths.ts index 76af1f82..12262d51 100644 --- a/packages/nuxi/src/utils/paths.ts +++ b/packages/nuxi/src/utils/paths.ts @@ -1,3 +1,4 @@ +import { delimiter } from 'node:path' import process from 'node:process' import { relative } from 'pathe' @@ -8,5 +9,5 @@ export function relativeToProcess(path: string) { } export function withNodePath(path: string) { - return [path, ...(process.env.NODE_PATH?.split(':') || [])] + return [path, ...(process.env.NODE_PATH?.split(delimiter) || [])] }