diff --git a/package.json b/package.json index b2b1d13ce31f2..a4c2b46ee23d9 100644 --- a/package.json +++ b/package.json @@ -270,6 +270,7 @@ "open": "^8.4.0", "openai": "~4.3.1", "ora": "5.3.0", + "oxc-transform": "^0.123.0", "parse-markdown-links": "^1.0.4", "parse5": "4.0.0", "picocolors": "catalog:", diff --git a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts index f92c181e70d8d..4795ef09f2d67 100644 --- a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts +++ b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts @@ -15,6 +15,7 @@ import { runTypeCheck as _runTypeCheck, TypeCheckOptions, } from '@nx/js'; +import { emitOxcDeclarations } from '@nx/js/src/utils/typescript/oxc-declaration-emitter'; import * as esbuild from 'esbuild'; import { normalizeOptions } from './lib/normalize'; @@ -136,6 +137,36 @@ export async function* esbuildExecutor( setup(build: esbuild.PluginBuild) { build.onEnd(async (result: esbuild.BuildResult) => { if ( + options.useOxcDeclarations && + options.declaration + ) { + // Type-check without emitting if needed + if (!options.skipTypeCheck) { + const typeCheckOpts = getTypeCheckOptions( + options, + context + ); + typeCheckOpts.mode = 'noEmit'; + const { errors, warnings } = + await _runTypeCheck(typeCheckOpts); + if (errors.length > 0 || warnings.length > 0) { + await printDiagnostics(errors, warnings); + } + hasTypeErrors = errors.length > 0; + } + // Emit declarations with oxc + const projectRoot = + context.projectGraph.nodes[context.projectName] + .data.root; + const oxcResult = await emitOxcDeclarations({ + projectRoot: join(context.root, projectRoot), + outDir: options.outputPath, + rootDir: + options.declarationRootDir ?? context.root, + }); + hasTypeErrors = + hasTypeErrors || oxcResult.errors.length > 0; + } else if ( !options.skipTypeCheck || (options.isTsSolutionSetup && options.declaration) ) { @@ -191,8 +222,36 @@ export async function* esbuildExecutor( } ); } else { - // Run type-checks first and bail if they don't pass. - if ( + // Run type-checks and/or declaration emission. + if (options.useOxcDeclarations && options.declaration) { + // When using oxc for declarations, run type-check separately (noEmit mode) + // if needed, then emit declarations with oxc-transform. + if (!options.skipTypeCheck) { + const typeCheckOpts = getTypeCheckOptions(options, context); + // Override to noEmit since oxc handles declaration emission + typeCheckOpts.mode = 'noEmit'; + const { errors, warnings } = await _runTypeCheck(typeCheckOpts); + if (errors.length > 0 || warnings.length > 0) { + await printDiagnostics(errors, warnings); + } + if (errors.length > 0) { + yield { success: false }; + return; + } + } + + const projectRoot = + context.projectGraph.nodes[context.projectName].data.root; + const { errors } = await emitOxcDeclarations({ + projectRoot: join(context.root, projectRoot), + outDir: options.outputPath, + rootDir: options.declarationRootDir ?? context.root, + }); + if (errors.length > 0) { + yield { success: false }; + return; + } + } else if ( !options.skipTypeCheck || (options.isTsSolutionSetup && options.declaration) ) { diff --git a/packages/esbuild/src/executors/esbuild/schema.d.ts b/packages/esbuild/src/executors/esbuild/schema.d.ts index 79e0220aa9ba7..22b317c89c1ac 100644 --- a/packages/esbuild/src/executors/esbuild/schema.d.ts +++ b/packages/esbuild/src/executors/esbuild/schema.d.ts @@ -9,6 +9,12 @@ export interface EsBuildExecutorOptions { bundle?: boolean; declaration?: boolean; declarationRootDir?: string; + /** + * Use oxc-transform for generating TypeScript declaration files (.d.ts) + * instead of the TypeScript compiler. Requires `isolatedDeclarations: true` + * in the project's tsconfig. + */ + useOxcDeclarations?: boolean; deleteOutputPath?: boolean; esbuildOptions?: Record; esbuildConfig?: string; diff --git a/packages/esbuild/src/executors/esbuild/schema.json b/packages/esbuild/src/executors/esbuild/schema.json index a6e3b67dea118..ea1ba91cdeb83 100644 --- a/packages/esbuild/src/executors/esbuild/schema.json +++ b/packages/esbuild/src/executors/esbuild/schema.json @@ -62,6 +62,11 @@ "type": "string", "description": "Sets the rootDir for the declaration (*.d.ts) files." }, + "useOxcDeclarations": { + "type": "boolean", + "description": "Use oxc-transform for generating TypeScript declaration files (.d.ts) instead of the TypeScript compiler. Requires `isolatedDeclarations: true` in the project's tsconfig. Significantly faster than TSC-based emission.", + "default": false + }, "watch": { "type": "boolean", "description": "Enable re-building when files change.", diff --git a/packages/js/package.json b/packages/js/package.json index ef07c90d2ddb2..ebd4d15163668 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -64,9 +64,13 @@ "nx": "workspace:*" }, "peerDependencies": { + "oxc-transform": "^0.123.0", "verdaccio": "^6.0.5" }, "peerDependenciesMeta": { + "oxc-transform": { + "optional": true + }, "verdaccio": { "optional": true } diff --git a/packages/js/src/plugins/rollup/oxc-declarations.spec.ts b/packages/js/src/plugins/rollup/oxc-declarations.spec.ts new file mode 100644 index 0000000000000..cb99a0e8fcb18 --- /dev/null +++ b/packages/js/src/plugins/rollup/oxc-declarations.spec.ts @@ -0,0 +1,328 @@ +import { oxcDeclarations } from './oxc-declarations'; +import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'fs'; +import { join } from 'path'; +import { tmpdir } from 'os'; + +// Mock oxc-transform since it has native bindings that Jest can't load +jest.mock('oxc-transform', () => ({ + isolatedDeclaration: jest.fn( + async (filename: string, source: string, _options?: any) => { + // Simple mock that converts TS source to a minimal .d.ts + // by wrapping exported functions/interfaces in declare statements + let code = ''; + if (source.includes('export function')) { + const match = source.match(/export function (\w+)\(([^)]*)\):\s*(\w+)/); + if (match) { + code = `export declare function ${match[1]}(${match[2]}): ${match[3]};\n`; + } + } + if (source.includes('export interface')) { + // Pass through interface declarations as-is (they're already type-only) + code += source.replace(/export interface/g, 'export declare interface'); + } + return { code, map: null }; + } + ), +})); + +describe('oxcDeclarations', () => { + let testDir: string; + let srcDir: string; + let outDir: string; + + beforeEach(() => { + testDir = join(tmpdir(), `oxc-decl-test-${Date.now()}`); + srcDir = join(testDir, 'src'); + outDir = join(testDir, 'dist'); + mkdirSync(srcDir, { recursive: true }); + mkdirSync(outDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(testDir, { recursive: true, force: true }); + }); + + it('should create a plugin with the correct name', () => { + const plugin = oxcDeclarations({ projectRoot: testDir }); + expect(plugin.name).toBe('nx-oxc-declarations'); + }); + + it('should generate .d.ts for a chunk with a .ts source', async () => { + writeFileSync( + join(srcDir, 'index.ts'), + `export function greet(name: string): string { return 'Hello ' + name; }\n` + ); + + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + const bundle = { + 'index.js': { + type: 'chunk' as const, + facadeModuleId: join(srcDir, 'index.ts'), + isEntry: true, + fileName: 'index.js', + exports: [], + modules: {}, + code: '', + isDynamicEntry: false, + isImplicitEntry: false, + moduleIds: [], + importedBindings: {}, + imports: [], + dynamicImports: [], + referencedFiles: [], + implicitlyLoadedBefore: [], + map: null, + name: 'index', + preliminaryFileName: 'index.js', + sourcemapFileName: null, + }, + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, bundle as any); + + const dtsPath = join(outDir, 'index.d.ts'); + expect(existsSync(dtsPath)).toBe(true); + + const content = readFileSync(dtsPath, 'utf-8'); + expect(content).toContain('greet'); + expect(content).toContain('declare'); + expect(mockContext.error).not.toHaveBeenCalled(); + }); + + it('should generate .d.ts for tree-shaken type-only files', async () => { + writeFileSync( + join(srcDir, 'types.ts'), + `export interface User { name: string; age: number; }\n` + ); + + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + // Empty bundle — simulating that types.ts was tree-shaken + await plugin.writeBundle.call(mockContext, { dir: outDir }, {} as any); + + const dtsPath = join(outDir, 'src', 'types.d.ts'); + expect(existsSync(dtsPath)).toBe(true); + + const content = readFileSync(dtsPath, 'utf-8'); + expect(content).toContain('User'); + expect(content).toContain('interface'); + }); + + it('should skip non-.ts chunks', async () => { + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + const bundle = { + 'index.js': { + type: 'chunk' as const, + facadeModuleId: join(srcDir, 'index.js'), + isEntry: true, + fileName: 'index.js', + exports: [], + modules: {}, + code: '', + isDynamicEntry: false, + isImplicitEntry: false, + moduleIds: [], + importedBindings: {}, + imports: [], + dynamicImports: [], + referencedFiles: [], + implicitlyLoadedBefore: [], + map: null, + name: 'index', + preliminaryFileName: 'index.js', + sourcemapFileName: null, + }, + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, bundle as any); + + const dtsPath = join(outDir, 'index.d.ts'); + expect(existsSync(dtsPath)).toBe(false); + }); + + it('should skip .spec.ts and .test.ts files in tree walk', async () => { + writeFileSync( + join(srcDir, 'utils.spec.ts'), + `export function testHelper(): void {}\n` + ); + writeFileSync( + join(srcDir, 'utils.test.ts'), + `export function testHelper2(): void {}\n` + ); + + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, {} as any); + + expect(existsSync(join(outDir, 'src', 'utils.spec.d.ts'))).toBe(false); + expect(existsSync(join(outDir, 'src', 'utils.test.d.ts'))).toBe(false); + }); + + it('should warn when source file is not found', async () => { + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + const bundle = { + 'index.js': { + type: 'chunk' as const, + facadeModuleId: join(srcDir, 'nonexistent.ts'), + isEntry: true, + fileName: 'index.js', + exports: [], + modules: {}, + code: '', + isDynamicEntry: false, + isImplicitEntry: false, + moduleIds: [], + importedBindings: {}, + imports: [], + dynamicImports: [], + referencedFiles: [], + implicitlyLoadedBefore: [], + map: null, + name: 'index', + preliminaryFileName: 'index.js', + sourcemapFileName: null, + }, + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, bundle as any); + + expect(mockContext.warn).toHaveBeenCalledWith( + expect.stringContaining('Source file not found') + ); + }); + + it('should skip chunks without facadeModuleId', async () => { + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + const bundle = { + 'chunk-abc.js': { + type: 'chunk' as const, + facadeModuleId: null, + isEntry: false, + fileName: 'chunk-abc.js', + exports: [], + modules: {}, + code: '', + isDynamicEntry: false, + isImplicitEntry: false, + moduleIds: [], + importedBindings: {}, + imports: [], + dynamicImports: [], + referencedFiles: [], + implicitlyLoadedBefore: [], + map: null, + name: 'chunk-abc', + preliminaryFileName: 'chunk-abc.js', + sourcemapFileName: null, + }, + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, bundle as any); + + expect(existsSync(join(outDir, 'chunk-abc.d.ts'))).toBe(false); + expect(mockContext.error).not.toHaveBeenCalled(); + }); + + it('should not regenerate .d.ts files already created in phase 1', async () => { + // Create a source file that will be both a bundle entry and in the source tree + writeFileSync( + join(srcDir, 'index.ts'), + `export function greet(name: string): string { return 'Hello ' + name; }\n` + ); + + const plugin = oxcDeclarations({ + projectRoot: testDir, + sourceRoot: srcDir, + }); + + const { isolatedDeclaration } = require('oxc-transform'); + (isolatedDeclaration as jest.Mock).mockClear(); + + const mockContext = { + warn: jest.fn(), + error: jest.fn(), + }; + + const bundle = { + 'src/index.js': { + type: 'chunk' as const, + facadeModuleId: join(srcDir, 'index.ts'), + isEntry: true, + fileName: 'src/index.js', + exports: [], + modules: {}, + code: '', + isDynamicEntry: false, + isImplicitEntry: false, + moduleIds: [], + importedBindings: {}, + imports: [], + dynamicImports: [], + referencedFiles: [], + implicitlyLoadedBefore: [], + map: null, + name: 'index', + preliminaryFileName: 'src/index.js', + sourcemapFileName: null, + }, + }; + + await plugin.writeBundle.call(mockContext, { dir: outDir }, bundle as any); + + // Phase 1 creates dist/src/index.d.ts + // Phase 2 should skip it since it already exists + expect(isolatedDeclaration).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/js/src/plugins/rollup/oxc-declarations.ts b/packages/js/src/plugins/rollup/oxc-declarations.ts new file mode 100644 index 0000000000000..533bb933d58f4 --- /dev/null +++ b/packages/js/src/plugins/rollup/oxc-declarations.ts @@ -0,0 +1,181 @@ +// nx-ignore-next-line +import type { OutputBundle, OutputOptions, PluginContext } from 'rollup'; +import { + readFileSync, + writeFileSync, + mkdirSync, + existsSync, + readdirSync, + statSync, +} from 'node:fs'; +import { resolve, dirname, join, relative } from 'node:path'; + +// NOTE: This is here so we can share between `@nx/rollup` and `@nx/vite`. + +function formatDeclarationError(error: unknown): string { + if (error instanceof Error) { + return error.stack ?? error.message; + } + return String(error); +} + +export interface OxcDeclarationsOptions { + /** + * The root directory of the project (where src/ lives). + */ + projectRoot: string; + /** + * The source directory to walk for tree-shaken type-only files. + * Defaults to `${projectRoot}/src`. + */ + sourceRoot?: string; + /** + * Whether to generate source maps for declaration files. + * Defaults to `false`. + */ + sourcemap?: boolean; + /** + * Whether to strip `@internal` JSDoc annotations from declarations. + * Defaults to `false`. + */ + stripInternal?: boolean; +} + +/** + * A Rollup/Vite plugin that generates TypeScript declaration files (.d.ts) + * using oxc-transform's `isolatedDeclaration` instead of the TypeScript + * compiler. + * + * This is significantly faster than TSC-based declaration emission and works + * for projects that have `isolatedDeclarations: true` in their tsconfig. + * + * Modeled after the oxcDtsPlugin from the Analog project. + */ +export function oxcDeclarations(options: OxcDeclarationsOptions) { + const { projectRoot, sourcemap = false, stripInternal = false } = options; + const sourceRoot = options.sourceRoot ?? resolve(projectRoot, 'src'); + + return { + name: 'nx-oxc-declarations', + async writeBundle( + this: PluginContext, + outputOptions: OutputOptions, + bundle: OutputBundle + ): Promise { + const { isolatedDeclaration } = await import('oxc-transform'); + const outDir = outputOptions.dir!; + + // Phase 1: Generate .d.ts for each bundle entry chunk that has a .ts source + for (const [fileName, chunk] of Object.entries(bundle)) { + if (chunk.type !== 'chunk' || !chunk.facadeModuleId) continue; + + const sourceFile = chunk.facadeModuleId; + if (!sourceFile.endsWith('.ts') || sourceFile.endsWith('.d.ts')) + continue; + + if (!existsSync(sourceFile)) { + this.warn( + [ + `Skipping declaration emit for bundle entry "${fileName}".`, + `Source file not found: ${sourceFile}`, + 'A follow-up source-tree pass will attempt to emit the declaration.', + ].join('\n') + ); + continue; + } + + try { + const source = readFileSync(sourceFile, 'utf-8'); + const result = await isolatedDeclaration(sourceFile, source, { + sourcemap, + stripInternal, + }); + + if (result.code) { + const dtsPath = join(outDir, fileName.replace(/\.js$/, '.d.ts')); + mkdirSync(dirname(dtsPath), { recursive: true }); + writeFileSync(dtsPath, result.code); + if (result.map && sourcemap) { + writeFileSync(dtsPath + '.map', JSON.stringify(result.map)); + } + } + } catch (error) { + this.error( + [ + `Failed to emit declaration for bundle entry "${fileName}".`, + `Source file: ${sourceFile}`, + formatDeclarationError(error), + ].join('\n') + ); + } + } + + // Phase 2: Generate .d.ts for type-only source files that were tree-shaken + // from the bundle (e.g., files that only export types/interfaces). + if (existsSync(sourceRoot)) { + for (const tsFile of walkTs(sourceRoot)) { + const relPath = relative(projectRoot, tsFile); + const dtsOut = join(outDir, relPath.replace(/\.ts$/, '.d.ts')); + + // Skip if already generated in Phase 1 + if (existsSync(dtsOut)) continue; + + try { + const source = readFileSync(tsFile, 'utf-8'); + const result = await isolatedDeclaration(tsFile, source, { + sourcemap, + stripInternal, + }); + + if (result.code) { + mkdirSync(dirname(dtsOut), { recursive: true }); + writeFileSync(dtsOut, result.code); + if (result.map && sourcemap) { + writeFileSync(dtsOut + '.map', JSON.stringify(result.map)); + } + } + } catch (error) { + this.warn( + [ + `Failed to emit declaration for source file "${tsFile}".`, + `Output path: ${dtsOut}`, + formatDeclarationError(error), + ].join('\n') + ); + } + } + } + }, + }; +} + +/** + * Recursively walk a directory and yield all TypeScript source files, + * skipping test files and existing declaration files. + */ +function* walkTs(dir: string): Generator { + let entries: string[]; + try { + entries = readdirSync(dir); + } catch { + return; + } + + for (const entry of entries) { + const full = join(dir, entry); + try { + if (statSync(full).isDirectory()) { + yield* walkTs(full); + } else if ( + full.endsWith('.ts') && + !full.endsWith('.spec.ts') && + !full.endsWith('.test.ts') && + !full.endsWith('.d.ts') + ) { + yield full; + } + } catch { + // Skip files we can't stat + } + } +} diff --git a/packages/js/src/utils/typescript/oxc-declaration-emitter.ts b/packages/js/src/utils/typescript/oxc-declaration-emitter.ts new file mode 100644 index 0000000000000..3314f170ccebe --- /dev/null +++ b/packages/js/src/utils/typescript/oxc-declaration-emitter.ts @@ -0,0 +1,125 @@ +import { + readFileSync, + writeFileSync, + mkdirSync, + existsSync, + readdirSync, + statSync, +} from 'node:fs'; +import { resolve, dirname, join, relative } from 'node:path'; +import { logger } from '@nx/devkit'; + +export interface OxcDeclarationEmitterOptions { + /** + * The root directory of the project. + */ + projectRoot: string; + /** + * The source directory to scan for TypeScript files. + * Defaults to `${projectRoot}/src`. + */ + sourceRoot?: string; + /** + * The output directory for generated .d.ts files. + */ + outDir: string; + /** + * The root directory used for computing relative output paths. + * Defaults to projectRoot. + */ + rootDir?: string; + /** + * Whether to generate source maps for declaration files. + * Defaults to `false`. + */ + sourcemap?: boolean; + /** + * Whether to strip `@internal` JSDoc annotations from declarations. + * Defaults to `false`. + */ + stripInternal?: boolean; +} + +/** + * Generates TypeScript declaration files (.d.ts) for all source files in a + * project using oxc-transform's `isolatedDeclaration`. This is a standalone + * function that can be used by any executor (esbuild, etc.) as an alternative + * to running the TypeScript compiler with `emitDeclarationOnly`. + * + * Requires `isolatedDeclarations: true` in the project's tsconfig. + */ +export async function emitOxcDeclarations( + options: OxcDeclarationEmitterOptions +): Promise<{ errors: string[] }> { + const { + projectRoot, + outDir, + sourcemap = false, + stripInternal = false, + } = options; + const sourceRoot = options.sourceRoot ?? resolve(projectRoot, 'src'); + const rootDir = options.rootDir ?? projectRoot; + const errors: string[] = []; + + const { isolatedDeclaration } = await import('oxc-transform'); + + for (const tsFile of walkTs(sourceRoot)) { + const relPath = relative(rootDir, tsFile); + const dtsOut = join(outDir, relPath.replace(/\.ts$/, '.d.ts')); + + try { + const source = readFileSync(tsFile, 'utf-8'); + const result = await isolatedDeclaration(tsFile, source, { + sourcemap, + stripInternal, + }); + + if (result.code) { + mkdirSync(dirname(dtsOut), { recursive: true }); + writeFileSync(dtsOut, result.code); + if (result.map && sourcemap) { + writeFileSync(dtsOut + '.map', JSON.stringify(result.map)); + } + } + } catch (error) { + const message = `Failed to emit declaration for "${tsFile}": ${ + error instanceof Error ? error.message : String(error) + }`; + errors.push(message); + logger.error(message); + } + } + + return { errors }; +} + +/** + * Recursively walk a directory and yield all TypeScript source files, + * skipping test files and existing declaration files. + */ +function* walkTs(dir: string): Generator { + let entries: string[]; + try { + entries = readdirSync(dir); + } catch { + return; + } + + for (const entry of entries) { + const full = join(dir, entry); + try { + if (statSync(full).isDirectory()) { + yield* walkTs(full); + } else if ( + full.endsWith('.ts') && + !full.endsWith('.spec.ts') && + !full.endsWith('.test.ts') && + !full.endsWith('.d.ts') + ) { + yield full; + } + } catch { + // Skip files we can't stat + } + } +} diff --git a/packages/js/src/utils/versions.ts b/packages/js/src/utils/versions.ts index 5a292ae8f81d8..7b557ff26f78d 100644 --- a/packages/js/src/utils/versions.ts +++ b/packages/js/src/utils/versions.ts @@ -8,6 +8,7 @@ export const swcHelpersVersion = '~0.5.18'; export const swcNodeVersion = '~1.11.1'; export const tsLibVersion = '^2.3.0'; export const typesNodeVersion = '20.19.9'; +export const oxcTransformVersion = '^0.123.0'; export const verdaccioVersion = '^6.3.2'; // Typescript diff --git a/packages/rollup/src/executors/rollup/schema.d.ts b/packages/rollup/src/executors/rollup/schema.d.ts index 3b6f2dcc10c12..0113a21284784 100644 --- a/packages/rollup/src/executors/rollup/schema.d.ts +++ b/packages/rollup/src/executors/rollup/schema.d.ts @@ -34,5 +34,6 @@ export interface RollupExecutorOptions { skipTypeCheck?: boolean; skipTypeField?: boolean; useLegacyTypescriptPlugin?: boolean; + useOxcDeclarations?: boolean; watch?: boolean; } diff --git a/packages/rollup/src/executors/rollup/schema.json b/packages/rollup/src/executors/rollup/schema.json index fec980f48f291..06b0e05eb264a 100644 --- a/packages/rollup/src/executors/rollup/schema.json +++ b/packages/rollup/src/executors/rollup/schema.json @@ -160,6 +160,11 @@ "type": "boolean", "description": "Use rollup-plugin-typescript2 instead of @rollup/plugin-typescript.", "default": false + }, + "useOxcDeclarations": { + "type": "boolean", + "description": "Use oxc-transform for generating TypeScript declaration files (.d.ts) instead of the TypeScript compiler. Requires `isolatedDeclarations: true` in the project's tsconfig. Significantly faster and removes the need for TypeScript during builds when using a non-tsc compiler (swc, babel).", + "default": false } }, "required": ["tsConfig", "main", "outputPath"], diff --git a/packages/rollup/src/plugins/with-nx/with-nx-options.ts b/packages/rollup/src/plugins/with-nx/with-nx-options.ts index 977771181facb..099336d1a7ace 100644 --- a/packages/rollup/src/plugins/with-nx/with-nx-options.ts +++ b/packages/rollup/src/plugins/with-nx/with-nx-options.ts @@ -84,6 +84,13 @@ export interface RollupWithNxPluginOptions { * Use rollup-plugin-typescript2 instead of @rollup/plugin-typescript. */ useLegacyTypescriptPlugin?: boolean; + /** + * Use oxc-transform for generating TypeScript declaration files (.d.ts) + * instead of the TypeScript compiler. Requires `isolatedDeclarations: true` + * in the project's tsconfig. This is significantly faster and removes the + * need for TypeScript during builds when using a non-tsc compiler (swc, babel). + */ + useOxcDeclarations?: boolean; /** * Whether to generate a package.json file in the output path. It's not supported when the workspace is * set up with TypeScript Project References along with the package managers' Workspaces feature. Otherwise, diff --git a/packages/rollup/src/plugins/with-nx/with-nx.ts b/packages/rollup/src/plugins/with-nx/with-nx.ts index 255063e0caff7..2df84181d6c0a 100644 --- a/packages/rollup/src/plugins/with-nx/with-nx.ts +++ b/packages/rollup/src/plugins/with-nx/with-nx.ts @@ -6,6 +6,7 @@ import { readJsonFile, workspaceRoot, } from '@nx/devkit'; +import { oxcDeclarations } from '@nx/js/src/plugins/rollup/oxc-declarations'; import { typeDefinitions } from '@nx/js/src/plugins/rollup/type-definitions'; import { calculateProjectBuildableDependencies, @@ -251,45 +252,56 @@ export function withNx( image(), json(), // TypeScript compilation and declaration generation - options.useLegacyTypescriptPlugin === true - ? (() => { - // TODO(v23): Remove in Nx 23 - // Show deprecation warning - logger.warn( - `rollup-plugin-typescript2 is deprecated and will be removed in Nx 23. ` + - `You are explicitly using it with 'useLegacyTypescriptPlugin: true'. ` + - `Consider removing this option to use the official @rollup/plugin-typescript.` - ); - - return require('rollup-plugin-typescript2')({ - check: !options.skipTypeCheck, - tsconfig: tsConfigPath, - tsconfigOverride: { - compilerOptions, - }, - }); - })() - : (() => { - // @rollup/plugin-typescript needs outDir and declarationDir to match Rollup's output directory - const { outDir, declarationDir, ...tsCompilerOptions } = - compilerOptions; - const rollupOutputDir = Array.isArray(finalConfig.output) - ? finalConfig.output[0].dir - : finalConfig.output.dir; - return require('@rollup/plugin-typescript')({ - tsconfig: tsConfigPath, - compilerOptions: { - ...tsCompilerOptions, - composite: false, - outDir: rollupOutputDir, - declarationDir: rollupOutputDir, - noEmitOnError: !options.skipTypeCheck, - }, - }); - })(), - typeDefinitions({ - projectRoot, - }), + // When useOxcDeclarations is enabled with a non-tsc compiler, skip + // TypeScript entirely — SWC/Babel handles JS, oxc handles declarations. + ...(options.useOxcDeclarations && (useSwc || useBabel) + ? [] + : [ + options.useLegacyTypescriptPlugin === true + ? (() => { + // TODO(v23): Remove in Nx 23 + // Show deprecation warning + logger.warn( + `rollup-plugin-typescript2 is deprecated and will be removed in Nx 23. ` + + `You are explicitly using it with 'useLegacyTypescriptPlugin: true'. ` + + `Consider removing this option to use the official @rollup/plugin-typescript.` + ); + + return require('rollup-plugin-typescript2')({ + check: !options.skipTypeCheck, + tsconfig: tsConfigPath, + tsconfigOverride: { + compilerOptions, + }, + }); + })() + : (() => { + // @rollup/plugin-typescript needs outDir and declarationDir to match Rollup's output directory + const { outDir, declarationDir, ...tsCompilerOptions } = + compilerOptions; + const rollupOutputDir = Array.isArray(finalConfig.output) + ? finalConfig.output[0].dir + : finalConfig.output.dir; + return require('@rollup/plugin-typescript')({ + tsconfig: tsConfigPath, + compilerOptions: { + ...tsCompilerOptions, + composite: false, + outDir: rollupOutputDir, + declarationDir: rollupOutputDir, + noEmitOnError: !options.skipTypeCheck, + }, + }); + })(), + ]), + options.useOxcDeclarations + ? oxcDeclarations({ + projectRoot, + sourceRoot: join(workspaceRoot, projectSourceRoot), + }) + : typeDefinitions({ + projectRoot, + }), postcss({ inject: true, extract: options.extractCss, diff --git a/packages/rollup/src/utils/ensure-dependencies.ts b/packages/rollup/src/utils/ensure-dependencies.ts index a8ab278976e15..db146773591d4 100644 --- a/packages/rollup/src/utils/ensure-dependencies.ts +++ b/packages/rollup/src/utils/ensure-dependencies.ts @@ -3,38 +3,42 @@ import { type GeneratorCallback, type Tree, } from '@nx/devkit'; -import { swcCoreVersion, swcHelpersVersion } from '@nx/js/src/utils/versions'; +import { + oxcTransformVersion, + swcCoreVersion, + swcHelpersVersion, +} from '@nx/js/src/utils/versions'; import { coreJsVersion, swcLoaderVersion, tsLibVersion } from './versions'; export type EnsureDependenciesOptions = { compiler?: 'babel' | 'swc' | 'tsc'; + useOxcDeclarations?: boolean; }; export function ensureDependencies( tree: Tree, options: EnsureDependenciesOptions ): GeneratorCallback { + const devDependencies: Record = {}; + switch (options.compiler) { case 'swc': - return addDependenciesToPackageJson( - tree, - {}, - { - '@swc/helpers': swcHelpersVersion, - '@swc/core': swcCoreVersion, - 'swc-loader': swcLoaderVersion, - } - ); + devDependencies['@swc/helpers'] = swcHelpersVersion; + devDependencies['@swc/core'] = swcCoreVersion; + devDependencies['swc-loader'] = swcLoaderVersion; + break; case 'babel': - return addDependenciesToPackageJson( - tree, - {}, - { - 'core-js': coreJsVersion, // needed for preset-env to work - tslib: tsLibVersion, - } - ); + devDependencies['core-js'] = coreJsVersion; + devDependencies['tslib'] = tsLibVersion; + break; default: - return addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion }); + devDependencies['tslib'] = tsLibVersion; + break; } + + if (options.useOxcDeclarations) { + devDependencies['oxc-transform'] = oxcTransformVersion; + } + + return addDependenciesToPackageJson(tree, {}, devDependencies); } diff --git a/packages/vite/plugins/nx-oxc-declarations.plugin.ts b/packages/vite/plugins/nx-oxc-declarations.plugin.ts new file mode 100644 index 0000000000000..1550a0d4903bc --- /dev/null +++ b/packages/vite/plugins/nx-oxc-declarations.plugin.ts @@ -0,0 +1,57 @@ +import type { Plugin } from 'vite'; + +export interface NxOxcDeclarationsPluginOptions { + /** + * The root directory of the project (where src/ lives). + * Defaults to `import.meta.dirname` if not provided. + */ + projectRoot?: string; + /** + * The source directory to walk for tree-shaken type-only files. + * Defaults to `${projectRoot}/src`. + */ + sourceRoot?: string; + /** + * Whether to generate source maps for declaration files. + * Defaults to `false`. + */ + sourcemap?: boolean; + /** + * Whether to strip `@internal` JSDoc annotations from declarations. + * Defaults to `false`. + */ + stripInternal?: boolean; +} + +/** + * Vite plugin that generates TypeScript declaration files (.d.ts) using + * oxc-transform's `isolatedDeclaration` instead of the TypeScript compiler. + * + * This is a faster alternative to `vite-plugin-dts` for projects that have + * `isolatedDeclarations: true` enabled in their tsconfig. + * + * Usage in vite.config.ts: + * ```ts + * import { nxOxcDeclarationsPlugin } from '@nx/vite/plugins/nx-oxc-declarations.plugin'; + * + * export default defineConfig({ + * plugins: [ + * nxOxcDeclarationsPlugin({ projectRoot: import.meta.dirname }), + * ], + * }); + * ``` + */ +export function nxOxcDeclarationsPlugin( + options: NxOxcDeclarationsPluginOptions = {} +): Plugin { + // Re-export the shared implementation from @nx/js + const { + oxcDeclarations, + } = require('@nx/js/src/plugins/rollup/oxc-declarations'); + return oxcDeclarations({ + projectRoot: options.projectRoot ?? process.cwd(), + sourceRoot: options.sourceRoot, + sourcemap: options.sourcemap, + stripInternal: options.stripInternal, + }) as Plugin; +} diff --git a/packages/vite/src/executors/build/schema.d.ts b/packages/vite/src/executors/build/schema.d.ts index adcf25fe89e0a..730305db13a0a 100644 --- a/packages/vite/src/executors/build/schema.d.ts +++ b/packages/vite/src/executors/build/schema.d.ts @@ -1,6 +1,14 @@ export interface ViteBuildExecutorOptions { buildLibsFromSource?: boolean; configFile?: string; + /** + * How to generate TypeScript declaration files (.d.ts) during the build. + * - `'tsc'` — uses the TypeScript compiler (via vite-plugin-dts) + * - `'oxc'` — uses oxc-transform's `isolatedDeclaration` (requires `isolatedDeclarations: true` in tsconfig) + * - `'rolldown-plugin-dts'` — uses Rolldown-native DTS bundling + * - `'none'` — skips declaration generation + */ + declarations?: 'tsc' | 'oxc' | 'rolldown-plugin-dts' | 'none'; generatePackageJson?: boolean; includeDevDependenciesInPackageJson?: boolean; outputPath?: string; diff --git a/packages/vite/src/executors/build/schema.json b/packages/vite/src/executors/build/schema.json index 5ac5218446ba9..cc78f4ac91be6 100644 --- a/packages/vite/src/executors/build/schema.json +++ b/packages/vite/src/executors/build/schema.json @@ -73,6 +73,11 @@ "type": "boolean", "description": "Use the new Environments API for building multiple environments at once. Only works with Vite 6.0.0 or higher.", "default": false + }, + "declarations": { + "type": "string", + "description": "How to generate TypeScript declaration files (.d.ts) during the build. 'tsc' uses the TypeScript compiler (via vite-plugin-dts), 'oxc' uses oxc-transform's isolatedDeclaration (requires isolatedDeclarations: true in tsconfig), 'rolldown-plugin-dts' uses Rolldown-native DTS bundling, 'none' skips declaration generation.", + "enum": ["tsc", "oxc", "rolldown-plugin-dts", "none"] } }, "definitions": {}, diff --git a/packages/vite/src/utils/ensure-dependencies.ts b/packages/vite/src/utils/ensure-dependencies.ts index bb22fa6008d38..8c581d46c3484 100644 --- a/packages/vite/src/utils/ensure-dependencies.ts +++ b/packages/vite/src/utils/ensure-dependencies.ts @@ -6,12 +6,14 @@ import { type Tree, } from '@nx/devkit'; import { coerce, major } from 'semver'; +import { oxcTransformVersion } from '@nx/js/src/utils/versions'; import { ajvVersion, analogVitestAngular, edgeRuntimeVmVersion, happyDomVersion, jsdomVersion, + rolldownPluginDtsVersion, vitePluginDtsVersion, vitePluginReactSwcVersion, vitePluginReactV4Version, @@ -23,6 +25,7 @@ export type EnsureDependenciesOptions = { compiler?: 'babel' | 'swc'; includeLib?: boolean; testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string; + declarations?: 'tsc' | 'oxc' | 'rolldown-plugin-dts' | 'none'; }; export function ensureDependencies( @@ -64,10 +67,18 @@ export function ensureDependencies( } if (schema.includeLib) { - devDependencies['vite-plugin-dts'] = vitePluginDtsVersion; - if (detectPackageManager() !== 'pnpm') { - devDependencies['ajv'] = ajvVersion; + const decl = schema.declarations ?? 'tsc'; + if (decl === 'oxc') { + devDependencies['oxc-transform'] = oxcTransformVersion; + } else if (decl === 'rolldown-plugin-dts') { + devDependencies['rolldown-plugin-dts'] = rolldownPluginDtsVersion; + } else if (decl === 'tsc') { + devDependencies['vite-plugin-dts'] = vitePluginDtsVersion; + if (detectPackageManager() !== 'pnpm') { + devDependencies['ajv'] = ajvVersion; + } } + // 'none' — no declaration dependencies needed } return addDependenciesToPackageJson(host, {}, devDependencies); diff --git a/packages/vite/src/utils/generator-utils.ts b/packages/vite/src/utils/generator-utils.ts index 9730e3bf1c349..0c06422483e66 100644 --- a/packages/vite/src/utils/generator-utils.ts +++ b/packages/vite/src/utils/generator-utils.ts @@ -380,6 +380,15 @@ export interface ViteConfigFileOptions { useEsmExtension?: boolean; port?: number; previewPort?: number; + /** + * How to generate TypeScript declaration files (.d.ts) during the build. + * - `'tsc'` — uses the TypeScript compiler (via vite-plugin-dts) + * - `'oxc'` — uses oxc-transform's `isolatedDeclaration` (requires `isolatedDeclarations: true` in tsconfig) + * - `'rolldown-plugin-dts'` — uses Rolldown-native DTS bundling + * - `'none'` — skips declaration generation + * Defaults to `'tsc'` when not specified. + */ + declarations?: 'tsc' | 'oxc' | 'rolldown-plugin-dts' | 'none'; } export function createOrEditViteConfig( @@ -442,10 +451,19 @@ export function createOrEditViteConfig( const plugins: string[] = options.plugins ? [...options.plugins] : []; if (!onlyVitest && options.includeLib) { - imports.push( - `import dts from 'vite-plugin-dts'`, - `import * as path from 'path'` - ); + const decl = options.declarations ?? 'tsc'; + if (decl === 'oxc') { + imports.push( + `import { nxOxcDeclarationsPlugin } from '@nx/vite/plugins/nx-oxc-declarations.plugin'` + ); + } else if (decl === 'rolldown-plugin-dts') { + imports.push(`import { dts } from 'rolldown-plugin-dts'`); + } else if (decl === 'tsc') { + imports.push( + `import dts from 'vite-plugin-dts'`, + `import * as path from 'path'` + ); + } } if (!isTsSolutionSetup) { @@ -457,11 +475,20 @@ export function createOrEditViteConfig( } if (!onlyVitest && options.includeLib) { - plugins.push( - `dts({ entryRoot: 'src', tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json')${ - !isTsSolutionSetup ? ', pathsToAliases: false' : '' - } })` - ); + const decl = options.declarations ?? 'tsc'; + if (decl === 'oxc') { + plugins.push( + `nxOxcDeclarationsPlugin({ projectRoot: import.meta.dirname })` + ); + } else if (decl === 'rolldown-plugin-dts') { + plugins.push(`dts()`); + } else if (decl === 'tsc') { + plugins.push( + `dts({ entryRoot: 'src', tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json')${ + !isTsSolutionSetup ? ', pathsToAliases: false' : '' + } })` + ); + } } const reportsDirectory = isTsSolutionSetup diff --git a/packages/vite/src/utils/versions.ts b/packages/vite/src/utils/versions.ts index ee874c8f970c6..0be8e417aa8c6 100644 --- a/packages/vite/src/utils/versions.ts +++ b/packages/vite/src/utils/versions.ts @@ -20,6 +20,8 @@ export const happyDomVersion = '~9.20.3'; export const edgeRuntimeVmVersion = '~3.0.2'; export const jitiVersion = '2.4.2'; +export const rolldownPluginDtsVersion = '^0.22.0'; + export const analogVitestAngular = '~2.1.2'; // Coverage providers diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ba983bd265e8..78d6f40581c34 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1163,6 +1163,9 @@ importers: ora: specifier: 5.3.0 version: 5.3.0 + oxc-transform: + specifier: ^0.123.0 + version: 0.123.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) parse-markdown-links: specifier: ^1.0.4 version: 1.0.4 @@ -9276,6 +9279,12 @@ packages: '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.1.2': + resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} engines: {node: '>= 10'} @@ -11018,42 +11027,84 @@ packages: cpu: [arm] os: [android] + '@oxc-transform/binding-android-arm-eabi@0.123.0': + resolution: {integrity: sha512-glB9LSiKsRmhb8yuBcbaCByx+JQ/KbAZe9U5+iUuLuLaRr7llg/saPybaDiiEaz3IcVxnodKgsA4IxUnPV3+fw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@oxc-transform/binding-android-arm64@0.117.0': resolution: {integrity: sha512-1LrDd1CPochtLx04pAafdah6QtOQQj0/Evttevi+0u8rCI5FKucIG7pqBHkIQi/y7pycFYIj+GebhET80maeUg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@oxc-transform/binding-android-arm64@0.123.0': + resolution: {integrity: sha512-qge60UoJalkq8ftU9vHyq5Xu+kDtPF8sSSqQavzNWURGFLtXKyuxSl+7ovTurvUAwgVkaHcvEZsXWip71tKlqg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@oxc-transform/binding-darwin-arm64@0.117.0': resolution: {integrity: sha512-K1Xo52xJOvFfHSkz2ax9X5Qsku23RCfTIPbHZWdUCAQ1TQooI+sFcewSubhVUJ4DVK12/tYT//XXboumin+FHA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@oxc-transform/binding-darwin-arm64@0.123.0': + resolution: {integrity: sha512-uJv6bgXTwVlJvmYmGjv/IeAPUn5MTUeU8Uf+nLEUpPW0QDP0g7ttZWEI+OjY9seHO0DQ5dNi0+wzcTCk+UmoJA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@oxc-transform/binding-darwin-x64@0.117.0': resolution: {integrity: sha512-ftFT/8Laolfq49mRRWLkIhd1AbJ0MI5bW3LwddvdoAg9zXwkx4qhzTYyBPRZhvXWftts+NjlHfHsXCOqI4tPtw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@oxc-transform/binding-darwin-x64@0.123.0': + resolution: {integrity: sha512-Bkm2zhQ10D9xI/ZyMErQi3GOWouYMR8SqI+yvBggLz/EE1moo0Hpm0qQTJYwpFsi+uO64tAu1asaNKxCmVpaFw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@oxc-transform/binding-freebsd-x64@0.117.0': resolution: {integrity: sha512-QDRyw0atg9BMnwOwnJeW6REzWPLEjiWtsCc2Sj612F1hCdvP+n0L3o8sHinEWM+BiOkOYtUxHA69WjUslc3G+g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@oxc-transform/binding-freebsd-x64@0.123.0': + resolution: {integrity: sha512-pEbYQN2OPHL6khErdZ6Q0XI+VriAz1TZglm9euj4qX2a30PobOyzebaHEZMpmiPTS82rB6kPcSjsBbjY4bXVaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@oxc-transform/binding-linux-arm-gnueabihf@0.117.0': resolution: {integrity: sha512-UvpvOjyQVgiIJahIpMT0qAsLJT8O1ibHTBgXGOsZkQgw1xmjARPQ07dpRcucPPn6cqCF3wrxfbqtr2vFHaMkdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@oxc-transform/binding-linux-arm-gnueabihf@0.123.0': + resolution: {integrity: sha512-oEZS8HsrtHON4ph/a35ILBH4Nra5Y0uP3CsGOc7SUSftEt8GZ+Xr3lXj67ZXsEZiZbsw3cUte23YhUf09nfaFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@oxc-transform/binding-linux-arm-musleabihf@0.117.0': resolution: {integrity: sha512-cIhztGFjKk8ngP+/7EPkEhzWMGr2neezxgWirSn/f/MirjH234oHHGJ2diKIbGQEsy0aOuJMTkL9NLfzfmH51A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@oxc-transform/binding-linux-arm-musleabihf@0.123.0': + resolution: {integrity: sha512-869HBeT1tXl6GsmxZJTET7Lbx6hW8XoM8pw6PyTQ82GjodFSlk6if4rWifYNrPOsgMw1/q4mwYJcX850eFPJow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@oxc-transform/binding-linux-arm64-gnu@0.117.0': resolution: {integrity: sha512-mXbDfvDN0RZVg7v4LohNzU0kK3fMAZgkUKTkpFVgxEvzibEG5VpSznkypUwHI4a8U8pz+K6mGaLetX3Xt+CvvA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11061,6 +11112,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-transform/binding-linux-arm64-gnu@0.123.0': + resolution: {integrity: sha512-4OUNnatZNNvMwnylsfr+IeaCByBKiXPk4wQFMUf0xS8cUnOdjOtb6qMQ94nWuPA9d+Ywu32qfY+N4Fdaf3sNRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@oxc-transform/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11068,6 +11126,13 @@ packages: os: [linux] libc: [musl] + '@oxc-transform/binding-linux-arm64-musl@0.123.0': + resolution: {integrity: sha512-C54h8AoUpwzw3+Ge+Vv2YYuuVh7XwVB5Mi/KiwByPPS/WFoJpmkSPvtFeAazdYbo4iKEGLrRI8vt+gEib1lDMw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@oxc-transform/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11075,6 +11140,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-transform/binding-linux-ppc64-gnu@0.123.0': + resolution: {integrity: sha512-X+obOgFjX/61UZ1Wm5ncNZYC43R3bV9eU7DdCAEO6VXubSXcwIjxaf3QrUvBDYPifrdWSy/OerzJbhI9TgHYPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@oxc-transform/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11082,6 +11154,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-transform/binding-linux-riscv64-gnu@0.123.0': + resolution: {integrity: sha512-EzerdFa2KvEzYHuzFp9W/KZaulI4OIKE8FIC0X21V757ljZKRfskIqtGAFX/CAvoIF3C2zNepDWFZlpcJ5nJ1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@oxc-transform/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11089,6 +11168,13 @@ packages: os: [linux] libc: [musl] + '@oxc-transform/binding-linux-riscv64-musl@0.123.0': + resolution: {integrity: sha512-WFh7tcPYqxo2YQXnIuQ/ZZ4uFHeR06tDEFD8qNl1egRrqTZskHvV/NBelOthfHmkizWiGJx8ZnvN69UrL3q12A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + '@oxc-transform/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11096,6 +11182,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-transform/binding-linux-s390x-gnu@0.123.0': + resolution: {integrity: sha512-A5ahPjG/2Zg5/3RndWRSaKO/9uIirjYuv8OBWa+HBA1Im607dCceSfc9k1PCHt0MdjtsfiyArO+kk2TP5R0Ebg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@oxc-transform/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11103,6 +11196,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-transform/binding-linux-x64-gnu@0.123.0': + resolution: {integrity: sha512-9g1rEynmIh0qkJWc/1Zbd1VRFzYkk6KcmwcCoq3hslgGBIJEvrjPlP7cQgAiCaTFCVjfoPYWAy+5xjf9sCNY1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@oxc-transform/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11110,35 +11210,71 @@ packages: os: [linux] libc: [musl] + '@oxc-transform/binding-linux-x64-musl@0.123.0': + resolution: {integrity: sha512-/eoNDuGDfEjNVqmgDNkFlGmoo5MOnRxaO9IhwKyWoXXUn7tzA5C45op7Kv/Njb6BcGr4RN2KH7OjsEAqjMDmuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@oxc-transform/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-Ebxx6NPqhzlrjvx4+PdSqbOq+li0f7X59XtJljDghkbJsbnkHvhLmPR09ifHt5X32UlZN63ekjwcg/nbmHLLlA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@oxc-transform/binding-openharmony-arm64@0.123.0': + resolution: {integrity: sha512-rGeHHsE/KZ7G/iEtSsQAk4HZ3Wl2v4oMgcOjSvlVJejl+5ttUcKAjxgW2j+c1zFREJVpCHEyspi3fFxJkdJ/Ww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@oxc-transform/binding-wasm32-wasi@0.117.0': resolution: {integrity: sha512-Nn8mmcBiQ0XKHLTb05QBlH+CDkn7jf5YDVv9FtKhy4zJT0NEU9y3dXVbfcurOpsVrG9me4ktzDQNCaAoJjUQyw==} engines: {node: '>=14.0.0'} cpu: [wasm32] + '@oxc-transform/binding-wasm32-wasi@0.123.0': + resolution: {integrity: sha512-JMFXeeWvFDioW2gP9dgD6LDbPmCMCrXNwDWMAXcKDmZILx0rARt+z79GACKTBSyyKURkYGe3+wJj+oI3JKnvug==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@oxc-transform/binding-win32-arm64-msvc@0.117.0': resolution: {integrity: sha512-15cbsF8diXWGnHrTsVgVeabETiT/KdMAfRAcot99xsaVecJs3pITNNjC6Qj+/TPNpehbgIFjlhhxOVSbQsTBgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@oxc-transform/binding-win32-arm64-msvc@0.123.0': + resolution: {integrity: sha512-hSQ7VokhPAO0NMrsRz+2Zh4fcxx28qFlX78/7jG/+tWZgiB/aEukadf3XPcYQ3ymqoL8SvDN3nQ7bNTHAiZSCg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@oxc-transform/binding-win32-ia32-msvc@0.117.0': resolution: {integrity: sha512-I6DkhCuFX6p9rckdWiLuZfBWrrYUC7sNX+zLaCfa5zvrPNwo1/29KkefvqXVxu3AWT/6oZAbtc0A8/mqhETJPQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] + '@oxc-transform/binding-win32-ia32-msvc@0.123.0': + resolution: {integrity: sha512-7bIydPGt68qdfPXYLzBHYUia8Wi0dP6g/8zmrXN1HfUugkdt4Kh121fmw4KH+kcIT1BTICDHcXU4bJ6k3QmSgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + '@oxc-transform/binding-win32-x64-msvc@0.117.0': resolution: {integrity: sha512-V7YzavQnYcRJBeJkp0qpb3FKrlm5I57XJetCYB4jsjStuboQmnFMZ/XQH55Szlf/kVyeU9ddQwv72gJJ5BrGjQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@oxc-transform/binding-win32-x64-msvc@0.123.0': + resolution: {integrity: sha512-pVmtG6GGI3eZ5J4NP75rR5yA1EuwEq+94kBQipq1rZXsukj6ghNkd3OGgzOA+W/fQL3V9AlnY9BriqCT21eVQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@pagefind/darwin-arm64@1.3.0': resolution: {integrity: sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==} cpu: [arm64] @@ -21703,6 +21839,10 @@ packages: resolution: {integrity: sha512-u1Stl2uhDh9bFuOGjGXQIqx46IRUNMyHQkq59LayXNGS2flNv7RpZpRSWs5S5deuNP6jJZ12gtMBze+m4dOhmw==} engines: {node: ^20.19.0 || >=22.12.0} + oxc-transform@0.123.0: + resolution: {integrity: sha512-uuuNWbCDv391SEeF2id/TvSAMUKU8U9347cbNcpRkwcv5sobBS6C5kXE0ZLuxVEUlWatr2kfsolrA10zdPogDg==} + engines: {node: ^20.19.0 || >=22.12.0} + oxc-walker@0.7.0: resolution: {integrity: sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==} peerDependencies: @@ -35278,6 +35418,13 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': optional: true @@ -38002,65 +38149,130 @@ snapshots: '@oxc-transform/binding-android-arm-eabi@0.117.0': optional: true + '@oxc-transform/binding-android-arm-eabi@0.123.0': + optional: true + '@oxc-transform/binding-android-arm64@0.117.0': optional: true + '@oxc-transform/binding-android-arm64@0.123.0': + optional: true + '@oxc-transform/binding-darwin-arm64@0.117.0': optional: true + '@oxc-transform/binding-darwin-arm64@0.123.0': + optional: true + '@oxc-transform/binding-darwin-x64@0.117.0': optional: true + '@oxc-transform/binding-darwin-x64@0.123.0': + optional: true + '@oxc-transform/binding-freebsd-x64@0.117.0': optional: true + '@oxc-transform/binding-freebsd-x64@0.123.0': + optional: true + '@oxc-transform/binding-linux-arm-gnueabihf@0.117.0': optional: true + '@oxc-transform/binding-linux-arm-gnueabihf@0.123.0': + optional: true + '@oxc-transform/binding-linux-arm-musleabihf@0.117.0': optional: true + '@oxc-transform/binding-linux-arm-musleabihf@0.123.0': + optional: true + '@oxc-transform/binding-linux-arm64-gnu@0.117.0': optional: true + '@oxc-transform/binding-linux-arm64-gnu@0.123.0': + optional: true + '@oxc-transform/binding-linux-arm64-musl@0.117.0': optional: true + '@oxc-transform/binding-linux-arm64-musl@0.123.0': + optional: true + '@oxc-transform/binding-linux-ppc64-gnu@0.117.0': optional: true + '@oxc-transform/binding-linux-ppc64-gnu@0.123.0': + optional: true + '@oxc-transform/binding-linux-riscv64-gnu@0.117.0': optional: true + '@oxc-transform/binding-linux-riscv64-gnu@0.123.0': + optional: true + '@oxc-transform/binding-linux-riscv64-musl@0.117.0': optional: true + '@oxc-transform/binding-linux-riscv64-musl@0.123.0': + optional: true + '@oxc-transform/binding-linux-s390x-gnu@0.117.0': optional: true + '@oxc-transform/binding-linux-s390x-gnu@0.123.0': + optional: true + '@oxc-transform/binding-linux-x64-gnu@0.117.0': optional: true + '@oxc-transform/binding-linux-x64-gnu@0.123.0': + optional: true + '@oxc-transform/binding-linux-x64-musl@0.117.0': optional: true + '@oxc-transform/binding-linux-x64-musl@0.123.0': + optional: true + '@oxc-transform/binding-openharmony-arm64@0.117.0': optional: true + '@oxc-transform/binding-openharmony-arm64@0.123.0': + optional: true + '@oxc-transform/binding-wasm32-wasi@0.117.0': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true + '@oxc-transform/binding-wasm32-wasi@0.123.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + '@oxc-transform/binding-win32-arm64-msvc@0.117.0': optional: true + '@oxc-transform/binding-win32-arm64-msvc@0.123.0': + optional: true + '@oxc-transform/binding-win32-ia32-msvc@0.117.0': optional: true + '@oxc-transform/binding-win32-ia32-msvc@0.123.0': + optional: true + '@oxc-transform/binding-win32-x64-msvc@0.117.0': optional: true + '@oxc-transform/binding-win32-x64-msvc@0.123.0': + optional: true + '@pagefind/darwin-arm64@1.3.0': optional: true @@ -52500,6 +52712,32 @@ snapshots: '@oxc-transform/binding-win32-ia32-msvc': 0.117.0 '@oxc-transform/binding-win32-x64-msvc': 0.117.0 + oxc-transform@0.123.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1): + optionalDependencies: + '@oxc-transform/binding-android-arm-eabi': 0.123.0 + '@oxc-transform/binding-android-arm64': 0.123.0 + '@oxc-transform/binding-darwin-arm64': 0.123.0 + '@oxc-transform/binding-darwin-x64': 0.123.0 + '@oxc-transform/binding-freebsd-x64': 0.123.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.123.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.123.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.123.0 + '@oxc-transform/binding-linux-arm64-musl': 0.123.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.123.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.123.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.123.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.123.0 + '@oxc-transform/binding-linux-x64-gnu': 0.123.0 + '@oxc-transform/binding-linux-x64-musl': 0.123.0 + '@oxc-transform/binding-openharmony-arm64': 0.123.0 + '@oxc-transform/binding-wasm32-wasi': 0.123.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) + '@oxc-transform/binding-win32-arm64-msvc': 0.123.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.123.0 + '@oxc-transform/binding-win32-x64-msvc': 0.123.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + oxc-walker@0.7.0(oxc-parser@0.117.0): dependencies: magic-regexp: 0.10.0