@openpkg-ts/cli 0.5.1 → 0.6.0
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/README.md +114 -145
- package/dist/bin/openpkg.js +441 -265
- package/dist/src/index.d.ts +1 -10
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,11 +10,24 @@ npm install -g @openpkg-ts/cli
|
|
|
10
10
|
npx @openpkg-ts/cli <command>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Command Structure
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Commands organized under `openpkg spec` and `openpkg docs`. Legacy commands work as aliases.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
openpkg spec snapshot ./src/index.ts -o spec.json
|
|
19
|
+
openpkg spec validate spec.json
|
|
20
|
+
|
|
21
|
+
openpkg docs init
|
|
22
|
+
openpkg docs generate spec.json -o ./docs
|
|
23
|
+
openpkg docs add function-section
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
## Spec Commands
|
|
29
|
+
|
|
30
|
+
### list
|
|
18
31
|
|
|
19
32
|
```bash
|
|
20
33
|
openpkg list src/index.ts
|
|
@@ -24,31 +37,21 @@ Output: JSON array of `{ name, kind, file, line, description }`
|
|
|
24
37
|
|
|
25
38
|
### get
|
|
26
39
|
|
|
27
|
-
Get detailed spec for single export.
|
|
28
|
-
|
|
29
40
|
```bash
|
|
30
41
|
openpkg get src/index.ts createClient
|
|
31
42
|
```
|
|
32
43
|
|
|
33
44
|
Output: JSON with `{ export, types }` - full spec for the export plus referenced types.
|
|
34
45
|
|
|
35
|
-
### snapshot
|
|
36
|
-
|
|
37
|
-
Generate full OpenPkg spec from TypeScript.
|
|
46
|
+
### spec snapshot
|
|
38
47
|
|
|
39
48
|
```bash
|
|
40
|
-
|
|
41
|
-
openpkg snapshot src/index.ts -o
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
openpkg snapshot src/index.ts -o -
|
|
45
|
-
|
|
46
|
-
# With options
|
|
47
|
-
openpkg snapshot src/index.ts --max-depth 4 --runtime --verify
|
|
48
|
-
openpkg snapshot src/index.ts --only "use*,create*" --ignore "*Internal"
|
|
49
|
+
openpkg spec snapshot src/index.ts -o openpkg.json
|
|
50
|
+
openpkg spec snapshot src/index.ts -o - # stdout
|
|
51
|
+
openpkg spec snapshot src/index.ts --max-depth 4 --runtime --verify
|
|
52
|
+
openpkg spec snapshot src/index.ts --only "use*,create*" --ignore "*Internal"
|
|
49
53
|
```
|
|
50
54
|
|
|
51
|
-
Options:
|
|
52
55
|
| Flag | Description |
|
|
53
56
|
|------|-------------|
|
|
54
57
|
| `-o, --output <file>` | Output file (default: openpkg.json, `-` for stdout) |
|
|
@@ -59,195 +62,161 @@ Options:
|
|
|
59
62
|
| `--ignore <exports>` | Ignore exports (comma-separated, wildcards) |
|
|
60
63
|
| `--verify` | Exit 1 if any exports fail |
|
|
61
64
|
|
|
62
|
-
###
|
|
63
|
-
|
|
64
|
-
Generate documentation from spec.
|
|
65
|
+
### spec validate
|
|
65
66
|
|
|
66
67
|
```bash
|
|
67
|
-
|
|
68
|
-
openpkg
|
|
69
|
-
|
|
70
|
-
# HTML
|
|
71
|
-
openpkg docs openpkg.json -f html -o api.html
|
|
68
|
+
openpkg spec validate openpkg.json
|
|
69
|
+
openpkg spec validate openpkg.json --version 1.0
|
|
70
|
+
```
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
openpkg docs openpkg.json -f json
|
|
72
|
+
### spec diagnostics
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
openpkg
|
|
74
|
+
```bash
|
|
75
|
+
openpkg spec diagnostics openpkg.json
|
|
76
|
+
```
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
openpkg snapshot src/index.ts -o - | openpkg docs - -f md
|
|
78
|
+
### spec filter
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
openpkg
|
|
80
|
+
```bash
|
|
81
|
+
openpkg spec filter openpkg.json --kind function,class
|
|
82
|
+
openpkg spec filter openpkg.json --has-description -o documented.json
|
|
83
|
+
openpkg spec filter openpkg.json --search "user" --summary
|
|
84
|
+
openpkg spec filter openpkg.json --deprecated --quiet | jq '.exports[].name'
|
|
84
85
|
```
|
|
85
86
|
|
|
86
|
-
Options:
|
|
87
87
|
| Flag | Description |
|
|
88
88
|
|------|-------------|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
| `--
|
|
92
|
-
|
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
| `--kind <kinds>` | Filter by kinds (comma-separated) |
|
|
90
|
+
| `--name <names>` | Filter by exact names (comma-separated) |
|
|
91
|
+
| `--id <ids>` | Filter by export IDs (comma-separated) |
|
|
92
|
+
| `--tag <tags>` | Filter by tags (comma-separated) |
|
|
93
|
+
| `--deprecated` | Only deprecated exports |
|
|
94
|
+
| `--no-deprecated` | Exclude deprecated exports |
|
|
95
|
+
| `--has-description` | Only exports with descriptions |
|
|
96
|
+
| `--missing-description` | Only exports without descriptions |
|
|
97
|
+
| `--search <term>` | Search name/description (case-insensitive) |
|
|
98
|
+
| `--module <path>` | Filter by source file path (contains) |
|
|
99
|
+
| `-o, --output <file>` | Output file (default: stdout) |
|
|
100
|
+
| `--summary` | Only output matched/total counts |
|
|
101
|
+
| `--quiet` | Output raw spec only (no wrapper) |
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
### spec diff
|
|
97
104
|
|
|
98
105
|
```bash
|
|
99
|
-
openpkg diff old.json new.json
|
|
100
|
-
openpkg diff old.json new.json --summary
|
|
106
|
+
openpkg spec diff old.json new.json
|
|
107
|
+
openpkg spec diff old.json new.json --summary
|
|
101
108
|
```
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
- `breaking` - categorized breaking changes
|
|
105
|
-
- `added` - new exports
|
|
106
|
-
- `removed` - removed exports
|
|
107
|
-
- `changed` - modified exports
|
|
108
|
-
- `docsOnly` - documentation-only changes
|
|
109
|
-
- `summary.semverBump` - recommended version bump
|
|
110
|
+
### spec breaking
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Check for breaking changes. Exit 1 if any found.
|
|
112
|
+
Exit 1 if breaking changes found.
|
|
114
113
|
|
|
115
114
|
```bash
|
|
116
|
-
openpkg breaking old.json new.json
|
|
115
|
+
openpkg spec breaking old.json new.json
|
|
117
116
|
```
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"breaking": [
|
|
123
|
-
{ "id": "createClient", "name": "createClient", "kind": "function", "severity": "high", "reason": "signature changed" }
|
|
124
|
-
],
|
|
125
|
-
"count": 1
|
|
126
|
-
}
|
|
127
|
-
```
|
|
118
|
+
### spec semver
|
|
128
119
|
|
|
129
|
-
|
|
120
|
+
```bash
|
|
121
|
+
openpkg spec semver old.json new.json
|
|
122
|
+
```
|
|
130
123
|
|
|
131
|
-
|
|
124
|
+
### spec changelog
|
|
132
125
|
|
|
133
126
|
```bash
|
|
134
|
-
openpkg
|
|
127
|
+
openpkg spec changelog old.json new.json
|
|
128
|
+
openpkg spec changelog old.json new.json --format json
|
|
135
129
|
```
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
```json
|
|
139
|
-
{
|
|
140
|
-
"bump": "major",
|
|
141
|
-
"reason": "1 breaking change detected"
|
|
142
|
-
}
|
|
143
|
-
```
|
|
131
|
+
---
|
|
144
132
|
|
|
145
|
-
|
|
133
|
+
## Docs Commands
|
|
146
134
|
|
|
147
|
-
|
|
135
|
+
### docs init
|
|
136
|
+
|
|
137
|
+
Initialize docs configuration.
|
|
148
138
|
|
|
149
139
|
```bash
|
|
150
|
-
openpkg
|
|
151
|
-
openpkg validate openpkg.json --version 1.0
|
|
140
|
+
openpkg docs init
|
|
152
141
|
```
|
|
153
142
|
|
|
154
|
-
|
|
155
|
-
```json
|
|
156
|
-
{
|
|
157
|
-
"valid": true,
|
|
158
|
-
"errors": []
|
|
159
|
-
}
|
|
160
|
-
```
|
|
143
|
+
Creates `openpkg.config.json` with default settings.
|
|
161
144
|
|
|
162
|
-
###
|
|
145
|
+
### docs generate
|
|
163
146
|
|
|
164
|
-
Generate
|
|
147
|
+
Generate documentation from spec.
|
|
165
148
|
|
|
166
149
|
```bash
|
|
167
|
-
|
|
168
|
-
openpkg
|
|
169
|
-
```
|
|
150
|
+
# Markdown (default)
|
|
151
|
+
openpkg docs generate openpkg.json -o api.md
|
|
170
152
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
## Breaking Changes
|
|
174
|
-
- **Removed** `oldFunction` (function)
|
|
153
|
+
# React layout (single layout + spec JSON, add components via registry)
|
|
154
|
+
openpkg docs generate openpkg.json -f react -o ./app/api
|
|
175
155
|
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
```
|
|
156
|
+
# HTML
|
|
157
|
+
openpkg docs generate openpkg.json -f html -o api.html
|
|
179
158
|
|
|
180
|
-
|
|
159
|
+
# JSON (simplified structure)
|
|
160
|
+
openpkg docs generate openpkg.json -f json
|
|
181
161
|
|
|
182
|
-
|
|
162
|
+
# Split: one file per export
|
|
163
|
+
openpkg docs generate openpkg.json --split -o docs/api/
|
|
183
164
|
|
|
184
|
-
|
|
185
|
-
openpkg
|
|
165
|
+
# With adapter
|
|
166
|
+
openpkg docs generate openpkg.json -a fumadocs -o docs/api/
|
|
167
|
+
|
|
168
|
+
# From stdin
|
|
169
|
+
openpkg spec snapshot src/index.ts -o - | openpkg docs generate - -f md
|
|
186
170
|
```
|
|
187
171
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
172
|
+
| Flag | Description |
|
|
173
|
+
|------|-------------|
|
|
174
|
+
| `-o, --output <path>` | Output file or directory (default: stdout) |
|
|
175
|
+
| `-f, --format <fmt>` | Format: `md`, `json`, `html`, `react` (default: md) |
|
|
176
|
+
| `--split` | One file per export (requires `-o` as directory) |
|
|
177
|
+
| `-a, --adapter <name>` | Use adapter: `fumadocs`, `raw` (default: raw) |
|
|
178
|
+
|
|
179
|
+
### docs add
|
|
180
|
+
|
|
181
|
+
Add components from shadcn-compatible registry.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
openpkg docs add function-section
|
|
185
|
+
openpkg docs add class-section interface-section
|
|
186
|
+
openpkg docs add export-card param-table signature
|
|
199
187
|
```
|
|
200
188
|
|
|
201
|
-
###
|
|
189
|
+
### docs list
|
|
202
190
|
|
|
203
|
-
|
|
191
|
+
List available registry components.
|
|
204
192
|
|
|
205
193
|
```bash
|
|
206
|
-
openpkg
|
|
207
|
-
openpkg filter openpkg.json --has-description -o documented.json
|
|
208
|
-
openpkg filter openpkg.json --search "user" --summary
|
|
209
|
-
openpkg filter openpkg.json --deprecated --quiet | jq '.exports[].name'
|
|
194
|
+
openpkg docs list
|
|
210
195
|
```
|
|
211
196
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
| `--kind <kinds>` | Filter by kinds (comma-separated) |
|
|
216
|
-
| `--name <names>` | Filter by exact names (comma-separated) |
|
|
217
|
-
| `--id <ids>` | Filter by export IDs (comma-separated) |
|
|
218
|
-
| `--tag <tags>` | Filter by tags (comma-separated) |
|
|
219
|
-
| `--deprecated` | Only deprecated exports |
|
|
220
|
-
| `--no-deprecated` | Exclude deprecated exports |
|
|
221
|
-
| `--has-description` | Only exports with descriptions |
|
|
222
|
-
| `--missing-description` | Only exports without descriptions |
|
|
223
|
-
| `--search <term>` | Search name/description (case-insensitive) |
|
|
224
|
-
| `--module <path>` | Filter by source file path (contains) |
|
|
225
|
-
| `-o, --output <file>` | Output file (default: stdout) |
|
|
226
|
-
| `--summary` | Only output matched/total counts |
|
|
227
|
-
| `--quiet` | Output raw spec only (no wrapper) |
|
|
197
|
+
16 components available: layouts, sections, primitives.
|
|
198
|
+
|
|
199
|
+
### docs view
|
|
228
200
|
|
|
229
|
-
|
|
201
|
+
View component details and dependencies.
|
|
230
202
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
{
|
|
234
|
-
"spec": { ... },
|
|
235
|
-
"matched": 12,
|
|
236
|
-
"total": 45
|
|
237
|
-
}
|
|
203
|
+
```bash
|
|
204
|
+
openpkg docs view function-section
|
|
238
205
|
```
|
|
239
206
|
|
|
207
|
+
---
|
|
208
|
+
|
|
240
209
|
## Pipelines
|
|
241
210
|
|
|
242
211
|
Commands are composable via stdin/stdout:
|
|
243
212
|
|
|
244
213
|
```bash
|
|
245
214
|
# Extract and generate docs
|
|
246
|
-
openpkg snapshot src/index.ts -o - | openpkg docs - -f md > api.md
|
|
215
|
+
openpkg spec snapshot src/index.ts -o - | openpkg docs generate - -f md > api.md
|
|
247
216
|
|
|
248
217
|
# Extract, verify, then diff
|
|
249
|
-
openpkg snapshot src/index.ts --verify -o new.json
|
|
250
|
-
openpkg diff baseline.json new.json --summary
|
|
218
|
+
openpkg spec snapshot src/index.ts --verify -o new.json
|
|
219
|
+
openpkg spec diff baseline.json new.json --summary
|
|
251
220
|
```
|
|
252
221
|
|
|
253
222
|
## Programmatic Use
|
package/dist/bin/openpkg.js
CHANGED
|
@@ -5,13 +5,11 @@ import {
|
|
|
5
5
|
} from "../shared/chunk-1dqs11h6.js";
|
|
6
6
|
|
|
7
7
|
// bin/openpkg.ts
|
|
8
|
-
import
|
|
9
|
-
import { getExport, listExports } from "@openpkg-ts/sdk";
|
|
10
|
-
import { Command as Command10 } from "commander";
|
|
8
|
+
import { Command as Command12 } from "commander";
|
|
11
9
|
// package.json
|
|
12
10
|
var package_default = {
|
|
13
11
|
name: "@openpkg-ts/cli",
|
|
14
|
-
version: "0.
|
|
12
|
+
version: "0.6.0",
|
|
15
13
|
description: "CLI for OpenPkg TypeScript API extraction and documentation generation",
|
|
16
14
|
homepage: "https://github.com/ryanwaits/openpkg-ts#readme",
|
|
17
15
|
repository: {
|
|
@@ -34,8 +32,8 @@ var package_default = {
|
|
|
34
32
|
test: "bun test"
|
|
35
33
|
},
|
|
36
34
|
dependencies: {
|
|
37
|
-
"@openpkg-ts/adapters": "^0.3.
|
|
38
|
-
"@openpkg-ts/sdk": "^0.
|
|
35
|
+
"@openpkg-ts/adapters": "^0.3.3",
|
|
36
|
+
"@openpkg-ts/sdk": "^0.34.0",
|
|
39
37
|
commander: "^14.0.0"
|
|
40
38
|
},
|
|
41
39
|
devDependencies: {
|
|
@@ -253,71 +251,97 @@ function createChangelogCommand() {
|
|
|
253
251
|
});
|
|
254
252
|
}
|
|
255
253
|
|
|
256
|
-
// src/commands/
|
|
254
|
+
// src/commands/docs/index.ts
|
|
255
|
+
import { Command as Command9 } from "commander";
|
|
256
|
+
|
|
257
|
+
// src/commands/docs/add.ts
|
|
258
|
+
import { spawn } from "node:child_process";
|
|
259
|
+
import { Command as Command4 } from "commander";
|
|
260
|
+
|
|
261
|
+
// src/commands/docs/utils.ts
|
|
257
262
|
import * as fs4 from "node:fs";
|
|
258
263
|
import * as path4 from "node:path";
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const resolved = path4.resolve(filePath);
|
|
263
|
-
const content = fs4.readFileSync(resolved, "utf-8");
|
|
264
|
-
return JSON.parse(content);
|
|
265
|
-
}
|
|
266
|
-
function createDiagnosticsCommand() {
|
|
267
|
-
return new Command4("diagnostics").description("Analyze spec for quality issues (missing docs, deprecated without reason)").argument("<spec>", "Path to spec file (JSON)").option("--verbose", "Show detailed information including skipped export details").action(async (specPath, options) => {
|
|
264
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
265
|
+
const pkgJsonPath = path4.join(cwd, "package.json");
|
|
266
|
+
if (fs4.existsSync(pkgJsonPath)) {
|
|
268
267
|
try {
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
268
|
+
const pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
|
|
269
|
+
if (pkg.packageManager) {
|
|
270
|
+
if (pkg.packageManager.startsWith("bun"))
|
|
271
|
+
return "bun";
|
|
272
|
+
if (pkg.packageManager.startsWith("pnpm"))
|
|
273
|
+
return "pnpm";
|
|
274
|
+
if (pkg.packageManager.startsWith("yarn"))
|
|
275
|
+
return "yarn";
|
|
276
|
+
if (pkg.packageManager.startsWith("npm"))
|
|
277
|
+
return "npm";
|
|
277
278
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
279
|
+
} catch {}
|
|
280
|
+
}
|
|
281
|
+
if (fs4.existsSync(path4.join(cwd, "bun.lockb")) || fs4.existsSync(path4.join(cwd, "bun.lock"))) {
|
|
282
|
+
return "bun";
|
|
283
|
+
}
|
|
284
|
+
if (fs4.existsSync(path4.join(cwd, "pnpm-lock.yaml"))) {
|
|
285
|
+
return "pnpm";
|
|
286
|
+
}
|
|
287
|
+
if (fs4.existsSync(path4.join(cwd, "yarn.lock"))) {
|
|
288
|
+
return "yarn";
|
|
289
|
+
}
|
|
290
|
+
return "npm";
|
|
291
|
+
}
|
|
292
|
+
function getDlxCommand(pkg, pm) {
|
|
293
|
+
const packageManager = pm || detectPackageManager();
|
|
294
|
+
switch (packageManager) {
|
|
295
|
+
case "bun":
|
|
296
|
+
return { cmd: "bunx", args: [pkg] };
|
|
297
|
+
case "pnpm":
|
|
298
|
+
return { cmd: "pnpm", args: ["dlx", pkg] };
|
|
299
|
+
case "yarn":
|
|
300
|
+
return { cmd: "yarn", args: ["dlx", pkg] };
|
|
301
|
+
default:
|
|
302
|
+
return { cmd: "npx", args: [pkg] };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function getShadcnCommand(subcommand, args = []) {
|
|
306
|
+
const dlx = getDlxCommand("shadcn@latest");
|
|
307
|
+
return {
|
|
308
|
+
cmd: dlx.cmd,
|
|
309
|
+
args: [...dlx.args, subcommand, ...args]
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/commands/docs/add.ts
|
|
314
|
+
function createAddCommand() {
|
|
315
|
+
return new Command4("add").description("Install @openpkg components (wrapper for shadcn add)").argument("<components...>", "Components to install").option("-o, --overwrite", "Overwrite existing files").option("-c, --cwd <path>", "Working directory").option("-y, --yes", "Skip confirmation prompt").option("-s, --silent", "Mute output").action(async (components, options) => {
|
|
316
|
+
const prefixedComponents = components.map((c) => c.startsWith("@") ? c : `@openpkg/${c}`);
|
|
317
|
+
const extraArgs = [];
|
|
318
|
+
if (options.overwrite)
|
|
319
|
+
extraArgs.push("--overwrite");
|
|
320
|
+
if (options.cwd)
|
|
321
|
+
extraArgs.push("--cwd", options.cwd);
|
|
322
|
+
if (options.yes)
|
|
323
|
+
extraArgs.push("--yes");
|
|
324
|
+
if (options.silent)
|
|
325
|
+
extraArgs.push("--silent");
|
|
326
|
+
const { cmd, args } = getShadcnCommand("add", [...prefixedComponents, ...extraArgs]);
|
|
327
|
+
if (!options.silent) {
|
|
328
|
+
console.log(`Running: ${cmd} ${args.join(" ")}`);
|
|
329
|
+
console.log("");
|
|
313
330
|
}
|
|
331
|
+
const child = spawn(cmd, args, {
|
|
332
|
+
stdio: "inherit",
|
|
333
|
+
shell: true
|
|
334
|
+
});
|
|
335
|
+
child.on("close", (code) => {
|
|
336
|
+
process.exit(code || 0);
|
|
337
|
+
});
|
|
314
338
|
});
|
|
315
339
|
}
|
|
316
340
|
|
|
317
|
-
// src/commands/docs.ts
|
|
341
|
+
// src/commands/docs/generate.ts
|
|
318
342
|
import * as fs5 from "node:fs";
|
|
319
343
|
import * as path5 from "node:path";
|
|
320
|
-
import {
|
|
344
|
+
import { loadSpec as loadSpec4, query, toReact } from "@openpkg-ts/sdk";
|
|
321
345
|
import { Command as Command5 } from "commander";
|
|
322
346
|
async function readStdin() {
|
|
323
347
|
const chunks = [];
|
|
@@ -332,10 +356,32 @@ function getExtension(format) {
|
|
|
332
356
|
return ".json";
|
|
333
357
|
case "html":
|
|
334
358
|
return ".html";
|
|
359
|
+
case "react":
|
|
360
|
+
return ".tsx";
|
|
335
361
|
default:
|
|
336
362
|
return ".md";
|
|
337
363
|
}
|
|
338
364
|
}
|
|
365
|
+
function applyFilters(spec, options) {
|
|
366
|
+
let qb = query(spec);
|
|
367
|
+
if (options.kind) {
|
|
368
|
+
const kinds = options.kind.split(",").map((k) => k.trim());
|
|
369
|
+
qb = qb.byKind(...kinds);
|
|
370
|
+
}
|
|
371
|
+
if (options.tag) {
|
|
372
|
+
const tags = options.tag.split(",").map((t) => t.trim());
|
|
373
|
+
qb = qb.byTag(...tags);
|
|
374
|
+
}
|
|
375
|
+
if (options.search) {
|
|
376
|
+
qb = qb.search(options.search);
|
|
377
|
+
}
|
|
378
|
+
if (options.deprecated === true) {
|
|
379
|
+
qb = qb.deprecated(true);
|
|
380
|
+
} else if (options.deprecated === false) {
|
|
381
|
+
qb = qb.deprecated(false);
|
|
382
|
+
}
|
|
383
|
+
return qb.toSpec();
|
|
384
|
+
}
|
|
339
385
|
function renderExport(docs, exportId, format, collapseUnionThreshold) {
|
|
340
386
|
const exp = docs.getExport(exportId);
|
|
341
387
|
if (!exp)
|
|
@@ -364,8 +410,8 @@ function renderFull(docs, format, collapseUnionThreshold) {
|
|
|
364
410
|
return docs.toMarkdown({ frontmatter: true, codeSignatures: true, collapseUnionThreshold });
|
|
365
411
|
}
|
|
366
412
|
}
|
|
367
|
-
function
|
|
368
|
-
return new Command5("
|
|
413
|
+
function createGenerateCommand() {
|
|
414
|
+
return new Command5("generate").description("Generate documentation from OpenPkg spec").argument("<spec>", "Path to openpkg.json spec file (use - for stdin)").option("-o, --output <path>", "Output file or directory (default: stdout)").option("-f, --format <format>", "Output format: md, json, html, react (default: md)", "md").option("--split", "Output one file per export (requires --output as directory)").option("-e, --export <name>", "Generate docs for a single export by name").option("-a, --adapter <name>", "Use adapter for generation (default: raw)").option("--collapse-unions <n>", "Collapse unions with more than N members").option("-k, --kind <kinds>", "Filter by kind(s), comma-separated").option("-t, --tag <tags>", "Filter by tag(s), comma-separated").option("-s, --search <term>", "Search name and description").option("--deprecated", "Only include deprecated exports").option("--no-deprecated", "Exclude deprecated exports").option("--variant <variant>", "React layout variant: full (single page) or index (links)", "full").option("--components-path <path>", "React components import path", "@/components/api").action(async (specPath, options) => {
|
|
369
415
|
const format = options.format || "md";
|
|
370
416
|
try {
|
|
371
417
|
if (options.adapter && options.adapter !== "raw") {
|
|
@@ -387,36 +433,56 @@ function createDocsCommand() {
|
|
|
387
433
|
console.error(JSON.stringify({ error: "--adapter requires --output <directory>" }));
|
|
388
434
|
process.exit(1);
|
|
389
435
|
}
|
|
390
|
-
let
|
|
436
|
+
let spec2;
|
|
391
437
|
if (specPath === "-") {
|
|
392
438
|
const input = await readStdin();
|
|
393
|
-
|
|
439
|
+
spec2 = JSON.parse(input);
|
|
394
440
|
} else {
|
|
395
441
|
const specFile = path5.resolve(specPath);
|
|
396
442
|
if (!fs5.existsSync(specFile)) {
|
|
397
443
|
console.error(JSON.stringify({ error: `Spec file not found: ${specFile}` }));
|
|
398
444
|
process.exit(1);
|
|
399
445
|
}
|
|
400
|
-
|
|
446
|
+
spec2 = JSON.parse(fs5.readFileSync(specFile, "utf-8"));
|
|
401
447
|
}
|
|
402
|
-
|
|
448
|
+
spec2 = applyFilters(spec2, options);
|
|
449
|
+
await adapter.generate(spec2, path5.resolve(options.output));
|
|
403
450
|
console.error(`Generated docs with ${options.adapter} adapter to ${options.output}`);
|
|
404
451
|
return;
|
|
405
452
|
}
|
|
406
|
-
let
|
|
453
|
+
let spec;
|
|
407
454
|
if (specPath === "-") {
|
|
408
455
|
const input = await readStdin();
|
|
409
|
-
|
|
410
|
-
docs = loadSpec4(spec);
|
|
456
|
+
spec = JSON.parse(input);
|
|
411
457
|
} else {
|
|
412
458
|
const specFile = path5.resolve(specPath);
|
|
413
459
|
if (!fs5.existsSync(specFile)) {
|
|
414
460
|
console.error(JSON.stringify({ error: `Spec file not found: ${specFile}` }));
|
|
415
461
|
process.exit(1);
|
|
416
462
|
}
|
|
417
|
-
|
|
463
|
+
spec = JSON.parse(fs5.readFileSync(specFile, "utf-8"));
|
|
418
464
|
}
|
|
465
|
+
spec = applyFilters(spec, options);
|
|
466
|
+
const docs = loadSpec4(spec);
|
|
419
467
|
const collapseUnionThreshold = options.collapseUnions ? parseInt(options.collapseUnions, 10) : undefined;
|
|
468
|
+
if (format === "react") {
|
|
469
|
+
if (!options.output) {
|
|
470
|
+
console.error(JSON.stringify({ error: "--format react requires --output <directory>" }));
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
const variant = options.variant === "index" ? "index" : "full";
|
|
474
|
+
await toReact(spec, {
|
|
475
|
+
outDir: path5.resolve(options.output),
|
|
476
|
+
variant,
|
|
477
|
+
componentsPath: options.componentsPath ?? "@/components/api"
|
|
478
|
+
});
|
|
479
|
+
console.error(`Generated React layout to ${options.output}`);
|
|
480
|
+
console.error(` - page.tsx: Layout file`);
|
|
481
|
+
console.error(` - openpkg.json: Spec data`);
|
|
482
|
+
console.error(`
|
|
483
|
+
Next: Add components with 'openpkg docs add function-section'`);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
420
486
|
if (options.export) {
|
|
421
487
|
const exports = docs.getAllExports();
|
|
422
488
|
const exp = exports.find((e) => e.name === options.export);
|
|
@@ -469,108 +535,115 @@ function createDocsCommand() {
|
|
|
469
535
|
});
|
|
470
536
|
}
|
|
471
537
|
|
|
472
|
-
// src/commands/
|
|
538
|
+
// src/commands/docs/init.ts
|
|
473
539
|
import * as fs6 from "node:fs";
|
|
474
540
|
import * as path6 from "node:path";
|
|
475
|
-
import { filterSpec } from "@openpkg-ts/sdk";
|
|
476
541
|
import { Command as Command6 } from "commander";
|
|
477
|
-
var
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
"
|
|
484
|
-
"module",
|
|
485
|
-
"namespace",
|
|
486
|
-
"reference",
|
|
487
|
-
"external"
|
|
488
|
-
];
|
|
489
|
-
function loadSpec5(filePath) {
|
|
490
|
-
const resolved = path6.resolve(filePath);
|
|
491
|
-
const content = fs6.readFileSync(resolved, "utf-8");
|
|
492
|
-
return JSON.parse(content);
|
|
542
|
+
var COMPONENTS_JSON = "components.json";
|
|
543
|
+
var REGISTRY_URL = "https://raw.githubusercontent.com/anthropics/openpkg-ts/main/registry/r/{name}.json";
|
|
544
|
+
function loadComponentsJson() {
|
|
545
|
+
const configPath = path6.resolve(COMPONENTS_JSON);
|
|
546
|
+
if (!fs6.existsSync(configPath))
|
|
547
|
+
return null;
|
|
548
|
+
return JSON.parse(fs6.readFileSync(configPath, "utf-8"));
|
|
493
549
|
}
|
|
494
|
-
function
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
function createFilterCommand() {
|
|
507
|
-
return new Command6("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 (case-insensitive)").option("--search-members", "Also search member names/descriptions").option("--search-docs", "Also search param/return descriptions and examples").option("--module <path>", "Filter by source file path (contains)").option("-o, --output <file>", "Output file (default: stdout)").option("--summary", "Only output matched/total counts").option("--quiet", "Output raw spec only (no wrapper)").action(async (specPath, options) => {
|
|
508
|
-
try {
|
|
509
|
-
const spec = loadSpec5(specPath);
|
|
510
|
-
const criteria = {};
|
|
511
|
-
if (options.kind) {
|
|
512
|
-
const kinds = parseList(options.kind);
|
|
513
|
-
if (kinds)
|
|
514
|
-
criteria.kinds = validateKinds(kinds);
|
|
515
|
-
}
|
|
516
|
-
if (options.name)
|
|
517
|
-
criteria.names = parseList(options.name);
|
|
518
|
-
if (options.id)
|
|
519
|
-
criteria.ids = parseList(options.id);
|
|
520
|
-
if (options.tag)
|
|
521
|
-
criteria.tags = parseList(options.tag);
|
|
522
|
-
if (options.deprecated !== undefined)
|
|
523
|
-
criteria.deprecated = options.deprecated;
|
|
524
|
-
if (options.hasDescription)
|
|
525
|
-
criteria.hasDescription = true;
|
|
526
|
-
if (options.missingDescription)
|
|
527
|
-
criteria.hasDescription = false;
|
|
528
|
-
if (options.search)
|
|
529
|
-
criteria.search = options.search;
|
|
530
|
-
if (options.searchMembers)
|
|
531
|
-
criteria.searchMembers = true;
|
|
532
|
-
if (options.searchDocs)
|
|
533
|
-
criteria.searchDocs = true;
|
|
534
|
-
if (options.module)
|
|
535
|
-
criteria.module = options.module;
|
|
536
|
-
const result = filterSpec(spec, criteria);
|
|
537
|
-
let output;
|
|
538
|
-
if (options.summary) {
|
|
539
|
-
output = { matched: result.matched, total: result.total };
|
|
540
|
-
} else if (options.quiet) {
|
|
541
|
-
output = result.spec;
|
|
542
|
-
} else {
|
|
543
|
-
output = { spec: result.spec, matched: result.matched, total: result.total };
|
|
544
|
-
}
|
|
545
|
-
const json = JSON.stringify(output, null, 2);
|
|
546
|
-
if (options.output) {
|
|
547
|
-
fs6.writeFileSync(path6.resolve(options.output), json);
|
|
548
|
-
} else {
|
|
549
|
-
console.log(json);
|
|
550
|
-
}
|
|
551
|
-
} catch (err) {
|
|
552
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
553
|
-
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
550
|
+
function createInitCommand() {
|
|
551
|
+
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) => {
|
|
552
|
+
const configPath = path6.resolve(COMPONENTS_JSON);
|
|
553
|
+
const registryUrl = options.registry || REGISTRY_URL;
|
|
554
|
+
if (!fs6.existsSync(configPath)) {
|
|
555
|
+
console.error(`${COMPONENTS_JSON} not found.`);
|
|
556
|
+
console.error('Run "npx shadcn@latest init" first to initialize shadcn.');
|
|
557
|
+
process.exit(1);
|
|
558
|
+
}
|
|
559
|
+
const config = loadComponentsJson();
|
|
560
|
+
if (!config) {
|
|
561
|
+
console.error(`Failed to parse ${COMPONENTS_JSON}`);
|
|
554
562
|
process.exit(1);
|
|
555
563
|
}
|
|
564
|
+
config.registries = config.registries || {};
|
|
565
|
+
config.registries["@openpkg"] = registryUrl;
|
|
566
|
+
fs6.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
567
|
+
console.log(`Added @openpkg registry to ${COMPONENTS_JSON}`);
|
|
568
|
+
console.log("");
|
|
569
|
+
console.log("Usage:");
|
|
570
|
+
console.log(" npx shadcn@latest add @openpkg/function-section");
|
|
571
|
+
console.log(" npx shadcn@latest add @openpkg/export-card");
|
|
572
|
+
console.log("");
|
|
573
|
+
console.log("List components:");
|
|
574
|
+
console.log(" openpkg docs list");
|
|
556
575
|
});
|
|
557
576
|
}
|
|
558
577
|
|
|
578
|
+
// src/commands/docs/list.ts
|
|
579
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
580
|
+
import { Command as Command7 } from "commander";
|
|
581
|
+
function createListCommand() {
|
|
582
|
+
return new Command7("list").description("List @openpkg components (wrapper for shadcn list)").option("-q, --query <query>", "Search query").option("-l, --limit <number>", "Max items to display").option("-c, --cwd <cwd>", "Working directory").action(async (options) => {
|
|
583
|
+
const extraArgs = ["@openpkg"];
|
|
584
|
+
if (options.query)
|
|
585
|
+
extraArgs.push("-q", options.query);
|
|
586
|
+
if (options.limit)
|
|
587
|
+
extraArgs.push("-l", options.limit);
|
|
588
|
+
if (options.cwd)
|
|
589
|
+
extraArgs.push("-c", options.cwd);
|
|
590
|
+
const { cmd, args } = getShadcnCommand("list", extraArgs);
|
|
591
|
+
const child = spawn2(cmd, args, {
|
|
592
|
+
stdio: "inherit",
|
|
593
|
+
shell: true
|
|
594
|
+
});
|
|
595
|
+
child.on("close", (code) => {
|
|
596
|
+
process.exit(code || 0);
|
|
597
|
+
});
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/commands/docs/view.ts
|
|
602
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
603
|
+
import { Command as Command8 } from "commander";
|
|
604
|
+
function createViewCommand() {
|
|
605
|
+
return new Command8("view").description("View @openpkg component before installing (wrapper for shadcn view)").argument("<components...>", "Components to view").option("-c, --cwd <cwd>", "Working directory").action(async (components, options) => {
|
|
606
|
+
const prefixedComponents = components.map((c) => c.startsWith("@") ? c : `@openpkg/${c}`);
|
|
607
|
+
const extraArgs = [...prefixedComponents];
|
|
608
|
+
if (options.cwd)
|
|
609
|
+
extraArgs.push("-c", options.cwd);
|
|
610
|
+
const { cmd, args } = getShadcnCommand("view", extraArgs);
|
|
611
|
+
const child = spawn3(cmd, args, {
|
|
612
|
+
stdio: "inherit",
|
|
613
|
+
shell: true
|
|
614
|
+
});
|
|
615
|
+
child.on("close", (code) => {
|
|
616
|
+
process.exit(code || 0);
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// src/commands/docs/index.ts
|
|
622
|
+
function createDocsCommand() {
|
|
623
|
+
const docs = new Command9("docs").description("Documentation generation and component registry");
|
|
624
|
+
docs.addCommand(createGenerateCommand());
|
|
625
|
+
docs.addCommand(createInitCommand());
|
|
626
|
+
docs.addCommand(createListCommand());
|
|
627
|
+
docs.addCommand(createViewCommand());
|
|
628
|
+
docs.addCommand(createAddCommand());
|
|
629
|
+
return docs;
|
|
630
|
+
}
|
|
631
|
+
|
|
559
632
|
// src/commands/semver.ts
|
|
560
633
|
import * as fs7 from "node:fs";
|
|
561
634
|
import * as path7 from "node:path";
|
|
562
635
|
import { diffSpec as diffSpec3, recommendSemverBump as recommendSemverBump2 } from "@openpkg-ts/spec";
|
|
563
|
-
import { Command as
|
|
564
|
-
function
|
|
636
|
+
import { Command as Command10 } from "commander";
|
|
637
|
+
function loadSpec5(filePath) {
|
|
565
638
|
const resolved = path7.resolve(filePath);
|
|
566
639
|
const content = fs7.readFileSync(resolved, "utf-8");
|
|
567
640
|
return JSON.parse(content);
|
|
568
641
|
}
|
|
569
642
|
function createSemverCommand() {
|
|
570
|
-
return new
|
|
643
|
+
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) => {
|
|
571
644
|
try {
|
|
572
|
-
const oldSpec =
|
|
573
|
-
const newSpec =
|
|
645
|
+
const oldSpec = loadSpec5(oldPath);
|
|
646
|
+
const newSpec = loadSpec5(newPath);
|
|
574
647
|
const diff = diffSpec3(oldSpec, newSpec);
|
|
575
648
|
const recommendation = recommendSemverBump2(diff);
|
|
576
649
|
const result = {
|
|
@@ -586,19 +659,48 @@ function createSemverCommand() {
|
|
|
586
659
|
});
|
|
587
660
|
}
|
|
588
661
|
|
|
589
|
-
// src/commands/
|
|
662
|
+
// src/commands/spec.ts
|
|
590
663
|
import * as fs8 from "node:fs";
|
|
591
664
|
import * as path8 from "node:path";
|
|
592
665
|
import {
|
|
666
|
+
analyzeSpec,
|
|
593
667
|
extractSpec,
|
|
668
|
+
filterSpec,
|
|
669
|
+
getExport,
|
|
670
|
+
listExports,
|
|
594
671
|
loadConfig,
|
|
595
672
|
mergeConfig
|
|
596
673
|
} from "@openpkg-ts/sdk";
|
|
597
|
-
import {
|
|
598
|
-
|
|
599
|
-
|
|
674
|
+
import { getValidationErrors } from "@openpkg-ts/spec";
|
|
675
|
+
import { Command as Command11 } from "commander";
|
|
676
|
+
var VALID_KINDS = [
|
|
677
|
+
"function",
|
|
678
|
+
"class",
|
|
679
|
+
"variable",
|
|
680
|
+
"interface",
|
|
681
|
+
"type",
|
|
682
|
+
"enum",
|
|
683
|
+
"module",
|
|
684
|
+
"namespace",
|
|
685
|
+
"reference",
|
|
686
|
+
"external"
|
|
687
|
+
];
|
|
688
|
+
function loadSpec6(filePath) {
|
|
689
|
+
const resolved = path8.resolve(filePath);
|
|
690
|
+
const content = fs8.readFileSync(resolved, "utf-8");
|
|
691
|
+
return JSON.parse(content);
|
|
692
|
+
}
|
|
693
|
+
function parseList(val) {
|
|
694
|
+
if (!val)
|
|
600
695
|
return;
|
|
601
|
-
return
|
|
696
|
+
return val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
697
|
+
}
|
|
698
|
+
function validateKinds(kinds) {
|
|
699
|
+
const invalid = kinds.filter((k) => !VALID_KINDS.includes(k));
|
|
700
|
+
if (invalid.length > 0) {
|
|
701
|
+
throw new Error(`Invalid kind(s): ${invalid.join(", ")}. Valid kinds: ${VALID_KINDS.join(", ")}`);
|
|
702
|
+
}
|
|
703
|
+
return kinds;
|
|
602
704
|
}
|
|
603
705
|
function formatDiagnostics(diagnostics) {
|
|
604
706
|
return diagnostics.map((d) => ({
|
|
@@ -609,11 +711,8 @@ function formatDiagnostics(diagnostics) {
|
|
|
609
711
|
...d.location && { location: d.location }
|
|
610
712
|
}));
|
|
611
713
|
}
|
|
612
|
-
function
|
|
613
|
-
return new
|
|
614
|
-
|
|
615
|
-
` + `Config: Reads from openpkg.config.json or package.json "openpkg" field.
|
|
616
|
-
` + "CLI flags override config file settings.").argument("<entry>", "Entry point file path").option("-o, --output <file>", "Output file (default: openpkg.json, use - for stdout)", "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, wildcards supported)").option("--ignore <exports>", "Ignore exports (comma-separated, wildcards supported)").option("--verify", "Exit 1 if any exports fail").option("--verbose", "Show detailed output including skipped exports").option("--include-private", "Include private/protected class members").option("--external-include <patterns...>", "Resolve re-exports from these packages (globs supported)").option("--external-exclude <patterns...>", "Never resolve from these packages").option("--external-depth <n>", "Max transitive depth for external resolution (default: 1)", "1").action(async (entry, options) => {
|
|
714
|
+
function createSnapshotSubcommand() {
|
|
715
|
+
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("--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) => {
|
|
617
716
|
const entryFile = path8.resolve(entry);
|
|
618
717
|
const entryDir = path8.dirname(entryFile);
|
|
619
718
|
const fileConfig = loadConfig(entryDir);
|
|
@@ -630,8 +729,8 @@ function createSnapshotCommand() {
|
|
|
630
729
|
maxTypeDepth: parseInt(options.maxDepth ?? "4", 10),
|
|
631
730
|
resolveExternalTypes: !options.skipResolve,
|
|
632
731
|
schemaExtraction: options.runtime ? "hybrid" : "static",
|
|
633
|
-
only:
|
|
634
|
-
ignore:
|
|
732
|
+
only: parseList(options.only),
|
|
733
|
+
ignore: parseList(options.ignore),
|
|
635
734
|
includePrivate: options.includePrivate,
|
|
636
735
|
...mergedConfig.externals && { externals: mergedConfig.externals }
|
|
637
736
|
};
|
|
@@ -653,58 +752,15 @@ function createSnapshotCommand() {
|
|
|
653
752
|
}
|
|
654
753
|
}
|
|
655
754
|
},
|
|
656
|
-
...externalExports.length > 0 && {
|
|
657
|
-
external: {
|
|
658
|
-
count: externalExports.length,
|
|
659
|
-
...options.verbose && {
|
|
660
|
-
exports: externalExports.map((e) => ({
|
|
661
|
-
name: e.name,
|
|
662
|
-
package: e.source?.package
|
|
663
|
-
}))
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
...result.runtimeSchemas && {
|
|
668
|
-
runtime: {
|
|
669
|
-
extracted: result.runtimeSchemas.extracted,
|
|
670
|
-
merged: result.runtimeSchemas.merged,
|
|
671
|
-
vendors: result.runtimeSchemas.vendors
|
|
672
|
-
}
|
|
673
|
-
}
|
|
755
|
+
...externalExports.length > 0 && { external: { count: externalExports.length } }
|
|
674
756
|
};
|
|
675
757
|
console.error(JSON.stringify(summary, null, 2));
|
|
676
|
-
if (externalExports.length > 0 || (result.verification?.skipped ?? 0) > 0) {
|
|
677
|
-
console.error("");
|
|
678
|
-
if (externalExports.length > 0) {
|
|
679
|
-
if (options.verbose) {
|
|
680
|
-
console.error(`⚠ ${externalExports.length} external re-export(s) (install dependencies for full type info):`);
|
|
681
|
-
for (const exp of externalExports) {
|
|
682
|
-
console.error(` - ${exp.name} from "${exp.source?.package}"`);
|
|
683
|
-
}
|
|
684
|
-
} else {
|
|
685
|
-
console.error(`⚠ ${externalExports.length} external re-export(s) (install dependencies for full type info)`);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
const skipped = result.verification?.details.skipped ?? [];
|
|
689
|
-
if (skipped.length > 0) {
|
|
690
|
-
if (options.verbose) {
|
|
691
|
-
console.error(`⚠ ${skipped.length} export(s) skipped:`);
|
|
692
|
-
for (const skip of skipped) {
|
|
693
|
-
const pkgInfo = skip.package ? ` from "${skip.package}"` : "";
|
|
694
|
-
console.error(` - ${skip.name} (${skip.reason})${pkgInfo}`);
|
|
695
|
-
}
|
|
696
|
-
} else {
|
|
697
|
-
console.error(`⚠ ${skipped.length} export(s) skipped (use --verbose for details)`);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
758
|
if (options.verify && result.verification && result.verification.failed > 0) {
|
|
702
|
-
|
|
759
|
+
console.error(JSON.stringify({
|
|
703
760
|
error: "Export verification failed",
|
|
704
761
|
failed: result.verification.details.failed,
|
|
705
762
|
diagnostics: formatDiagnostics(result.diagnostics)
|
|
706
|
-
};
|
|
707
|
-
console.error(JSON.stringify(errorOutput, null, 2));
|
|
763
|
+
}, null, 2));
|
|
708
764
|
process.exit(1);
|
|
709
765
|
}
|
|
710
766
|
const specJson = JSON.stringify(result.spec, null, 2);
|
|
@@ -717,40 +773,118 @@ function createSnapshotCommand() {
|
|
|
717
773
|
}
|
|
718
774
|
} catch (err) {
|
|
719
775
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
720
|
-
|
|
721
|
-
error: error.message,
|
|
722
|
-
...error.stack && { stack: error.stack }
|
|
723
|
-
};
|
|
724
|
-
console.error(JSON.stringify(errorOutput, null, 2));
|
|
776
|
+
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
725
777
|
process.exit(1);
|
|
726
778
|
}
|
|
727
779
|
});
|
|
728
780
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
import * as fs9 from "node:fs";
|
|
732
|
-
import * as path9 from "node:path";
|
|
733
|
-
import { getValidationErrors } from "@openpkg-ts/spec";
|
|
734
|
-
import { Command as Command9 } from "commander";
|
|
735
|
-
function loadJSON2(filePath) {
|
|
736
|
-
const resolved = path9.resolve(filePath);
|
|
737
|
-
const content = fs9.readFileSync(resolved, "utf-8");
|
|
738
|
-
return JSON.parse(content);
|
|
739
|
-
}
|
|
740
|
-
function createValidateCommand() {
|
|
741
|
-
return new Command9("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) => {
|
|
781
|
+
function createValidateSubcommand() {
|
|
782
|
+
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) => {
|
|
742
783
|
try {
|
|
743
|
-
const spec =
|
|
784
|
+
const spec = loadSpec6(specPath);
|
|
744
785
|
const version = options.version ?? "latest";
|
|
745
786
|
const errors = getValidationErrors(spec, version);
|
|
787
|
+
console.log(JSON.stringify({ valid: errors.length === 0, errors }, null, 2));
|
|
788
|
+
if (errors.length > 0)
|
|
789
|
+
process.exit(1);
|
|
790
|
+
} catch (err) {
|
|
791
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
792
|
+
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
793
|
+
process.exit(1);
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
function createFilterSubcommand() {
|
|
798
|
+
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) => {
|
|
799
|
+
try {
|
|
800
|
+
const spec = loadSpec6(specPath);
|
|
801
|
+
const criteria = {};
|
|
802
|
+
if (options.kind) {
|
|
803
|
+
const kinds = parseList(options.kind);
|
|
804
|
+
if (kinds)
|
|
805
|
+
criteria.kinds = validateKinds(kinds);
|
|
806
|
+
}
|
|
807
|
+
if (options.name)
|
|
808
|
+
criteria.names = parseList(options.name);
|
|
809
|
+
if (options.id)
|
|
810
|
+
criteria.ids = parseList(options.id);
|
|
811
|
+
if (options.tag)
|
|
812
|
+
criteria.tags = parseList(options.tag);
|
|
813
|
+
if (options.deprecated !== undefined)
|
|
814
|
+
criteria.deprecated = options.deprecated;
|
|
815
|
+
if (options.hasDescription)
|
|
816
|
+
criteria.hasDescription = true;
|
|
817
|
+
if (options.missingDescription)
|
|
818
|
+
criteria.hasDescription = false;
|
|
819
|
+
if (options.search)
|
|
820
|
+
criteria.search = options.search;
|
|
821
|
+
if (options.searchMembers)
|
|
822
|
+
criteria.searchMembers = true;
|
|
823
|
+
if (options.searchDocs)
|
|
824
|
+
criteria.searchDocs = true;
|
|
825
|
+
if (options.module)
|
|
826
|
+
criteria.module = options.module;
|
|
827
|
+
const result = filterSpec(spec, criteria);
|
|
828
|
+
let output;
|
|
829
|
+
if (options.summary) {
|
|
830
|
+
output = { matched: result.matched, total: result.total };
|
|
831
|
+
} else if (options.quiet) {
|
|
832
|
+
output = result.spec;
|
|
833
|
+
} else {
|
|
834
|
+
output = { spec: result.spec, matched: result.matched, total: result.total };
|
|
835
|
+
}
|
|
836
|
+
const json = JSON.stringify(output, null, 2);
|
|
837
|
+
if (options.output) {
|
|
838
|
+
fs8.writeFileSync(path8.resolve(options.output), json);
|
|
839
|
+
} else {
|
|
840
|
+
console.log(json);
|
|
841
|
+
}
|
|
842
|
+
} catch (err) {
|
|
843
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
844
|
+
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
845
|
+
process.exit(1);
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
function createLintSubcommand() {
|
|
850
|
+
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) => {
|
|
851
|
+
try {
|
|
852
|
+
const spec = loadSpec6(specPath);
|
|
853
|
+
const diagnostics = analyzeSpec(spec);
|
|
854
|
+
const generation = spec.generation;
|
|
855
|
+
const skipped = generation?.skipped ?? [];
|
|
856
|
+
const externalExports = spec.exports.filter((e) => e.kind === "external");
|
|
857
|
+
const byReason = {};
|
|
858
|
+
for (const skip of skipped) {
|
|
859
|
+
byReason[skip.reason] = (byReason[skip.reason] ?? 0) + 1;
|
|
860
|
+
}
|
|
746
861
|
const result = {
|
|
747
|
-
|
|
748
|
-
|
|
862
|
+
summary: {
|
|
863
|
+
total: diagnostics.missingDescriptions.length + diagnostics.deprecatedNoReason.length + diagnostics.missingParamDocs.length,
|
|
864
|
+
missingDescriptions: diagnostics.missingDescriptions.length,
|
|
865
|
+
deprecatedNoReason: diagnostics.deprecatedNoReason.length,
|
|
866
|
+
missingParamDocs: diagnostics.missingParamDocs.length,
|
|
867
|
+
...skipped.length > 0 && { skippedExports: skipped.length },
|
|
868
|
+
...externalExports.length > 0 && { externalExports: externalExports.length }
|
|
869
|
+
},
|
|
870
|
+
diagnostics,
|
|
871
|
+
...skipped.length > 0 && {
|
|
872
|
+
skippedExports: {
|
|
873
|
+
total: skipped.length,
|
|
874
|
+
byReason,
|
|
875
|
+
...options.verbose && { details: skipped }
|
|
876
|
+
}
|
|
877
|
+
},
|
|
878
|
+
...externalExports.length > 0 && {
|
|
879
|
+
externalExports: {
|
|
880
|
+
count: externalExports.length,
|
|
881
|
+
...options.verbose && {
|
|
882
|
+
details: externalExports.map((e) => ({ name: e.name, package: e.source?.package }))
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
749
886
|
};
|
|
750
887
|
console.log(JSON.stringify(result, null, 2));
|
|
751
|
-
if (errors.length > 0) {
|
|
752
|
-
process.exit(1);
|
|
753
|
-
}
|
|
754
888
|
} catch (err) {
|
|
755
889
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
756
890
|
console.error(JSON.stringify({ error: error.message }, null, 2));
|
|
@@ -758,40 +892,82 @@ function createValidateCommand() {
|
|
|
758
892
|
}
|
|
759
893
|
});
|
|
760
894
|
}
|
|
895
|
+
function createListSubcommand() {
|
|
896
|
+
return new Command11("list").description("List exports from a TypeScript entry point").argument("<entry>", "Entry point file path").action(async (entry) => {
|
|
897
|
+
const entryFile = path8.resolve(entry);
|
|
898
|
+
const result = await listExports({ entryFile });
|
|
899
|
+
if (result.errors.length > 0) {
|
|
900
|
+
console.error(JSON.stringify({ errors: result.errors }, null, 2));
|
|
901
|
+
process.exit(1);
|
|
902
|
+
}
|
|
903
|
+
console.log(JSON.stringify(result.exports, null, 2));
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
function createGetSubcommand() {
|
|
907
|
+
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) => {
|
|
908
|
+
const entryFile = path8.resolve(entry);
|
|
909
|
+
const result = await getExport({ entryFile, exportName: name });
|
|
910
|
+
if (!result.export) {
|
|
911
|
+
const errorMsg = result.errors.length > 0 ? result.errors.join("; ") : `Export '${name}' not found`;
|
|
912
|
+
console.error(JSON.stringify({ error: errorMsg }, null, 2));
|
|
913
|
+
process.exit(1);
|
|
914
|
+
}
|
|
915
|
+
const output = { export: result.export };
|
|
916
|
+
if (result.types.length > 0) {
|
|
917
|
+
output.types = result.types;
|
|
918
|
+
}
|
|
919
|
+
console.log(JSON.stringify(output, null, 2));
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
function createSpecCommand() {
|
|
923
|
+
const spec = new Command11("spec").description("Spec extraction and manipulation commands");
|
|
924
|
+
spec.addCommand(createSnapshotSubcommand());
|
|
925
|
+
spec.addCommand(createValidateSubcommand());
|
|
926
|
+
spec.addCommand(createFilterSubcommand());
|
|
927
|
+
spec.addCommand(createLintSubcommand());
|
|
928
|
+
spec.addCommand(createListSubcommand());
|
|
929
|
+
spec.addCommand(createGetSubcommand());
|
|
930
|
+
return spec;
|
|
931
|
+
}
|
|
761
932
|
|
|
762
933
|
// bin/openpkg.ts
|
|
763
|
-
var program = new
|
|
934
|
+
var program = new Command12;
|
|
764
935
|
program.name("openpkg").description("OpenPkg CLI - TypeScript API extraction primitives").version(package_default.version);
|
|
765
|
-
program.
|
|
766
|
-
const entryFile = path10.resolve(entry);
|
|
767
|
-
const result = await listExports({ entryFile });
|
|
768
|
-
if (result.errors.length > 0) {
|
|
769
|
-
console.error(JSON.stringify({ errors: result.errors }, null, 2));
|
|
770
|
-
process.exit(1);
|
|
771
|
-
}
|
|
772
|
-
console.log(JSON.stringify(result.exports, null, 2));
|
|
773
|
-
});
|
|
774
|
-
program.command("get").description("Get detailed spec for a single export").argument("<entry>", "Entry point file path").argument("<name>", "Export name").action(async (entry, name) => {
|
|
775
|
-
const entryFile = path10.resolve(entry);
|
|
776
|
-
const result = await getExport({ entryFile, exportName: name });
|
|
777
|
-
if (!result.export) {
|
|
778
|
-
const errorMsg = result.errors.length > 0 ? result.errors.join("; ") : `Export '${name}' not found`;
|
|
779
|
-
console.error(JSON.stringify({ error: errorMsg }, null, 2));
|
|
780
|
-
process.exit(1);
|
|
781
|
-
}
|
|
782
|
-
const output = { export: result.export };
|
|
783
|
-
if (result.types.length > 0) {
|
|
784
|
-
output.types = result.types;
|
|
785
|
-
}
|
|
786
|
-
console.log(JSON.stringify(output, null, 2));
|
|
787
|
-
});
|
|
788
|
-
program.addCommand(createSnapshotCommand());
|
|
789
|
-
program.addCommand(createDiffCommand());
|
|
936
|
+
program.addCommand(createSpecCommand());
|
|
790
937
|
program.addCommand(createDocsCommand());
|
|
938
|
+
program.addCommand(createDiffCommand());
|
|
791
939
|
program.addCommand(createBreakingCommand());
|
|
792
940
|
program.addCommand(createChangelogCommand());
|
|
793
941
|
program.addCommand(createSemverCommand());
|
|
794
|
-
program.
|
|
795
|
-
|
|
796
|
-
|
|
942
|
+
var specCmd = program.commands.find((c) => c.name() === "spec");
|
|
943
|
+
var snapshotAlias = new Command12("snapshot").description("(alias) → openpkg spec snapshot").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
944
|
+
const args = process.argv.slice(3);
|
|
945
|
+
await specCmd.commands.find((c) => c.name() === "snapshot").parseAsync(args, { from: "user" });
|
|
946
|
+
});
|
|
947
|
+
program.addCommand(snapshotAlias);
|
|
948
|
+
var listAlias = new Command12("list").description("(alias) → openpkg spec list").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
949
|
+
const args = process.argv.slice(3);
|
|
950
|
+
await specCmd.commands.find((c) => c.name() === "list").parseAsync(args, { from: "user" });
|
|
951
|
+
});
|
|
952
|
+
program.addCommand(listAlias);
|
|
953
|
+
var getAlias = new Command12("get").description("(alias) → openpkg spec get").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
954
|
+
const args = process.argv.slice(3);
|
|
955
|
+
await specCmd.commands.find((c) => c.name() === "get").parseAsync(args, { from: "user" });
|
|
956
|
+
});
|
|
957
|
+
program.addCommand(getAlias);
|
|
958
|
+
var validateAlias = new Command12("validate").description("(alias) → openpkg spec validate").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
959
|
+
const args = process.argv.slice(3);
|
|
960
|
+
await specCmd.commands.find((c) => c.name() === "validate").parseAsync(args, { from: "user" });
|
|
961
|
+
});
|
|
962
|
+
program.addCommand(validateAlias);
|
|
963
|
+
var filterAlias = new Command12("filter").description("(alias) → openpkg spec filter").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
964
|
+
const args = process.argv.slice(3);
|
|
965
|
+
await specCmd.commands.find((c) => c.name() === "filter").parseAsync(args, { from: "user" });
|
|
966
|
+
});
|
|
967
|
+
program.addCommand(filterAlias);
|
|
968
|
+
var diagnosticsAlias = new Command12("diagnostics").description("(alias) → openpkg spec lint").allowUnknownOption().allowExcessArguments().action(async () => {
|
|
969
|
+
const args = process.argv.slice(3);
|
|
970
|
+
await specCmd.commands.find((c) => c.name() === "lint").parseAsync(args, { from: "user" });
|
|
971
|
+
});
|
|
972
|
+
program.addCommand(diagnosticsAlias);
|
|
797
973
|
program.parse();
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
1
|
import { getExport, listExports } from "@openpkg-ts/sdk";
|
|
2
|
-
import {
|
|
3
|
-
type FilterResult = {
|
|
4
|
-
spec: OpenPkg;
|
|
5
|
-
matched: number;
|
|
6
|
-
total: number;
|
|
7
|
-
};
|
|
8
|
-
type FilterSummaryResult = {
|
|
9
|
-
matched: number;
|
|
10
|
-
total: number;
|
|
11
|
-
};
|
|
2
|
+
import { FilterResult, FilterSummaryResult } from "./commands/filter";
|
|
12
3
|
export { listExports, getExport, FilterSummaryResult, FilterResult };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpkg-ts/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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.
|
|
26
|
+
"@openpkg-ts/adapters": "^0.3.3",
|
|
27
|
+
"@openpkg-ts/sdk": "^0.34.0",
|
|
28
28
|
"commander": "^14.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|