@openpkg-ts/sdk 0.34.0 → 0.35.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/dist/browser.d.ts +497 -497
- package/dist/browser.js +1 -1
- package/dist/index.d.ts +289 -149
- package/dist/index.js +654 -440
- package/dist/shared/{chunk-91b592v7.js → chunk-skapcfq1.js} +81 -81
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
toPagefindRecords,
|
|
26
26
|
toSearchIndex,
|
|
27
27
|
toSearchIndexJSON
|
|
28
|
-
} from "./shared/chunk-
|
|
28
|
+
} from "./shared/chunk-skapcfq1.js";
|
|
29
29
|
|
|
30
30
|
// src/primitives/diff.ts
|
|
31
31
|
import {
|
|
@@ -45,7 +45,10 @@ function loadConfig(cwd) {
|
|
|
45
45
|
try {
|
|
46
46
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
47
47
|
return JSON.parse(content);
|
|
48
|
-
} catch {
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
50
|
+
console.warn(`Warning: Invalid JSON in ${CONFIG_FILENAME}: ${msg}`);
|
|
51
|
+
}
|
|
49
52
|
}
|
|
50
53
|
const pkgPath = path.join(cwd, "package.json");
|
|
51
54
|
if (fs.existsSync(pkgPath)) {
|
|
@@ -55,7 +58,10 @@ function loadConfig(cwd) {
|
|
|
55
58
|
if (pkg.openpkg) {
|
|
56
59
|
return pkg.openpkg;
|
|
57
60
|
}
|
|
58
|
-
} catch {
|
|
61
|
+
} catch (err) {
|
|
62
|
+
const msg = err instanceof SyntaxError ? err.message : String(err);
|
|
63
|
+
console.warn(`Warning: Invalid JSON in package.json: ${msg}`);
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
return null;
|
|
61
67
|
}
|
|
@@ -73,6 +79,7 @@ function mergeConfig(fileConfig, cliOptions) {
|
|
|
73
79
|
}
|
|
74
80
|
// src/core/loader.ts
|
|
75
81
|
import * as fs2 from "node:fs";
|
|
82
|
+
import { validateSpec } from "@openpkg-ts/spec";
|
|
76
83
|
|
|
77
84
|
// src/render/html.ts
|
|
78
85
|
var defaultCSS = `
|
|
@@ -1098,7 +1105,21 @@ function loadSpec(spec) {
|
|
|
1098
1105
|
return createDocsInstance(spec);
|
|
1099
1106
|
}
|
|
1100
1107
|
function createDocs(input) {
|
|
1101
|
-
|
|
1108
|
+
let spec;
|
|
1109
|
+
if (typeof input === "string") {
|
|
1110
|
+
try {
|
|
1111
|
+
spec = JSON.parse(fs2.readFileSync(input, "utf-8"));
|
|
1112
|
+
} catch (err) {
|
|
1113
|
+
throw new Error(`Failed to parse spec file: ${err instanceof Error ? err.message : String(err)}`);
|
|
1114
|
+
}
|
|
1115
|
+
} else {
|
|
1116
|
+
spec = input;
|
|
1117
|
+
}
|
|
1118
|
+
const validation = validateSpec(spec);
|
|
1119
|
+
if (!validation.ok) {
|
|
1120
|
+
const errors = validation.errors.slice(0, 5).map((e) => `${e.instancePath || "/"}: ${e.message}`).join("; ");
|
|
1121
|
+
throw new Error(`Invalid OpenPkg spec: ${errors}`);
|
|
1122
|
+
}
|
|
1102
1123
|
return createDocsInstance(spec);
|
|
1103
1124
|
}
|
|
1104
1125
|
function createDocsInstance(spec) {
|
|
@@ -2514,9 +2535,11 @@ function buildSchemaInternal(type, checker, ctx) {
|
|
|
2514
2535
|
function buildFunctionSchema(callSignatures, checker, ctx) {
|
|
2515
2536
|
const buildSignatures = () => {
|
|
2516
2537
|
const signatures = callSignatures.map((sig) => {
|
|
2517
|
-
const params = sig.getParameters().
|
|
2518
|
-
const paramType = checker.getTypeOfSymbolAtLocation(param, param.valueDeclaration);
|
|
2538
|
+
const params = sig.getParameters().flatMap((param) => {
|
|
2519
2539
|
const decl = param.valueDeclaration;
|
|
2540
|
+
if (!decl)
|
|
2541
|
+
return [];
|
|
2542
|
+
const paramType = checker.getTypeOfSymbolAtLocation(param, decl);
|
|
2520
2543
|
const isOptional = !!decl?.questionToken || !!decl?.initializer;
|
|
2521
2544
|
return {
|
|
2522
2545
|
name: param.getName(),
|
|
@@ -2697,7 +2720,9 @@ function extractParameters(signature, ctx) {
|
|
|
2697
2720
|
const jsdocTags = signatureDecl ? ts4.getJSDocTags(signatureDecl) : [];
|
|
2698
2721
|
for (const param of signature.getParameters()) {
|
|
2699
2722
|
const decl = param.valueDeclaration;
|
|
2700
|
-
|
|
2723
|
+
if (!decl)
|
|
2724
|
+
continue;
|
|
2725
|
+
const type = checker.getTypeOfSymbolAtLocation(param, decl);
|
|
2701
2726
|
if (decl && ts4.isObjectBindingPattern(decl.name)) {
|
|
2702
2727
|
const expandedParams = expandBindingPattern(decl, type, jsdocTags, ctx);
|
|
2703
2728
|
result.push(...expandedParams);
|
|
@@ -2842,7 +2867,12 @@ function registerReferencedTypes(type, ctx, depth = 0) {
|
|
|
2842
2867
|
}
|
|
2843
2868
|
if (type.flags & ts4.TypeFlags.Object) {
|
|
2844
2869
|
const props = type.getProperties();
|
|
2845
|
-
|
|
2870
|
+
const limit = ctx.maxProperties;
|
|
2871
|
+
if (props.length > limit && ctx.onTruncation) {
|
|
2872
|
+
const typeName = type.getSymbol()?.getName() ?? "anonymous";
|
|
2873
|
+
ctx.onTruncation(typeName, props.length, limit);
|
|
2874
|
+
}
|
|
2875
|
+
for (const prop of props.slice(0, limit)) {
|
|
2846
2876
|
const propType = checker.getTypeOfSymbol(prop);
|
|
2847
2877
|
registerReferencedTypes(propType, ctx, depth + 1);
|
|
2848
2878
|
}
|
|
@@ -3041,7 +3071,12 @@ class TypeRegistry {
|
|
|
3041
3071
|
}
|
|
3042
3072
|
const props = {};
|
|
3043
3073
|
const required = [];
|
|
3044
|
-
|
|
3074
|
+
const limit = ctx.maxProperties;
|
|
3075
|
+
if (properties.length > limit && ctx.onTruncation) {
|
|
3076
|
+
const typeName = type.getSymbol()?.getName() ?? "anonymous";
|
|
3077
|
+
ctx.onTruncation(typeName, properties.length, limit);
|
|
3078
|
+
}
|
|
3079
|
+
for (const prop of properties.slice(0, limit)) {
|
|
3045
3080
|
const propName = prop.getName();
|
|
3046
3081
|
if (propName.startsWith("_"))
|
|
3047
3082
|
continue;
|
|
@@ -3075,7 +3110,9 @@ function createContext(program, sourceFile, options = {}) {
|
|
|
3075
3110
|
typeRegistry: new TypeRegistry,
|
|
3076
3111
|
exportedIds: new Set,
|
|
3077
3112
|
visitedTypes: new Set,
|
|
3078
|
-
includePrivate: options.includePrivate ?? false
|
|
3113
|
+
includePrivate: options.includePrivate ?? false,
|
|
3114
|
+
maxProperties: options.maxProperties ?? 20,
|
|
3115
|
+
onTruncation: options.onTruncation
|
|
3079
3116
|
};
|
|
3080
3117
|
}
|
|
3081
3118
|
function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
|
|
@@ -3083,7 +3120,12 @@ function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
|
|
|
3083
3120
|
const inherited = [];
|
|
3084
3121
|
const visited = new Set;
|
|
3085
3122
|
const inheritedNames = new Set;
|
|
3086
|
-
|
|
3123
|
+
let typeToWalk = classType;
|
|
3124
|
+
if (isStatic) {
|
|
3125
|
+
const symbol = classType.getSymbol();
|
|
3126
|
+
const valueDecl = symbol?.valueDeclaration;
|
|
3127
|
+
typeToWalk = symbol && valueDecl ? checker.getTypeOfSymbolAtLocation(symbol, valueDecl) : undefined;
|
|
3128
|
+
}
|
|
3087
3129
|
if (!typeToWalk)
|
|
3088
3130
|
return inherited;
|
|
3089
3131
|
walkBaseTypes(typeToWalk, ownMemberNames, inherited, inheritedNames, visited, ctx, isStatic);
|
|
@@ -3234,6 +3276,8 @@ function serializeClass(node, ctx) {
|
|
|
3234
3276
|
methodsByName.set(methodMember.name, methodMember);
|
|
3235
3277
|
} else {
|
|
3236
3278
|
const existing = methodsByName.get(methodMember.name);
|
|
3279
|
+
if (!existing)
|
|
3280
|
+
continue;
|
|
3237
3281
|
if (!existing.description && methodMember.description) {
|
|
3238
3282
|
existing.description = methodMember.description;
|
|
3239
3283
|
}
|
|
@@ -4707,9 +4751,9 @@ function getDescriptionPreview(symbol, checker) {
|
|
|
4707
4751
|
}
|
|
4708
4752
|
// src/builder/spec-builder.ts
|
|
4709
4753
|
import * as fs7 from "node:fs";
|
|
4710
|
-
import * as
|
|
4754
|
+
import * as path8 from "node:path";
|
|
4711
4755
|
import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
|
|
4712
|
-
import
|
|
4756
|
+
import ts16 from "typescript";
|
|
4713
4757
|
|
|
4714
4758
|
// src/ast/resolve.ts
|
|
4715
4759
|
import ts13 from "typescript";
|
|
@@ -4746,6 +4790,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
4746
4790
|
import * as fs5 from "node:fs";
|
|
4747
4791
|
import * as os from "node:os";
|
|
4748
4792
|
import * as path5 from "node:path";
|
|
4793
|
+
var MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
4749
4794
|
function isStandardJSONSchema(obj) {
|
|
4750
4795
|
if (typeof obj !== "object" || obj === null)
|
|
4751
4796
|
return false;
|
|
@@ -4845,6 +4890,7 @@ async function extract() {
|
|
|
4845
4890
|
const absPath = path.resolve(modulePath);
|
|
4846
4891
|
const mod = await import(pathToFileURL(absPath).href);
|
|
4847
4892
|
const results = [];
|
|
4893
|
+
const warnings = [];
|
|
4848
4894
|
|
|
4849
4895
|
// Build exports map - handle both ESM and CJS (where exports are in mod.default)
|
|
4850
4896
|
const exports = {};
|
|
@@ -4877,7 +4923,7 @@ async function extract() {
|
|
|
4877
4923
|
inputSchema
|
|
4878
4924
|
});
|
|
4879
4925
|
} catch (e) {
|
|
4880
|
-
|
|
4926
|
+
warnings.push({ code: 'SCHEMA_FAILED', message: String(e), exportName: name });
|
|
4881
4927
|
}
|
|
4882
4928
|
continue;
|
|
4883
4929
|
}
|
|
@@ -4891,15 +4937,15 @@ async function extract() {
|
|
|
4891
4937
|
outputSchema: sanitizeTypeBoxSchema(value)
|
|
4892
4938
|
});
|
|
4893
4939
|
} catch (e) {
|
|
4894
|
-
|
|
4940
|
+
warnings.push({ code: 'TYPEBOX_FAILED', message: String(e), exportName: name });
|
|
4895
4941
|
}
|
|
4896
4942
|
continue;
|
|
4897
4943
|
}
|
|
4898
4944
|
}
|
|
4899
4945
|
|
|
4900
|
-
console.log(JSON.stringify({ success: true, results }));
|
|
4946
|
+
console.log(JSON.stringify({ success: true, results, warnings }));
|
|
4901
4947
|
} catch (e) {
|
|
4902
|
-
console.log(JSON.stringify({ success: false, error: e.message }));
|
|
4948
|
+
console.log(JSON.stringify({ success: false, error: e.message, warnings: [] }));
|
|
4903
4949
|
}
|
|
4904
4950
|
}
|
|
4905
4951
|
|
|
@@ -4931,6 +4977,7 @@ async function extract() {
|
|
|
4931
4977
|
const absPath = path.resolve(modulePath);
|
|
4932
4978
|
const mod = await import(pathToFileURL(absPath).href);
|
|
4933
4979
|
const results: Array<{exportName: string; vendor: string; outputSchema: unknown; inputSchema?: unknown}> = [];
|
|
4980
|
+
const warnings: Array<{code: string; message: string; exportName?: string}> = [];
|
|
4934
4981
|
|
|
4935
4982
|
// Build exports map
|
|
4936
4983
|
const exports: Record<string, unknown> = {};
|
|
@@ -4959,7 +5006,9 @@ async function extract() {
|
|
|
4959
5006
|
const outputSchema = (jsonSchema.output as Function)(options);
|
|
4960
5007
|
const inputSchema = typeof jsonSchema.input === 'function' ? (jsonSchema.input as Function)(options) : undefined;
|
|
4961
5008
|
results.push({ exportName: name, vendor: std.vendor as string, outputSchema, inputSchema });
|
|
4962
|
-
} catch {
|
|
5009
|
+
} catch (e) {
|
|
5010
|
+
warnings.push({ code: 'SCHEMA_FAILED', message: String(e), exportName: name });
|
|
5011
|
+
}
|
|
4963
5012
|
continue;
|
|
4964
5013
|
}
|
|
4965
5014
|
}
|
|
@@ -4968,13 +5017,15 @@ async function extract() {
|
|
|
4968
5017
|
if (isTypeBoxSchema(value)) {
|
|
4969
5018
|
try {
|
|
4970
5019
|
results.push({ exportName: name, vendor: 'typebox', outputSchema: sanitizeTypeBoxSchema(value) });
|
|
4971
|
-
} catch {
|
|
5020
|
+
} catch (e) {
|
|
5021
|
+
warnings.push({ code: 'TYPEBOX_FAILED', message: String(e), exportName: name });
|
|
5022
|
+
}
|
|
4972
5023
|
}
|
|
4973
5024
|
}
|
|
4974
5025
|
|
|
4975
|
-
console.log(JSON.stringify({ success: true, results }));
|
|
5026
|
+
console.log(JSON.stringify({ success: true, results, warnings }));
|
|
4976
5027
|
} catch (e) {
|
|
4977
|
-
console.log(JSON.stringify({ success: false, error: (e as Error).message }));
|
|
5028
|
+
console.log(JSON.stringify({ success: false, error: (e as Error).message, warnings: [] }));
|
|
4978
5029
|
}
|
|
4979
5030
|
}
|
|
4980
5031
|
|
|
@@ -4984,7 +5035,8 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
|
|
|
4984
5035
|
const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
|
|
4985
5036
|
const result = {
|
|
4986
5037
|
schemas: new Map,
|
|
4987
|
-
errors: []
|
|
5038
|
+
errors: [],
|
|
5039
|
+
warnings: []
|
|
4988
5040
|
};
|
|
4989
5041
|
const runtime = detectTsRuntime();
|
|
4990
5042
|
if (!runtime) {
|
|
@@ -5009,16 +5061,32 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
|
|
|
5009
5061
|
});
|
|
5010
5062
|
let stdout = "";
|
|
5011
5063
|
let stderr = "";
|
|
5064
|
+
let stdoutTruncated = false;
|
|
5065
|
+
let stderrTruncated = false;
|
|
5012
5066
|
child.stdout.on("data", (data) => {
|
|
5013
|
-
stdout
|
|
5067
|
+
if (stdout.length < MAX_BUFFER_SIZE) {
|
|
5068
|
+
const chunk = data.toString();
|
|
5069
|
+
stdout += chunk.slice(0, MAX_BUFFER_SIZE - stdout.length);
|
|
5070
|
+
if (stdout.length >= MAX_BUFFER_SIZE)
|
|
5071
|
+
stdoutTruncated = true;
|
|
5072
|
+
}
|
|
5014
5073
|
});
|
|
5015
5074
|
child.stderr.on("data", (data) => {
|
|
5016
|
-
stderr
|
|
5075
|
+
if (stderr.length < MAX_BUFFER_SIZE) {
|
|
5076
|
+
const chunk = data.toString();
|
|
5077
|
+
stderr += chunk.slice(0, MAX_BUFFER_SIZE - stderr.length);
|
|
5078
|
+
if (stderr.length >= MAX_BUFFER_SIZE)
|
|
5079
|
+
stderrTruncated = true;
|
|
5080
|
+
}
|
|
5017
5081
|
});
|
|
5018
5082
|
child.on("close", (code) => {
|
|
5019
5083
|
try {
|
|
5020
5084
|
fs5.unlinkSync(workerPath);
|
|
5021
|
-
} catch {
|
|
5085
|
+
} catch (cleanupErr) {
|
|
5086
|
+
if (cleanupErr?.code !== "ENOENT") {
|
|
5087
|
+
result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5022
5090
|
if (code !== 0) {
|
|
5023
5091
|
result.errors.push(`Extraction failed (${runtime.name}): ${stderr || `exit code ${code}`}`);
|
|
5024
5092
|
resolve2(result);
|
|
@@ -5039,15 +5107,34 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
|
|
|
5039
5107
|
inputSchema: item.inputSchema
|
|
5040
5108
|
});
|
|
5041
5109
|
}
|
|
5110
|
+
if (Array.isArray(parsed.warnings)) {
|
|
5111
|
+
for (const w of parsed.warnings) {
|
|
5112
|
+
result.warnings.push({
|
|
5113
|
+
code: w.code,
|
|
5114
|
+
message: w.message,
|
|
5115
|
+
exportName: w.exportName
|
|
5116
|
+
});
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5042
5119
|
} catch (e) {
|
|
5043
5120
|
result.errors.push(`Failed to parse extraction output: ${e}`);
|
|
5044
5121
|
}
|
|
5122
|
+
if (stdoutTruncated) {
|
|
5123
|
+
result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stdout exceeded 10MB buffer limit" });
|
|
5124
|
+
}
|
|
5125
|
+
if (stderrTruncated) {
|
|
5126
|
+
result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stderr exceeded 10MB buffer limit" });
|
|
5127
|
+
}
|
|
5045
5128
|
resolve2(result);
|
|
5046
5129
|
});
|
|
5047
5130
|
child.on("error", (err) => {
|
|
5048
5131
|
try {
|
|
5049
5132
|
fs5.unlinkSync(workerPath);
|
|
5050
|
-
} catch {
|
|
5133
|
+
} catch (cleanupErr) {
|
|
5134
|
+
if (cleanupErr?.code !== "ENOENT") {
|
|
5135
|
+
result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5051
5138
|
result.errors.push(`Subprocess error: ${err.message}`);
|
|
5052
5139
|
resolve2(result);
|
|
5053
5140
|
});
|
|
@@ -5055,7 +5142,11 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
|
|
|
5055
5142
|
} catch (e) {
|
|
5056
5143
|
try {
|
|
5057
5144
|
fs5.unlinkSync(workerPath);
|
|
5058
|
-
} catch {
|
|
5145
|
+
} catch (cleanupErr) {
|
|
5146
|
+
if (cleanupErr?.code !== "ENOENT") {
|
|
5147
|
+
result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5059
5150
|
result.errors.push(`Failed to create worker script: ${e}`);
|
|
5060
5151
|
return result;
|
|
5061
5152
|
}
|
|
@@ -5072,7 +5163,7 @@ function readTsconfigOutDir(baseDir) {
|
|
|
5072
5163
|
if (tsconfig.compilerOptions?.outDir) {
|
|
5073
5164
|
return tsconfig.compilerOptions.outDir.replace(/^\.\//, "");
|
|
5074
5165
|
}
|
|
5075
|
-
} catch {}
|
|
5166
|
+
} catch (_e) {}
|
|
5076
5167
|
return null;
|
|
5077
5168
|
}
|
|
5078
5169
|
function resolveCompiledPath(tsPath, baseDir) {
|
|
@@ -5116,7 +5207,8 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
|
|
|
5116
5207
|
const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
|
|
5117
5208
|
const result = {
|
|
5118
5209
|
schemas: new Map,
|
|
5119
|
-
errors: []
|
|
5210
|
+
errors: [],
|
|
5211
|
+
warnings: []
|
|
5120
5212
|
};
|
|
5121
5213
|
if (!fs5.existsSync(compiledJsPath)) {
|
|
5122
5214
|
result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
|
|
@@ -5130,11 +5222,23 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
|
|
|
5130
5222
|
});
|
|
5131
5223
|
let stdout = "";
|
|
5132
5224
|
let stderr = "";
|
|
5225
|
+
let stdoutTruncated = false;
|
|
5226
|
+
let stderrTruncated = false;
|
|
5133
5227
|
child.stdout.on("data", (data) => {
|
|
5134
|
-
stdout
|
|
5228
|
+
if (stdout.length < MAX_BUFFER_SIZE) {
|
|
5229
|
+
const chunk = data.toString();
|
|
5230
|
+
stdout += chunk.slice(0, MAX_BUFFER_SIZE - stdout.length);
|
|
5231
|
+
if (stdout.length >= MAX_BUFFER_SIZE)
|
|
5232
|
+
stdoutTruncated = true;
|
|
5233
|
+
}
|
|
5135
5234
|
});
|
|
5136
5235
|
child.stderr.on("data", (data) => {
|
|
5137
|
-
stderr
|
|
5236
|
+
if (stderr.length < MAX_BUFFER_SIZE) {
|
|
5237
|
+
const chunk = data.toString();
|
|
5238
|
+
stderr += chunk.slice(0, MAX_BUFFER_SIZE - stderr.length);
|
|
5239
|
+
if (stderr.length >= MAX_BUFFER_SIZE)
|
|
5240
|
+
stderrTruncated = true;
|
|
5241
|
+
}
|
|
5138
5242
|
});
|
|
5139
5243
|
child.on("close", (code) => {
|
|
5140
5244
|
if (code !== 0) {
|
|
@@ -5157,9 +5261,24 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
|
|
|
5157
5261
|
inputSchema: item.inputSchema
|
|
5158
5262
|
});
|
|
5159
5263
|
}
|
|
5264
|
+
if (Array.isArray(parsed.warnings)) {
|
|
5265
|
+
for (const w of parsed.warnings) {
|
|
5266
|
+
result.warnings.push({
|
|
5267
|
+
code: w.code,
|
|
5268
|
+
message: w.message,
|
|
5269
|
+
exportName: w.exportName
|
|
5270
|
+
});
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5160
5273
|
} catch (e) {
|
|
5161
5274
|
result.errors.push(`Failed to parse extraction output: ${e}`);
|
|
5162
5275
|
}
|
|
5276
|
+
if (stdoutTruncated) {
|
|
5277
|
+
result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stdout exceeded 10MB buffer limit" });
|
|
5278
|
+
}
|
|
5279
|
+
if (stderrTruncated) {
|
|
5280
|
+
result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stderr exceeded 10MB buffer limit" });
|
|
5281
|
+
}
|
|
5163
5282
|
resolve2(result);
|
|
5164
5283
|
});
|
|
5165
5284
|
child.on("error", (err) => {
|
|
@@ -5195,7 +5314,8 @@ async function extractStandardSchemasFromProject(entryFile, baseDir, options = {
|
|
|
5195
5314
|
const hint = isTypeScript && !runtime ? " Install bun, tsx, or ts-node for direct TS execution." : "";
|
|
5196
5315
|
return {
|
|
5197
5316
|
schemas: new Map,
|
|
5198
|
-
errors: [`Could not find compiled JS for ${entryFile}.${hint}`]
|
|
5317
|
+
errors: [`Could not find compiled JS for ${entryFile}.${hint}`],
|
|
5318
|
+
warnings: []
|
|
5199
5319
|
};
|
|
5200
5320
|
}
|
|
5201
5321
|
|
|
@@ -5394,72 +5514,149 @@ function mergeRuntimeSchemas(staticExports, runtimeSchemas) {
|
|
|
5394
5514
|
return { merged, exports };
|
|
5395
5515
|
}
|
|
5396
5516
|
|
|
5397
|
-
// src/builder/
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5517
|
+
// src/builder/type-cache.ts
|
|
5518
|
+
import ts15 from "typescript";
|
|
5519
|
+
|
|
5520
|
+
// src/utils/cache-manager.ts
|
|
5521
|
+
class CacheManager {
|
|
5522
|
+
cache;
|
|
5523
|
+
maxSize;
|
|
5524
|
+
ttl;
|
|
5525
|
+
constructor(options = {}) {
|
|
5526
|
+
this.maxSize = options.maxSize ?? 1000;
|
|
5527
|
+
this.ttl = options.ttl;
|
|
5528
|
+
this.cache = new Map;
|
|
5529
|
+
}
|
|
5530
|
+
get(key) {
|
|
5531
|
+
const entry = this.cache.get(key);
|
|
5532
|
+
if (!entry)
|
|
5533
|
+
return;
|
|
5534
|
+
if (entry.expiresAt && Date.now() > entry.expiresAt) {
|
|
5535
|
+
this.cache.delete(key);
|
|
5536
|
+
return;
|
|
5537
|
+
}
|
|
5538
|
+
this.cache.delete(key);
|
|
5539
|
+
this.cache.set(key, entry);
|
|
5540
|
+
return entry.value;
|
|
5402
5541
|
}
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5542
|
+
has(key) {
|
|
5543
|
+
const entry = this.cache.get(key);
|
|
5544
|
+
if (!entry)
|
|
5545
|
+
return false;
|
|
5546
|
+
if (entry.expiresAt && Date.now() > entry.expiresAt) {
|
|
5547
|
+
this.cache.delete(key);
|
|
5548
|
+
return false;
|
|
5549
|
+
}
|
|
5550
|
+
return true;
|
|
5551
|
+
}
|
|
5552
|
+
set(key, value) {
|
|
5553
|
+
if (this.cache.has(key)) {
|
|
5554
|
+
this.cache.delete(key);
|
|
5555
|
+
}
|
|
5556
|
+
if (this.cache.size >= this.maxSize) {
|
|
5557
|
+
const firstKey = this.cache.keys().next().value;
|
|
5558
|
+
if (firstKey !== undefined) {
|
|
5559
|
+
this.cache.delete(firstKey);
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
const entry = {
|
|
5563
|
+
value,
|
|
5564
|
+
...this.ttl ? { expiresAt: Date.now() + this.ttl } : {}
|
|
5565
|
+
};
|
|
5566
|
+
this.cache.set(key, entry);
|
|
5567
|
+
}
|
|
5568
|
+
delete(key) {
|
|
5569
|
+
return this.cache.delete(key);
|
|
5570
|
+
}
|
|
5571
|
+
clear() {
|
|
5572
|
+
this.cache.clear();
|
|
5573
|
+
}
|
|
5574
|
+
get size() {
|
|
5575
|
+
return this.cache.size;
|
|
5576
|
+
}
|
|
5577
|
+
keys() {
|
|
5578
|
+
return this.cache.keys();
|
|
5579
|
+
}
|
|
5580
|
+
values() {
|
|
5581
|
+
const result = [];
|
|
5582
|
+
const now = Date.now();
|
|
5583
|
+
for (const [key, entry] of this.cache) {
|
|
5584
|
+
if (entry.expiresAt && now > entry.expiresAt) {
|
|
5585
|
+
this.cache.delete(key);
|
|
5586
|
+
continue;
|
|
5587
|
+
}
|
|
5588
|
+
result.push(entry.value);
|
|
5589
|
+
}
|
|
5590
|
+
return result;
|
|
5409
5591
|
}
|
|
5410
|
-
return internalTagCache;
|
|
5411
5592
|
}
|
|
5593
|
+
|
|
5594
|
+
// src/builder/type-cache.ts
|
|
5595
|
+
var typeDefinitionCache = new CacheManager({ maxSize: 1000 });
|
|
5596
|
+
var internalTagCache = new CacheManager({ maxSize: 1000 });
|
|
5597
|
+
var regexCache = new CacheManager({ maxSize: 100 });
|
|
5412
5598
|
function clearTypeDefinitionCache() {
|
|
5413
|
-
typeDefinitionCache
|
|
5414
|
-
internalTagCache
|
|
5599
|
+
typeDefinitionCache.clear();
|
|
5600
|
+
internalTagCache.clear();
|
|
5601
|
+
regexCache.clear();
|
|
5415
5602
|
}
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5603
|
+
function getRegexCache() {
|
|
5604
|
+
return regexCache;
|
|
5605
|
+
}
|
|
5606
|
+
function findTypeDefinition(typeName, program, sourceFile) {
|
|
5607
|
+
if (typeDefinitionCache.has(typeName)) {
|
|
5608
|
+
return typeDefinitionCache.get(typeName);
|
|
5609
|
+
}
|
|
5610
|
+
const checker = program.getTypeChecker();
|
|
5611
|
+
const findInNode = (node) => {
|
|
5612
|
+
if ((ts15.isInterfaceDeclaration(node) || ts15.isTypeAliasDeclaration(node) || ts15.isClassDeclaration(node) || ts15.isEnumDeclaration(node)) && node.name?.text === typeName) {
|
|
5613
|
+
const sf = node.getSourceFile();
|
|
5614
|
+
return sf.fileName;
|
|
5615
|
+
}
|
|
5616
|
+
return ts15.forEachChild(node, findInNode);
|
|
5617
|
+
};
|
|
5618
|
+
const entryResult = findInNode(sourceFile);
|
|
5619
|
+
if (entryResult) {
|
|
5620
|
+
typeDefinitionCache.set(typeName, entryResult);
|
|
5621
|
+
return entryResult;
|
|
5622
|
+
}
|
|
5623
|
+
for (const sf of program.getSourceFiles()) {
|
|
5624
|
+
if (sf.isDeclarationFile && !sf.fileName.includes("node_modules")) {
|
|
5625
|
+
const result = findInNode(sf);
|
|
5626
|
+
if (result) {
|
|
5627
|
+
typeDefinitionCache.set(typeName, result);
|
|
5628
|
+
return result;
|
|
5433
5629
|
}
|
|
5434
5630
|
}
|
|
5435
5631
|
}
|
|
5436
|
-
|
|
5632
|
+
const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
|
|
5633
|
+
if (symbol?.declarations?.[0]) {
|
|
5634
|
+
const result = symbol.declarations[0].getSourceFile().fileName;
|
|
5635
|
+
typeDefinitionCache.set(typeName, result);
|
|
5636
|
+
return result;
|
|
5637
|
+
}
|
|
5638
|
+
typeDefinitionCache.set(typeName, undefined);
|
|
5639
|
+
return;
|
|
5437
5640
|
}
|
|
5438
|
-
function
|
|
5439
|
-
const
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
if (entry.status === "skipped" && entry.skipReason) {
|
|
5443
|
-
skippedDetails.push({ name: entry.name, reason: entry.skipReason });
|
|
5444
|
-
} else if (entry.status === "failed" && entry.error) {
|
|
5445
|
-
failedDetails.push({ name: entry.name, error: entry.error });
|
|
5446
|
-
}
|
|
5641
|
+
function hasInternalTag(typeName, program, sourceFile) {
|
|
5642
|
+
const cached = internalTagCache.get(typeName);
|
|
5643
|
+
if (cached !== undefined) {
|
|
5644
|
+
return cached;
|
|
5447
5645
|
}
|
|
5448
|
-
const
|
|
5449
|
-
const
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
skipped: skippedDetails,
|
|
5459
|
-
failed: failedDetails
|
|
5460
|
-
}
|
|
5461
|
-
};
|
|
5646
|
+
const checker = program.getTypeChecker();
|
|
5647
|
+
const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
|
|
5648
|
+
if (!symbol) {
|
|
5649
|
+
internalTagCache.set(typeName, false);
|
|
5650
|
+
return false;
|
|
5651
|
+
}
|
|
5652
|
+
const jsTags = symbol.getJsDocTags();
|
|
5653
|
+
const isInternal = jsTags.some((tag) => tag.name === "internal");
|
|
5654
|
+
internalTagCache.set(typeName, isInternal);
|
|
5655
|
+
return isInternal;
|
|
5462
5656
|
}
|
|
5657
|
+
|
|
5658
|
+
// src/builder/verification.ts
|
|
5659
|
+
import * as path7 from "node:path";
|
|
5463
5660
|
var BUILTIN_TYPES2 = new Set([
|
|
5464
5661
|
"Array",
|
|
5465
5662
|
"ArrayBuffer",
|
|
@@ -5518,19 +5715,39 @@ var BUILTIN_TYPES2 = new Set([
|
|
|
5518
5715
|
"InstanceType",
|
|
5519
5716
|
"ThisType"
|
|
5520
5717
|
]);
|
|
5521
|
-
function
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
const
|
|
5525
|
-
|
|
5526
|
-
}
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
if (only && only.length > 0) {
|
|
5531
|
-
return only.some((p) => matchesPattern(name, p));
|
|
5718
|
+
function buildVerificationSummary(discoveredCount, extractedCount, tracker) {
|
|
5719
|
+
const skippedDetails = [];
|
|
5720
|
+
const failedDetails = [];
|
|
5721
|
+
for (const entry of tracker.values()) {
|
|
5722
|
+
if (entry.status === "skipped" && entry.skipReason) {
|
|
5723
|
+
skippedDetails.push({ name: entry.name, reason: entry.skipReason });
|
|
5724
|
+
} else if (entry.status === "failed" && entry.error) {
|
|
5725
|
+
failedDetails.push({ name: entry.name, error: entry.error });
|
|
5726
|
+
}
|
|
5532
5727
|
}
|
|
5533
|
-
|
|
5728
|
+
const skipped = skippedDetails.length;
|
|
5729
|
+
const failed = failedDetails.length;
|
|
5730
|
+
const delta = discoveredCount - extractedCount - skipped;
|
|
5731
|
+
return {
|
|
5732
|
+
discovered: discoveredCount,
|
|
5733
|
+
extracted: extractedCount,
|
|
5734
|
+
skipped,
|
|
5735
|
+
failed,
|
|
5736
|
+
delta,
|
|
5737
|
+
details: {
|
|
5738
|
+
skipped: skippedDetails,
|
|
5739
|
+
failed: failedDetails
|
|
5740
|
+
}
|
|
5741
|
+
};
|
|
5742
|
+
}
|
|
5743
|
+
function isExternalType2(definedIn, baseDir) {
|
|
5744
|
+
if (!definedIn)
|
|
5745
|
+
return true;
|
|
5746
|
+
if (definedIn.includes("node_modules"))
|
|
5747
|
+
return true;
|
|
5748
|
+
const normalizedDefined = path7.resolve(definedIn);
|
|
5749
|
+
const normalizedBase = path7.resolve(baseDir);
|
|
5750
|
+
return !normalizedDefined.startsWith(normalizedBase);
|
|
5534
5751
|
}
|
|
5535
5752
|
function shouldSkipDanglingRef(name) {
|
|
5536
5753
|
if (name.startsWith("__"))
|
|
@@ -5543,255 +5760,6 @@ function shouldSkipDanglingRef(name) {
|
|
|
5543
5760
|
return true;
|
|
5544
5761
|
return false;
|
|
5545
5762
|
}
|
|
5546
|
-
async function extract(options) {
|
|
5547
|
-
clearTypeDefinitionCache();
|
|
5548
|
-
const {
|
|
5549
|
-
entryFile,
|
|
5550
|
-
baseDir,
|
|
5551
|
-
content,
|
|
5552
|
-
maxTypeDepth,
|
|
5553
|
-
maxExternalTypeDepth,
|
|
5554
|
-
resolveExternalTypes,
|
|
5555
|
-
includeSchema,
|
|
5556
|
-
only,
|
|
5557
|
-
ignore,
|
|
5558
|
-
onProgress,
|
|
5559
|
-
isDtsSource,
|
|
5560
|
-
includePrivate
|
|
5561
|
-
} = options;
|
|
5562
|
-
const diagnostics = [];
|
|
5563
|
-
let exports = [];
|
|
5564
|
-
const result = createProgram({ entryFile, baseDir, content });
|
|
5565
|
-
const { program, sourceFile } = result;
|
|
5566
|
-
if (!sourceFile) {
|
|
5567
|
-
return {
|
|
5568
|
-
spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
|
|
5569
|
-
diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
|
|
5570
|
-
};
|
|
5571
|
-
}
|
|
5572
|
-
const typeChecker = program.getTypeChecker();
|
|
5573
|
-
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
5574
|
-
if (!moduleSymbol) {
|
|
5575
|
-
return {
|
|
5576
|
-
spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
|
|
5577
|
-
diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
|
|
5578
|
-
};
|
|
5579
|
-
}
|
|
5580
|
-
const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
|
|
5581
|
-
const exportedIds = new Set;
|
|
5582
|
-
for (const symbol of exportedSymbols) {
|
|
5583
|
-
exportedIds.add(symbol.getName());
|
|
5584
|
-
}
|
|
5585
|
-
const exportTracker = new Map;
|
|
5586
|
-
for (const symbol of exportedSymbols) {
|
|
5587
|
-
const name = symbol.getName();
|
|
5588
|
-
const included = shouldIncludeExport(name, only, ignore);
|
|
5589
|
-
exportTracker.set(name, {
|
|
5590
|
-
name,
|
|
5591
|
-
discovered: true,
|
|
5592
|
-
status: included ? "pending" : "skipped",
|
|
5593
|
-
...included ? {} : { skipReason: "filtered" }
|
|
5594
|
-
});
|
|
5595
|
-
}
|
|
5596
|
-
const ctx = createContext(program, sourceFile, {
|
|
5597
|
-
maxTypeDepth,
|
|
5598
|
-
maxExternalTypeDepth,
|
|
5599
|
-
resolveExternalTypes,
|
|
5600
|
-
includePrivate
|
|
5601
|
-
});
|
|
5602
|
-
ctx.exportedIds = exportedIds;
|
|
5603
|
-
const filteredSymbols = exportedSymbols.filter((s) => shouldIncludeExport(s.getName(), only, ignore));
|
|
5604
|
-
const total = filteredSymbols.length;
|
|
5605
|
-
for (let i = 0;i < filteredSymbols.length; i++) {
|
|
5606
|
-
const symbol = filteredSymbols[i];
|
|
5607
|
-
const exportName = symbol.getName();
|
|
5608
|
-
const tracker = exportTracker.get(exportName);
|
|
5609
|
-
onProgress?.(i + 1, total, exportName);
|
|
5610
|
-
if (i > 0 && i % YIELD_BATCH_SIZE === 0) {
|
|
5611
|
-
await new Promise((r) => setImmediate(r));
|
|
5612
|
-
}
|
|
5613
|
-
try {
|
|
5614
|
-
const { declaration, targetSymbol, isTypeOnly } = resolveExportTarget2(symbol, typeChecker);
|
|
5615
|
-
if (!declaration) {
|
|
5616
|
-
let externalPackage;
|
|
5617
|
-
const allDecls = [
|
|
5618
|
-
...targetSymbol.declarations ?? [],
|
|
5619
|
-
...symbol.declarations ?? []
|
|
5620
|
-
];
|
|
5621
|
-
for (const decl of allDecls) {
|
|
5622
|
-
const sf = decl.getSourceFile();
|
|
5623
|
-
if (sf?.fileName.includes("node_modules")) {
|
|
5624
|
-
const match = sf.fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
|
|
5625
|
-
if (match) {
|
|
5626
|
-
externalPackage = match[1];
|
|
5627
|
-
break;
|
|
5628
|
-
}
|
|
5629
|
-
}
|
|
5630
|
-
if (ts15.isExportSpecifier(decl)) {
|
|
5631
|
-
const exportDecl = decl.parent?.parent;
|
|
5632
|
-
if (exportDecl && ts15.isExportDeclaration(exportDecl) && exportDecl.moduleSpecifier) {
|
|
5633
|
-
const moduleText = exportDecl.moduleSpecifier.getText().slice(1, -1);
|
|
5634
|
-
if (!moduleText.startsWith(".") && !moduleText.startsWith("/")) {
|
|
5635
|
-
externalPackage = moduleText;
|
|
5636
|
-
break;
|
|
5637
|
-
}
|
|
5638
|
-
}
|
|
5639
|
-
}
|
|
5640
|
-
}
|
|
5641
|
-
if (externalPackage) {
|
|
5642
|
-
const shouldResolve = matchesExternalPattern(externalPackage, options.externals?.include, options.externals?.exclude);
|
|
5643
|
-
if (shouldResolve) {
|
|
5644
|
-
const resolvedModule = resolveExternalModule(externalPackage, sourceFile.fileName, program.getCompilerOptions());
|
|
5645
|
-
if (resolvedModule) {
|
|
5646
|
-
const visitedExternals = new Set;
|
|
5647
|
-
const extractedExport = extractExternalExport(exportName, resolvedModule, program, ctx, visitedExternals);
|
|
5648
|
-
if (extractedExport) {
|
|
5649
|
-
exports.push(extractedExport);
|
|
5650
|
-
tracker.status = "success";
|
|
5651
|
-
tracker.kind = extractedExport.kind;
|
|
5652
|
-
continue;
|
|
5653
|
-
}
|
|
5654
|
-
}
|
|
5655
|
-
}
|
|
5656
|
-
const externalExport = {
|
|
5657
|
-
id: exportName,
|
|
5658
|
-
name: exportName,
|
|
5659
|
-
kind: "external",
|
|
5660
|
-
source: {
|
|
5661
|
-
package: externalPackage
|
|
5662
|
-
}
|
|
5663
|
-
};
|
|
5664
|
-
exports.push(externalExport);
|
|
5665
|
-
tracker.status = "success";
|
|
5666
|
-
tracker.kind = "external";
|
|
5667
|
-
} else {
|
|
5668
|
-
tracker.status = "skipped";
|
|
5669
|
-
tracker.skipReason = "no-declaration";
|
|
5670
|
-
}
|
|
5671
|
-
continue;
|
|
5672
|
-
}
|
|
5673
|
-
const exp = serializeDeclaration2(declaration, symbol, targetSymbol, exportName, ctx, isTypeOnly);
|
|
5674
|
-
if (exp) {
|
|
5675
|
-
exports.push(exp);
|
|
5676
|
-
tracker.status = "success";
|
|
5677
|
-
tracker.kind = exp.kind;
|
|
5678
|
-
} else {
|
|
5679
|
-
tracker.status = "skipped";
|
|
5680
|
-
tracker.skipReason = "internal";
|
|
5681
|
-
}
|
|
5682
|
-
} catch (err) {
|
|
5683
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
5684
|
-
tracker.status = "failed";
|
|
5685
|
-
tracker.error = errorMsg;
|
|
5686
|
-
diagnostics.push({
|
|
5687
|
-
message: `Failed to serialize '${exportName}': ${errorMsg}`,
|
|
5688
|
-
severity: "warning",
|
|
5689
|
-
code: "SERIALIZATION_FAILED"
|
|
5690
|
-
});
|
|
5691
|
-
}
|
|
5692
|
-
}
|
|
5693
|
-
const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
|
|
5694
|
-
const meta = await getPackageMeta(entryFile, baseDir);
|
|
5695
|
-
const types = ctx.typeRegistry.getAll();
|
|
5696
|
-
const projectBaseDir = baseDir ?? path7.dirname(entryFile);
|
|
5697
|
-
const definedTypes = new Set(types.map((t) => t.id));
|
|
5698
|
-
const forgottenExports = collectForgottenExports(exports, types, program, sourceFile, exportedIds, projectBaseDir, definedTypes);
|
|
5699
|
-
for (const forgotten of forgottenExports) {
|
|
5700
|
-
const refSummary = forgotten.referencedBy.slice(0, 3).map((r) => `${r.exportName} (${r.location})`).join(", ");
|
|
5701
|
-
const moreRefs = forgotten.referencedBy.length > 3 ? ` +${forgotten.referencedBy.length - 3} more` : "";
|
|
5702
|
-
if (forgotten.isExternal) {
|
|
5703
|
-
diagnostics.push({
|
|
5704
|
-
message: `External type '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
5705
|
-
severity: "info",
|
|
5706
|
-
code: "EXTERNAL_TYPE_REF",
|
|
5707
|
-
suggestion: forgotten.definedIn ? `Type is from: ${forgotten.definedIn}` : "Type is from an external package"
|
|
5708
|
-
});
|
|
5709
|
-
} else {
|
|
5710
|
-
diagnostics.push({
|
|
5711
|
-
message: `Forgotten export: '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
5712
|
-
severity: "warning",
|
|
5713
|
-
code: "FORGOTTEN_EXPORT",
|
|
5714
|
-
suggestion: forgotten.fix ?? `Export this type from your public API`,
|
|
5715
|
-
location: forgotten.definedIn ? { file: forgotten.definedIn } : undefined
|
|
5716
|
-
});
|
|
5717
|
-
}
|
|
5718
|
-
}
|
|
5719
|
-
const externalTypes = types.filter((t) => t.kind === "external");
|
|
5720
|
-
if (externalTypes.length > 0) {
|
|
5721
|
-
diagnostics.push({
|
|
5722
|
-
message: `${externalTypes.length} external type(s) from dependencies: ${externalTypes.slice(0, 5).map((t) => t.id).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
|
|
5723
|
-
severity: "info",
|
|
5724
|
-
code: "EXTERNAL_TYPES"
|
|
5725
|
-
});
|
|
5726
|
-
}
|
|
5727
|
-
let runtimeMetadata;
|
|
5728
|
-
if (options.schemaExtraction === "hybrid") {
|
|
5729
|
-
const projectBaseDir2 = baseDir || path7.dirname(entryFile);
|
|
5730
|
-
const runtimeResult = await extractStandardSchemasFromProject(entryFile, projectBaseDir2, {
|
|
5731
|
-
target: options.schemaTarget || "draft-2020-12",
|
|
5732
|
-
timeout: 15000
|
|
5733
|
-
});
|
|
5734
|
-
if (runtimeResult.schemas.size > 0) {
|
|
5735
|
-
const mergeResult = mergeRuntimeSchemas(exports, runtimeResult.schemas);
|
|
5736
|
-
exports = mergeResult.exports;
|
|
5737
|
-
const method = runtimeResult.info?.method === "direct-ts" ? `direct-ts (${runtimeResult.info.runtime})` : "compiled";
|
|
5738
|
-
runtimeMetadata = {
|
|
5739
|
-
extracted: runtimeResult.schemas.size,
|
|
5740
|
-
merged: mergeResult.merged,
|
|
5741
|
-
vendors: [...new Set([...runtimeResult.schemas.values()].map((s) => s.vendor))],
|
|
5742
|
-
errors: runtimeResult.errors,
|
|
5743
|
-
method
|
|
5744
|
-
};
|
|
5745
|
-
}
|
|
5746
|
-
for (const error of runtimeResult.errors) {
|
|
5747
|
-
diagnostics.push({
|
|
5748
|
-
message: `Runtime schema extraction: ${error}`,
|
|
5749
|
-
severity: "warning",
|
|
5750
|
-
code: "RUNTIME_SCHEMA_ERROR"
|
|
5751
|
-
});
|
|
5752
|
-
}
|
|
5753
|
-
}
|
|
5754
|
-
const normalizedExports = exports.map((exp) => normalizeExport(exp, { dialect: "draft-2020-12" }));
|
|
5755
|
-
const normalizedTypes = types.map((t) => normalizeType(t, { dialect: "draft-2020-12" }));
|
|
5756
|
-
const spec = {
|
|
5757
|
-
...includeSchema ? { $schema: SCHEMA_URL } : {},
|
|
5758
|
-
openpkg: SCHEMA_VERSION,
|
|
5759
|
-
meta,
|
|
5760
|
-
exports: normalizedExports,
|
|
5761
|
-
types: normalizedTypes,
|
|
5762
|
-
generation: {
|
|
5763
|
-
generator: "@openpkg-ts/sdk",
|
|
5764
|
-
timestamp: new Date().toISOString(),
|
|
5765
|
-
mode: isDtsSource ? "declaration-only" : "source",
|
|
5766
|
-
...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {},
|
|
5767
|
-
...isDtsSource && {
|
|
5768
|
-
limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
|
|
5769
|
-
},
|
|
5770
|
-
...verification.details.skipped.length > 0 && {
|
|
5771
|
-
skipped: verification.details.skipped
|
|
5772
|
-
}
|
|
5773
|
-
}
|
|
5774
|
-
};
|
|
5775
|
-
const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
|
|
5776
|
-
const degradedMode = isDtsSource ? { reason: "dts-source", stats: computeDegradedStats(normalizedExports) } : undefined;
|
|
5777
|
-
if (verification.failed > 0) {
|
|
5778
|
-
const failedNames = verification.details.failed.map((f) => f.name).join(", ");
|
|
5779
|
-
diagnostics.push({
|
|
5780
|
-
message: `Export verification: ${verification.failed} export(s) failed: ${failedNames}`,
|
|
5781
|
-
severity: "warning",
|
|
5782
|
-
code: "EXPORT_VERIFICATION_FAILED",
|
|
5783
|
-
suggestion: "Check serialization errors for these exports"
|
|
5784
|
-
});
|
|
5785
|
-
}
|
|
5786
|
-
return {
|
|
5787
|
-
spec,
|
|
5788
|
-
diagnostics,
|
|
5789
|
-
verification,
|
|
5790
|
-
...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {},
|
|
5791
|
-
...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {},
|
|
5792
|
-
...degradedMode ? { degradedMode } : {}
|
|
5793
|
-
};
|
|
5794
|
-
}
|
|
5795
5763
|
function collectAllRefsWithContext(obj, refs, state) {
|
|
5796
5764
|
if (obj === null || obj === undefined)
|
|
5797
5765
|
return;
|
|
@@ -5835,68 +5803,6 @@ function collectAllRefsWithContext(obj, refs, state) {
|
|
|
5835
5803
|
}
|
|
5836
5804
|
}
|
|
5837
5805
|
}
|
|
5838
|
-
function findTypeDefinition(typeName, program, sourceFile) {
|
|
5839
|
-
const cache = getTypeDefinitionCache();
|
|
5840
|
-
if (cache.has(typeName)) {
|
|
5841
|
-
return cache.get(typeName);
|
|
5842
|
-
}
|
|
5843
|
-
const checker = program.getTypeChecker();
|
|
5844
|
-
const findInNode = (node) => {
|
|
5845
|
-
if ((ts15.isInterfaceDeclaration(node) || ts15.isTypeAliasDeclaration(node) || ts15.isClassDeclaration(node) || ts15.isEnumDeclaration(node)) && node.name?.text === typeName) {
|
|
5846
|
-
const sf = node.getSourceFile();
|
|
5847
|
-
return sf.fileName;
|
|
5848
|
-
}
|
|
5849
|
-
return ts15.forEachChild(node, findInNode);
|
|
5850
|
-
};
|
|
5851
|
-
const entryResult = findInNode(sourceFile);
|
|
5852
|
-
if (entryResult) {
|
|
5853
|
-
cache.set(typeName, entryResult);
|
|
5854
|
-
return entryResult;
|
|
5855
|
-
}
|
|
5856
|
-
for (const sf of program.getSourceFiles()) {
|
|
5857
|
-
if (sf.isDeclarationFile && !sf.fileName.includes("node_modules")) {
|
|
5858
|
-
const result = findInNode(sf);
|
|
5859
|
-
if (result) {
|
|
5860
|
-
cache.set(typeName, result);
|
|
5861
|
-
return result;
|
|
5862
|
-
}
|
|
5863
|
-
}
|
|
5864
|
-
}
|
|
5865
|
-
const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
|
|
5866
|
-
if (symbol?.declarations?.[0]) {
|
|
5867
|
-
const result = symbol.declarations[0].getSourceFile().fileName;
|
|
5868
|
-
cache.set(typeName, result);
|
|
5869
|
-
return result;
|
|
5870
|
-
}
|
|
5871
|
-
cache.set(typeName, undefined);
|
|
5872
|
-
return;
|
|
5873
|
-
}
|
|
5874
|
-
function isExternalType2(definedIn, baseDir) {
|
|
5875
|
-
if (!definedIn)
|
|
5876
|
-
return true;
|
|
5877
|
-
if (definedIn.includes("node_modules"))
|
|
5878
|
-
return true;
|
|
5879
|
-
const normalizedDefined = path7.resolve(definedIn);
|
|
5880
|
-
const normalizedBase = path7.resolve(baseDir);
|
|
5881
|
-
return !normalizedDefined.startsWith(normalizedBase);
|
|
5882
|
-
}
|
|
5883
|
-
function hasInternalTag(typeName, program, sourceFile) {
|
|
5884
|
-
const cache = getInternalTagCache();
|
|
5885
|
-
const cached = cache.get(typeName);
|
|
5886
|
-
if (cached !== undefined) {
|
|
5887
|
-
return cached;
|
|
5888
|
-
}
|
|
5889
|
-
const checker = program.getTypeChecker();
|
|
5890
|
-
const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
|
|
5891
|
-
if (!symbol) {
|
|
5892
|
-
cache.set(typeName, false);
|
|
5893
|
-
return false;
|
|
5894
|
-
}
|
|
5895
|
-
const jsTags = symbol.getJsDocTags();
|
|
5896
|
-
const isInternal = jsTags.some((tag) => tag.name === "internal");
|
|
5897
|
-
cache.set(typeName, isInternal);
|
|
5898
|
-
return isInternal;
|
|
5899
|
-
}
|
|
5900
5806
|
function collectForgottenExports(exports, types, program, sourceFile, exportedIds, baseDir, definedTypes) {
|
|
5901
5807
|
const referencedTypes = new Map;
|
|
5902
5808
|
for (const exp of exports) {
|
|
@@ -5937,29 +5843,336 @@ function collectForgottenExports(exports, types, program, sourceFile, exportedId
|
|
|
5937
5843
|
}
|
|
5938
5844
|
return forgottenExports;
|
|
5939
5845
|
}
|
|
5846
|
+
|
|
5847
|
+
// src/builder/spec-builder.ts
|
|
5848
|
+
var YIELD_BATCH_SIZE = 5;
|
|
5849
|
+
function computeDegradedStats(exports) {
|
|
5850
|
+
let exportsWithoutDescription = 0;
|
|
5851
|
+
let paramsWithoutDocs = 0;
|
|
5852
|
+
let missingExamples = 0;
|
|
5853
|
+
for (const exp of exports) {
|
|
5854
|
+
if (!exp.description)
|
|
5855
|
+
exportsWithoutDescription++;
|
|
5856
|
+
if (!exp.examples || exp.examples.length === 0)
|
|
5857
|
+
missingExamples++;
|
|
5858
|
+
const signatures = exp.signatures;
|
|
5859
|
+
if (signatures) {
|
|
5860
|
+
for (const sig of signatures) {
|
|
5861
|
+
for (const param of sig.parameters ?? []) {
|
|
5862
|
+
if (!param.description)
|
|
5863
|
+
paramsWithoutDocs++;
|
|
5864
|
+
}
|
|
5865
|
+
}
|
|
5866
|
+
}
|
|
5867
|
+
}
|
|
5868
|
+
return { exportsWithoutDescription, paramsWithoutDocs, missingExamples };
|
|
5869
|
+
}
|
|
5870
|
+
function matchesPattern(name, pattern) {
|
|
5871
|
+
if (!pattern.includes("*"))
|
|
5872
|
+
return name === pattern;
|
|
5873
|
+
const regexCache2 = getRegexCache();
|
|
5874
|
+
let regex = regexCache2.get(pattern);
|
|
5875
|
+
if (!regex) {
|
|
5876
|
+
regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
5877
|
+
regexCache2.set(pattern, regex);
|
|
5878
|
+
}
|
|
5879
|
+
return regex.test(name);
|
|
5880
|
+
}
|
|
5881
|
+
function shouldIncludeExport(name, only, ignore) {
|
|
5882
|
+
if (ignore?.some((p) => matchesPattern(name, p)))
|
|
5883
|
+
return false;
|
|
5884
|
+
if (only && only.length > 0) {
|
|
5885
|
+
return only.some((p) => matchesPattern(name, p));
|
|
5886
|
+
}
|
|
5887
|
+
return true;
|
|
5888
|
+
}
|
|
5889
|
+
async function extract(options) {
|
|
5890
|
+
clearTypeDefinitionCache();
|
|
5891
|
+
try {
|
|
5892
|
+
const {
|
|
5893
|
+
entryFile,
|
|
5894
|
+
baseDir,
|
|
5895
|
+
content,
|
|
5896
|
+
maxTypeDepth,
|
|
5897
|
+
maxExternalTypeDepth,
|
|
5898
|
+
resolveExternalTypes,
|
|
5899
|
+
includeSchema,
|
|
5900
|
+
only,
|
|
5901
|
+
ignore,
|
|
5902
|
+
onProgress,
|
|
5903
|
+
isDtsSource,
|
|
5904
|
+
includePrivate,
|
|
5905
|
+
maxProperties,
|
|
5906
|
+
onTruncation
|
|
5907
|
+
} = options;
|
|
5908
|
+
const diagnostics = [];
|
|
5909
|
+
let exports = [];
|
|
5910
|
+
const result = createProgram({ entryFile, baseDir, content });
|
|
5911
|
+
const { program, sourceFile } = result;
|
|
5912
|
+
if (!sourceFile) {
|
|
5913
|
+
return {
|
|
5914
|
+
spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
|
|
5915
|
+
diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
|
|
5916
|
+
};
|
|
5917
|
+
}
|
|
5918
|
+
const typeChecker = program.getTypeChecker();
|
|
5919
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
5920
|
+
if (!moduleSymbol) {
|
|
5921
|
+
return {
|
|
5922
|
+
spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
|
|
5923
|
+
diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
|
|
5924
|
+
};
|
|
5925
|
+
}
|
|
5926
|
+
const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
|
|
5927
|
+
const exportedIds = new Set;
|
|
5928
|
+
for (const symbol of exportedSymbols) {
|
|
5929
|
+
exportedIds.add(symbol.getName());
|
|
5930
|
+
}
|
|
5931
|
+
const exportTracker = new Map;
|
|
5932
|
+
for (const symbol of exportedSymbols) {
|
|
5933
|
+
const name = symbol.getName();
|
|
5934
|
+
const included = shouldIncludeExport(name, only, ignore);
|
|
5935
|
+
exportTracker.set(name, {
|
|
5936
|
+
name,
|
|
5937
|
+
discovered: true,
|
|
5938
|
+
status: included ? "pending" : "skipped",
|
|
5939
|
+
...included ? {} : { skipReason: "filtered" }
|
|
5940
|
+
});
|
|
5941
|
+
}
|
|
5942
|
+
const ctx = createContext(program, sourceFile, {
|
|
5943
|
+
maxTypeDepth,
|
|
5944
|
+
maxExternalTypeDepth,
|
|
5945
|
+
resolveExternalTypes,
|
|
5946
|
+
includePrivate,
|
|
5947
|
+
maxProperties,
|
|
5948
|
+
onTruncation
|
|
5949
|
+
});
|
|
5950
|
+
ctx.exportedIds = exportedIds;
|
|
5951
|
+
const filteredSymbols = exportedSymbols.filter((s) => shouldIncludeExport(s.getName(), only, ignore));
|
|
5952
|
+
const total = filteredSymbols.length;
|
|
5953
|
+
for (let i = 0;i < filteredSymbols.length; i++) {
|
|
5954
|
+
const symbol = filteredSymbols[i];
|
|
5955
|
+
const exportName = symbol.getName();
|
|
5956
|
+
const tracker = exportTracker.get(exportName);
|
|
5957
|
+
if (!tracker)
|
|
5958
|
+
continue;
|
|
5959
|
+
onProgress?.(i + 1, total, exportName);
|
|
5960
|
+
if (i > 0 && i % YIELD_BATCH_SIZE === 0) {
|
|
5961
|
+
await new Promise((r) => setImmediate(r));
|
|
5962
|
+
}
|
|
5963
|
+
try {
|
|
5964
|
+
const { declaration, targetSymbol, isTypeOnly } = resolveExportTarget2(symbol, typeChecker);
|
|
5965
|
+
if (!declaration) {
|
|
5966
|
+
let externalPackage;
|
|
5967
|
+
const allDecls = [...targetSymbol.declarations ?? [], ...symbol.declarations ?? []];
|
|
5968
|
+
for (const decl of allDecls) {
|
|
5969
|
+
const sf = decl.getSourceFile();
|
|
5970
|
+
if (sf?.fileName.includes("node_modules")) {
|
|
5971
|
+
const match = sf.fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
|
|
5972
|
+
if (match) {
|
|
5973
|
+
externalPackage = match[1];
|
|
5974
|
+
break;
|
|
5975
|
+
}
|
|
5976
|
+
}
|
|
5977
|
+
if (ts16.isExportSpecifier(decl)) {
|
|
5978
|
+
const exportDecl = decl.parent?.parent;
|
|
5979
|
+
if (exportDecl && ts16.isExportDeclaration(exportDecl) && exportDecl.moduleSpecifier) {
|
|
5980
|
+
const moduleText = exportDecl.moduleSpecifier.getText().slice(1, -1);
|
|
5981
|
+
if (!moduleText.startsWith(".") && !moduleText.startsWith("/")) {
|
|
5982
|
+
externalPackage = moduleText;
|
|
5983
|
+
break;
|
|
5984
|
+
}
|
|
5985
|
+
}
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
if (externalPackage) {
|
|
5989
|
+
const shouldResolve = matchesExternalPattern(externalPackage, options.externals?.include, options.externals?.exclude);
|
|
5990
|
+
if (shouldResolve) {
|
|
5991
|
+
const resolvedModule = resolveExternalModule(externalPackage, sourceFile.fileName, program.getCompilerOptions());
|
|
5992
|
+
if (resolvedModule) {
|
|
5993
|
+
const visitedExternals = new Set;
|
|
5994
|
+
const extractedExport = extractExternalExport(exportName, resolvedModule, program, ctx, visitedExternals);
|
|
5995
|
+
if (extractedExport) {
|
|
5996
|
+
exports.push(extractedExport);
|
|
5997
|
+
tracker.status = "success";
|
|
5998
|
+
tracker.kind = extractedExport.kind;
|
|
5999
|
+
continue;
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
const externalExport = {
|
|
6004
|
+
id: exportName,
|
|
6005
|
+
name: exportName,
|
|
6006
|
+
kind: "external",
|
|
6007
|
+
source: {
|
|
6008
|
+
package: externalPackage
|
|
6009
|
+
}
|
|
6010
|
+
};
|
|
6011
|
+
exports.push(externalExport);
|
|
6012
|
+
tracker.status = "success";
|
|
6013
|
+
tracker.kind = "external";
|
|
6014
|
+
} else {
|
|
6015
|
+
tracker.status = "skipped";
|
|
6016
|
+
tracker.skipReason = "no-declaration";
|
|
6017
|
+
}
|
|
6018
|
+
continue;
|
|
6019
|
+
}
|
|
6020
|
+
const exp = serializeDeclaration2(declaration, symbol, targetSymbol, exportName, ctx, isTypeOnly);
|
|
6021
|
+
if (exp) {
|
|
6022
|
+
exports.push(exp);
|
|
6023
|
+
tracker.status = "success";
|
|
6024
|
+
tracker.kind = exp.kind;
|
|
6025
|
+
} else {
|
|
6026
|
+
tracker.status = "skipped";
|
|
6027
|
+
tracker.skipReason = "internal";
|
|
6028
|
+
}
|
|
6029
|
+
} catch (err) {
|
|
6030
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
6031
|
+
tracker.status = "failed";
|
|
6032
|
+
tracker.error = errorMsg;
|
|
6033
|
+
diagnostics.push({
|
|
6034
|
+
message: `Failed to serialize '${exportName}': ${errorMsg}`,
|
|
6035
|
+
severity: "warning",
|
|
6036
|
+
code: "SERIALIZATION_FAILED"
|
|
6037
|
+
});
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
|
|
6041
|
+
const meta = await getPackageMeta(entryFile, baseDir);
|
|
6042
|
+
const types = ctx.typeRegistry.getAll();
|
|
6043
|
+
const projectBaseDir = baseDir ?? path8.dirname(entryFile);
|
|
6044
|
+
const definedTypes = new Set(types.map((t) => t.id));
|
|
6045
|
+
const forgottenExports = collectForgottenExports(exports, types, program, sourceFile, exportedIds, projectBaseDir, definedTypes);
|
|
6046
|
+
for (const forgotten of forgottenExports) {
|
|
6047
|
+
const refSummary = forgotten.referencedBy.slice(0, 3).map((r) => `${r.exportName} (${r.location})`).join(", ");
|
|
6048
|
+
const moreRefs = forgotten.referencedBy.length > 3 ? ` +${forgotten.referencedBy.length - 3} more` : "";
|
|
6049
|
+
if (forgotten.isExternal) {
|
|
6050
|
+
diagnostics.push({
|
|
6051
|
+
message: `External type '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
6052
|
+
severity: "info",
|
|
6053
|
+
code: "EXTERNAL_TYPE_REF",
|
|
6054
|
+
suggestion: forgotten.definedIn ? `Type is from: ${forgotten.definedIn}` : "Type is from an external package"
|
|
6055
|
+
});
|
|
6056
|
+
} else {
|
|
6057
|
+
diagnostics.push({
|
|
6058
|
+
message: `Forgotten export: '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
|
|
6059
|
+
severity: "warning",
|
|
6060
|
+
code: "FORGOTTEN_EXPORT",
|
|
6061
|
+
suggestion: forgotten.fix ?? `Export this type from your public API`,
|
|
6062
|
+
location: forgotten.definedIn ? { file: forgotten.definedIn } : undefined
|
|
6063
|
+
});
|
|
6064
|
+
}
|
|
6065
|
+
}
|
|
6066
|
+
const externalTypes = types.filter((t) => t.kind === "external");
|
|
6067
|
+
if (externalTypes.length > 0) {
|
|
6068
|
+
diagnostics.push({
|
|
6069
|
+
message: `${externalTypes.length} external type(s) from dependencies: ${externalTypes.slice(0, 5).map((t) => t.id).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
|
|
6070
|
+
severity: "info",
|
|
6071
|
+
code: "EXTERNAL_TYPES"
|
|
6072
|
+
});
|
|
6073
|
+
}
|
|
6074
|
+
let runtimeMetadata;
|
|
6075
|
+
if (options.schemaExtraction === "hybrid") {
|
|
6076
|
+
const projectBaseDir2 = baseDir || path8.dirname(entryFile);
|
|
6077
|
+
const runtimeResult = await extractStandardSchemasFromProject(entryFile, projectBaseDir2, {
|
|
6078
|
+
target: options.schemaTarget || "draft-2020-12",
|
|
6079
|
+
timeout: 15000
|
|
6080
|
+
});
|
|
6081
|
+
if (runtimeResult.schemas.size > 0) {
|
|
6082
|
+
const mergeResult = mergeRuntimeSchemas(exports, runtimeResult.schemas);
|
|
6083
|
+
exports = mergeResult.exports;
|
|
6084
|
+
const method = runtimeResult.info?.method === "direct-ts" ? `direct-ts (${runtimeResult.info.runtime})` : "compiled";
|
|
6085
|
+
runtimeMetadata = {
|
|
6086
|
+
extracted: runtimeResult.schemas.size,
|
|
6087
|
+
merged: mergeResult.merged,
|
|
6088
|
+
vendors: [...new Set([...runtimeResult.schemas.values()].map((s) => s.vendor))],
|
|
6089
|
+
errors: runtimeResult.errors,
|
|
6090
|
+
warnings: runtimeResult.warnings,
|
|
6091
|
+
method
|
|
6092
|
+
};
|
|
6093
|
+
}
|
|
6094
|
+
for (const error of runtimeResult.errors) {
|
|
6095
|
+
diagnostics.push({
|
|
6096
|
+
message: `Runtime schema extraction: ${error}`,
|
|
6097
|
+
severity: "warning",
|
|
6098
|
+
code: "RUNTIME_SCHEMA_ERROR"
|
|
6099
|
+
});
|
|
6100
|
+
}
|
|
6101
|
+
for (const warning of runtimeResult.warnings) {
|
|
6102
|
+
diagnostics.push({
|
|
6103
|
+
message: `Schema extraction skipped${warning.exportName ? ` (${warning.exportName})` : ""}: ${warning.message}`,
|
|
6104
|
+
severity: "warning",
|
|
6105
|
+
code: warning.code
|
|
6106
|
+
});
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6109
|
+
const normalizedExports = exports.map((exp) => normalizeExport(exp, { dialect: "draft-2020-12" }));
|
|
6110
|
+
const normalizedTypes = types.map((t) => normalizeType(t, { dialect: "draft-2020-12" }));
|
|
6111
|
+
const spec = {
|
|
6112
|
+
...includeSchema ? { $schema: SCHEMA_URL } : {},
|
|
6113
|
+
openpkg: SCHEMA_VERSION,
|
|
6114
|
+
meta,
|
|
6115
|
+
exports: normalizedExports,
|
|
6116
|
+
types: normalizedTypes,
|
|
6117
|
+
generation: {
|
|
6118
|
+
generator: "@openpkg-ts/sdk",
|
|
6119
|
+
timestamp: new Date().toISOString(),
|
|
6120
|
+
mode: isDtsSource ? "declaration-only" : "source",
|
|
6121
|
+
...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {},
|
|
6122
|
+
...isDtsSource && {
|
|
6123
|
+
limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
|
|
6124
|
+
},
|
|
6125
|
+
...verification.details.skipped.length > 0 && {
|
|
6126
|
+
skipped: verification.details.skipped
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
};
|
|
6130
|
+
const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
|
|
6131
|
+
const degradedMode = isDtsSource ? { reason: "dts-source", stats: computeDegradedStats(normalizedExports) } : undefined;
|
|
6132
|
+
if (verification.failed > 0) {
|
|
6133
|
+
const failedNames = verification.details.failed.map((f) => f.name).join(", ");
|
|
6134
|
+
diagnostics.push({
|
|
6135
|
+
message: `Export verification: ${verification.failed} export(s) failed: ${failedNames}`,
|
|
6136
|
+
severity: "warning",
|
|
6137
|
+
code: "EXPORT_VERIFICATION_FAILED",
|
|
6138
|
+
suggestion: "Check serialization errors for these exports"
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
return {
|
|
6142
|
+
spec,
|
|
6143
|
+
diagnostics,
|
|
6144
|
+
verification,
|
|
6145
|
+
...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {},
|
|
6146
|
+
...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {},
|
|
6147
|
+
...degradedMode ? { degradedMode } : {}
|
|
6148
|
+
};
|
|
6149
|
+
} finally {
|
|
6150
|
+
clearTypeDefinitionCache();
|
|
6151
|
+
}
|
|
6152
|
+
}
|
|
5940
6153
|
function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportName, ctx, isTypeOnly = false) {
|
|
5941
6154
|
let result = null;
|
|
5942
|
-
if (
|
|
6155
|
+
if (ts16.isFunctionDeclaration(declaration)) {
|
|
5943
6156
|
result = serializeFunctionExport(declaration, ctx);
|
|
5944
|
-
} else if (
|
|
6157
|
+
} else if (ts16.isClassDeclaration(declaration)) {
|
|
5945
6158
|
result = serializeClass(declaration, ctx);
|
|
5946
|
-
} else if (
|
|
6159
|
+
} else if (ts16.isInterfaceDeclaration(declaration)) {
|
|
5947
6160
|
result = serializeInterface(declaration, ctx);
|
|
5948
|
-
} else if (
|
|
6161
|
+
} else if (ts16.isTypeAliasDeclaration(declaration)) {
|
|
5949
6162
|
result = serializeTypeAlias(declaration, ctx);
|
|
5950
|
-
} else if (
|
|
6163
|
+
} else if (ts16.isEnumDeclaration(declaration)) {
|
|
5951
6164
|
result = serializeEnum(declaration, ctx);
|
|
5952
|
-
} else if (
|
|
6165
|
+
} else if (ts16.isVariableDeclaration(declaration)) {
|
|
5953
6166
|
const varStatement = declaration.parent?.parent;
|
|
5954
|
-
if (varStatement &&
|
|
5955
|
-
if (declaration.initializer &&
|
|
5956
|
-
const varName =
|
|
6167
|
+
if (varStatement && ts16.isVariableStatement(varStatement)) {
|
|
6168
|
+
if (declaration.initializer && ts16.isArrowFunction(declaration.initializer)) {
|
|
6169
|
+
const varName = ts16.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
|
|
5957
6170
|
result = serializeFunctionExport(declaration.initializer, ctx, varName);
|
|
5958
6171
|
} else {
|
|
5959
6172
|
result = serializeVariable(declaration, varStatement, ctx);
|
|
5960
6173
|
}
|
|
5961
6174
|
}
|
|
5962
|
-
} else if (
|
|
6175
|
+
} else if (ts16.isNamespaceExport(declaration) || ts16.isModuleDeclaration(declaration)) {
|
|
5963
6176
|
try {
|
|
5964
6177
|
result = serializeNamespaceExport(exportSymbol, exportName, ctx);
|
|
5965
6178
|
} catch {
|
|
@@ -5972,7 +6185,7 @@ function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportN
|
|
|
5972
6185
|
examples: []
|
|
5973
6186
|
};
|
|
5974
6187
|
}
|
|
5975
|
-
} else if (
|
|
6188
|
+
} else if (ts16.isNamespaceImport(declaration)) {
|
|
5976
6189
|
try {
|
|
5977
6190
|
result = serializeNamespaceExport(exportSymbol, exportName, ctx);
|
|
5978
6191
|
} catch {
|
|
@@ -5985,7 +6198,7 @@ function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportN
|
|
|
5985
6198
|
examples: []
|
|
5986
6199
|
};
|
|
5987
6200
|
}
|
|
5988
|
-
} else if (
|
|
6201
|
+
} else if (ts16.isSourceFile(declaration)) {
|
|
5989
6202
|
try {
|
|
5990
6203
|
result = serializeNamespaceExport(exportSymbol, exportName, ctx);
|
|
5991
6204
|
} catch {
|
|
@@ -6015,7 +6228,7 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
|
|
|
6015
6228
|
const members = [];
|
|
6016
6229
|
const checker = ctx.program.getTypeChecker();
|
|
6017
6230
|
let targetSymbol = symbol;
|
|
6018
|
-
if (symbol.flags &
|
|
6231
|
+
if (symbol.flags & ts16.SymbolFlags.Alias) {
|
|
6019
6232
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
6020
6233
|
if (aliased && aliased !== symbol) {
|
|
6021
6234
|
targetSymbol = aliased;
|
|
@@ -6042,31 +6255,31 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
|
|
|
6042
6255
|
function serializeNamespaceMember(symbol, memberName, ctx) {
|
|
6043
6256
|
const checker = ctx.program.getTypeChecker();
|
|
6044
6257
|
let targetSymbol = symbol;
|
|
6045
|
-
if (symbol.flags &
|
|
6258
|
+
if (symbol.flags & ts16.SymbolFlags.Alias) {
|
|
6046
6259
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
6047
6260
|
if (aliased && aliased !== symbol) {
|
|
6048
6261
|
targetSymbol = aliased;
|
|
6049
6262
|
}
|
|
6050
6263
|
}
|
|
6051
6264
|
const declarations = targetSymbol.declarations ?? [];
|
|
6052
|
-
const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !==
|
|
6265
|
+
const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts16.SyntaxKind.ExportSpecifier) || declarations[0];
|
|
6053
6266
|
if (!declaration)
|
|
6054
6267
|
return null;
|
|
6055
6268
|
const type = checker.getTypeAtLocation(declaration);
|
|
6056
6269
|
const callSignatures = type.getCallSignatures();
|
|
6057
6270
|
const deprecated = isSymbolDeprecated(targetSymbol);
|
|
6058
6271
|
let kind = "variable";
|
|
6059
|
-
if (
|
|
6272
|
+
if (ts16.isFunctionDeclaration(declaration) || ts16.isFunctionExpression(declaration)) {
|
|
6060
6273
|
kind = "function";
|
|
6061
|
-
} else if (
|
|
6274
|
+
} else if (ts16.isClassDeclaration(declaration)) {
|
|
6062
6275
|
kind = "class";
|
|
6063
|
-
} else if (
|
|
6276
|
+
} else if (ts16.isInterfaceDeclaration(declaration)) {
|
|
6064
6277
|
kind = "interface";
|
|
6065
|
-
} else if (
|
|
6278
|
+
} else if (ts16.isTypeAliasDeclaration(declaration)) {
|
|
6066
6279
|
kind = "type";
|
|
6067
|
-
} else if (
|
|
6280
|
+
} else if (ts16.isEnumDeclaration(declaration)) {
|
|
6068
6281
|
kind = "enum";
|
|
6069
|
-
} else if (
|
|
6282
|
+
} else if (ts16.isVariableDeclaration(declaration)) {
|
|
6070
6283
|
if (callSignatures.length > 0) {
|
|
6071
6284
|
kind = "function";
|
|
6072
6285
|
}
|
|
@@ -6113,11 +6326,11 @@ function getJSDocFromExportSymbol(symbol) {
|
|
|
6113
6326
|
const examples = [];
|
|
6114
6327
|
const decl = symbol.declarations?.[0];
|
|
6115
6328
|
if (decl) {
|
|
6116
|
-
const exportDecl =
|
|
6117
|
-
if (exportDecl &&
|
|
6118
|
-
const jsDocs =
|
|
6329
|
+
const exportDecl = ts16.isNamespaceExport(decl) ? decl.parent : decl;
|
|
6330
|
+
if (exportDecl && ts16.isExportDeclaration(exportDecl)) {
|
|
6331
|
+
const jsDocs = ts16.getJSDocCommentsAndTags(exportDecl);
|
|
6119
6332
|
for (const doc of jsDocs) {
|
|
6120
|
-
if (
|
|
6333
|
+
if (ts16.isJSDoc(doc) && doc.comment) {
|
|
6121
6334
|
const commentText = typeof doc.comment === "string" ? doc.comment : doc.comment.map((c) => ("text" in c) ? c.text : "").join("");
|
|
6122
6335
|
if (commentText) {
|
|
6123
6336
|
return {
|
|
@@ -6179,7 +6392,7 @@ function createEmptySpec(entryFile, includeSchema, isDtsSource) {
|
|
|
6179
6392
|
return {
|
|
6180
6393
|
...includeSchema ? { $schema: SCHEMA_URL } : {},
|
|
6181
6394
|
openpkg: SCHEMA_VERSION,
|
|
6182
|
-
meta: { name:
|
|
6395
|
+
meta: { name: path8.basename(entryFile, path8.extname(entryFile)) },
|
|
6183
6396
|
exports: [],
|
|
6184
6397
|
generation: {
|
|
6185
6398
|
generator: "@openpkg-ts/sdk",
|
|
@@ -6192,19 +6405,19 @@ function createEmptySpec(entryFile, includeSchema, isDtsSource) {
|
|
|
6192
6405
|
};
|
|
6193
6406
|
}
|
|
6194
6407
|
async function getPackageMeta(entryFile, baseDir) {
|
|
6195
|
-
const searchDir = baseDir ??
|
|
6196
|
-
const pkgPath =
|
|
6408
|
+
const searchDir = baseDir ?? path8.dirname(entryFile);
|
|
6409
|
+
const pkgPath = path8.join(searchDir, "package.json");
|
|
6197
6410
|
try {
|
|
6198
6411
|
if (fs7.existsSync(pkgPath)) {
|
|
6199
6412
|
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
6200
6413
|
return {
|
|
6201
|
-
name: pkg.name ??
|
|
6414
|
+
name: pkg.name ?? path8.basename(searchDir),
|
|
6202
6415
|
version: pkg.version,
|
|
6203
6416
|
description: pkg.description
|
|
6204
6417
|
};
|
|
6205
6418
|
}
|
|
6206
6419
|
} catch {}
|
|
6207
|
-
return { name:
|
|
6420
|
+
return { name: path8.basename(searchDir) };
|
|
6208
6421
|
}
|
|
6209
6422
|
|
|
6210
6423
|
// src/primitives/spec.ts
|
|
@@ -6326,6 +6539,7 @@ export {
|
|
|
6326
6539
|
analyzeSpec,
|
|
6327
6540
|
TypeRegistry,
|
|
6328
6541
|
QueryBuilder,
|
|
6542
|
+
CacheManager,
|
|
6329
6543
|
CONFIG_FILENAME,
|
|
6330
6544
|
BUILTIN_TYPE_SCHEMAS,
|
|
6331
6545
|
ARRAY_PROTOTYPE_METHODS
|