@openpkg-ts/extract 0.14.0 → 0.14.1
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/tspec.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
extract
|
|
4
|
-
} from "../shared/chunk-
|
|
4
|
+
} from "../shared/chunk-khwn5myc.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/spec.ts
|
|
7
7
|
import * as fs from "node:fs";
|
|
@@ -9,7 +9,7 @@ import * as path from "node:path";
|
|
|
9
9
|
import { normalize, validateSpec } from "@openpkg-ts/spec";
|
|
10
10
|
import { Command } from "commander";
|
|
11
11
|
function createProgram() {
|
|
12
|
-
const program = new Command("tspec").description("Extract TypeScript package API to OpenPkg spec").argument("[entry]", "Entry point file").option("-o, --output <file>", "Output file", "openpkg.json").option("--max-depth <n>", "Max type depth
|
|
12
|
+
const program = new Command("tspec").description("Extract TypeScript package API to OpenPkg spec").argument("[entry]", "Entry point file").option("-o, --output <file>", "Output file", "openpkg.json").option("--max-depth <n>", "Max type depth (default: 4)").option("--skip-resolve", "Skip external type resolution").option("--runtime", "Enable Standard Schema runtime extraction").action(async (entry, options) => {
|
|
13
13
|
const entryFile = entry || findEntryPoint(process.cwd());
|
|
14
14
|
if (!entryFile) {
|
|
15
15
|
console.error("No entry point found. Please specify an entry file.");
|
|
@@ -18,7 +18,7 @@ function createProgram() {
|
|
|
18
18
|
console.log(`Extracting from: ${entryFile}`);
|
|
19
19
|
const result = await extract({
|
|
20
20
|
entryFile: path.resolve(entryFile),
|
|
21
|
-
maxTypeDepth: parseInt(options.maxDepth),
|
|
21
|
+
...options.maxDepth ? { maxTypeDepth: parseInt(options.maxDepth) } : {},
|
|
22
22
|
resolveExternalTypes: !options.skipResolve,
|
|
23
23
|
schemaExtraction: options.runtime ? "hybrid" : "static"
|
|
24
24
|
});
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
// src/ast/registry.ts
|
|
2
|
-
import * as fs from "node:fs";
|
|
3
|
-
import * as path from "node:path";
|
|
4
2
|
import ts from "typescript";
|
|
5
3
|
var PRIMITIVES = new Set([
|
|
6
4
|
"string",
|
|
@@ -94,48 +92,6 @@ function isExternalType(decl) {
|
|
|
94
92
|
return false;
|
|
95
93
|
return sourceFile.fileName.includes("node_modules");
|
|
96
94
|
}
|
|
97
|
-
function extractPackageName(filePath) {
|
|
98
|
-
const nmIndex = filePath.lastIndexOf("node_modules");
|
|
99
|
-
if (nmIndex === -1)
|
|
100
|
-
return;
|
|
101
|
-
const afterNm = filePath.slice(nmIndex + "node_modules/".length);
|
|
102
|
-
const parts = afterNm.split("/");
|
|
103
|
-
if (parts[0].startsWith("@") && parts.length >= 2) {
|
|
104
|
-
return `${parts[0]}/${parts[1]}`;
|
|
105
|
-
}
|
|
106
|
-
return parts[0];
|
|
107
|
-
}
|
|
108
|
-
function getPackageVersion(filePath, packageName) {
|
|
109
|
-
const nmIndex = filePath.lastIndexOf("node_modules");
|
|
110
|
-
if (nmIndex === -1)
|
|
111
|
-
return;
|
|
112
|
-
const nmDir = filePath.slice(0, nmIndex + "node_modules".length);
|
|
113
|
-
const pkgJsonPath = path.join(nmDir, packageName, "package.json");
|
|
114
|
-
try {
|
|
115
|
-
if (fs.existsSync(pkgJsonPath)) {
|
|
116
|
-
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
117
|
-
return pkg.version;
|
|
118
|
-
}
|
|
119
|
-
} catch {}
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
function buildExternalSource(decl) {
|
|
123
|
-
const sourceFile = decl.getSourceFile();
|
|
124
|
-
if (!sourceFile)
|
|
125
|
-
return;
|
|
126
|
-
const filePath = sourceFile.fileName;
|
|
127
|
-
if (!filePath.includes("node_modules"))
|
|
128
|
-
return;
|
|
129
|
-
const packageName = extractPackageName(filePath);
|
|
130
|
-
if (!packageName)
|
|
131
|
-
return;
|
|
132
|
-
const version = getPackageVersion(filePath, packageName);
|
|
133
|
-
return {
|
|
134
|
-
file: filePath,
|
|
135
|
-
package: packageName,
|
|
136
|
-
version
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
95
|
|
|
140
96
|
class TypeRegistry {
|
|
141
97
|
types = new Map;
|
|
@@ -167,17 +123,19 @@ class TypeRegistry {
|
|
|
167
123
|
return;
|
|
168
124
|
if (symbol.flags & ts.SymbolFlags.TypeParameter)
|
|
169
125
|
return;
|
|
126
|
+
if (symbol.flags & ts.SymbolFlags.Method)
|
|
127
|
+
return;
|
|
128
|
+
if (symbol.flags & ts.SymbolFlags.Function)
|
|
129
|
+
return;
|
|
170
130
|
if (isGenericTypeParameter(name))
|
|
171
131
|
return;
|
|
172
132
|
if (this.has(name))
|
|
173
133
|
return name;
|
|
174
|
-
if (exportedIds.has(name))
|
|
175
|
-
return name;
|
|
176
134
|
if (this.processing.has(name))
|
|
177
135
|
return name;
|
|
178
136
|
this.processing.add(name);
|
|
179
137
|
try {
|
|
180
|
-
const specType = this.
|
|
138
|
+
const specType = this.buildStubType(symbol, checker);
|
|
181
139
|
if (specType) {
|
|
182
140
|
this.add(specType);
|
|
183
141
|
return specType.id;
|
|
@@ -187,7 +145,7 @@ class TypeRegistry {
|
|
|
187
145
|
}
|
|
188
146
|
return;
|
|
189
147
|
}
|
|
190
|
-
|
|
148
|
+
buildStubType(symbol, checker) {
|
|
191
149
|
const name = symbol.getName();
|
|
192
150
|
const decl = symbol.declarations?.[0];
|
|
193
151
|
let kind = "type";
|
|
@@ -203,139 +161,21 @@ class TypeRegistry {
|
|
|
203
161
|
if (external) {
|
|
204
162
|
kind = "external";
|
|
205
163
|
}
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
let members;
|
|
209
|
-
if (decl && (ts.isClassDeclaration(decl) || ts.isInterfaceDeclaration(decl))) {
|
|
210
|
-
members = this.extractShallowMembers(decl, checker);
|
|
211
|
-
}
|
|
164
|
+
const type = checker.getDeclaredTypeOfSymbol(symbol);
|
|
165
|
+
const typeString = checker.typeToString(type);
|
|
212
166
|
return {
|
|
213
167
|
id: name,
|
|
214
168
|
name,
|
|
215
169
|
kind,
|
|
216
|
-
schema,
|
|
217
|
-
|
|
218
|
-
...external ? { external: true } : {},
|
|
219
|
-
...source ? { source } : {}
|
|
170
|
+
schema: { type: typeString },
|
|
171
|
+
...external ? { external: true } : {}
|
|
220
172
|
};
|
|
221
173
|
}
|
|
222
|
-
buildShallowSchema(type, checker) {
|
|
223
|
-
if (type.isUnion()) {
|
|
224
|
-
const allEnumLiterals = type.types.every((t) => t.flags & (ts.TypeFlags.EnumLiteral | ts.TypeFlags.NumberLiteral));
|
|
225
|
-
if (allEnumLiterals) {
|
|
226
|
-
const values = type.types.map((t) => {
|
|
227
|
-
if (t.flags & ts.TypeFlags.NumberLiteral) {
|
|
228
|
-
return t.value;
|
|
229
|
-
}
|
|
230
|
-
return checker.typeToString(t);
|
|
231
|
-
}).filter((v) => v !== undefined);
|
|
232
|
-
if (values.every((v) => typeof v === "number")) {
|
|
233
|
-
return { type: "number", enum: values };
|
|
234
|
-
}
|
|
235
|
-
return { type: "string", enum: values };
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
anyOf: type.types.map((t) => {
|
|
239
|
-
if (t.flags & ts.TypeFlags.EnumLiteral) {
|
|
240
|
-
const value = t.value;
|
|
241
|
-
if (typeof value === "number") {
|
|
242
|
-
return { type: "number", enum: [value] };
|
|
243
|
-
}
|
|
244
|
-
return { type: checker.typeToString(t) };
|
|
245
|
-
}
|
|
246
|
-
const sym = t.getSymbol() || t.aliasSymbol;
|
|
247
|
-
if (sym && sym.flags & ts.SymbolFlags.EnumMember) {
|
|
248
|
-
return { type: checker.typeToString(t) };
|
|
249
|
-
}
|
|
250
|
-
if (sym && !sym.getName().startsWith("__")) {
|
|
251
|
-
return { $ref: `#/types/${sym.getName()}` };
|
|
252
|
-
}
|
|
253
|
-
if (t.flags & ts.TypeFlags.StringLiteral) {
|
|
254
|
-
return { type: "string", enum: [t.value] };
|
|
255
|
-
}
|
|
256
|
-
if (t.flags & ts.TypeFlags.NumberLiteral) {
|
|
257
|
-
return { type: "number", enum: [t.value] };
|
|
258
|
-
}
|
|
259
|
-
return { type: checker.typeToString(t) };
|
|
260
|
-
})
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
if (type.isIntersection()) {
|
|
264
|
-
return {
|
|
265
|
-
allOf: type.types.map((t) => {
|
|
266
|
-
const sym = t.getSymbol() || t.aliasSymbol;
|
|
267
|
-
if (sym && !sym.getName().startsWith("__")) {
|
|
268
|
-
return { $ref: `#/types/${sym.getName()}` };
|
|
269
|
-
}
|
|
270
|
-
return { type: checker.typeToString(t) };
|
|
271
|
-
})
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
const props = type.getProperties();
|
|
275
|
-
if (props.length > 0) {
|
|
276
|
-
const properties = {};
|
|
277
|
-
const required = [];
|
|
278
|
-
for (const prop of props.slice(0, 30)) {
|
|
279
|
-
const propName = prop.getName();
|
|
280
|
-
if (propName.startsWith("_"))
|
|
281
|
-
continue;
|
|
282
|
-
const propType = checker.getTypeOfSymbol(prop);
|
|
283
|
-
const callSigs = propType.getCallSignatures();
|
|
284
|
-
if (callSigs.length > 0) {
|
|
285
|
-
properties[propName] = { type: "function" };
|
|
286
|
-
} else {
|
|
287
|
-
const propSym = propType.getSymbol() || propType.aliasSymbol;
|
|
288
|
-
const symName = propSym?.getName();
|
|
289
|
-
if (propSym && symName && !symName.startsWith("__") && symName !== propName) {
|
|
290
|
-
properties[propName] = { $ref: `#/types/${symName}` };
|
|
291
|
-
} else {
|
|
292
|
-
properties[propName] = { type: checker.typeToString(propType) };
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
if (!(prop.flags & ts.SymbolFlags.Optional)) {
|
|
296
|
-
required.push(propName);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
type: "object",
|
|
301
|
-
properties,
|
|
302
|
-
...required.length ? { required } : {}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
return { type: checker.typeToString(type) };
|
|
306
|
-
}
|
|
307
|
-
extractShallowMembers(decl, checker) {
|
|
308
|
-
const members = [];
|
|
309
|
-
for (const member of decl.members) {
|
|
310
|
-
if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {
|
|
311
|
-
const name = member.name?.getText();
|
|
312
|
-
if (!name || name.startsWith("#") || name.startsWith("_"))
|
|
313
|
-
continue;
|
|
314
|
-
const type = checker.getTypeAtLocation(member);
|
|
315
|
-
const sym = type.getSymbol() || type.aliasSymbol;
|
|
316
|
-
members.push({
|
|
317
|
-
name,
|
|
318
|
-
kind: "property",
|
|
319
|
-
schema: sym && !sym.getName().startsWith("__") ? { $ref: `#/types/${sym.getName()}` } : { type: checker.typeToString(type) }
|
|
320
|
-
});
|
|
321
|
-
} else if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) {
|
|
322
|
-
const name = member.name?.getText();
|
|
323
|
-
if (!name || name.startsWith("#") || name.startsWith("_"))
|
|
324
|
-
continue;
|
|
325
|
-
members.push({
|
|
326
|
-
name,
|
|
327
|
-
kind: "method"
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return members;
|
|
332
|
-
}
|
|
333
174
|
registerFromSymbol(symbol, checker) {
|
|
334
175
|
const name = symbol.getName();
|
|
335
176
|
if (this.has(name))
|
|
336
177
|
return this.get(name);
|
|
337
|
-
const
|
|
338
|
-
const specType = this.buildSpecType(symbol, type, checker);
|
|
178
|
+
const specType = this.buildStubType(symbol, checker);
|
|
339
179
|
if (specType) {
|
|
340
180
|
this.add(specType);
|
|
341
181
|
return specType;
|
|
@@ -445,7 +285,7 @@ function isSymbolDeprecated(symbol) {
|
|
|
445
285
|
}
|
|
446
286
|
|
|
447
287
|
// src/compiler/program.ts
|
|
448
|
-
import * as
|
|
288
|
+
import * as path from "node:path";
|
|
449
289
|
import ts3 from "typescript";
|
|
450
290
|
var DEFAULT_COMPILER_OPTIONS = {
|
|
451
291
|
target: ts3.ScriptTarget.Latest,
|
|
@@ -456,14 +296,14 @@ var DEFAULT_COMPILER_OPTIONS = {
|
|
|
456
296
|
};
|
|
457
297
|
function createProgram({
|
|
458
298
|
entryFile,
|
|
459
|
-
baseDir =
|
|
299
|
+
baseDir = path.dirname(entryFile),
|
|
460
300
|
content
|
|
461
301
|
}) {
|
|
462
302
|
const configPath = ts3.findConfigFile(baseDir, ts3.sys.fileExists, "tsconfig.json");
|
|
463
303
|
let compilerOptions = { ...DEFAULT_COMPILER_OPTIONS };
|
|
464
304
|
if (configPath) {
|
|
465
305
|
const configFile = ts3.readConfigFile(configPath, ts3.sys.readFile);
|
|
466
|
-
const parsedConfig = ts3.parseJsonConfigFileContent(configFile.config, ts3.sys,
|
|
306
|
+
const parsedConfig = ts3.parseJsonConfigFileContent(configFile.config, ts3.sys, path.dirname(configPath));
|
|
467
307
|
compilerOptions = { ...compilerOptions, ...parsedConfig.options };
|
|
468
308
|
}
|
|
469
309
|
const allowJsVal = compilerOptions.allowJs;
|
|
@@ -615,12 +455,19 @@ function buildSchema(type, checker, ctx, _depth = 0) {
|
|
|
615
455
|
return { type: checker.typeToString(type) };
|
|
616
456
|
}
|
|
617
457
|
if (ctx?.visitedTypes.has(type)) {
|
|
458
|
+
const callSignatures = type.getCallSignatures();
|
|
459
|
+
if (callSignatures.length > 0) {
|
|
460
|
+
return buildFunctionSchema(callSignatures, checker, ctx);
|
|
461
|
+
}
|
|
618
462
|
const symbol2 = type.getSymbol() || type.aliasSymbol;
|
|
619
463
|
if (symbol2) {
|
|
620
464
|
return { $ref: `#/types/${symbol2.getName()}` };
|
|
621
465
|
}
|
|
622
466
|
return { type: checker.typeToString(type) };
|
|
623
467
|
}
|
|
468
|
+
if (ctx && type.flags & ts4.TypeFlags.Object) {
|
|
469
|
+
ctx.visitedTypes.add(type);
|
|
470
|
+
}
|
|
624
471
|
if (type.flags & ts4.TypeFlags.String)
|
|
625
472
|
return { type: "string" };
|
|
626
473
|
if (type.flags & ts4.TypeFlags.Number)
|
|
@@ -734,6 +581,12 @@ function buildSchema(type, checker, ctx, _depth = 0) {
|
|
|
734
581
|
};
|
|
735
582
|
}
|
|
736
583
|
}
|
|
584
|
+
if (type.flags & ts4.TypeFlags.Object) {
|
|
585
|
+
const callSignatures = type.getCallSignatures();
|
|
586
|
+
if (callSignatures.length > 0) {
|
|
587
|
+
return buildFunctionSchema(callSignatures, checker, ctx);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
737
590
|
const symbol = type.getSymbol() || type.aliasSymbol;
|
|
738
591
|
if (symbol && !isAnonymous(type)) {
|
|
739
592
|
const name = symbol.getName();
|
|
@@ -749,10 +602,6 @@ function buildSchema(type, checker, ctx, _depth = 0) {
|
|
|
749
602
|
}
|
|
750
603
|
if (type.flags & ts4.TypeFlags.Object) {
|
|
751
604
|
const objectType = type;
|
|
752
|
-
const callSignatures = type.getCallSignatures();
|
|
753
|
-
if (callSignatures.length > 0) {
|
|
754
|
-
return buildFunctionSchema(callSignatures, checker, ctx);
|
|
755
|
-
}
|
|
756
605
|
const properties = type.getProperties();
|
|
757
606
|
if (properties.length > 0 || objectType.objectFlags & ts4.ObjectFlags.Anonymous) {
|
|
758
607
|
return buildObjectSchema(properties, checker, ctx);
|
|
@@ -1032,7 +881,9 @@ function extractDefaultValue(initializer) {
|
|
|
1032
881
|
}
|
|
1033
882
|
return initializer.getText();
|
|
1034
883
|
}
|
|
1035
|
-
function registerReferencedTypes(type, ctx) {
|
|
884
|
+
function registerReferencedTypes(type, ctx, depth = 0) {
|
|
885
|
+
if (depth > ctx.maxTypeDepth)
|
|
886
|
+
return;
|
|
1036
887
|
if (ctx.visitedTypes.has(type))
|
|
1037
888
|
return;
|
|
1038
889
|
const isPrimitive = type.flags & (ts5.TypeFlags.String | ts5.TypeFlags.Number | ts5.TypeFlags.Boolean | ts5.TypeFlags.Void | ts5.TypeFlags.Undefined | ts5.TypeFlags.Null | ts5.TypeFlags.Any | ts5.TypeFlags.Unknown | ts5.TypeFlags.Never | ts5.TypeFlags.StringLiteral | ts5.TypeFlags.NumberLiteral | ts5.TypeFlags.BooleanLiteral);
|
|
@@ -1044,17 +895,24 @@ function registerReferencedTypes(type, ctx) {
|
|
|
1044
895
|
const typeArgs = type.typeArguments;
|
|
1045
896
|
if (typeArgs) {
|
|
1046
897
|
for (const arg of typeArgs) {
|
|
1047
|
-
registerReferencedTypes(arg, ctx);
|
|
898
|
+
registerReferencedTypes(arg, ctx, depth + 1);
|
|
1048
899
|
}
|
|
1049
900
|
}
|
|
1050
901
|
if (type.isUnion()) {
|
|
1051
902
|
for (const t of type.types) {
|
|
1052
|
-
registerReferencedTypes(t, ctx);
|
|
903
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
1053
904
|
}
|
|
1054
905
|
}
|
|
1055
906
|
if (type.isIntersection()) {
|
|
1056
907
|
for (const t of type.types) {
|
|
1057
|
-
registerReferencedTypes(t, ctx);
|
|
908
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (type.flags & ts5.TypeFlags.Object) {
|
|
912
|
+
const props = type.getProperties();
|
|
913
|
+
for (const prop of props.slice(0, 20)) {
|
|
914
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
915
|
+
registerReferencedTypes(propType, ctx, depth + 1);
|
|
1058
916
|
}
|
|
1059
917
|
}
|
|
1060
918
|
}
|
|
@@ -1166,8 +1024,8 @@ function serializeProperty(node, ctx) {
|
|
|
1166
1024
|
const { description, tags } = getJSDocComment(node);
|
|
1167
1025
|
const visibility = getVisibility(node);
|
|
1168
1026
|
const type = checker.getTypeAtLocation(node);
|
|
1169
|
-
const schema = buildSchema(type, checker, ctx);
|
|
1170
1027
|
registerReferencedTypes(type, ctx);
|
|
1028
|
+
const schema = buildSchema(type, checker, ctx);
|
|
1171
1029
|
const flags = {};
|
|
1172
1030
|
if (isStatic(node))
|
|
1173
1031
|
flags.static = true;
|
|
@@ -1541,8 +1399,8 @@ function serializeTypeAlias(node, ctx) {
|
|
|
1541
1399
|
const source = getSourceLocation(node, declSourceFile);
|
|
1542
1400
|
const typeParameters = extractTypeParameters(node, ctx.typeChecker);
|
|
1543
1401
|
const type = ctx.typeChecker.getTypeAtLocation(node);
|
|
1544
|
-
const schema = buildSchema(type, ctx.typeChecker, ctx);
|
|
1545
1402
|
registerReferencedTypes(type, ctx);
|
|
1403
|
+
const schema = buildSchema(type, ctx.typeChecker, ctx);
|
|
1546
1404
|
return {
|
|
1547
1405
|
id: name,
|
|
1548
1406
|
name,
|
|
@@ -1566,8 +1424,8 @@ function serializeVariable(node, statement, ctx) {
|
|
|
1566
1424
|
const { description, tags, examples } = getJSDocComment(statement);
|
|
1567
1425
|
const source = getSourceLocation(node, declSourceFile);
|
|
1568
1426
|
const type = ctx.typeChecker.getTypeAtLocation(node);
|
|
1569
|
-
const schema = buildSchema(type, ctx.typeChecker, ctx);
|
|
1570
1427
|
registerReferencedTypes(type, ctx);
|
|
1428
|
+
const schema = buildSchema(type, ctx.typeChecker, ctx);
|
|
1571
1429
|
return {
|
|
1572
1430
|
id: name,
|
|
1573
1431
|
name,
|
|
@@ -1581,8 +1439,8 @@ function serializeVariable(node, statement, ctx) {
|
|
|
1581
1439
|
}
|
|
1582
1440
|
|
|
1583
1441
|
// src/builder/spec-builder.ts
|
|
1584
|
-
import * as
|
|
1585
|
-
import * as
|
|
1442
|
+
import * as fs from "node:fs";
|
|
1443
|
+
import * as path2 from "node:path";
|
|
1586
1444
|
import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
|
|
1587
1445
|
import ts8 from "typescript";
|
|
1588
1446
|
|
|
@@ -1605,9 +1463,14 @@ function createContext(program, sourceFile, options = {}) {
|
|
|
1605
1463
|
// src/builder/spec-builder.ts
|
|
1606
1464
|
var BUILTIN_TYPES2 = new Set([
|
|
1607
1465
|
"Array",
|
|
1466
|
+
"ArrayBuffer",
|
|
1467
|
+
"ArrayBufferLike",
|
|
1468
|
+
"ArrayLike",
|
|
1608
1469
|
"Promise",
|
|
1609
1470
|
"Map",
|
|
1610
1471
|
"Set",
|
|
1472
|
+
"WeakMap",
|
|
1473
|
+
"WeakSet",
|
|
1611
1474
|
"Record",
|
|
1612
1475
|
"Partial",
|
|
1613
1476
|
"Required",
|
|
@@ -1621,6 +1484,15 @@ var BUILTIN_TYPES2 = new Set([
|
|
|
1621
1484
|
"Readonly",
|
|
1622
1485
|
"ReadonlyArray",
|
|
1623
1486
|
"Awaited",
|
|
1487
|
+
"PromiseLike",
|
|
1488
|
+
"Iterable",
|
|
1489
|
+
"Iterator",
|
|
1490
|
+
"IterableIterator",
|
|
1491
|
+
"Generator",
|
|
1492
|
+
"AsyncGenerator",
|
|
1493
|
+
"AsyncIterable",
|
|
1494
|
+
"AsyncIterator",
|
|
1495
|
+
"AsyncIterableIterator",
|
|
1624
1496
|
"Date",
|
|
1625
1497
|
"RegExp",
|
|
1626
1498
|
"Error",
|
|
@@ -1630,8 +1502,34 @@ var BUILTIN_TYPES2 = new Set([
|
|
|
1630
1502
|
"Number",
|
|
1631
1503
|
"Boolean",
|
|
1632
1504
|
"Symbol",
|
|
1633
|
-
"BigInt"
|
|
1505
|
+
"BigInt",
|
|
1506
|
+
"Uint8Array",
|
|
1507
|
+
"Int8Array",
|
|
1508
|
+
"Uint16Array",
|
|
1509
|
+
"Int16Array",
|
|
1510
|
+
"Uint32Array",
|
|
1511
|
+
"Int32Array",
|
|
1512
|
+
"Float32Array",
|
|
1513
|
+
"Float64Array",
|
|
1514
|
+
"BigInt64Array",
|
|
1515
|
+
"BigUint64Array",
|
|
1516
|
+
"DataView",
|
|
1517
|
+
"SharedArrayBuffer",
|
|
1518
|
+
"ConstructorParameters",
|
|
1519
|
+
"InstanceType",
|
|
1520
|
+
"ThisType"
|
|
1634
1521
|
]);
|
|
1522
|
+
function shouldSkipDanglingRef(name) {
|
|
1523
|
+
if (name.startsWith("__"))
|
|
1524
|
+
return true;
|
|
1525
|
+
if (/^[A-Z]$/.test(name))
|
|
1526
|
+
return true;
|
|
1527
|
+
if (/^T[A-Z]/.test(name))
|
|
1528
|
+
return true;
|
|
1529
|
+
if (["Key", "Value", "Item", "Element"].includes(name))
|
|
1530
|
+
return true;
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1635
1533
|
async function extract(options) {
|
|
1636
1534
|
const {
|
|
1637
1535
|
entryFile,
|
|
@@ -1701,10 +1599,9 @@ async function extract(options) {
|
|
|
1701
1599
|
const externalTypes = types.filter((t) => t.kind === "external");
|
|
1702
1600
|
if (externalTypes.length > 0) {
|
|
1703
1601
|
diagnostics.push({
|
|
1704
|
-
message: `${externalTypes.length} external type(s)
|
|
1705
|
-
severity: "
|
|
1706
|
-
code: "
|
|
1707
|
-
suggestion: "Types are from external packages. Full resolution requires type declarations."
|
|
1602
|
+
message: `${externalTypes.length} external type(s) from dependencies: ${externalTypes.slice(0, 5).map((t) => t.id).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
|
|
1603
|
+
severity: "info",
|
|
1604
|
+
code: "EXTERNAL_TYPES"
|
|
1708
1605
|
});
|
|
1709
1606
|
}
|
|
1710
1607
|
const spec = {
|
|
@@ -1744,7 +1641,7 @@ function collectDanglingRefs(exports, types) {
|
|
|
1744
1641
|
const referencedTypes = new Set;
|
|
1745
1642
|
collectAllRefs(exports, referencedTypes);
|
|
1746
1643
|
collectAllRefs(types, referencedTypes);
|
|
1747
|
-
return Array.from(referencedTypes).filter((ref) => !definedTypes.has(ref) && !BUILTIN_TYPES2.has(ref));
|
|
1644
|
+
return Array.from(referencedTypes).filter((ref) => !definedTypes.has(ref) && !BUILTIN_TYPES2.has(ref) && !shouldSkipDanglingRef(ref));
|
|
1748
1645
|
}
|
|
1749
1646
|
function resolveExportTarget(symbol, checker) {
|
|
1750
1647
|
let targetSymbol = symbol;
|
|
@@ -1867,7 +1764,7 @@ function createEmptySpec(entryFile, includeSchema) {
|
|
|
1867
1764
|
return {
|
|
1868
1765
|
...includeSchema ? { $schema: SCHEMA_URL } : {},
|
|
1869
1766
|
openpkg: SCHEMA_VERSION,
|
|
1870
|
-
meta: { name:
|
|
1767
|
+
meta: { name: path2.basename(entryFile, path2.extname(entryFile)) },
|
|
1871
1768
|
exports: [],
|
|
1872
1769
|
generation: {
|
|
1873
1770
|
generator: "@openpkg-ts/extract",
|
|
@@ -1876,18 +1773,18 @@ function createEmptySpec(entryFile, includeSchema) {
|
|
|
1876
1773
|
};
|
|
1877
1774
|
}
|
|
1878
1775
|
async function getPackageMeta(entryFile, baseDir) {
|
|
1879
|
-
const searchDir = baseDir ??
|
|
1880
|
-
const pkgPath =
|
|
1776
|
+
const searchDir = baseDir ?? path2.dirname(entryFile);
|
|
1777
|
+
const pkgPath = path2.join(searchDir, "package.json");
|
|
1881
1778
|
try {
|
|
1882
|
-
if (
|
|
1883
|
-
const pkg = JSON.parse(
|
|
1779
|
+
if (fs.existsSync(pkgPath)) {
|
|
1780
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
1884
1781
|
return {
|
|
1885
|
-
name: pkg.name ??
|
|
1782
|
+
name: pkg.name ?? path2.basename(searchDir),
|
|
1886
1783
|
version: pkg.version,
|
|
1887
1784
|
description: pkg.description
|
|
1888
1785
|
};
|
|
1889
1786
|
}
|
|
1890
1787
|
} catch {}
|
|
1891
|
-
return { name:
|
|
1788
|
+
return { name: path2.basename(searchDir) };
|
|
1892
1789
|
}
|
|
1893
1790
|
export { TypeRegistry, getJSDocComment, getSourceLocation, getParamDescription, extractTypeParameters, isSymbolDeprecated, createProgram, BUILTIN_TYPE_SCHEMAS, isPrimitiveName, isBuiltinGeneric, isAnonymous, buildSchema, isPureRefSchema, withDescription, schemaIsAny, schemasAreEqual, deduplicateSchemas, findDiscriminatorProperty, extractParameters, registerReferencedTypes, serializeClass, serializeEnum, serializeFunctionExport, serializeInterface, serializeTypeAlias, serializeVariable, extract };
|
package/dist/src/index.d.ts
CHANGED
|
@@ -8,21 +8,14 @@ declare class TypeRegistry {
|
|
|
8
8
|
has(id: string): boolean;
|
|
9
9
|
getAll(): SpecType[];
|
|
10
10
|
/**
|
|
11
|
-
* Register a type from a ts.Type
|
|
11
|
+
* Register a type from a ts.Type (lightweight stub).
|
|
12
12
|
* Returns the type ID if registered, undefined if skipped.
|
|
13
13
|
*/
|
|
14
14
|
registerType(type: ts.Type, checker: ts.TypeChecker, exportedIds: Set<string>): string | undefined;
|
|
15
|
-
private buildSpecType;
|
|
16
15
|
/**
|
|
17
|
-
* Build a
|
|
18
|
-
* Only captures top-level structure with $refs.
|
|
16
|
+
* Build a lightweight stub type (no deep schema extraction).
|
|
19
17
|
*/
|
|
20
|
-
private
|
|
21
|
-
/**
|
|
22
|
-
* Extract shallow members for classes/interfaces.
|
|
23
|
-
* Only captures property names and simple type info.
|
|
24
|
-
*/
|
|
25
|
-
private extractShallowMembers;
|
|
18
|
+
private buildStubType;
|
|
26
19
|
registerFromSymbol(symbol: ts.Symbol, checker: ts.TypeChecker): SpecType | undefined;
|
|
27
20
|
}
|
|
28
21
|
import { SpecExample, SpecSource, SpecTag, SpecTypeParameter } from "@openpkg-ts/spec";
|
|
@@ -253,7 +246,7 @@ declare function extractParameters(signature: ts11.Signature, ctx: SerializerCon
|
|
|
253
246
|
* Recursively register types referenced by a ts.Type.
|
|
254
247
|
* Uses ctx.visitedTypes to prevent infinite recursion on circular types.
|
|
255
248
|
*/
|
|
256
|
-
declare function registerReferencedTypes(type: ts11.Type, ctx: SerializerContext): void;
|
|
249
|
+
declare function registerReferencedTypes(type: ts11.Type, ctx: SerializerContext, depth?: number): void;
|
|
257
250
|
import { SpecSchema } from "@openpkg-ts/spec";
|
|
258
251
|
import ts12 from "typescript";
|
|
259
252
|
/**
|
package/dist/src/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
serializeTypeAlias,
|
|
27
27
|
serializeVariable,
|
|
28
28
|
withDescription
|
|
29
|
-
} from "../shared/chunk-
|
|
29
|
+
} from "../shared/chunk-khwn5myc.js";
|
|
30
30
|
// src/schema/registry.ts
|
|
31
31
|
function isTypeReference(type) {
|
|
32
32
|
return !!(type.flags & 524288 && type.objectFlags && type.objectFlags & 4);
|