|
7 | 7 | * 3. buildNapiBinding() - Builds the native Rust binding via NAPI |
8 | 8 | * 4. syncCorePackageExports() - Creates shim files to re-export from @voidzero-dev/vite-plus-core |
9 | 9 | * 5. syncTestPackageExports() - Creates shim files to re-export from @voidzero-dev/vite-plus-test |
10 | | - * 6. copySkillDocs() - Copies docs into skills/vite-plus/docs for runtime MCP access |
11 | | - * 7. syncReadmeFromRoot() - Keeps package README in sync |
| 10 | + * 6. syncVersionsExport() - Generates ./versions module with bundled tool versions |
| 11 | + * 7. copySkillDocs() - Copies docs into skills/vite-plus/docs for runtime MCP access |
| 12 | + * 8. syncReadmeFromRoot() - Keeps package README in sync |
12 | 13 | * |
13 | 14 | * The sync functions allow this package to be a drop-in replacement for 'vite' by |
14 | 15 | * re-exporting all the same subpaths (./client, ./types/*, etc.) while delegating |
@@ -38,6 +39,8 @@ import { |
38 | 39 | } from 'typescript'; |
39 | 40 |
|
40 | 41 | import { generateLicenseFile } from '../../scripts/generate-license.ts'; |
| 42 | +import corePkg from '../core/package.json' with { type: 'json' }; |
| 43 | +import testPkg from '../test/package.json' with { type: 'json' }; |
41 | 44 |
|
42 | 45 | const projectDir = dirname(fileURLToPath(import.meta.url)); |
43 | 46 | const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test'; |
@@ -80,6 +83,7 @@ if (!skipNative) { |
80 | 83 | if (!skipTs) { |
81 | 84 | await syncCorePackageExports(); |
82 | 85 | await syncTestPackageExports(); |
| 86 | + await syncVersionsExport(); |
83 | 87 | } |
84 | 88 | await copySkillDocs(); |
85 | 89 | await syncReadmeFromRoot(); |
@@ -425,6 +429,75 @@ async function syncTestPackageExports() { |
425 | 429 | console.log(`\nSynced ${Object.keys(generatedExports).length} exports from test package`); |
426 | 430 | } |
427 | 431 |
|
| 432 | +/** |
| 433 | + * Read version from a dependency's package.json in node_modules. |
| 434 | + * Uses readFile because these packages don't export ./package.json. |
| 435 | + * |
| 436 | + * TODO: Once https://github.com/oxc-project/oxc/pull/20784 lands and oxlint/oxfmt/oxlint-tsgolint |
| 437 | + * export ./package.json, this function can be removed and replaced with static imports: |
| 438 | + * ```js |
| 439 | + * import oxlintPkg from 'oxlint/package.json' with { type: 'json' }; |
| 440 | + * import oxfmtPkg from 'oxfmt/package.json' with { type: 'json' }; |
| 441 | + * import oxlintTsgolintPkg from 'oxlint-tsgolint/package.json' with { type: 'json' }; |
| 442 | + * ``` |
| 443 | + */ |
| 444 | +async function readDepVersion(packageName: string): Promise<string | null> { |
| 445 | + try { |
| 446 | + const pkgPath = join(projectDir, 'node_modules', packageName, 'package.json'); |
| 447 | + const pkg = JSON.parse(await readFile(pkgPath, 'utf-8')); |
| 448 | + return pkg.version ?? null; |
| 449 | + } catch { |
| 450 | + return null; |
| 451 | + } |
| 452 | +} |
| 453 | + |
| 454 | +/** |
| 455 | + * Generate ./versions export module with bundled tool versions. |
| 456 | + * |
| 457 | + * Collects versions from: |
| 458 | + * - core/test package.json bundledVersions (vite, rolldown, tsdown, vitest) |
| 459 | + * - CLI dependency package.json (oxlint, oxfmt, oxlint-tsgolint) |
| 460 | + * |
| 461 | + * Generates dist/versions.js and dist/versions.d.ts with inlined constants. |
| 462 | + */ |
| 463 | +async function syncVersionsExport() { |
| 464 | + console.log('\nSyncing versions export...'); |
| 465 | + const distDir = join(projectDir, 'dist'); |
| 466 | + |
| 467 | + // Collect versions from bundledVersions (core + test) |
| 468 | + const versions: Record<string, string> = { |
| 469 | + ...(corePkg as Record<string, any>).bundledVersions, |
| 470 | + ...(testPkg as Record<string, any>).bundledVersions, |
| 471 | + }; |
| 472 | + |
| 473 | + // Collect versions from CLI dependencies (oxlint, oxfmt, oxlint-tsgolint) |
| 474 | + // These don't export ./package.json, so we read from node_modules directly |
| 475 | + const depTools = ['oxlint', 'oxfmt', 'oxlint-tsgolint'] as const; |
| 476 | + for (const name of depTools) { |
| 477 | + const version = await readDepVersion(name); |
| 478 | + if (version) { |
| 479 | + versions[name] = version; |
| 480 | + } |
| 481 | + } |
| 482 | + |
| 483 | + // dist/versions.js — inlined constants (no runtime I/O) |
| 484 | + await writeFile( |
| 485 | + join(distDir, 'versions.js'), |
| 486 | + `export const versions = ${JSON.stringify(versions, null, 2)};\n`, |
| 487 | + ); |
| 488 | + |
| 489 | + // dist/versions.d.ts — type declarations |
| 490 | + const typeFields = Object.keys(versions) |
| 491 | + .map((k) => ` readonly '${k}': string;`) |
| 492 | + .join('\n'); |
| 493 | + await writeFile( |
| 494 | + join(distDir, 'versions.d.ts'), |
| 495 | + `export declare const versions: {\n${typeFields}\n};\n`, |
| 496 | + ); |
| 497 | + |
| 498 | + console.log(` Created ./versions (${Object.keys(versions).length} tools)`); |
| 499 | +} |
| 500 | + |
428 | 501 | /** |
429 | 502 | * Copy markdown doc files from the monorepo docs/ directory into skills/vite-plus/docs/, |
430 | 503 | * preserving the relative directory structure. This keeps stable file paths for |
|
0 commit comments