Skip to content

Commit 0886d3e

Browse files
Merge pull request #3 from CarlosGamezSynergy/feat/add-automatic-CLI-version-control
Feat/add automatic cli version control
2 parents 4b388d8 + 8271ddd commit 0886d3e

File tree

5 files changed

+93
-4
lines changed

5 files changed

+93
-4
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@
4141
"./package.json": "./package.json"
4242
},
4343
"scripts": {
44-
"build": "tsc",
44+
"build": "node ./scripts/generate-version.js && tsc",
4545
"prepublishOnly": "pnpm build",
46-
"test": "vitest --run",
47-
"watch": "tsc --watch"
46+
"test": "node ./scripts/generate-version.js && vitest --run",
47+
"watch": "tsc --watch",
48+
"clean:generated": "rm -rf src/generated"
4849
},
4950
"keywords": [
5051
"zod",

scripts/generate-version.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
import url from 'node:url';
5+
6+
function generate() {
7+
const repoRoot = path.resolve(url.fileURLToPath(new URL('..', import.meta.url)));
8+
const pkgPath = path.join(repoRoot, 'package.json');
9+
const outDir = path.join(repoRoot, 'src', 'generated');
10+
const outFile = path.join(outDir, 'version.ts');
11+
12+
if (!fs.existsSync(pkgPath)) {
13+
console.error('package.json not found at', pkgPath);
14+
process.exit(1);
15+
}
16+
17+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
18+
const version = pkg.version || '0.0.0';
19+
20+
if (!fs.existsSync(outDir)) {
21+
fs.mkdirSync(outDir, { recursive: true });
22+
}
23+
24+
const contents = `// THIS FILE IS AUTO-GENERATED. DO NOT EDIT.\nexport const VERSION = '${version}';\n`;
25+
26+
fs.writeFileSync(outFile, contents, 'utf8');
27+
// Make the file readable
28+
try {
29+
fs.chmodSync(outFile, 0o644);
30+
} catch (e) {
31+
// ignore on platforms that don't support chmod in this way
32+
}
33+
// Log lightly for visibility in CI
34+
console.log('Wrote', outFile);
35+
}
36+
37+
generate();

src/cli/cli.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,42 @@ import chalk from "chalk";
44
import { program } from "commander";
55
import process from "node:process";
66
import path from "path";
7+
import fs from "node:fs";
8+
import url from "node:url";
79
import type { ZodToD2Config } from "../types/ZodToD2Config.type.js";
810
import { ensureDirectoryExists } from "../utils/ensureDirectoryExists.js";
911
import { zodToD2 } from "./zodToD2.js";
1012

13+
// Read version from package.json so the CLI stays in sync with the package
14+
// Prefer the generated VERSION at build time. If missing (for local dev without running the
15+
// generator), fall back to reading package.json at runtime.
16+
let CLI_VERSION = "0.0.0";
17+
try {
18+
// Attempt to import generated version (TypeScript source will be compiled to dist)
19+
// Use require-like dynamic handling because ts-node or tests may run without build step
20+
// Importing the TS file directly via import will be done by the compiler in production.
21+
// eslint-disable-next-line @typescript-eslint/no-var-requires
22+
// Try require first (works in node when transpiled to JS)
23+
// eslint-disable-next-line @typescript-eslint/no-var-requires
24+
const generated = require("../generated/version");
25+
CLI_VERSION = generated?.VERSION ?? CLI_VERSION;
26+
} catch (err) {
27+
// Fallback: read package.json synchronously
28+
try {
29+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
30+
const pkgPath = path.resolve(__dirname, "../../package.json");
31+
const pkgRaw = fs.readFileSync(pkgPath, "utf8");
32+
const pkg = JSON.parse(pkgRaw) as { version?: string };
33+
CLI_VERSION = pkg.version ?? CLI_VERSION;
34+
} catch (e) {
35+
// final fallback already set
36+
}
37+
}
38+
1139
program
1240
.name("zod2d2")
1341
.description("CLI tool to convert Zod schemas to D2 diagrams")
14-
.version("0.0.22")
42+
.version(CLI_VERSION)
1543
.helpOption("-h, --help", chalk.blue("Display help for command"));
1644

1745
program

src/generated/version.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// THIS FILE IS AUTO-GENERATED. DO NOT EDIT.
2+
export const VERSION = '0.0.21';

test/cli/version.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { test, expect } from 'vitest';
2+
import { execSync } from 'node:child_process';
3+
import path from 'node:path';
4+
import fs from 'node:fs';
5+
6+
test('CLI generated version matches package.json', async () => {
7+
const repoRoot = path.resolve(__dirname, '..', '..');
8+
// Run generator to ensure generated file is up-to-date
9+
execSync('node ./scripts/generate-version.js', { cwd: repoRoot, stdio: 'ignore' });
10+
11+
// Dynamically import the generated version module
12+
const generatedPath = path.join(repoRoot, 'src', 'generated', 'version');
13+
const generated = await import(generatedPath);
14+
const generatedVersion = generated.VERSION;
15+
16+
// Read package.json
17+
const pkgRaw = fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8');
18+
const pkg = JSON.parse(pkgRaw) as { version?: string };
19+
20+
expect(generatedVersion).toBe(pkg.version);
21+
});

0 commit comments

Comments
 (0)