@openpkg-ts/cli 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/openpkg.js +126 -192
- package/dist/shared/chunk-3s189drz.js +4 -0
- package/dist/src/index.d.ts +40 -1
- package/dist/src/index.js +1 -1
- package/package.json +3 -3
- package/dist/shared/chunk-1dqs11h6.js +0 -20
package/dist/bin/openpkg.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
|
-
__require
|
|
4
|
-
|
|
5
|
-
} from "../shared/chunk-1dqs11h6.js";
|
|
3
|
+
__require
|
|
4
|
+
} from "../shared/chunk-3s189drz.js";
|
|
6
5
|
|
|
7
6
|
// bin/openpkg.ts
|
|
8
7
|
import { Command as Command12 } from "commander";
|
|
9
8
|
// package.json
|
|
10
9
|
var package_default = {
|
|
11
10
|
name: "@openpkg-ts/cli",
|
|
12
|
-
version: "0.6.
|
|
11
|
+
version: "0.6.3",
|
|
13
12
|
description: "CLI for OpenPkg TypeScript API extraction and documentation generation",
|
|
14
13
|
homepage: "https://github.com/ryanwaits/openpkg-ts#readme",
|
|
15
14
|
repository: {
|
|
@@ -32,8 +31,8 @@ var package_default = {
|
|
|
32
31
|
test: "bun test"
|
|
33
32
|
},
|
|
34
33
|
dependencies: {
|
|
35
|
-
"@openpkg-ts/adapters": "^0.3.
|
|
36
|
-
"@openpkg-ts/sdk": "^0.35.
|
|
34
|
+
"@openpkg-ts/adapters": "^0.3.14",
|
|
35
|
+
"@openpkg-ts/sdk": "^0.35.1",
|
|
37
36
|
commander: "^14.0.0"
|
|
38
37
|
},
|
|
39
38
|
devDependencies: {
|
|
@@ -47,18 +46,66 @@ var package_default = {
|
|
|
47
46
|
};
|
|
48
47
|
|
|
49
48
|
// src/commands/breaking.ts
|
|
49
|
+
import { categorizeBreakingChanges, diffSpec } from "@openpkg-ts/spec";
|
|
50
|
+
import { Command } from "commander";
|
|
51
|
+
|
|
52
|
+
// src/commands/utils.ts
|
|
50
53
|
import * as fs from "node:fs";
|
|
51
54
|
import * as path from "node:path";
|
|
52
|
-
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
55
|
+
import { getValidationErrors } from "@openpkg-ts/spec";
|
|
56
|
+
function handleCommandError(err) {
|
|
57
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
58
|
+
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
async function loadSpecInput(specPath) {
|
|
62
|
+
if (specPath === "-") {
|
|
63
|
+
const chunks = [];
|
|
64
|
+
for await (const chunk of process.stdin) {
|
|
65
|
+
chunks.push(chunk);
|
|
66
|
+
}
|
|
67
|
+
const input = Buffer.concat(chunks).toString("utf-8");
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(input);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
72
|
+
throw new Error(`Invalid JSON in stdin: ${msg}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const resolved = path.resolve(specPath);
|
|
76
|
+
if (!fs.existsSync(resolved)) {
|
|
77
|
+
throw new Error(`Spec file not found: ${resolved}`);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
81
|
+
} catch (err) {
|
|
82
|
+
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
83
|
+
throw new Error(`Invalid JSON in ${specPath}: ${msg}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
57
86
|
function loadSpec(filePath) {
|
|
58
87
|
const resolved = path.resolve(filePath);
|
|
59
|
-
|
|
60
|
-
|
|
88
|
+
let content;
|
|
89
|
+
let spec;
|
|
90
|
+
try {
|
|
91
|
+
content = fs.readFileSync(resolved, "utf-8");
|
|
92
|
+
} catch (err) {
|
|
93
|
+
throw new Error(`Failed to read spec file: ${err instanceof Error ? err.message : String(err)}`);
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
spec = JSON.parse(content);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
throw new Error(`Invalid JSON in spec file: ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
}
|
|
100
|
+
const errors = getValidationErrors(spec);
|
|
101
|
+
if (errors.length > 0) {
|
|
102
|
+
const details = errors.slice(0, 5).map((e) => `${e.instancePath || "/"}: ${e.message}`).join("; ");
|
|
103
|
+
throw new Error(`Invalid OpenPkg spec: ${details}`);
|
|
104
|
+
}
|
|
105
|
+
return spec;
|
|
61
106
|
}
|
|
107
|
+
|
|
108
|
+
// src/commands/breaking.ts
|
|
62
109
|
function createBreakingCommand() {
|
|
63
110
|
return new Command("breaking").description("Check for breaking changes between two specs").argument("<old>", "Path to old spec file (JSON)").argument("<new>", "Path to new spec file (JSON)").action(async (oldPath, newPath) => {
|
|
64
111
|
try {
|
|
@@ -75,32 +122,21 @@ function createBreakingCommand() {
|
|
|
75
122
|
process.exit(1);
|
|
76
123
|
}
|
|
77
124
|
} catch (err) {
|
|
78
|
-
|
|
79
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
80
|
-
process.exit(1);
|
|
125
|
+
handleCommandError(err);
|
|
81
126
|
}
|
|
82
127
|
});
|
|
83
128
|
}
|
|
84
129
|
|
|
85
130
|
// src/commands/changelog.ts
|
|
86
|
-
import * as fs3 from "node:fs";
|
|
87
|
-
import * as path3 from "node:path";
|
|
88
131
|
import { Command as Command3 } from "commander";
|
|
89
132
|
|
|
90
133
|
// src/commands/diff.ts
|
|
91
|
-
import * as fs2 from "node:fs";
|
|
92
|
-
import * as path2 from "node:path";
|
|
93
134
|
import {
|
|
94
135
|
categorizeBreakingChanges as categorizeBreakingChanges2,
|
|
95
136
|
diffSpec as diffSpec2,
|
|
96
137
|
recommendSemverBump
|
|
97
138
|
} from "@openpkg-ts/spec";
|
|
98
139
|
import { Command as Command2 } from "commander";
|
|
99
|
-
function loadSpec2(filePath) {
|
|
100
|
-
const resolved = path2.resolve(filePath);
|
|
101
|
-
const content = fs2.readFileSync(resolved, "utf-8");
|
|
102
|
-
return JSON.parse(content);
|
|
103
|
-
}
|
|
104
140
|
function toExportMap(spec) {
|
|
105
141
|
const map = new Map;
|
|
106
142
|
for (const exp of spec.exports) {
|
|
@@ -178,8 +214,8 @@ function describeChange(cat) {
|
|
|
178
214
|
function createDiffCommand() {
|
|
179
215
|
return new Command2("diff").description("Compare two OpenPkg specs and show differences").argument("<old>", "Path to old spec file (JSON)").argument("<new>", "Path to new spec file (JSON)").option("--json", "Output as JSON (default)").option("--summary", "Only show summary").action(async (oldPath, newPath, options) => {
|
|
180
216
|
try {
|
|
181
|
-
const oldSpec =
|
|
182
|
-
const newSpec =
|
|
217
|
+
const oldSpec = loadSpec(oldPath);
|
|
218
|
+
const newSpec = loadSpec(newPath);
|
|
183
219
|
const result = enrichDiff(oldSpec, newSpec);
|
|
184
220
|
if (options.summary) {
|
|
185
221
|
console.log(JSON.stringify(result.summary, null, 2));
|
|
@@ -187,19 +223,12 @@ function createDiffCommand() {
|
|
|
187
223
|
console.log(JSON.stringify(result, null, 2));
|
|
188
224
|
}
|
|
189
225
|
} catch (err) {
|
|
190
|
-
|
|
191
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
192
|
-
process.exit(1);
|
|
226
|
+
handleCommandError(err);
|
|
193
227
|
}
|
|
194
228
|
});
|
|
195
229
|
}
|
|
196
230
|
|
|
197
231
|
// src/commands/changelog.ts
|
|
198
|
-
function loadSpec3(filePath) {
|
|
199
|
-
const resolved = path3.resolve(filePath);
|
|
200
|
-
const content = fs3.readFileSync(resolved, "utf-8");
|
|
201
|
-
return JSON.parse(content);
|
|
202
|
-
}
|
|
203
232
|
function formatMarkdown(diff) {
|
|
204
233
|
const lines = [];
|
|
205
234
|
if (diff.removed.length > 0 || diff.changed.length > 0) {
|
|
@@ -235,8 +264,8 @@ function formatMarkdown(diff) {
|
|
|
235
264
|
function createChangelogCommand() {
|
|
236
265
|
return new Command3("changelog").description("Generate changelog from diff between two specs").argument("<old>", "Path to old spec file (JSON)").argument("<new>", "Path to new spec file (JSON)").option("--format <format>", "Output format: md or json", "md").action(async (oldPath, newPath, options) => {
|
|
237
266
|
try {
|
|
238
|
-
const oldSpec =
|
|
239
|
-
const newSpec =
|
|
267
|
+
const oldSpec = loadSpec(oldPath);
|
|
268
|
+
const newSpec = loadSpec(newPath);
|
|
240
269
|
const diff = enrichDiff(oldSpec, newSpec);
|
|
241
270
|
if (options.format === "json") {
|
|
242
271
|
console.log(JSON.stringify(diff, null, 2));
|
|
@@ -244,9 +273,7 @@ function createChangelogCommand() {
|
|
|
244
273
|
console.log(formatMarkdown(diff));
|
|
245
274
|
}
|
|
246
275
|
} catch (err) {
|
|
247
|
-
|
|
248
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
249
|
-
process.exit(1);
|
|
276
|
+
handleCommandError(err);
|
|
250
277
|
}
|
|
251
278
|
});
|
|
252
279
|
}
|
|
@@ -259,13 +286,13 @@ import { spawn } from "node:child_process";
|
|
|
259
286
|
import { Command as Command4 } from "commander";
|
|
260
287
|
|
|
261
288
|
// src/commands/docs/utils.ts
|
|
262
|
-
import * as
|
|
263
|
-
import * as
|
|
289
|
+
import * as fs2 from "node:fs";
|
|
290
|
+
import * as path2 from "node:path";
|
|
264
291
|
function detectPackageManager(cwd = process.cwd()) {
|
|
265
|
-
const pkgJsonPath =
|
|
266
|
-
if (
|
|
292
|
+
const pkgJsonPath = path2.join(cwd, "package.json");
|
|
293
|
+
if (fs2.existsSync(pkgJsonPath)) {
|
|
267
294
|
try {
|
|
268
|
-
const pkg = JSON.parse(
|
|
295
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
269
296
|
if (pkg.packageManager) {
|
|
270
297
|
if (pkg.packageManager.startsWith("bun"))
|
|
271
298
|
return "bun";
|
|
@@ -278,13 +305,13 @@ function detectPackageManager(cwd = process.cwd()) {
|
|
|
278
305
|
}
|
|
279
306
|
} catch {}
|
|
280
307
|
}
|
|
281
|
-
if (
|
|
308
|
+
if (fs2.existsSync(path2.join(cwd, "bun.lockb")) || fs2.existsSync(path2.join(cwd, "bun.lock"))) {
|
|
282
309
|
return "bun";
|
|
283
310
|
}
|
|
284
|
-
if (
|
|
311
|
+
if (fs2.existsSync(path2.join(cwd, "pnpm-lock.yaml"))) {
|
|
285
312
|
return "pnpm";
|
|
286
313
|
}
|
|
287
|
-
if (
|
|
314
|
+
if (fs2.existsSync(path2.join(cwd, "yarn.lock"))) {
|
|
288
315
|
return "yarn";
|
|
289
316
|
}
|
|
290
317
|
return "npm";
|
|
@@ -339,21 +366,10 @@ function createAddCommand() {
|
|
|
339
366
|
}
|
|
340
367
|
|
|
341
368
|
// src/commands/docs/generate.ts
|
|
342
|
-
import * as
|
|
343
|
-
import * as
|
|
344
|
-
import { loadSpec as
|
|
369
|
+
import * as fs3 from "node:fs";
|
|
370
|
+
import * as path3 from "node:path";
|
|
371
|
+
import { loadSpec as loadSpec2, query, toReact } from "@openpkg-ts/sdk";
|
|
345
372
|
import { Command as Command5 } from "commander";
|
|
346
|
-
async function readStdin() {
|
|
347
|
-
try {
|
|
348
|
-
const chunks = [];
|
|
349
|
-
for await (const chunk of process.stdin) {
|
|
350
|
-
chunks.push(chunk);
|
|
351
|
-
}
|
|
352
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
353
|
-
} catch (err) {
|
|
354
|
-
throw new Error(`stdin read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
373
|
function getExtension(format) {
|
|
358
374
|
switch (format) {
|
|
359
375
|
case "json":
|
|
@@ -463,57 +479,15 @@ function createGenerateCommand() {
|
|
|
463
479
|
console.error(JSON.stringify({ error: "--adapter requires --output <directory>" }));
|
|
464
480
|
process.exit(1);
|
|
465
481
|
}
|
|
466
|
-
let spec2;
|
|
467
|
-
if (specPath === "-") {
|
|
468
|
-
const input = await readStdin();
|
|
469
|
-
try {
|
|
470
|
-
spec2 = JSON.parse(input);
|
|
471
|
-
} catch (err) {
|
|
472
|
-
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
473
|
-
throw new Error(`Invalid JSON in stdin: ${msg}`);
|
|
474
|
-
}
|
|
475
|
-
} else {
|
|
476
|
-
const specFile = path5.resolve(specPath);
|
|
477
|
-
if (!fs5.existsSync(specFile)) {
|
|
478
|
-
console.error(JSON.stringify({ error: `Spec file not found: ${specFile}` }));
|
|
479
|
-
process.exit(1);
|
|
480
|
-
}
|
|
481
|
-
try {
|
|
482
|
-
spec2 = JSON.parse(fs5.readFileSync(specFile, "utf-8"));
|
|
483
|
-
} catch (err) {
|
|
484
|
-
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
485
|
-
throw new Error(`Invalid JSON in ${specPath}: ${msg}`);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
482
|
+
let spec2 = await loadSpecInput(specPath);
|
|
488
483
|
spec2 = applyFilters(spec2, options);
|
|
489
|
-
await adapter.generate(spec2,
|
|
484
|
+
await adapter.generate(spec2, path3.resolve(options.output));
|
|
490
485
|
console.error(`Generated docs with ${options.adapter} adapter to ${options.output}`);
|
|
491
486
|
return;
|
|
492
487
|
}
|
|
493
|
-
let spec;
|
|
494
|
-
if (specPath === "-") {
|
|
495
|
-
const input = await readStdin();
|
|
496
|
-
try {
|
|
497
|
-
spec = JSON.parse(input);
|
|
498
|
-
} catch (err) {
|
|
499
|
-
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
500
|
-
throw new Error(`Invalid JSON in stdin: ${msg}`);
|
|
501
|
-
}
|
|
502
|
-
} else {
|
|
503
|
-
const specFile = path5.resolve(specPath);
|
|
504
|
-
if (!fs5.existsSync(specFile)) {
|
|
505
|
-
console.error(JSON.stringify({ error: `Spec file not found: ${specFile}` }));
|
|
506
|
-
process.exit(1);
|
|
507
|
-
}
|
|
508
|
-
try {
|
|
509
|
-
spec = JSON.parse(fs5.readFileSync(specFile, "utf-8"));
|
|
510
|
-
} catch (err) {
|
|
511
|
-
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
512
|
-
throw new Error(`Invalid JSON in ${specPath}: ${msg}`);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
488
|
+
let spec = await loadSpecInput(specPath);
|
|
515
489
|
spec = applyFilters(spec, options);
|
|
516
|
-
const docs =
|
|
490
|
+
const docs = loadSpec2(spec);
|
|
517
491
|
const collapseUnionThreshold = options.collapseUnions ? parseInt(options.collapseUnions, 10) : undefined;
|
|
518
492
|
if (format === "react") {
|
|
519
493
|
if (!options.output) {
|
|
@@ -522,7 +496,7 @@ function createGenerateCommand() {
|
|
|
522
496
|
}
|
|
523
497
|
const variant = options.variant === "index" ? "index" : "full";
|
|
524
498
|
await toReact(spec, {
|
|
525
|
-
outDir:
|
|
499
|
+
outDir: path3.resolve(options.output),
|
|
526
500
|
variant,
|
|
527
501
|
componentsPath: options.componentsPath ?? "@/components/api"
|
|
528
502
|
});
|
|
@@ -542,8 +516,8 @@ Next: Add components with 'openpkg docs add function-section'`);
|
|
|
542
516
|
}
|
|
543
517
|
const output2 = renderExport(docs, exp.id, format, collapseUnionThreshold);
|
|
544
518
|
if (options.output && options.output !== "-") {
|
|
545
|
-
const outputPath =
|
|
546
|
-
|
|
519
|
+
const outputPath = path3.resolve(options.output);
|
|
520
|
+
fs3.writeFileSync(outputPath, output2);
|
|
547
521
|
console.error(`Wrote ${outputPath}`);
|
|
548
522
|
} else {
|
|
549
523
|
console.log(output2);
|
|
@@ -555,63 +529,61 @@ Next: Add components with 'openpkg docs add function-section'`);
|
|
|
555
529
|
console.error(JSON.stringify({ error: "--split requires --output <directory>" }));
|
|
556
530
|
process.exit(1);
|
|
557
531
|
}
|
|
558
|
-
const outDir =
|
|
559
|
-
if (!
|
|
560
|
-
|
|
532
|
+
const outDir = path3.resolve(options.output);
|
|
533
|
+
if (!fs3.existsSync(outDir)) {
|
|
534
|
+
fs3.mkdirSync(outDir, { recursive: true });
|
|
561
535
|
}
|
|
562
536
|
const exports = docs.getAllExports();
|
|
563
537
|
for (const exp of exports) {
|
|
564
|
-
const filename =
|
|
565
|
-
const filePath =
|
|
566
|
-
const resolvedPath =
|
|
567
|
-
const resolvedOutDir =
|
|
568
|
-
if (!resolvedPath.startsWith(resolvedOutDir +
|
|
538
|
+
const filename = path3.basename(`${exp.name}${getExtension(format)}`);
|
|
539
|
+
const filePath = path3.join(outDir, filename);
|
|
540
|
+
const resolvedPath = path3.resolve(filePath);
|
|
541
|
+
const resolvedOutDir = path3.resolve(outDir);
|
|
542
|
+
if (!resolvedPath.startsWith(resolvedOutDir + path3.sep)) {
|
|
569
543
|
console.error(JSON.stringify({ error: `Path traversal detected: ${exp.name}` }));
|
|
570
544
|
process.exit(1);
|
|
571
545
|
}
|
|
572
546
|
const content = renderExport(docs, exp.id, format, collapseUnionThreshold);
|
|
573
|
-
|
|
547
|
+
fs3.writeFileSync(filePath, content);
|
|
574
548
|
}
|
|
575
549
|
console.error(`Wrote ${exports.length} files to ${outDir}`);
|
|
576
550
|
return;
|
|
577
551
|
}
|
|
578
552
|
const output = renderFull(docs, format, collapseUnionThreshold);
|
|
579
553
|
if (options.output && options.output !== "-") {
|
|
580
|
-
const outputPath =
|
|
581
|
-
|
|
554
|
+
const outputPath = path3.resolve(options.output);
|
|
555
|
+
fs3.writeFileSync(outputPath, output);
|
|
582
556
|
console.error(`Wrote ${outputPath}`);
|
|
583
557
|
} else {
|
|
584
558
|
console.log(output);
|
|
585
559
|
}
|
|
586
560
|
} catch (err) {
|
|
587
|
-
|
|
588
|
-
console.error(JSON.stringify({ error: error.message }));
|
|
589
|
-
process.exit(1);
|
|
561
|
+
handleCommandError(err);
|
|
590
562
|
}
|
|
591
563
|
});
|
|
592
564
|
}
|
|
593
565
|
|
|
594
566
|
// src/commands/docs/init.ts
|
|
595
|
-
import * as
|
|
596
|
-
import * as
|
|
567
|
+
import * as fs4 from "node:fs";
|
|
568
|
+
import * as path4 from "node:path";
|
|
597
569
|
import { Command as Command6 } from "commander";
|
|
598
570
|
var COMPONENTS_JSON = "components.json";
|
|
599
571
|
var REGISTRY_URL = "https://raw.githubusercontent.com/anthropics/openpkg-ts/main/registry/r/{name}.json";
|
|
600
572
|
function loadComponentsJson() {
|
|
601
|
-
const configPath =
|
|
602
|
-
if (!
|
|
573
|
+
const configPath = path4.resolve(COMPONENTS_JSON);
|
|
574
|
+
if (!fs4.existsSync(configPath))
|
|
603
575
|
return null;
|
|
604
576
|
try {
|
|
605
|
-
return JSON.parse(
|
|
577
|
+
return JSON.parse(fs4.readFileSync(configPath, "utf-8"));
|
|
606
578
|
} catch {
|
|
607
579
|
return null;
|
|
608
580
|
}
|
|
609
581
|
}
|
|
610
582
|
function createInitCommand() {
|
|
611
583
|
return new Command6("init").description("Add @openpkg registry to components.json for shadcn CLI").option("--registry <url>", "Custom registry URL", REGISTRY_URL).action(async (options) => {
|
|
612
|
-
const configPath =
|
|
584
|
+
const configPath = path4.resolve(COMPONENTS_JSON);
|
|
613
585
|
const registryUrl = options.registry || REGISTRY_URL;
|
|
614
|
-
if (!
|
|
586
|
+
if (!fs4.existsSync(configPath)) {
|
|
615
587
|
console.error(`${COMPONENTS_JSON} not found.`);
|
|
616
588
|
console.error('Run "npx shadcn@latest init" first to initialize shadcn.');
|
|
617
589
|
process.exit(1);
|
|
@@ -623,7 +595,7 @@ function createInitCommand() {
|
|
|
623
595
|
}
|
|
624
596
|
config.registries = config.registries || {};
|
|
625
597
|
config.registries["@openpkg"] = registryUrl;
|
|
626
|
-
|
|
598
|
+
fs4.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
627
599
|
console.log(`Added @openpkg registry to ${COMPONENTS_JSON}`);
|
|
628
600
|
console.log("");
|
|
629
601
|
console.log("Usage:");
|
|
@@ -690,20 +662,13 @@ function createDocsCommand() {
|
|
|
690
662
|
}
|
|
691
663
|
|
|
692
664
|
// src/commands/semver.ts
|
|
693
|
-
import * as fs7 from "node:fs";
|
|
694
|
-
import * as path7 from "node:path";
|
|
695
665
|
import { diffSpec as diffSpec3, recommendSemverBump as recommendSemverBump2 } from "@openpkg-ts/spec";
|
|
696
666
|
import { Command as Command10 } from "commander";
|
|
697
|
-
function loadSpec5(filePath) {
|
|
698
|
-
const resolved = path7.resolve(filePath);
|
|
699
|
-
const content = fs7.readFileSync(resolved, "utf-8");
|
|
700
|
-
return JSON.parse(content);
|
|
701
|
-
}
|
|
702
667
|
function createSemverCommand() {
|
|
703
668
|
return new Command10("semver").description("Recommend semver bump based on spec changes").argument("<old>", "Path to old spec file (JSON)").argument("<new>", "Path to new spec file (JSON)").action(async (oldPath, newPath) => {
|
|
704
669
|
try {
|
|
705
|
-
const oldSpec =
|
|
706
|
-
const newSpec =
|
|
670
|
+
const oldSpec = loadSpec(oldPath);
|
|
671
|
+
const newSpec = loadSpec(newPath);
|
|
707
672
|
const diff = diffSpec3(oldSpec, newSpec);
|
|
708
673
|
const recommendation = recommendSemverBump2(diff);
|
|
709
674
|
const result = {
|
|
@@ -712,16 +677,14 @@ function createSemverCommand() {
|
|
|
712
677
|
};
|
|
713
678
|
console.log(JSON.stringify(result, null, 2));
|
|
714
679
|
} catch (err) {
|
|
715
|
-
|
|
716
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
717
|
-
process.exit(1);
|
|
680
|
+
handleCommandError(err);
|
|
718
681
|
}
|
|
719
682
|
});
|
|
720
683
|
}
|
|
721
684
|
|
|
722
685
|
// src/commands/spec.ts
|
|
723
|
-
import * as
|
|
724
|
-
import * as
|
|
686
|
+
import * as fs5 from "node:fs";
|
|
687
|
+
import * as path5 from "node:path";
|
|
725
688
|
import {
|
|
726
689
|
analyzeSpec,
|
|
727
690
|
extractSpec,
|
|
@@ -731,7 +694,7 @@ import {
|
|
|
731
694
|
loadConfig,
|
|
732
695
|
mergeConfig
|
|
733
696
|
} from "@openpkg-ts/sdk";
|
|
734
|
-
import { getValidationErrors } from "@openpkg-ts/spec";
|
|
697
|
+
import { getValidationErrors as getValidationErrors2 } from "@openpkg-ts/spec";
|
|
735
698
|
import { Command as Command11 } from "commander";
|
|
736
699
|
var VALID_KINDS2 = [
|
|
737
700
|
"function",
|
|
@@ -745,27 +708,6 @@ var VALID_KINDS2 = [
|
|
|
745
708
|
"reference",
|
|
746
709
|
"external"
|
|
747
710
|
];
|
|
748
|
-
function loadSpec6(filePath) {
|
|
749
|
-
const resolved = path8.resolve(filePath);
|
|
750
|
-
let content;
|
|
751
|
-
let spec;
|
|
752
|
-
try {
|
|
753
|
-
content = fs8.readFileSync(resolved, "utf-8");
|
|
754
|
-
} catch (err) {
|
|
755
|
-
throw new Error(`Failed to read spec file: ${err instanceof Error ? err.message : String(err)}`);
|
|
756
|
-
}
|
|
757
|
-
try {
|
|
758
|
-
spec = JSON.parse(content);
|
|
759
|
-
} catch (err) {
|
|
760
|
-
throw new Error(`Invalid JSON in spec file: ${err instanceof Error ? err.message : String(err)}`);
|
|
761
|
-
}
|
|
762
|
-
const errors = getValidationErrors(spec);
|
|
763
|
-
if (errors.length > 0) {
|
|
764
|
-
const details = errors.slice(0, 5).map((e) => `${e.instancePath || "/"}: ${e.message}`).join("; ");
|
|
765
|
-
throw new Error(`Invalid OpenPkg spec: ${details}`);
|
|
766
|
-
}
|
|
767
|
-
return spec;
|
|
768
|
-
}
|
|
769
711
|
function parseList(val) {
|
|
770
712
|
if (!val)
|
|
771
713
|
return;
|
|
@@ -789,8 +731,8 @@ function formatDiagnostics(diagnostics) {
|
|
|
789
731
|
}
|
|
790
732
|
function createSnapshotSubcommand() {
|
|
791
733
|
return new Command11("snapshot").description("Generate full OpenPkg spec from TypeScript entry point").argument("<entry>", "Entry point file path").option("-o, --output <file>", "Output file (default: openpkg.json)", "openpkg.json").option("--max-depth <n>", "Max type depth (default: 4)", "4").option("--skip-resolve", "Skip external type resolution").option("--runtime", "Enable Standard Schema runtime extraction").option("--only <exports>", "Filter exports (comma-separated)").option("--ignore <exports>", "Ignore exports (comma-separated)").option("--verify", "Exit 1 if any exports fail").option("--verbose", "Show detailed output").option("--quiet", "Suppress extraction warnings").option("--strict", "Exit 1 if any extraction warnings").option("--include-private", "Include private/protected class members").option("--external-include <patterns...>", "Resolve re-exports from these packages").option("--external-exclude <patterns...>", "Never resolve from these packages").option("--external-depth <n>", "Max transitive depth for external resolution", "1").action(async (entry, options) => {
|
|
792
|
-
const entryFile =
|
|
793
|
-
const entryDir =
|
|
734
|
+
const entryFile = path5.resolve(entry);
|
|
735
|
+
const entryDir = path5.dirname(entryFile);
|
|
794
736
|
const fileConfig = loadConfig(entryDir);
|
|
795
737
|
const cliConfig = options.externalInclude ? {
|
|
796
738
|
externals: {
|
|
@@ -858,37 +800,33 @@ Skipped ${extractionWarnings.length} schema(s) with extraction errors:`);
|
|
|
858
800
|
if (options.output === "-") {
|
|
859
801
|
console.log(specJson);
|
|
860
802
|
} else {
|
|
861
|
-
const outputPath =
|
|
862
|
-
|
|
803
|
+
const outputPath = path5.resolve(options.output ?? "openpkg.json");
|
|
804
|
+
fs5.writeFileSync(outputPath, specJson);
|
|
863
805
|
console.error(`Wrote ${outputPath}`);
|
|
864
806
|
}
|
|
865
807
|
} catch (err) {
|
|
866
|
-
|
|
867
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
868
|
-
process.exit(1);
|
|
808
|
+
handleCommandError(err);
|
|
869
809
|
}
|
|
870
810
|
});
|
|
871
811
|
}
|
|
872
812
|
function createValidateSubcommand() {
|
|
873
813
|
return new Command11("validate").description("Validate an OpenPkg spec against the schema").argument("<spec>", "Path to spec file (JSON)").option("--version <version>", "Schema version to validate against (default: latest)").action(async (specPath, options) => {
|
|
874
814
|
try {
|
|
875
|
-
const spec =
|
|
815
|
+
const spec = loadSpec(specPath);
|
|
876
816
|
const version = options.version ?? "latest";
|
|
877
|
-
const errors =
|
|
817
|
+
const errors = getValidationErrors2(spec, version);
|
|
878
818
|
console.log(JSON.stringify({ valid: errors.length === 0, errors }, null, 2));
|
|
879
819
|
if (errors.length > 0)
|
|
880
820
|
process.exit(1);
|
|
881
821
|
} catch (err) {
|
|
882
|
-
|
|
883
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
884
|
-
process.exit(1);
|
|
822
|
+
handleCommandError(err);
|
|
885
823
|
}
|
|
886
824
|
});
|
|
887
825
|
}
|
|
888
826
|
function createFilterSubcommand() {
|
|
889
827
|
return new Command11("filter").description("Filter an OpenPkg spec by various criteria").argument("<spec>", "Path to spec file (JSON)").option("--kind <kinds>", "Filter by kinds (comma-separated)").option("--name <names>", "Filter by exact names (comma-separated)").option("--id <ids>", "Filter by IDs (comma-separated)").option("--tag <tags>", "Filter by tags (comma-separated)").option("--deprecated", "Only deprecated exports").option("--no-deprecated", "Exclude deprecated exports").option("--has-description", "Only exports with descriptions").option("--missing-description", "Only exports without descriptions").option("--search <term>", "Search name/description").option("--search-members", "Also search member names/descriptions").option("--search-docs", "Also search param/return descriptions").option("--module <path>", "Filter by source file path").option("-o, --output <file>", "Output file (default: stdout)").option("--summary", "Only output matched/total counts").option("--quiet", "Output raw spec only").action(async (specPath, options) => {
|
|
890
828
|
try {
|
|
891
|
-
const spec =
|
|
829
|
+
const spec = loadSpec(specPath);
|
|
892
830
|
const criteria = {};
|
|
893
831
|
if (options.kind) {
|
|
894
832
|
const kinds = parseList(options.kind);
|
|
@@ -926,21 +864,19 @@ function createFilterSubcommand() {
|
|
|
926
864
|
}
|
|
927
865
|
const json = JSON.stringify(output, null, 2);
|
|
928
866
|
if (options.output) {
|
|
929
|
-
|
|
867
|
+
fs5.writeFileSync(path5.resolve(options.output), json);
|
|
930
868
|
} else {
|
|
931
869
|
console.log(json);
|
|
932
870
|
}
|
|
933
871
|
} catch (err) {
|
|
934
|
-
|
|
935
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
936
|
-
process.exit(1);
|
|
872
|
+
handleCommandError(err);
|
|
937
873
|
}
|
|
938
874
|
});
|
|
939
875
|
}
|
|
940
876
|
function createLintSubcommand() {
|
|
941
877
|
return new Command11("lint").description("Analyze spec for quality issues (missing docs, deprecated without reason)").argument("<spec>", "Path to spec file (JSON)").option("--verbose", "Show detailed information").action(async (specPath, options) => {
|
|
942
878
|
try {
|
|
943
|
-
const spec =
|
|
879
|
+
const spec = loadSpec(specPath);
|
|
944
880
|
const diagnostics = analyzeSpec(spec);
|
|
945
881
|
const generation = spec.generation;
|
|
946
882
|
const skipped = generation?.skipped ?? [];
|
|
@@ -977,15 +913,13 @@ function createLintSubcommand() {
|
|
|
977
913
|
};
|
|
978
914
|
console.log(JSON.stringify(result, null, 2));
|
|
979
915
|
} catch (err) {
|
|
980
|
-
|
|
981
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
982
|
-
process.exit(1);
|
|
916
|
+
handleCommandError(err);
|
|
983
917
|
}
|
|
984
918
|
});
|
|
985
919
|
}
|
|
986
920
|
function createListSubcommand() {
|
|
987
921
|
return new Command11("list").description("List exports from a TypeScript entry point").argument("<entry>", "Entry point file path").action(async (entry) => {
|
|
988
|
-
const entryFile =
|
|
922
|
+
const entryFile = path5.resolve(entry);
|
|
989
923
|
const result = await listExports({ entryFile });
|
|
990
924
|
if (result.errors.length > 0) {
|
|
991
925
|
console.error(JSON.stringify({ errors: result.errors }, null, 2));
|
|
@@ -996,7 +930,7 @@ function createListSubcommand() {
|
|
|
996
930
|
}
|
|
997
931
|
function createGetSubcommand() {
|
|
998
932
|
return new Command11("get").description("Get detailed spec for a single export").argument("<entry>", "Entry point file path").argument("<name>", "Export name").action(async (entry, name) => {
|
|
999
|
-
const entryFile =
|
|
933
|
+
const entryFile = path5.resolve(entry);
|
|
1000
934
|
const result = await getExport({ entryFile, exportName: name });
|
|
1001
935
|
if (!result.export) {
|
|
1002
936
|
const errorMsg = result.errors.length > 0 ? result.errors.join("; ") : `Export '${name}' not found`;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
1
|
import { getExport, listExports } from "@openpkg-ts/sdk";
|
|
2
|
+
import { CategorizedBreaking } from "@openpkg-ts/spec";
|
|
3
|
+
type BreakingResult = {
|
|
4
|
+
breaking: CategorizedBreaking[];
|
|
5
|
+
count: number;
|
|
6
|
+
};
|
|
7
|
+
import { CategorizedBreaking as CategorizedBreaking2, SemverBump, SpecExportKind } from "@openpkg-ts/spec";
|
|
8
|
+
/**
|
|
9
|
+
* A changed with details about what changed
|
|
10
|
+
*/
|
|
11
|
+
interface ChangedExport {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
kind: SpecExportKind;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Enriched diff result with categorized changes
|
|
19
|
+
*/
|
|
20
|
+
interface DiffResult {
|
|
21
|
+
breaking: CategorizedBreaking2[];
|
|
22
|
+
added: string[];
|
|
23
|
+
removed: RemovedExport[];
|
|
24
|
+
changed: ChangedExport[];
|
|
25
|
+
docsOnly: string[];
|
|
26
|
+
summary: {
|
|
27
|
+
breakingCount: number;
|
|
28
|
+
addedCount: number;
|
|
29
|
+
removedCount: number;
|
|
30
|
+
changedCount: number;
|
|
31
|
+
docsOnlyCount: number;
|
|
32
|
+
semverBump: SemverBump;
|
|
33
|
+
semverReason: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
interface RemovedExport {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
kind: SpecExportKind;
|
|
40
|
+
}
|
|
2
41
|
import { FilterResult, FilterSummaryResult } from "./commands/filter";
|
|
3
|
-
export { listExports, getExport, FilterSummaryResult, FilterResult };
|
|
42
|
+
export { listExports, getExport, RemovedExport, FilterSummaryResult, FilterResult, DiffResult, ChangedExport, BreakingResult };
|
package/dist/src/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpkg-ts/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "CLI for OpenPkg TypeScript API extraction and documentation generation",
|
|
5
5
|
"homepage": "https://github.com/ryanwaits/openpkg-ts#readme",
|
|
6
6
|
"repository": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"test": "bun test"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@openpkg-ts/adapters": "^0.3.
|
|
27
|
-
"@openpkg-ts/sdk": "^0.35.
|
|
26
|
+
"@openpkg-ts/adapters": "^0.3.14",
|
|
27
|
+
"@openpkg-ts/sdk": "^0.35.1",
|
|
28
28
|
"commander": "^14.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
-
|
|
20
|
-
export { __toESM, __require };
|