@nudojs/harvester 0.2.7 → 0.2.8-beta.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/index.d.ts +29 -1
- package/dist/index.js +786 -149
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import { Abs } from '@nudojs/core';
|
|
2
2
|
|
|
3
|
+
type DtsExportDraft = {
|
|
4
|
+
name: string;
|
|
5
|
+
/** `fn({ … }, …)` 或值约束 DSL;不可投影 → undefined + note */
|
|
6
|
+
dsl?: string;
|
|
7
|
+
note?: string;
|
|
8
|
+
kind: "function" | "value" | "class" | "other";
|
|
9
|
+
};
|
|
10
|
+
type DtsContractDraft = {
|
|
11
|
+
label: string;
|
|
12
|
+
files: string[];
|
|
13
|
+
exports: DtsExportDraft[];
|
|
14
|
+
draftSource: string;
|
|
15
|
+
stats: {
|
|
16
|
+
files: number;
|
|
17
|
+
exports: number;
|
|
18
|
+
skipped: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
/** 组装 `@nudo:draft` 模块(与 formatDraftModule 同纪律:不 ambient 绑定)。 */
|
|
22
|
+
declare function formatDtsContractDraft(label: string, files: string[], exports: DtsExportDraft[]): string;
|
|
23
|
+
/**
|
|
24
|
+
* 从 .d.ts 路径列表生成契约草稿(不写盘)。
|
|
25
|
+
* `label` 用于头注释(包名或描述)。
|
|
26
|
+
*/
|
|
27
|
+
declare function dtsToContractDraft(dtsFiles: string[], label?: string): DtsContractDraft;
|
|
28
|
+
/** 目录/文件入口:内部解析 .d.ts 列表。 */
|
|
29
|
+
declare function dtsPathToContractDraft(path: string, label?: string): DtsContractDraft;
|
|
30
|
+
|
|
3
31
|
/**
|
|
4
32
|
* Harvested env:Abs 原生(与 EnvDefinition 同形)。
|
|
5
33
|
* 收集与物化全程 Abs,不再经 TypeValue 桥。
|
|
@@ -19,4 +47,4 @@ declare function harvestDts(files: string[], opts?: {
|
|
|
19
47
|
}): HarvestedEnv;
|
|
20
48
|
declare function emitEnvModule(env: HarvestedEnv, pkgName: string): string;
|
|
21
49
|
|
|
22
|
-
export { type HarvestedEnv, emitEnvModule, harvestDts };
|
|
50
|
+
export { type DtsContractDraft, type DtsExportDraft, type HarvestedEnv, dtsPathToContractDraft, dtsToContractDraft, emitEnvModule, formatDtsContractDraft, harvestDts };
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,364 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { readFileSync, statSync } from "fs";
|
|
3
|
-
import
|
|
2
|
+
import { readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
3
|
+
import ts2 from "typescript";
|
|
4
4
|
import {
|
|
5
5
|
abs as makeAbs,
|
|
6
6
|
lit as termLit,
|
|
7
|
+
v as termVar,
|
|
7
8
|
numLit,
|
|
8
9
|
strLit,
|
|
9
10
|
boolLit,
|
|
10
11
|
objOf,
|
|
11
|
-
joinAbs
|
|
12
|
+
joinAbs,
|
|
13
|
+
relationFn,
|
|
14
|
+
getFnImpl,
|
|
15
|
+
substAbs
|
|
12
16
|
} from "@nudojs/core";
|
|
17
|
+
|
|
18
|
+
// src/dts-contract-draft.ts
|
|
19
|
+
import { readFileSync, existsSync, statSync, readdirSync } from "fs";
|
|
20
|
+
import { basename, dirname, join } from "path";
|
|
21
|
+
import ts from "typescript";
|
|
22
|
+
var BUILDERS = [
|
|
23
|
+
"fn",
|
|
24
|
+
"number",
|
|
25
|
+
"string",
|
|
26
|
+
"boolean",
|
|
27
|
+
"any",
|
|
28
|
+
"shape",
|
|
29
|
+
"array",
|
|
30
|
+
"lit",
|
|
31
|
+
"union"
|
|
32
|
+
];
|
|
33
|
+
function keywordDsl(node) {
|
|
34
|
+
switch (node.kind) {
|
|
35
|
+
case ts.SyntaxKind.NumberKeyword:
|
|
36
|
+
return "number()";
|
|
37
|
+
case ts.SyntaxKind.StringKeyword:
|
|
38
|
+
return "string()";
|
|
39
|
+
case ts.SyntaxKind.BooleanKeyword:
|
|
40
|
+
return "boolean()";
|
|
41
|
+
case ts.SyntaxKind.AnyKeyword:
|
|
42
|
+
case ts.SyntaxKind.UnknownKeyword:
|
|
43
|
+
case ts.SyntaxKind.VoidKeyword:
|
|
44
|
+
case ts.SyntaxKind.UndefinedKeyword:
|
|
45
|
+
case ts.SyntaxKind.NullKeyword:
|
|
46
|
+
case ts.SyntaxKind.ObjectKeyword:
|
|
47
|
+
case ts.SyntaxKind.NeverKeyword:
|
|
48
|
+
return "any()";
|
|
49
|
+
case ts.SyntaxKind.BigIntKeyword:
|
|
50
|
+
case ts.SyntaxKind.SymbolKeyword:
|
|
51
|
+
return void 0;
|
|
52
|
+
default:
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function litDsl(node) {
|
|
57
|
+
const lit = node.literal;
|
|
58
|
+
if (ts.isStringLiteral(lit)) return `lit(${JSON.stringify(lit.text)})`;
|
|
59
|
+
if (ts.isNumericLiteral(lit)) return `lit(${lit.text})`;
|
|
60
|
+
if (lit.kind === ts.SyntaxKind.TrueKeyword) return "lit(true)";
|
|
61
|
+
if (lit.kind === ts.SyntaxKind.FalseKeyword) return "lit(false)";
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
function typeRefName(node) {
|
|
65
|
+
const n = node.typeName;
|
|
66
|
+
if (ts.isIdentifier(n)) return n.text;
|
|
67
|
+
if (ts.isQualifiedName(n)) {
|
|
68
|
+
const parts = [];
|
|
69
|
+
let cur = n;
|
|
70
|
+
while (ts.isQualifiedName(cur)) {
|
|
71
|
+
parts.unshift(cur.right.text);
|
|
72
|
+
cur = cur.left;
|
|
73
|
+
}
|
|
74
|
+
if (ts.isIdentifier(cur)) parts.unshift(cur.text);
|
|
75
|
+
return parts.join(".");
|
|
76
|
+
}
|
|
77
|
+
return "?";
|
|
78
|
+
}
|
|
79
|
+
function typeToDsl(node, depth = 0) {
|
|
80
|
+
if (!node || depth > 6) return "any()";
|
|
81
|
+
const kw = keywordDsl(node);
|
|
82
|
+
if (kw !== void 0) return kw;
|
|
83
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
84
|
+
return litDsl(node) ?? "any()";
|
|
85
|
+
}
|
|
86
|
+
if (ts.isArrayTypeNode(node)) {
|
|
87
|
+
const el = typeToDsl(node.elementType, depth + 1) ?? "any()";
|
|
88
|
+
return `array(${el})`;
|
|
89
|
+
}
|
|
90
|
+
if (ts.isUnionTypeNode(node)) {
|
|
91
|
+
const parts = node.types.map((t) => typeToDsl(t, depth + 1) ?? "any()");
|
|
92
|
+
if (parts.length === 0) return "any()";
|
|
93
|
+
if (parts.length === 1) return parts[0];
|
|
94
|
+
return `union(${parts.join(", ")})`;
|
|
95
|
+
}
|
|
96
|
+
if (ts.isParenthesizedTypeNode(node)) {
|
|
97
|
+
return typeToDsl(node.type, depth + 1);
|
|
98
|
+
}
|
|
99
|
+
if (ts.isTypeLiteralNode(node)) {
|
|
100
|
+
const fields = [];
|
|
101
|
+
for (const m of node.members) {
|
|
102
|
+
if (!ts.isPropertySignature(m)) continue;
|
|
103
|
+
const key = m.name && (ts.isIdentifier(m.name) || ts.isStringLiteral(m.name)) ? ts.isIdentifier(m.name) ? m.name.text : m.name.text : void 0;
|
|
104
|
+
if (!key) continue;
|
|
105
|
+
const optional = m.questionToken ? true : false;
|
|
106
|
+
const val = typeToDsl(m.type, depth + 1) ?? "any()";
|
|
107
|
+
fields.push(optional ? `${key}: ${val}.optional()` : `${key}: ${val}`);
|
|
108
|
+
}
|
|
109
|
+
return fields.length === 0 ? "shape({})" : `shape({ ${fields.join(", ")} })`;
|
|
110
|
+
}
|
|
111
|
+
if (ts.isFunctionTypeNode(node) || ts.isConstructorTypeNode(node)) {
|
|
112
|
+
return fnSignatureDsl(node.parameters, node.type, depth);
|
|
113
|
+
}
|
|
114
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
115
|
+
const name = typeRefName(node);
|
|
116
|
+
const args = node.typeArguments ?? [];
|
|
117
|
+
if (name === "Array" || name === "ReadonlyArray" || name === "readonly") {
|
|
118
|
+
const el = args[0] ? typeToDsl(args[0], depth + 1) : "any()";
|
|
119
|
+
return `array(${el ?? "any()"})`;
|
|
120
|
+
}
|
|
121
|
+
if (name === "Promise") {
|
|
122
|
+
return args[0] ? typeToDsl(args[0], depth + 1) : "any()";
|
|
123
|
+
}
|
|
124
|
+
if (name === "Record") {
|
|
125
|
+
const val = args[1] ? typeToDsl(args[1], depth + 1) : "any()";
|
|
126
|
+
return `shape({}) /* open Record \u2192 ${val ?? "any()"} */`;
|
|
127
|
+
}
|
|
128
|
+
if (name === "Partial" && args[0]) {
|
|
129
|
+
const inner = typeToDsl(args[0], depth + 1);
|
|
130
|
+
return inner ?? "any()";
|
|
131
|
+
}
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
function fnSignatureDsl(params, ret, depth) {
|
|
140
|
+
const fields = [];
|
|
141
|
+
const notes = [];
|
|
142
|
+
params.forEach((p, i) => {
|
|
143
|
+
let name;
|
|
144
|
+
if (p.name && ts.isIdentifier(p.name)) name = p.name.text;
|
|
145
|
+
else name = `p${i}`;
|
|
146
|
+
if (p.dotDotDotToken) {
|
|
147
|
+
notes.push(`${name}: rest \u2014 array()`);
|
|
148
|
+
fields.push(`${name}: array(any())`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const optional = Boolean(p.questionToken) || p.initializer;
|
|
152
|
+
let dsl = typeToDsl(p.type, depth + 1);
|
|
153
|
+
if (dsl === void 0) {
|
|
154
|
+
notes.push(`${name}: unmodeled type \u2192 any()`);
|
|
155
|
+
dsl = "any()";
|
|
156
|
+
}
|
|
157
|
+
fields.push(optional ? `${name}: ${dsl}.optional()` : `${name}: ${dsl}`);
|
|
158
|
+
});
|
|
159
|
+
let retDsl = typeToDsl(ret, depth + 1);
|
|
160
|
+
if (retDsl === void 0) {
|
|
161
|
+
notes.push(`returns: unmodeled \u2192 any()`);
|
|
162
|
+
retDsl = "any()";
|
|
163
|
+
}
|
|
164
|
+
const obj = fields.length === 0 ? "{}" : `{ ${fields.join(", ")} }`;
|
|
165
|
+
return `fn(${obj}, ${retDsl})`;
|
|
166
|
+
}
|
|
167
|
+
function pickName(decl) {
|
|
168
|
+
return decl.name && ts.isIdentifier(decl.name) ? decl.name.text : void 0;
|
|
169
|
+
}
|
|
170
|
+
function collectExports(sourceFile) {
|
|
171
|
+
const out = [];
|
|
172
|
+
const push = (e) => {
|
|
173
|
+
out.push(e);
|
|
174
|
+
};
|
|
175
|
+
for (const stmt of sourceFile.statements) {
|
|
176
|
+
if ((ts.isFunctionDeclaration(stmt) || ts.isMethodSignature(stmt)) && stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
177
|
+
const name = pickName(stmt);
|
|
178
|
+
if (!name) continue;
|
|
179
|
+
const fn = stmt;
|
|
180
|
+
const dsl = fnSignatureDsl(fn.parameters, fn.type, 0);
|
|
181
|
+
push({ name, dsl, kind: "function" });
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (ts.isFunctionDeclaration(stmt) && pickName(stmt)) {
|
|
185
|
+
const isExport = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
186
|
+
if (!isExport) continue;
|
|
187
|
+
const name = pickName(stmt);
|
|
188
|
+
push({ name, dsl: fnSignatureDsl(stmt.parameters, stmt.type, 0), kind: "function" });
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (ts.isVariableStatement(stmt)) {
|
|
192
|
+
const isExport = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
193
|
+
if (!isExport) continue;
|
|
194
|
+
for (const d of stmt.declarationList.declarations) {
|
|
195
|
+
const name = pickName(d);
|
|
196
|
+
if (!name) continue;
|
|
197
|
+
const dsl = typeToDsl(d.type, 0);
|
|
198
|
+
if (dsl === void 0) {
|
|
199
|
+
push({ name, note: "unmodeled type", kind: "value" });
|
|
200
|
+
} else if (dsl.startsWith("fn(")) {
|
|
201
|
+
push({ name, dsl, kind: "function" });
|
|
202
|
+
} else {
|
|
203
|
+
push({ name, dsl, kind: "value" });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (ts.isClassDeclaration(stmt)) {
|
|
209
|
+
const isExport = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
210
|
+
if (!isExport) continue;
|
|
211
|
+
const name = pickName(stmt);
|
|
212
|
+
if (!name) {
|
|
213
|
+
push({ name: "default", note: "anonymous class", kind: "class" });
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
let anyMethod = false;
|
|
217
|
+
for (const m of stmt.members) {
|
|
218
|
+
if (ts.isMethodDeclaration(m) || ts.isMethodSignature(m)) {
|
|
219
|
+
const mname = pickName(m);
|
|
220
|
+
if (!mname) continue;
|
|
221
|
+
anyMethod = true;
|
|
222
|
+
push({
|
|
223
|
+
name: `${name}.${mname}`,
|
|
224
|
+
dsl: fnSignatureDsl(m.parameters, m.type, 0),
|
|
225
|
+
kind: "function"
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (!anyMethod) {
|
|
230
|
+
push({ name, note: "class without public methods projected", kind: "class" });
|
|
231
|
+
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (ts.isExportAssignment(stmt)) {
|
|
235
|
+
push({ name: "default", note: "export assignment \u2014 bind via sidecar default", kind: "other" });
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (ts.isInterfaceDeclaration(stmt) || ts.isTypeAliasDeclaration(stmt)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
243
|
+
}
|
|
244
|
+
function draftExportName(name) {
|
|
245
|
+
return name.includes(".") ? name.replace(/\./g, "_") : name;
|
|
246
|
+
}
|
|
247
|
+
function formatDtsContractDraft(label, files, exports) {
|
|
248
|
+
const draftable = exports.filter((e) => e.dsl !== void 0);
|
|
249
|
+
const used = /* @__PURE__ */ new Set(["fn"]);
|
|
250
|
+
for (const e of draftable) {
|
|
251
|
+
for (const b of BUILDERS) {
|
|
252
|
+
if (new RegExp(`\\b${b}\\b`).test(e.dsl)) used.add(b);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (draftable.some((e) => /\bany\s*\(/.test(e.dsl))) used.add("any");
|
|
256
|
+
const importList = BUILDERS.filter((b) => used.has(b)).join(", ");
|
|
257
|
+
const lines = [
|
|
258
|
+
"// @nudo:draft",
|
|
259
|
+
`// Generated by \`nudo contract --from-dts\` from ${label}`,
|
|
260
|
+
`// Sources: ${files.map((f) => basename(f)).join(", ")}`,
|
|
261
|
+
"//",
|
|
262
|
+
"// Reverse-engineered from TypeScript declarations \u2014 NOT a sidecar contract.",
|
|
263
|
+
"// This file is never loaded for check. Review each export, then copy it",
|
|
264
|
+
"// into <target>.nudo.js to accept (that is when obligations go live).",
|
|
265
|
+
"//",
|
|
266
|
+
"// After accept: strengthen with Pred builders (number().gt(0) \u2026) \u2014",
|
|
267
|
+
"// dts cannot express algebraic implications (x>0 \u21D2 x+1>1).",
|
|
268
|
+
"",
|
|
269
|
+
`import { ${importList} } from "@nudojs/core";`,
|
|
270
|
+
""
|
|
271
|
+
];
|
|
272
|
+
if (draftable.length === 0) {
|
|
273
|
+
lines.push("// (no projectable exports)");
|
|
274
|
+
lines.push("");
|
|
275
|
+
}
|
|
276
|
+
for (const e of exports) {
|
|
277
|
+
if (e.dsl === void 0) {
|
|
278
|
+
lines.push(`// ${e.name} \u2014 skipped (${e.note ?? "unmodeled"})`);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (e.note) lines.push(`// ${e.name} \u2014 ${e.note}`);
|
|
282
|
+
else lines.push(`// ${e.name} \u2014 from TypeScript`);
|
|
283
|
+
lines.push(`export const ${draftExportName(e.name)} = ${e.dsl};`);
|
|
284
|
+
if (e.name.includes(".")) {
|
|
285
|
+
lines.push(`// sidecar key may also be written as \`${e.name}\``);
|
|
286
|
+
}
|
|
287
|
+
lines.push("");
|
|
288
|
+
}
|
|
289
|
+
return lines.join("\n");
|
|
290
|
+
}
|
|
291
|
+
function readDtsFiles(paths, maxFiles = 16) {
|
|
292
|
+
const out = [];
|
|
293
|
+
const walk = (dir, depth) => {
|
|
294
|
+
if (depth > 6 || out.length >= maxFiles * 3) return;
|
|
295
|
+
let entries;
|
|
296
|
+
try {
|
|
297
|
+
entries = readdirSync(dir);
|
|
298
|
+
} catch {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
for (const name of entries) {
|
|
302
|
+
if (name === "node_modules" || name === "test" || name === "__tests__") continue;
|
|
303
|
+
const p = join(dir, name);
|
|
304
|
+
let st;
|
|
305
|
+
try {
|
|
306
|
+
st = statSync(p);
|
|
307
|
+
} catch {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (st.isDirectory()) walk(p, depth + 1);
|
|
311
|
+
else if (name.endsWith(".d.ts") && !name.endsWith(".d.ts.map")) out.push(p);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
for (const p of paths) {
|
|
315
|
+
if (!existsSync(p)) continue;
|
|
316
|
+
const st = statSync(p);
|
|
317
|
+
if (st.isDirectory()) walk(p, 0);
|
|
318
|
+
else if (/\.d\.ts$/.test(p) || /\.(m)?ts$/.test(p)) {
|
|
319
|
+
if (!p.endsWith(".d.ts.map")) out.push(p);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return out.slice(0, maxFiles);
|
|
323
|
+
}
|
|
324
|
+
function dtsToContractDraft(dtsFiles, label) {
|
|
325
|
+
const files = dtsFiles.filter((f) => existsSync(f));
|
|
326
|
+
const exports = [];
|
|
327
|
+
let skippedFiles = 0;
|
|
328
|
+
for (const file of files) {
|
|
329
|
+
let content;
|
|
330
|
+
try {
|
|
331
|
+
content = readFileSync(file, "utf8");
|
|
332
|
+
} catch {
|
|
333
|
+
skippedFiles++;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const sf = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);
|
|
337
|
+
for (const e of collectExports(sf)) {
|
|
338
|
+
if (exports.some((x) => x.name === e.name && x.dsl)) continue;
|
|
339
|
+
exports.push(e);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const name = label ?? (files[0] ? basename(files[0]).replace(/\.d\.ts$/, "") : "dts");
|
|
343
|
+
const draftSource = formatDtsContractDraft(name, files, exports);
|
|
344
|
+
return {
|
|
345
|
+
label: name,
|
|
346
|
+
files,
|
|
347
|
+
exports,
|
|
348
|
+
draftSource,
|
|
349
|
+
stats: {
|
|
350
|
+
files: files.length - skippedFiles,
|
|
351
|
+
exports: exports.filter((e) => e.dsl !== void 0).length,
|
|
352
|
+
skipped: exports.filter((e) => e.dsl === void 0).length + skippedFiles
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function dtsPathToContractDraft(path, label) {
|
|
357
|
+
const files = readDtsFiles([path]);
|
|
358
|
+
return dtsToContractDraft(files, label ?? basename(path).replace(/\.d\.ts$/, ""));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/index.ts
|
|
13
362
|
var MAX_ALIAS_DEPTH = 8;
|
|
14
363
|
function scopeKey(scope) {
|
|
15
364
|
return scope.moduleName ?? "\0global";
|
|
@@ -46,6 +395,25 @@ function absArr(element) {
|
|
|
46
395
|
function absPromise(inner) {
|
|
47
396
|
return absExact({ k: "eff", eff: "promise", inner });
|
|
48
397
|
}
|
|
398
|
+
function absMapType(name, key, value) {
|
|
399
|
+
return absExact({
|
|
400
|
+
k: "brand",
|
|
401
|
+
name,
|
|
402
|
+
shape: absObj({
|
|
403
|
+
__key: key,
|
|
404
|
+
__value: value
|
|
405
|
+
})
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function absSetType(name, elem) {
|
|
409
|
+
return absExact({
|
|
410
|
+
k: "brand",
|
|
411
|
+
name,
|
|
412
|
+
shape: absObj({
|
|
413
|
+
__elem: elem
|
|
414
|
+
})
|
|
415
|
+
});
|
|
416
|
+
}
|
|
49
417
|
function absObj(properties) {
|
|
50
418
|
const slots = {};
|
|
51
419
|
for (const [k, v] of Object.entries(properties)) {
|
|
@@ -56,14 +424,16 @@ function absObj(properties) {
|
|
|
56
424
|
function absBrand(name, properties) {
|
|
57
425
|
return absExact({ k: "brand", name, shape: absObj(properties) });
|
|
58
426
|
}
|
|
59
|
-
function absFnSig(paramTypes, returnType) {
|
|
60
|
-
return
|
|
61
|
-
k: "fn",
|
|
427
|
+
function absFnSig(paramTypes, returnType, extra) {
|
|
428
|
+
return relationFn(paramTypes, returnType, {
|
|
62
429
|
params: paramTypes.map((_, i) => `_arg${i}`),
|
|
63
|
-
|
|
64
|
-
|
|
430
|
+
conf: "exact",
|
|
431
|
+
...extra ?? {}
|
|
65
432
|
});
|
|
66
433
|
}
|
|
434
|
+
function typeVarAbs(name) {
|
|
435
|
+
return makeAbs({ k: "any" }, termVar(name), void 0, "path");
|
|
436
|
+
}
|
|
67
437
|
function absUnion(members) {
|
|
68
438
|
if (members.length === 0) return absNever();
|
|
69
439
|
return members.reduce((acc, m) => joinAbs(acc, m));
|
|
@@ -71,6 +441,19 @@ function absUnion(members) {
|
|
|
71
441
|
function isPlainUnknown(a) {
|
|
72
442
|
return a.shape.k === "unknown" && !(a.term?.op === "lit");
|
|
73
443
|
}
|
|
444
|
+
function hasTypeVar(a, depth = 0) {
|
|
445
|
+
if (depth > 6) return false;
|
|
446
|
+
if (a.term?.op === "var") return true;
|
|
447
|
+
const s = a.shape;
|
|
448
|
+
if (s.k === "arr") return hasTypeVar(s.element, depth + 1);
|
|
449
|
+
if (s.k === "tuple") return s.elements.some((e) => hasTypeVar(e, depth + 1));
|
|
450
|
+
if (s.k === "sum") return s.members.some((m) => hasTypeVar(m, depth + 1));
|
|
451
|
+
if (s.k === "obj") return Object.values(s.slots).some((sl) => hasTypeVar(sl.value, depth + 1));
|
|
452
|
+
if (s.k === "fn") {
|
|
453
|
+
return (s.paramTypes ?? []).some((p) => hasTypeVar(p, depth + 1)) || (s.returnType ? hasTypeVar(s.returnType, depth + 1) : false);
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
74
457
|
function harvestDts(files, opts) {
|
|
75
458
|
const maxBytes = opts?.maxFileBytes ?? 15e5;
|
|
76
459
|
const deadline = opts?.maxMs !== void 0 ? Date.now() + opts.maxMs : void 0;
|
|
@@ -84,6 +467,7 @@ function harvestDts(files, opts) {
|
|
|
84
467
|
classes: /* @__PURE__ */ new Map(),
|
|
85
468
|
instanceCache: /* @__PURE__ */ new Map(),
|
|
86
469
|
expanding: /* @__PURE__ */ new Set(),
|
|
470
|
+
typeParams: /* @__PURE__ */ new Set(),
|
|
87
471
|
moduleAliases: [],
|
|
88
472
|
importEquals: /* @__PURE__ */ new Map(),
|
|
89
473
|
declaredModules: /* @__PURE__ */ new Set(),
|
|
@@ -99,17 +483,17 @@ function harvestDts(files, opts) {
|
|
|
99
483
|
}
|
|
100
484
|
let content;
|
|
101
485
|
try {
|
|
102
|
-
const st =
|
|
486
|
+
const st = statSync2(file);
|
|
103
487
|
if (st.size > maxBytes) {
|
|
104
488
|
ctx.skipped++;
|
|
105
489
|
continue;
|
|
106
490
|
}
|
|
107
|
-
content =
|
|
491
|
+
content = readFileSync2(file, "utf8");
|
|
108
492
|
} catch {
|
|
109
493
|
ctx.skipped++;
|
|
110
494
|
continue;
|
|
111
495
|
}
|
|
112
|
-
const sourceFile =
|
|
496
|
+
const sourceFile = ts2.createSourceFile(file, content, ts2.ScriptTarget.Latest, true);
|
|
113
497
|
collectStatements(ctx, sourceFile.statements, { moduleName: void 0, ns: [] });
|
|
114
498
|
parsed++;
|
|
115
499
|
}
|
|
@@ -141,7 +525,7 @@ function emitEnvModule(env, pkgName) {
|
|
|
141
525
|
constLines.push("");
|
|
142
526
|
}
|
|
143
527
|
const lines = [];
|
|
144
|
-
lines.push("// Auto-generated by
|
|
528
|
+
lines.push("// Auto-generated by @nudojs/harvester \u2014 DO NOT EDIT");
|
|
145
529
|
lines.push(`// Source package: ${pkgName}`);
|
|
146
530
|
lines.push(
|
|
147
531
|
'import { num, str, bool, never as absNever, unknown as absUnknown, numLit, strLit, boolLit, objOf, relationFn, abs as makeAbs } from "@nudojs/core";'
|
|
@@ -185,13 +569,13 @@ function collectStatements(ctx, statements, scope) {
|
|
|
185
569
|
}
|
|
186
570
|
}
|
|
187
571
|
function collectStatement(ctx, stmt, scope) {
|
|
188
|
-
if (
|
|
572
|
+
if (ts2.isModuleDeclaration(stmt)) {
|
|
189
573
|
const body = stmt.body;
|
|
190
|
-
if (!body || !
|
|
574
|
+
if (!body || !ts2.isModuleBlock(body)) {
|
|
191
575
|
ctx.skipped++;
|
|
192
576
|
return;
|
|
193
577
|
}
|
|
194
|
-
if (
|
|
578
|
+
if (ts2.isStringLiteral(stmt.name)) {
|
|
195
579
|
ctx.declaredModules.add(stmt.name.text);
|
|
196
580
|
collectStatements(ctx, body.statements, { moduleName: stmt.name.text, ns: [] });
|
|
197
581
|
} else if (stmt.name.text === "global") {
|
|
@@ -201,7 +585,7 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
201
585
|
}
|
|
202
586
|
return;
|
|
203
587
|
}
|
|
204
|
-
if (
|
|
588
|
+
if (ts2.isFunctionDeclaration(stmt)) {
|
|
205
589
|
if (!stmt.name) {
|
|
206
590
|
ctx.skipped++;
|
|
207
591
|
return;
|
|
@@ -216,15 +600,23 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
216
600
|
ctx.symbols++;
|
|
217
601
|
return;
|
|
218
602
|
}
|
|
219
|
-
if (
|
|
603
|
+
if (ts2.isVariableStatement(stmt)) {
|
|
220
604
|
for (const decl of stmt.declarationList.declarations) {
|
|
221
|
-
if (!
|
|
605
|
+
if (!ts2.isIdentifier(decl.name)) {
|
|
222
606
|
ctx.skipped++;
|
|
223
607
|
continue;
|
|
224
608
|
}
|
|
225
|
-
const
|
|
226
|
-
if (
|
|
227
|
-
|
|
609
|
+
const ifaceName = decl.type && ts2.isTypeReferenceNode(decl.type) ? typeNameString(decl.type.typeName) : void 0;
|
|
610
|
+
if (ifaceName && (ctx.interfaces.has(ifaceName) || ctx.qualifiedInterfaces.has(ifaceName) || true)) {
|
|
611
|
+
ctx.pending.push({
|
|
612
|
+
t: "iface-expand",
|
|
613
|
+
scope,
|
|
614
|
+
localName: decl.name.text,
|
|
615
|
+
typeRefName: ifaceName
|
|
616
|
+
});
|
|
617
|
+
ctx.symbols++;
|
|
618
|
+
ctx.pending.push({ t: "var", scope, name: decl.name.text, typeNode: decl.type });
|
|
619
|
+
ctx.symbols++;
|
|
228
620
|
continue;
|
|
229
621
|
}
|
|
230
622
|
ctx.pending.push({ t: "var", scope, name: decl.name.text, typeNode: decl.type });
|
|
@@ -232,15 +624,15 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
232
624
|
}
|
|
233
625
|
return;
|
|
234
626
|
}
|
|
235
|
-
if (
|
|
627
|
+
if (ts2.isInterfaceDeclaration(stmt)) {
|
|
236
628
|
registerTypeDecl(ctx, scope, stmt.name.text, stmt);
|
|
237
629
|
return;
|
|
238
630
|
}
|
|
239
|
-
if (
|
|
631
|
+
if (ts2.isTypeAliasDeclaration(stmt)) {
|
|
240
632
|
registerAlias(ctx, scope, stmt);
|
|
241
633
|
return;
|
|
242
634
|
}
|
|
243
|
-
if (
|
|
635
|
+
if (ts2.isClassDeclaration(stmt)) {
|
|
244
636
|
if (!stmt.name) {
|
|
245
637
|
ctx.skipped++;
|
|
246
638
|
return;
|
|
@@ -251,18 +643,18 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
251
643
|
ctx.symbols++;
|
|
252
644
|
return;
|
|
253
645
|
}
|
|
254
|
-
if (
|
|
646
|
+
if (ts2.isEnumDeclaration(stmt)) {
|
|
255
647
|
if (stmt.name) {
|
|
256
648
|
ctx.pending.push({ t: "enum", scope, name: stmt.name.text });
|
|
257
649
|
ctx.symbols++;
|
|
258
650
|
}
|
|
259
651
|
return;
|
|
260
652
|
}
|
|
261
|
-
if (
|
|
653
|
+
if (ts2.isImportDeclaration(stmt)) {
|
|
262
654
|
return;
|
|
263
655
|
}
|
|
264
|
-
if (
|
|
265
|
-
if (
|
|
656
|
+
if (ts2.isImportEqualsDeclaration(stmt)) {
|
|
657
|
+
if (ts2.isIdentifier(stmt.name) && stmt.moduleReference && ts2.isExternalModuleReference(stmt.moduleReference) && ts2.isStringLiteral(stmt.moduleReference.expression)) {
|
|
266
658
|
const key = scopeKey(scope);
|
|
267
659
|
let bindings = ctx.importEquals.get(key);
|
|
268
660
|
if (!bindings) {
|
|
@@ -273,10 +665,10 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
273
665
|
}
|
|
274
666
|
return;
|
|
275
667
|
}
|
|
276
|
-
if (
|
|
668
|
+
if (ts2.isExportDeclaration(stmt)) {
|
|
277
669
|
const specifier = stmt.moduleSpecifier;
|
|
278
|
-
if (specifier &&
|
|
279
|
-
if (stmt.exportClause &&
|
|
670
|
+
if (specifier && ts2.isStringLiteral(specifier)) {
|
|
671
|
+
if (stmt.exportClause && ts2.isNamespaceExport(stmt.exportClause)) {
|
|
280
672
|
ctx.skipped++;
|
|
281
673
|
return;
|
|
282
674
|
}
|
|
@@ -289,7 +681,7 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
289
681
|
ctx.skipped++;
|
|
290
682
|
return;
|
|
291
683
|
}
|
|
292
|
-
if (stmt.exportClause &&
|
|
684
|
+
if (stmt.exportClause && ts2.isNamedExports(stmt.exportClause)) {
|
|
293
685
|
for (const el of stmt.exportClause.elements) {
|
|
294
686
|
const localName = (el.propertyName ?? el.name).text;
|
|
295
687
|
const exportedName = el.name.text;
|
|
@@ -306,8 +698,8 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
306
698
|
ctx.skipped++;
|
|
307
699
|
return;
|
|
308
700
|
}
|
|
309
|
-
if (
|
|
310
|
-
if (stmt.expression &&
|
|
701
|
+
if (ts2.isExportAssignment(stmt)) {
|
|
702
|
+
if (stmt.expression && ts2.isIdentifier(stmt.expression) && scope.moduleName !== void 0) {
|
|
311
703
|
const target = ctx.importEquals.get(scopeKey(scope))?.get(stmt.expression.text);
|
|
312
704
|
if (target !== void 0) {
|
|
313
705
|
ctx.moduleAliases.push([scope.moduleName, target]);
|
|
@@ -320,66 +712,122 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
320
712
|
ctx.skipped++;
|
|
321
713
|
}
|
|
322
714
|
function registerTypeDecl(ctx, scope, name, decl) {
|
|
323
|
-
|
|
324
|
-
|
|
715
|
+
const push = (map, key) => {
|
|
716
|
+
const list = map.get(key);
|
|
717
|
+
if (list) {
|
|
718
|
+
if (!list.includes(decl)) list.push(decl);
|
|
719
|
+
} else {
|
|
720
|
+
map.set(key, [decl]);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
push(ctx.interfaces, name);
|
|
724
|
+
if (ts2.isClassDeclaration(decl)) return;
|
|
325
725
|
const qualified = [...scope.ns, name].join(".");
|
|
326
|
-
if (qualified !== name
|
|
327
|
-
ctx.qualifiedInterfaces.set(qualified, decl);
|
|
328
|
-
}
|
|
726
|
+
if (qualified !== name) push(ctx.qualifiedInterfaces, qualified);
|
|
329
727
|
}
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
728
|
+
function interfaceDeclsOf(ctx, typeNode) {
|
|
729
|
+
const name = typeof typeNode === "string" ? typeNode : ts2.isTypeReferenceNode(typeNode) ? typeNameString(typeNode.typeName) : void 0;
|
|
730
|
+
if (!name) return [];
|
|
731
|
+
const short = name.includes(".") ? name.split(".").pop() : name;
|
|
732
|
+
const keys = name === short ? [name] : [name, short];
|
|
733
|
+
const seen = /* @__PURE__ */ new Set();
|
|
734
|
+
const out = [];
|
|
735
|
+
for (const key of keys) {
|
|
736
|
+
for (const d of [
|
|
737
|
+
...ctx.interfaces.get(key) ?? [],
|
|
738
|
+
...ctx.qualifiedInterfaces.get(key) ?? []
|
|
739
|
+
]) {
|
|
740
|
+
if (ts2.isInterfaceDeclaration(d) && !seen.has(d)) {
|
|
741
|
+
seen.add(d);
|
|
742
|
+
out.push(d);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
return out;
|
|
335
747
|
}
|
|
336
|
-
function expandInterfaceAsModuleMembers(ctx, scope,
|
|
337
|
-
for (const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
existing.
|
|
748
|
+
function expandInterfaceAsModuleMembers(ctx, scope, ifaces) {
|
|
749
|
+
for (const iface of ifaces) {
|
|
750
|
+
for (const member of iface.members) {
|
|
751
|
+
if (ts2.isMethodSignature(member)) {
|
|
752
|
+
const name = memberName(member);
|
|
753
|
+
if (name === void 0) continue;
|
|
754
|
+
const existing = ctx.pending.find(
|
|
755
|
+
(p) => p.t === "fn" && p.name === name && scopeKey(p.scope) === scopeKey(scope)
|
|
756
|
+
);
|
|
757
|
+
if (existing && existing.t === "fn") {
|
|
758
|
+
existing.decls.push(member);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
ctx.pending.push({ t: "fn", scope, name, decls: [member] });
|
|
762
|
+
ctx.symbols++;
|
|
346
763
|
continue;
|
|
347
764
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
765
|
+
if (ts2.isPropertySignature(member)) {
|
|
766
|
+
const name = memberName(member);
|
|
767
|
+
if (name === void 0) continue;
|
|
768
|
+
if (ctx.pending.some((p) => p.t === "var" && p.name === name && scopeKey(p.scope) === scopeKey(scope))) {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
ctx.pending.push({ t: "var", scope, name, typeNode: member.type });
|
|
772
|
+
ctx.symbols++;
|
|
773
|
+
}
|
|
357
774
|
}
|
|
358
775
|
}
|
|
359
776
|
}
|
|
360
777
|
function registerAlias(ctx, scope, stmt) {
|
|
361
778
|
const name = stmt.name.text;
|
|
362
|
-
|
|
779
|
+
const push = (map, key) => {
|
|
780
|
+
const list = map.get(key);
|
|
781
|
+
if (list) {
|
|
782
|
+
if (!list.includes(stmt)) list.push(stmt);
|
|
783
|
+
} else {
|
|
784
|
+
map.set(key, [stmt]);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
push(ctx.aliases, name);
|
|
363
788
|
const qualified = [...scope.ns, name].join(".");
|
|
364
|
-
if (qualified !== name
|
|
365
|
-
ctx.qualifiedAliases.set(qualified, stmt);
|
|
366
|
-
}
|
|
789
|
+
if (qualified !== name) push(ctx.qualifiedAliases, qualified);
|
|
367
790
|
}
|
|
368
791
|
function materialize(ctx) {
|
|
792
|
+
const expanded = [];
|
|
793
|
+
for (const p of ctx.pending) {
|
|
794
|
+
if (p.t !== "iface-expand") {
|
|
795
|
+
expanded.push(p);
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
const ifaces = interfaceDeclsOf(ctx, p.typeRefName);
|
|
799
|
+
if (ifaces.length === 0) {
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
const before = ctx.pending.length;
|
|
803
|
+
expandInterfaceAsModuleMembers(ctx, p.scope, ifaces);
|
|
804
|
+
for (let i = before; i < ctx.pending.length; i++) {
|
|
805
|
+
const n = ctx.pending[i];
|
|
806
|
+
if (n.t === "fn" || n.t === "var") expanded.push(n);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
ctx.pending = expanded;
|
|
369
810
|
for (const p of ctx.pending) {
|
|
811
|
+
if (p.t === "iface-expand") continue;
|
|
370
812
|
const rec = recordFor(ctx, p.scope);
|
|
371
813
|
if (p.t === "fn") {
|
|
372
814
|
if (rec[p.name] !== void 0) continue;
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
|
|
815
|
+
const sigs = p.decls.map((d) => signatureToFnSig(ctx, d));
|
|
816
|
+
const value = sigs[0];
|
|
817
|
+
const shape0 = value.shape.k === "fn" ? value.shape : void 0;
|
|
818
|
+
if (shape0 && sigs.length > 1) {
|
|
376
819
|
const returns = [];
|
|
377
|
-
for (const
|
|
378
|
-
if (
|
|
379
|
-
const ret =
|
|
380
|
-
if (!isPlainUnknown(ret)) returns.push(ret);
|
|
820
|
+
for (const s of sigs) {
|
|
821
|
+
if (s.shape.k !== "fn") continue;
|
|
822
|
+
const ret = s.shape.returnType;
|
|
823
|
+
if (ret && !isPlainUnknown(ret)) returns.push(ret);
|
|
381
824
|
}
|
|
382
|
-
|
|
825
|
+
const withVars = returns.filter((r) => hasTypeVar(r));
|
|
826
|
+
const pool = withVars.length > 0 ? withVars : returns;
|
|
827
|
+
const mergedRet = pool.length > 0 ? absUnion(pool) : absUnknown();
|
|
828
|
+
shape0.returnType = mergedRet;
|
|
829
|
+
const rel = getFnImpl(value)?.relation;
|
|
830
|
+
if (rel) rel.returnType = mergedRet;
|
|
383
831
|
}
|
|
384
832
|
rec[p.name] = value;
|
|
385
833
|
continue;
|
|
@@ -398,7 +846,7 @@ function materialize(ctx) {
|
|
|
398
846
|
case "value": {
|
|
399
847
|
const cls = ctx.classes.get(p.lookup ?? p.name);
|
|
400
848
|
if (cls) {
|
|
401
|
-
const ctor = cls.members.find(
|
|
849
|
+
const ctor = cls.members.find(ts2.isConstructorDeclaration);
|
|
402
850
|
const params = [];
|
|
403
851
|
if (ctor) {
|
|
404
852
|
for (const param of ctor.parameters) {
|
|
@@ -425,78 +873,111 @@ function materialize(ctx) {
|
|
|
425
873
|
}
|
|
426
874
|
}
|
|
427
875
|
function typeNameString(name) {
|
|
428
|
-
if (
|
|
876
|
+
if (ts2.isIdentifier(name)) return name.text;
|
|
429
877
|
return `${typeNameString(name.left)}.${name.right.text}`;
|
|
430
878
|
}
|
|
431
879
|
function memberName(node) {
|
|
432
880
|
const n = node.name;
|
|
433
881
|
if (!n) return void 0;
|
|
434
|
-
if (
|
|
882
|
+
if (ts2.isIdentifier(n) || ts2.isStringLiteral(n) || ts2.isNumericLiteral(n)) return n.text;
|
|
435
883
|
return void 0;
|
|
436
884
|
}
|
|
437
|
-
function instanceFor(ctx, key) {
|
|
438
|
-
const
|
|
885
|
+
function instanceFor(ctx, key, typeArgs) {
|
|
886
|
+
const cacheKey = typeArgs && typeArgs.length > 0 ? `${key}::${typeArgs.length}` : key;
|
|
887
|
+
const cached = ctx.instanceCache.get(cacheKey);
|
|
439
888
|
if (cached !== void 0) return cached;
|
|
440
|
-
const
|
|
889
|
+
const decls = interfaceDeclsOf(ctx, key);
|
|
890
|
+
const decl = decls[0];
|
|
441
891
|
if (!decl) return absUnknown();
|
|
442
892
|
if (ctx.expanding.has(key)) {
|
|
443
893
|
return absBrand(decl.name?.text ?? key, {});
|
|
444
894
|
}
|
|
445
895
|
ctx.expanding.add(key);
|
|
896
|
+
const savedTp = ctx.typeParams;
|
|
897
|
+
ctx.typeParams = new Set(savedTp);
|
|
898
|
+
for (const d of decls) {
|
|
899
|
+
for (const tp of d.typeParameters ?? []) ctx.typeParams.add(tp.name.text);
|
|
900
|
+
}
|
|
446
901
|
const properties = {};
|
|
447
902
|
try {
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
903
|
+
for (const d of decls) {
|
|
904
|
+
const members = d.members;
|
|
905
|
+
for (const member of members) {
|
|
906
|
+
const modifiers = member.modifiers;
|
|
907
|
+
if (modifiers?.some((mod) => mod.kind === ts2.SyntaxKind.StaticKeyword)) continue;
|
|
908
|
+
if (ts2.isPropertySignature(member) || ts2.isPropertyDeclaration(member)) {
|
|
909
|
+
const name = memberName(member);
|
|
910
|
+
if (name === void 0) continue;
|
|
911
|
+
let type = member.type ? mapType(ctx, member.type, 0) : absUnknown();
|
|
912
|
+
if (member.questionToken) type = absUnion([type, absUndefLit()]);
|
|
913
|
+
properties[name] = type;
|
|
914
|
+
} else if (ts2.isMethodSignature(member) || ts2.isMethodDeclaration(member)) {
|
|
915
|
+
const name = memberName(member);
|
|
916
|
+
if (name === void 0 || properties[name] !== void 0) continue;
|
|
917
|
+
properties[name] = signatureToFnSig(ctx, member);
|
|
918
|
+
} else if (ts2.isGetAccessorDeclaration(member) || ts2.isSetAccessorDeclaration(member)) {
|
|
919
|
+
const name = memberName(member);
|
|
920
|
+
if (name === void 0 || properties[name] !== void 0 || !member.type) continue;
|
|
921
|
+
properties[name] = mapType(ctx, member.type, 0);
|
|
922
|
+
}
|
|
466
923
|
}
|
|
467
924
|
}
|
|
468
925
|
} finally {
|
|
926
|
+
ctx.typeParams = savedTp;
|
|
469
927
|
ctx.expanding.delete(key);
|
|
470
928
|
}
|
|
471
|
-
|
|
472
|
-
|
|
929
|
+
let value = absBrand(decl.name?.text ?? key, properties);
|
|
930
|
+
if (typeArgs && typeArgs.length > 0 && Object.keys(properties).length <= 40) {
|
|
931
|
+
const map = /* @__PURE__ */ new Map();
|
|
932
|
+
const tps = decls[0].typeParameters ?? [];
|
|
933
|
+
tps.forEach((tp, i) => {
|
|
934
|
+
const arg = typeArgs[i];
|
|
935
|
+
if (arg) map.set(tp.name.text, arg);
|
|
936
|
+
});
|
|
937
|
+
if (map.size > 0) value = substAbs(value, map);
|
|
938
|
+
}
|
|
939
|
+
ctx.instanceCache.set(cacheKey, value);
|
|
473
940
|
return value;
|
|
474
941
|
}
|
|
475
942
|
function signatureToFnSig(ctx, sig) {
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
943
|
+
const savedTp = ctx.typeParams;
|
|
944
|
+
ctx.typeParams = new Set(savedTp);
|
|
945
|
+
for (const tp of sig.typeParameters ?? []) {
|
|
946
|
+
ctx.typeParams.add(tp.name.text);
|
|
947
|
+
}
|
|
948
|
+
try {
|
|
949
|
+
const paramTypes = sig.parameters.map((param) => {
|
|
950
|
+
let type;
|
|
951
|
+
if (param.dotDotDotToken) {
|
|
952
|
+
const inner = param.type && ts2.isArrayTypeNode(param.type) ? param.type.elementType : param.type;
|
|
953
|
+
type = inner ? absArr(mapType(ctx, inner, 0)) : absUnknown();
|
|
954
|
+
} else {
|
|
955
|
+
type = param.type ? mapType(ctx, param.type, 0) : absUnknown();
|
|
956
|
+
}
|
|
957
|
+
if (param.questionToken && !param.dotDotDotToken) type = absUnion([type, absUndefLit()]);
|
|
958
|
+
return type;
|
|
959
|
+
});
|
|
960
|
+
const returnType = sig.type ? mapType(ctx, sig.type, 0) : absUnknown();
|
|
961
|
+
const cond = ctx.pendingCond;
|
|
962
|
+
ctx.pendingCond = void 0;
|
|
963
|
+
return absFnSig(paramTypes, returnType, cond ? {
|
|
964
|
+
inferFrom: { fromVar: cond.fromVar, via: cond.via, inferVar: cond.inferVar },
|
|
965
|
+
condFallback: cond.fallback
|
|
966
|
+
} : void 0);
|
|
967
|
+
} finally {
|
|
968
|
+
ctx.typeParams = savedTp;
|
|
969
|
+
}
|
|
489
970
|
}
|
|
490
971
|
function mapTypeMembers(ctx, members, depth) {
|
|
491
972
|
const properties = {};
|
|
492
973
|
for (const member of members) {
|
|
493
|
-
if (
|
|
974
|
+
if (ts2.isPropertySignature(member)) {
|
|
494
975
|
const name = memberName(member);
|
|
495
976
|
if (name === void 0) continue;
|
|
496
977
|
let type = member.type ? mapType(ctx, member.type, depth) : absUnknown();
|
|
497
978
|
if (member.questionToken) type = absUnion([type, absUndefLit()]);
|
|
498
979
|
properties[name] = type;
|
|
499
|
-
} else if (
|
|
980
|
+
} else if (ts2.isMethodSignature(member)) {
|
|
500
981
|
const name = memberName(member);
|
|
501
982
|
if (name === void 0 || properties[name] !== void 0) continue;
|
|
502
983
|
properties[name] = signatureToFnSig(ctx, member);
|
|
@@ -507,38 +988,184 @@ function mapTypeMembers(ctx, members, depth) {
|
|
|
507
988
|
function mapTypeRef(ctx, node, depth) {
|
|
508
989
|
const name = typeNameString(node.typeName);
|
|
509
990
|
const args = node.typeArguments ?? [];
|
|
991
|
+
if (ctx.typeParams.has(name) && args.length === 0) {
|
|
992
|
+
return typeVarAbs(name);
|
|
993
|
+
}
|
|
510
994
|
if ((name === "Array" || name === "ReadonlyArray") && args.length >= 1) {
|
|
511
995
|
return absArr(mapType(ctx, args[0], depth));
|
|
512
996
|
}
|
|
997
|
+
if ((name === "List" || name === "ArrayLike" || name === "Collection" || name === "Many" || name === "NumericDictionary" || name === "Dictionary") && args.length >= 1) {
|
|
998
|
+
return absArr(mapType(ctx, args[0], depth));
|
|
999
|
+
}
|
|
513
1000
|
if (name === "Promise" && args.length >= 1) {
|
|
514
1001
|
return absPromise(mapType(ctx, args[0], depth));
|
|
515
1002
|
}
|
|
1003
|
+
if ((name === "Map" || name === "ReadonlyMap" || name === "WeakMap") && args.length >= 2) {
|
|
1004
|
+
return absMapType(name, mapType(ctx, args[0], depth), mapType(ctx, args[1], depth));
|
|
1005
|
+
}
|
|
1006
|
+
if ((name === "Set" || name === "ReadonlySet" || name === "WeakSet") && args.length >= 1) {
|
|
1007
|
+
return absSetType(name, mapType(ctx, args[0], depth));
|
|
1008
|
+
}
|
|
516
1009
|
if (name === "Record") {
|
|
517
1010
|
return absObj({});
|
|
518
1011
|
}
|
|
519
1012
|
if (ctx.interfaces.has(name) || ctx.qualifiedInterfaces.has(name)) {
|
|
520
|
-
return instanceFor(ctx, name);
|
|
1013
|
+
return instanceFor(ctx, name, args.map((a) => mapType(ctx, a, depth)));
|
|
521
1014
|
}
|
|
522
|
-
const
|
|
1015
|
+
const aliases = ctx.aliases.get(name) ?? ctx.qualifiedAliases.get(name) ?? [];
|
|
1016
|
+
const alias = aliases[0];
|
|
523
1017
|
if (alias) return mapType(ctx, alias.type, depth + 1);
|
|
524
1018
|
return absUnknown();
|
|
525
1019
|
}
|
|
1020
|
+
function collectInferNames(node, out = /* @__PURE__ */ new Set()) {
|
|
1021
|
+
const visit = (n) => {
|
|
1022
|
+
if (!n) return;
|
|
1023
|
+
if (ts2.isInferTypeNode(n)) {
|
|
1024
|
+
out.add(n.typeParameter.name.text);
|
|
1025
|
+
visit(n.typeParameter.constraint);
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
n.forEachChild(visit);
|
|
1029
|
+
};
|
|
1030
|
+
visit(node);
|
|
1031
|
+
return out;
|
|
1032
|
+
}
|
|
1033
|
+
function absExtends(check, ext) {
|
|
1034
|
+
if (check.term?.op === "var") return "unknown";
|
|
1035
|
+
if (ext.term?.op === "lit" && (ext.term.value === null || ext.term.value === void 0)) {
|
|
1036
|
+
if (check.term?.op === "lit") {
|
|
1037
|
+
return check.term.value === ext.term.value ? "true" : "false";
|
|
1038
|
+
}
|
|
1039
|
+
if (check.shape.k === "prim" || check.shape.k === "arr" || check.shape.k === "obj" || check.shape.k === "fn" || check.shape.k === "brand" || check.shape.k === "eff") {
|
|
1040
|
+
return "false";
|
|
1041
|
+
}
|
|
1042
|
+
return "unknown";
|
|
1043
|
+
}
|
|
1044
|
+
if (ext.shape.k === "unknown") return "true";
|
|
1045
|
+
if (ext.shape.k === "any") return "true";
|
|
1046
|
+
const cs = check.shape;
|
|
1047
|
+
const es = ext.shape;
|
|
1048
|
+
if (es.k === "prim" && cs.k === "prim") {
|
|
1049
|
+
return cs.type === es.type ? "true" : "false";
|
|
1050
|
+
}
|
|
1051
|
+
if (es.k === "sum") {
|
|
1052
|
+
const flags = es.members.map((m) => absExtends(check, m));
|
|
1053
|
+
if (flags.some((f) => f === "true")) return "true";
|
|
1054
|
+
if (flags.every((f) => f === "false")) return "false";
|
|
1055
|
+
return "unknown";
|
|
1056
|
+
}
|
|
1057
|
+
if (cs.k === "sum") {
|
|
1058
|
+
const flags = cs.members.map((m) => absExtends(m, ext));
|
|
1059
|
+
if (flags.every((f) => f === "true")) return "true";
|
|
1060
|
+
if (flags.every((f) => f === "false")) return "false";
|
|
1061
|
+
return "unknown";
|
|
1062
|
+
}
|
|
1063
|
+
if (cs.k === "arr" && es.k === "arr") {
|
|
1064
|
+
return absExtends(cs.element, es.element);
|
|
1065
|
+
}
|
|
1066
|
+
if (cs.k === "eff" && es.k === "eff" && cs.eff === es.eff) {
|
|
1067
|
+
return absExtends(cs.inner, es.inner);
|
|
1068
|
+
}
|
|
1069
|
+
if (cs.k === "brand" && es.k === "brand") {
|
|
1070
|
+
return cs.name === es.name ? "true" : "false";
|
|
1071
|
+
}
|
|
1072
|
+
if (cs.k === "never") return "true";
|
|
1073
|
+
return "unknown";
|
|
1074
|
+
}
|
|
1075
|
+
function matchExtendsInfer(pattern, actual, inferMap, depth = 0) {
|
|
1076
|
+
if (depth > 6) return "unknown";
|
|
1077
|
+
if (ts2.isInferTypeNode(pattern)) {
|
|
1078
|
+
const name = pattern.typeParameter.name.text;
|
|
1079
|
+
if (!inferMap.has(name)) inferMap.set(name, actual);
|
|
1080
|
+
return "true";
|
|
1081
|
+
}
|
|
1082
|
+
if (ts2.isArrayTypeNode(pattern) && actual.shape.k === "arr") {
|
|
1083
|
+
return matchExtendsInfer(pattern.elementType, actual.shape.element, inferMap, depth + 1);
|
|
1084
|
+
}
|
|
1085
|
+
if (ts2.isTypeReferenceNode(pattern)) {
|
|
1086
|
+
const name = typeNameString(pattern.typeName);
|
|
1087
|
+
const args = pattern.typeArguments ?? [];
|
|
1088
|
+
if ((name === "Array" || name === "ReadonlyArray" || name === "List" || name === "ArrayLike") && args[0] && actual.shape.k === "arr") {
|
|
1089
|
+
return matchExtendsInfer(args[0], actual.shape.element, inferMap, depth + 1);
|
|
1090
|
+
}
|
|
1091
|
+
if (name === "Promise" && args[0] && actual.shape.k === "eff" && actual.shape.eff === "promise") {
|
|
1092
|
+
return matchExtendsInfer(args[0], actual.shape.inner, inferMap, depth + 1);
|
|
1093
|
+
}
|
|
1094
|
+
return "unknown";
|
|
1095
|
+
}
|
|
1096
|
+
if (ts2.isUnionTypeNode(pattern)) {
|
|
1097
|
+
const flags = pattern.types.map((t) => matchExtendsInfer(t, actual, inferMap, depth + 1));
|
|
1098
|
+
if (flags.some((f) => f === "true")) return "true";
|
|
1099
|
+
if (flags.every((f) => f === "false")) return "false";
|
|
1100
|
+
return "unknown";
|
|
1101
|
+
}
|
|
1102
|
+
return "unknown";
|
|
1103
|
+
}
|
|
1104
|
+
function mapConditionalType(ctx, node, depth) {
|
|
1105
|
+
const inferMap = /* @__PURE__ */ new Map();
|
|
1106
|
+
const inferNames = collectInferNames(node.extendsType);
|
|
1107
|
+
const check = mapType(ctx, node.checkType, depth + 1);
|
|
1108
|
+
const astMatch = matchExtendsInfer(node.extendsType, check, inferMap);
|
|
1109
|
+
const extAbs = mapType(ctx, node.extendsType, depth + 1);
|
|
1110
|
+
const absMatch = astMatch !== "unknown" ? astMatch : absExtends(check, extAbs);
|
|
1111
|
+
const condMeta = analyzeCondPattern(ctx, node, check);
|
|
1112
|
+
const savedTp = ctx.typeParams;
|
|
1113
|
+
ctx.typeParams = new Set(savedTp);
|
|
1114
|
+
for (const n of inferNames) ctx.typeParams.add(n);
|
|
1115
|
+
try {
|
|
1116
|
+
const trueAbs = inferMap.size > 0 ? substAbs(mapType(ctx, node.trueType, depth + 1), inferMap) : mapType(ctx, node.trueType, depth + 1);
|
|
1117
|
+
const falseAbs = mapType(ctx, node.falseType, depth + 1);
|
|
1118
|
+
if (absMatch === "true") return trueAbs;
|
|
1119
|
+
if (absMatch === "false") return falseAbs;
|
|
1120
|
+
if (condMeta && check.term?.op === "var") {
|
|
1121
|
+
ctx.pendingCond = { ...condMeta, fallback: falseAbs };
|
|
1122
|
+
return typeVarAbs(condMeta.inferVar);
|
|
1123
|
+
}
|
|
1124
|
+
return absUnion([trueAbs, falseAbs]);
|
|
1125
|
+
} finally {
|
|
1126
|
+
ctx.typeParams = savedTp;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function analyzeCondPattern(_ctx, node, check) {
|
|
1130
|
+
if (check.term?.op !== "var") return void 0;
|
|
1131
|
+
const fromVar = check.term.id;
|
|
1132
|
+
const ext = node.extendsType;
|
|
1133
|
+
const names = collectInferNames(ext);
|
|
1134
|
+
const inferVar = [...names][0];
|
|
1135
|
+
if (!inferVar) return void 0;
|
|
1136
|
+
if (ts2.isArrayTypeNode(ext)) {
|
|
1137
|
+
return { fromVar, via: "arr", inferVar };
|
|
1138
|
+
}
|
|
1139
|
+
if (ts2.isTypeReferenceNode(ext)) {
|
|
1140
|
+
const n = typeNameString(ext.typeName);
|
|
1141
|
+
if (n === "Promise" || n === "PromiseLike") return { fromVar, via: "promise", inferVar };
|
|
1142
|
+
if (n === "Array" || n === "ReadonlyArray" || n === "List" || n === "ArrayLike") {
|
|
1143
|
+
return { fromVar, via: "arr", inferVar };
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
526
1148
|
function mapType(ctx, node, depth) {
|
|
527
1149
|
if (!node || depth > MAX_ALIAS_DEPTH) return absUnknown();
|
|
528
|
-
if (
|
|
529
|
-
if (
|
|
530
|
-
if (
|
|
531
|
-
if (
|
|
1150
|
+
if (ts2.isParenthesizedTypeNode(node)) return mapType(ctx, node.type, depth);
|
|
1151
|
+
if (ts2.isTypeReferenceNode(node)) return mapTypeRef(ctx, node, depth);
|
|
1152
|
+
if (ts2.isArrayTypeNode(node)) return absArr(mapType(ctx, node.elementType, depth));
|
|
1153
|
+
if (ts2.isTupleTypeNode(node)) {
|
|
532
1154
|
for (const element of node.elements) {
|
|
533
|
-
const inner =
|
|
1155
|
+
const inner = ts2.isNamedTupleMember(element) ? element.type : element;
|
|
534
1156
|
return absArr(mapType(ctx, inner, depth));
|
|
535
1157
|
}
|
|
536
1158
|
return absUnknown();
|
|
537
1159
|
}
|
|
538
|
-
if (
|
|
539
|
-
|
|
1160
|
+
if (ts2.isUnionTypeNode(node)) {
|
|
1161
|
+
const members = node.types.map((t) => mapType(ctx, t, depth));
|
|
1162
|
+
const hasLit = members.some((m) => m.term?.op === "lit");
|
|
1163
|
+
if (hasLit && members.length > 1) {
|
|
1164
|
+
return absExact({ k: "sum", members });
|
|
1165
|
+
}
|
|
1166
|
+
return absUnion(members);
|
|
540
1167
|
}
|
|
541
|
-
if (
|
|
1168
|
+
if (ts2.isIntersectionTypeNode(node)) {
|
|
542
1169
|
const members = node.types.map((t) => mapType(ctx, t, depth));
|
|
543
1170
|
if (members.length > 0 && members.every((m) => m.shape.k === "obj")) {
|
|
544
1171
|
const properties = {};
|
|
@@ -552,20 +1179,21 @@ function mapType(ctx, node, depth) {
|
|
|
552
1179
|
}
|
|
553
1180
|
return members[0] ?? absUnknown();
|
|
554
1181
|
}
|
|
555
|
-
if (
|
|
1182
|
+
if (ts2.isLiteralTypeNode(node)) {
|
|
556
1183
|
const lit = node.literal;
|
|
557
|
-
if (
|
|
558
|
-
if (
|
|
559
|
-
if (lit.kind ===
|
|
560
|
-
if (lit.kind ===
|
|
561
|
-
if (
|
|
1184
|
+
if (ts2.isStringLiteral(lit)) return absLit(lit.text);
|
|
1185
|
+
if (ts2.isNumericLiteral(lit)) return absLit(Number(lit.text));
|
|
1186
|
+
if (lit.kind === ts2.SyntaxKind.TrueKeyword) return absLit(true);
|
|
1187
|
+
if (lit.kind === ts2.SyntaxKind.FalseKeyword) return absLit(false);
|
|
1188
|
+
if (lit.kind === ts2.SyntaxKind.NullKeyword) return absNullLit();
|
|
1189
|
+
if (ts2.isPrefixUnaryExpression(lit) && lit.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(lit.operand)) {
|
|
562
1190
|
return absLit(-Number(lit.operand.text));
|
|
563
1191
|
}
|
|
564
1192
|
return absUnknown();
|
|
565
1193
|
}
|
|
566
|
-
if (
|
|
567
|
-
if (
|
|
568
|
-
const ctor = node.members.find(
|
|
1194
|
+
if (ts2.isFunctionTypeNode(node)) return signatureToFnSig(ctx, node);
|
|
1195
|
+
if (ts2.isTypeLiteralNode(node)) {
|
|
1196
|
+
const ctor = node.members.find(ts2.isConstructSignatureDeclaration);
|
|
569
1197
|
if (ctor) {
|
|
570
1198
|
const params = [];
|
|
571
1199
|
for (const param of ctor.parameters) {
|
|
@@ -577,30 +1205,36 @@ function mapType(ctx, node, depth) {
|
|
|
577
1205
|
}
|
|
578
1206
|
return absObj(mapTypeMembers(ctx, node.members, depth));
|
|
579
1207
|
}
|
|
580
|
-
if (
|
|
581
|
-
return node.operator ===
|
|
1208
|
+
if (ts2.isTypeOperatorNode(node)) {
|
|
1209
|
+
return node.operator === ts2.SyntaxKind.ReadonlyKeyword ? mapType(ctx, node.type, depth) : absUnknown();
|
|
1210
|
+
}
|
|
1211
|
+
if (ts2.isConditionalTypeNode(node)) {
|
|
1212
|
+
return mapConditionalType(ctx, node, depth);
|
|
1213
|
+
}
|
|
1214
|
+
if (ts2.isInferTypeNode(node)) {
|
|
1215
|
+
return typeVarAbs(node.typeParameter.name.text);
|
|
582
1216
|
}
|
|
583
1217
|
switch (node.kind) {
|
|
584
|
-
case
|
|
1218
|
+
case ts2.SyntaxKind.StringKeyword:
|
|
585
1219
|
return absPrim("string");
|
|
586
|
-
case
|
|
1220
|
+
case ts2.SyntaxKind.NumberKeyword:
|
|
587
1221
|
return absPrim("number");
|
|
588
|
-
case
|
|
1222
|
+
case ts2.SyntaxKind.BooleanKeyword:
|
|
589
1223
|
return absPrim("boolean");
|
|
590
|
-
case
|
|
1224
|
+
case ts2.SyntaxKind.BigIntKeyword:
|
|
591
1225
|
return absPrim("bigint");
|
|
592
|
-
case
|
|
1226
|
+
case ts2.SyntaxKind.SymbolKeyword:
|
|
593
1227
|
return absPrim("symbol");
|
|
594
|
-
case
|
|
595
|
-
case
|
|
596
|
-
case
|
|
1228
|
+
case ts2.SyntaxKind.AnyKeyword:
|
|
1229
|
+
case ts2.SyntaxKind.UnknownKeyword:
|
|
1230
|
+
case ts2.SyntaxKind.ObjectKeyword:
|
|
597
1231
|
return absUnknown();
|
|
598
|
-
case
|
|
599
|
-
case
|
|
1232
|
+
case ts2.SyntaxKind.VoidKeyword:
|
|
1233
|
+
case ts2.SyntaxKind.UndefinedKeyword:
|
|
600
1234
|
return absUndefLit();
|
|
601
|
-
case
|
|
1235
|
+
case ts2.SyntaxKind.NeverKeyword:
|
|
602
1236
|
return absNever();
|
|
603
|
-
case
|
|
1237
|
+
case ts2.SyntaxKind.NullKeyword:
|
|
604
1238
|
return absNullLit();
|
|
605
1239
|
default:
|
|
606
1240
|
return absUnknown();
|
|
@@ -685,6 +1319,9 @@ function emitAbs(a, expanding) {
|
|
|
685
1319
|
}
|
|
686
1320
|
}
|
|
687
1321
|
export {
|
|
1322
|
+
dtsPathToContractDraft,
|
|
1323
|
+
dtsToContractDraft,
|
|
688
1324
|
emitEnvModule,
|
|
1325
|
+
formatDtsContractDraft,
|
|
689
1326
|
harvestDts
|
|
690
1327
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nudojs/harvester",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8-beta.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20"
|
|
6
6
|
},
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"registry": "https://registry.npmjs.org"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"typescript": "^5.
|
|
33
|
-
"@nudojs/core": "
|
|
32
|
+
"typescript": "^5.9.3",
|
|
33
|
+
"@nudojs/core": "3.0.0-beta.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup src/index.ts --format esm --dts"
|