@nudojs/harvester 0.2.2 → 0.2.4
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 +5 -5
- package/dist/index.js +217 -108
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Abs } from '@nudojs/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Harvested env:Abs 原生(与 EnvDefinition 同形)。
|
|
5
|
+
* 收集与物化全程 Abs,不再经 TypeValue 桥。
|
|
6
6
|
*/
|
|
7
7
|
type HarvestedEnv = {
|
|
8
|
-
globals: Record<string,
|
|
9
|
-
modules: Record<string, Record<string,
|
|
8
|
+
globals: Record<string, Abs>;
|
|
9
|
+
modules: Record<string, Record<string, Abs>>;
|
|
10
10
|
stats: {
|
|
11
11
|
files: number;
|
|
12
12
|
symbols: number;
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,76 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { readFileSync, statSync } from "fs";
|
|
3
3
|
import ts from "typescript";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
abs as makeAbs,
|
|
6
|
+
lit as termLit,
|
|
7
|
+
numLit,
|
|
8
|
+
strLit,
|
|
9
|
+
boolLit,
|
|
10
|
+
objOf,
|
|
11
|
+
joinAbs
|
|
12
|
+
} from "@nudojs/core";
|
|
5
13
|
var MAX_ALIAS_DEPTH = 8;
|
|
6
14
|
function scopeKey(scope) {
|
|
7
15
|
return scope.moduleName ?? "\0global";
|
|
8
16
|
}
|
|
17
|
+
function absExact(shape) {
|
|
18
|
+
return makeAbs(shape, void 0, void 0, "exact");
|
|
19
|
+
}
|
|
20
|
+
function absNever() {
|
|
21
|
+
return absExact({ k: "never" });
|
|
22
|
+
}
|
|
23
|
+
function absUnknown() {
|
|
24
|
+
return makeAbs({ k: "unknown" }, void 0, void 0, "partial");
|
|
25
|
+
}
|
|
26
|
+
function absPrim(type) {
|
|
27
|
+
return absExact({ k: "prim", type });
|
|
28
|
+
}
|
|
29
|
+
function absNullLit() {
|
|
30
|
+
return makeAbs({ k: "unknown" }, termLit(null), void 0, "exact");
|
|
31
|
+
}
|
|
32
|
+
function absUndefLit() {
|
|
33
|
+
return makeAbs({ k: "unknown" }, termLit(void 0), void 0, "exact");
|
|
34
|
+
}
|
|
35
|
+
function absLit(value) {
|
|
36
|
+
if (typeof value === "number") return numLit(value);
|
|
37
|
+
if (typeof value === "string") return strLit(value);
|
|
38
|
+
if (typeof value === "boolean") return boolLit(value);
|
|
39
|
+
if (typeof value === "bigint") return absPrim("bigint");
|
|
40
|
+
if (value === null) return absNullLit();
|
|
41
|
+
return absUndefLit();
|
|
42
|
+
}
|
|
43
|
+
function absArr(element) {
|
|
44
|
+
return absExact({ k: "arr", element });
|
|
45
|
+
}
|
|
46
|
+
function absPromise(inner) {
|
|
47
|
+
return absExact({ k: "eff", eff: "promise", inner });
|
|
48
|
+
}
|
|
49
|
+
function absObj(properties) {
|
|
50
|
+
const slots = {};
|
|
51
|
+
for (const [k, v] of Object.entries(properties)) {
|
|
52
|
+
slots[k] = { value: v };
|
|
53
|
+
}
|
|
54
|
+
return objOf(slots);
|
|
55
|
+
}
|
|
56
|
+
function absBrand(name, properties) {
|
|
57
|
+
return absExact({ k: "brand", name, shape: absObj(properties) });
|
|
58
|
+
}
|
|
59
|
+
function absFnSig(paramTypes, returnType) {
|
|
60
|
+
return absExact({
|
|
61
|
+
k: "fn",
|
|
62
|
+
params: paramTypes.map((_, i) => `_arg${i}`),
|
|
63
|
+
paramTypes,
|
|
64
|
+
returnType
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function absUnion(members) {
|
|
68
|
+
if (members.length === 0) return absNever();
|
|
69
|
+
return members.reduce((acc, m) => joinAbs(acc, m));
|
|
70
|
+
}
|
|
71
|
+
function isPlainUnknown(a) {
|
|
72
|
+
return a.shape.k === "unknown" && !(a.term?.op === "lit");
|
|
73
|
+
}
|
|
9
74
|
function harvestDts(files, opts) {
|
|
10
75
|
const maxBytes = opts?.maxFileBytes ?? 15e5;
|
|
11
76
|
const deadline = opts?.maxMs !== void 0 ? Date.now() + opts.maxMs : void 0;
|
|
@@ -70,7 +135,7 @@ function emitEnvModule(env, pkgName) {
|
|
|
70
135
|
if (keys.length < 2) continue;
|
|
71
136
|
const constName = `mod${constIndex++}`;
|
|
72
137
|
constNameByRecord.set(record, constName);
|
|
73
|
-
constLines.push(` const ${constName}: Record<string,
|
|
138
|
+
constLines.push(` const ${constName}: Record<string, unknown> = {`);
|
|
74
139
|
emitEntries(constLines, record, 2);
|
|
75
140
|
constLines.push(` };`);
|
|
76
141
|
constLines.push("");
|
|
@@ -78,11 +143,9 @@ function emitEnvModule(env, pkgName) {
|
|
|
78
143
|
const lines = [];
|
|
79
144
|
lines.push("// Auto-generated by nudo harvest \u2014 DO NOT EDIT");
|
|
80
145
|
lines.push(`// Source package: ${pkgName}`);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
lines.push(`import { T } from "@nudojs/core";`);
|
|
85
|
-
}
|
|
146
|
+
lines.push(
|
|
147
|
+
'import { num, str, bool, never as absNever, unknown as absUnknown, numLit, strLit, boolLit, objOf, relationFn, abs as makeAbs } from "@nudojs/core";'
|
|
148
|
+
);
|
|
86
149
|
lines.push("");
|
|
87
150
|
lines.push("export function defineEnv() {");
|
|
88
151
|
lines.push(...constLines);
|
|
@@ -159,6 +222,11 @@ function collectStatement(ctx, stmt, scope) {
|
|
|
159
222
|
ctx.skipped++;
|
|
160
223
|
continue;
|
|
161
224
|
}
|
|
225
|
+
const iface = decl.type ? interfaceDeclOf(ctx, decl.type) : void 0;
|
|
226
|
+
if (iface) {
|
|
227
|
+
expandInterfaceAsModuleMembers(ctx, scope, iface);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
162
230
|
ctx.pending.push({ t: "var", scope, name: decl.name.text, typeNode: decl.type });
|
|
163
231
|
ctx.symbols++;
|
|
164
232
|
}
|
|
@@ -259,6 +327,36 @@ function registerTypeDecl(ctx, scope, name, decl) {
|
|
|
259
327
|
ctx.qualifiedInterfaces.set(qualified, decl);
|
|
260
328
|
}
|
|
261
329
|
}
|
|
330
|
+
function interfaceDeclOf(ctx, typeNode) {
|
|
331
|
+
if (!ts.isTypeReferenceNode(typeNode)) return void 0;
|
|
332
|
+
const name = typeNameString(typeNode.typeName);
|
|
333
|
+
const d = ctx.interfaces.get(name) ?? ctx.qualifiedInterfaces.get(name);
|
|
334
|
+
return d && ts.isInterfaceDeclaration(d) ? d : void 0;
|
|
335
|
+
}
|
|
336
|
+
function expandInterfaceAsModuleMembers(ctx, scope, iface) {
|
|
337
|
+
for (const member of iface.members) {
|
|
338
|
+
if (ts.isMethodSignature(member)) {
|
|
339
|
+
const name = memberName(member);
|
|
340
|
+
if (name === void 0) continue;
|
|
341
|
+
const existing = ctx.pending.find(
|
|
342
|
+
(p) => p.t === "fn" && p.name === name && scopeKey(p.scope) === scopeKey(scope)
|
|
343
|
+
);
|
|
344
|
+
if (existing && existing.t === "fn") {
|
|
345
|
+
existing.decls.push(member);
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
ctx.pending.push({ t: "fn", scope, name, decls: [member] });
|
|
349
|
+
ctx.symbols++;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (ts.isPropertySignature(member)) {
|
|
353
|
+
const name = memberName(member);
|
|
354
|
+
if (name === void 0) continue;
|
|
355
|
+
ctx.pending.push({ t: "var", scope, name, typeNode: member.type });
|
|
356
|
+
ctx.symbols++;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
262
360
|
function registerAlias(ctx, scope, stmt) {
|
|
263
361
|
const name = stmt.name.text;
|
|
264
362
|
if (!ctx.aliases.has(name)) ctx.aliases.set(name, stmt);
|
|
@@ -273,15 +371,15 @@ function materialize(ctx) {
|
|
|
273
371
|
if (p.t === "fn") {
|
|
274
372
|
if (rec[p.name] !== void 0) continue;
|
|
275
373
|
const value = signatureToFnSig(ctx, p.decls[0]);
|
|
276
|
-
const sig =
|
|
374
|
+
const sig = value.shape.k === "fn" ? value.shape : void 0;
|
|
277
375
|
if (sig) {
|
|
278
376
|
const returns = [];
|
|
279
377
|
for (const decl of p.decls) {
|
|
280
378
|
if (!decl.type) continue;
|
|
281
379
|
const ret = mapType(ctx, decl.type, 0);
|
|
282
|
-
if (ret
|
|
380
|
+
if (!isPlainUnknown(ret)) returns.push(ret);
|
|
283
381
|
}
|
|
284
|
-
sig.returnType = returns.length > 0 ? returns
|
|
382
|
+
sig.returnType = returns.length > 0 ? absUnion(returns) : absUnknown();
|
|
285
383
|
}
|
|
286
384
|
rec[p.name] = value;
|
|
287
385
|
continue;
|
|
@@ -289,8 +387,8 @@ function materialize(ctx) {
|
|
|
289
387
|
if (rec[p.name] !== void 0) continue;
|
|
290
388
|
switch (p.t) {
|
|
291
389
|
case "var": {
|
|
292
|
-
const mapped = p.typeNode ? mapType(ctx, p.typeNode, 0) :
|
|
293
|
-
if (mapped
|
|
390
|
+
const mapped = p.typeNode ? mapType(ctx, p.typeNode, 0) : absUnknown();
|
|
391
|
+
if (isPlainUnknown(mapped)) {
|
|
294
392
|
ctx.skipped++;
|
|
295
393
|
break;
|
|
296
394
|
}
|
|
@@ -304,19 +402,19 @@ function materialize(ctx) {
|
|
|
304
402
|
const params = [];
|
|
305
403
|
if (ctor) {
|
|
306
404
|
for (const param of ctor.parameters) {
|
|
307
|
-
let type = param.type ? mapType(ctx, param.type, 0) :
|
|
308
|
-
if (param.questionToken) type =
|
|
405
|
+
let type = param.type ? mapType(ctx, param.type, 0) : absUnknown();
|
|
406
|
+
if (param.questionToken) type = absUnion([type, absUndefLit()]);
|
|
309
407
|
params.push(type);
|
|
310
408
|
}
|
|
311
409
|
}
|
|
312
|
-
rec[p.name] =
|
|
410
|
+
rec[p.name] = absFnSig(params, instanceFor(ctx, p.lookup ?? p.name));
|
|
313
411
|
} else {
|
|
314
412
|
rec[p.name] = instanceFor(ctx, p.lookup ?? p.name);
|
|
315
413
|
}
|
|
316
414
|
break;
|
|
317
415
|
}
|
|
318
416
|
case "enum":
|
|
319
|
-
rec[p.name] =
|
|
417
|
+
rec[p.name] = absUnknown();
|
|
320
418
|
break;
|
|
321
419
|
}
|
|
322
420
|
}
|
|
@@ -340,9 +438,9 @@ function instanceFor(ctx, key) {
|
|
|
340
438
|
const cached = ctx.instanceCache.get(key);
|
|
341
439
|
if (cached !== void 0) return cached;
|
|
342
440
|
const decl = ctx.interfaces.get(key) ?? ctx.qualifiedInterfaces.get(key);
|
|
343
|
-
if (!decl) return
|
|
441
|
+
if (!decl) return absUnknown();
|
|
344
442
|
if (ctx.expanding.has(key)) {
|
|
345
|
-
return
|
|
443
|
+
return absBrand(decl.name?.text ?? key, {});
|
|
346
444
|
}
|
|
347
445
|
ctx.expanding.add(key);
|
|
348
446
|
const properties = {};
|
|
@@ -354,8 +452,8 @@ function instanceFor(ctx, key) {
|
|
|
354
452
|
if (ts.isPropertySignature(member) || ts.isPropertyDeclaration(member)) {
|
|
355
453
|
const name = memberName(member);
|
|
356
454
|
if (name === void 0) continue;
|
|
357
|
-
let type = member.type ? mapType(ctx, member.type, 0) :
|
|
358
|
-
if (member.questionToken) type =
|
|
455
|
+
let type = member.type ? mapType(ctx, member.type, 0) : absUnknown();
|
|
456
|
+
if (member.questionToken) type = absUnion([type, absUndefLit()]);
|
|
359
457
|
properties[name] = type;
|
|
360
458
|
} else if (ts.isMethodSignature(member) || ts.isMethodDeclaration(member)) {
|
|
361
459
|
const name = memberName(member);
|
|
@@ -370,7 +468,7 @@ function instanceFor(ctx, key) {
|
|
|
370
468
|
} finally {
|
|
371
469
|
ctx.expanding.delete(key);
|
|
372
470
|
}
|
|
373
|
-
const value =
|
|
471
|
+
const value = absBrand(decl.name?.text ?? key, properties);
|
|
374
472
|
ctx.instanceCache.set(key, value);
|
|
375
473
|
return value;
|
|
376
474
|
}
|
|
@@ -379,15 +477,15 @@ function signatureToFnSig(ctx, sig) {
|
|
|
379
477
|
let type;
|
|
380
478
|
if (param.dotDotDotToken) {
|
|
381
479
|
const inner = param.type && ts.isArrayTypeNode(param.type) ? param.type.elementType : param.type;
|
|
382
|
-
type = inner ?
|
|
480
|
+
type = inner ? absArr(mapType(ctx, inner, 0)) : absUnknown();
|
|
383
481
|
} else {
|
|
384
|
-
type = param.type ? mapType(ctx, param.type, 0) :
|
|
482
|
+
type = param.type ? mapType(ctx, param.type, 0) : absUnknown();
|
|
385
483
|
}
|
|
386
|
-
if (param.questionToken && !param.dotDotDotToken) type =
|
|
484
|
+
if (param.questionToken && !param.dotDotDotToken) type = absUnion([type, absUndefLit()]);
|
|
387
485
|
return type;
|
|
388
486
|
});
|
|
389
|
-
const returnType = sig.type ? mapType(ctx, sig.type, 0) :
|
|
390
|
-
return
|
|
487
|
+
const returnType = sig.type ? mapType(ctx, sig.type, 0) : absUnknown();
|
|
488
|
+
return absFnSig(paramTypes, returnType);
|
|
391
489
|
}
|
|
392
490
|
function mapTypeMembers(ctx, members, depth) {
|
|
393
491
|
const properties = {};
|
|
@@ -395,8 +493,8 @@ function mapTypeMembers(ctx, members, depth) {
|
|
|
395
493
|
if (ts.isPropertySignature(member)) {
|
|
396
494
|
const name = memberName(member);
|
|
397
495
|
if (name === void 0) continue;
|
|
398
|
-
let type = member.type ? mapType(ctx, member.type, depth) :
|
|
399
|
-
if (member.questionToken) type =
|
|
496
|
+
let type = member.type ? mapType(ctx, member.type, depth) : absUnknown();
|
|
497
|
+
if (member.questionToken) type = absUnion([type, absUndefLit()]);
|
|
400
498
|
properties[name] = type;
|
|
401
499
|
} else if (ts.isMethodSignature(member)) {
|
|
402
500
|
const name = memberName(member);
|
|
@@ -410,57 +508,60 @@ function mapTypeRef(ctx, node, depth) {
|
|
|
410
508
|
const name = typeNameString(node.typeName);
|
|
411
509
|
const args = node.typeArguments ?? [];
|
|
412
510
|
if ((name === "Array" || name === "ReadonlyArray") && args.length >= 1) {
|
|
413
|
-
return
|
|
511
|
+
return absArr(mapType(ctx, args[0], depth));
|
|
414
512
|
}
|
|
415
513
|
if (name === "Promise" && args.length >= 1) {
|
|
416
|
-
return
|
|
514
|
+
return absPromise(mapType(ctx, args[0], depth));
|
|
417
515
|
}
|
|
418
516
|
if (name === "Record") {
|
|
419
|
-
return
|
|
517
|
+
return absObj({});
|
|
420
518
|
}
|
|
421
519
|
if (ctx.interfaces.has(name) || ctx.qualifiedInterfaces.has(name)) {
|
|
422
520
|
return instanceFor(ctx, name);
|
|
423
521
|
}
|
|
424
522
|
const alias = ctx.aliases.get(name) ?? ctx.qualifiedAliases.get(name);
|
|
425
523
|
if (alias) return mapType(ctx, alias.type, depth + 1);
|
|
426
|
-
return
|
|
524
|
+
return absUnknown();
|
|
427
525
|
}
|
|
428
526
|
function mapType(ctx, node, depth) {
|
|
429
|
-
if (!node || depth > MAX_ALIAS_DEPTH) return
|
|
527
|
+
if (!node || depth > MAX_ALIAS_DEPTH) return absUnknown();
|
|
430
528
|
if (ts.isParenthesizedTypeNode(node)) return mapType(ctx, node.type, depth);
|
|
431
529
|
if (ts.isTypeReferenceNode(node)) return mapTypeRef(ctx, node, depth);
|
|
432
|
-
if (ts.isArrayTypeNode(node)) return
|
|
530
|
+
if (ts.isArrayTypeNode(node)) return absArr(mapType(ctx, node.elementType, depth));
|
|
433
531
|
if (ts.isTupleTypeNode(node)) {
|
|
434
532
|
for (const element of node.elements) {
|
|
435
533
|
const inner = ts.isNamedTupleMember(element) ? element.type : element;
|
|
436
|
-
return
|
|
534
|
+
return absArr(mapType(ctx, inner, depth));
|
|
437
535
|
}
|
|
438
|
-
return
|
|
536
|
+
return absUnknown();
|
|
439
537
|
}
|
|
440
538
|
if (ts.isUnionTypeNode(node)) {
|
|
441
|
-
return
|
|
539
|
+
return absUnion(node.types.map((t) => mapType(ctx, t, depth)));
|
|
442
540
|
}
|
|
443
541
|
if (ts.isIntersectionTypeNode(node)) {
|
|
444
542
|
const members = node.types.map((t) => mapType(ctx, t, depth));
|
|
445
|
-
if (members.length > 0 && members.every((m) => m.
|
|
543
|
+
if (members.length > 0 && members.every((m) => m.shape.k === "obj")) {
|
|
446
544
|
const properties = {};
|
|
447
545
|
for (const member of members) {
|
|
448
|
-
|
|
546
|
+
if (member.shape.k !== "obj") continue;
|
|
547
|
+
for (const [k, slot] of Object.entries(member.shape.slots)) {
|
|
548
|
+
properties[k] = slot.value;
|
|
549
|
+
}
|
|
449
550
|
}
|
|
450
|
-
return
|
|
551
|
+
return absObj(properties);
|
|
451
552
|
}
|
|
452
|
-
return members[0] ??
|
|
553
|
+
return members[0] ?? absUnknown();
|
|
453
554
|
}
|
|
454
555
|
if (ts.isLiteralTypeNode(node)) {
|
|
455
556
|
const lit = node.literal;
|
|
456
|
-
if (ts.isStringLiteral(lit)) return
|
|
457
|
-
if (ts.isNumericLiteral(lit)) return
|
|
458
|
-
if (lit.kind === ts.SyntaxKind.TrueKeyword) return
|
|
459
|
-
if (lit.kind === ts.SyntaxKind.FalseKeyword) return
|
|
557
|
+
if (ts.isStringLiteral(lit)) return absLit(lit.text);
|
|
558
|
+
if (ts.isNumericLiteral(lit)) return absLit(Number(lit.text));
|
|
559
|
+
if (lit.kind === ts.SyntaxKind.TrueKeyword) return absLit(true);
|
|
560
|
+
if (lit.kind === ts.SyntaxKind.FalseKeyword) return absLit(false);
|
|
460
561
|
if (ts.isPrefixUnaryExpression(lit) && lit.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(lit.operand)) {
|
|
461
|
-
return
|
|
562
|
+
return absLit(-Number(lit.operand.text));
|
|
462
563
|
}
|
|
463
|
-
return
|
|
564
|
+
return absUnknown();
|
|
464
565
|
}
|
|
465
566
|
if (ts.isFunctionTypeNode(node)) return signatureToFnSig(ctx, node);
|
|
466
567
|
if (ts.isTypeLiteralNode(node)) {
|
|
@@ -468,41 +569,41 @@ function mapType(ctx, node, depth) {
|
|
|
468
569
|
if (ctor) {
|
|
469
570
|
const params = [];
|
|
470
571
|
for (const param of ctor.parameters) {
|
|
471
|
-
let type = param.type ? mapType(ctx, param.type, depth) :
|
|
472
|
-
if (param.questionToken) type =
|
|
572
|
+
let type = param.type ? mapType(ctx, param.type, depth) : absUnknown();
|
|
573
|
+
if (param.questionToken) type = absUnion([type, absUndefLit()]);
|
|
473
574
|
params.push(type);
|
|
474
575
|
}
|
|
475
|
-
return
|
|
576
|
+
return absFnSig(params, ctor.type ? mapType(ctx, ctor.type, depth) : absUnknown());
|
|
476
577
|
}
|
|
477
|
-
return
|
|
578
|
+
return absObj(mapTypeMembers(ctx, node.members, depth));
|
|
478
579
|
}
|
|
479
580
|
if (ts.isTypeOperatorNode(node)) {
|
|
480
|
-
return node.operator === ts.SyntaxKind.ReadonlyKeyword ? mapType(ctx, node.type, depth) :
|
|
581
|
+
return node.operator === ts.SyntaxKind.ReadonlyKeyword ? mapType(ctx, node.type, depth) : absUnknown();
|
|
481
582
|
}
|
|
482
583
|
switch (node.kind) {
|
|
483
584
|
case ts.SyntaxKind.StringKeyword:
|
|
484
|
-
return
|
|
585
|
+
return absPrim("string");
|
|
485
586
|
case ts.SyntaxKind.NumberKeyword:
|
|
486
|
-
return
|
|
587
|
+
return absPrim("number");
|
|
487
588
|
case ts.SyntaxKind.BooleanKeyword:
|
|
488
|
-
return
|
|
589
|
+
return absPrim("boolean");
|
|
489
590
|
case ts.SyntaxKind.BigIntKeyword:
|
|
490
|
-
return
|
|
591
|
+
return absPrim("bigint");
|
|
491
592
|
case ts.SyntaxKind.SymbolKeyword:
|
|
492
|
-
return
|
|
593
|
+
return absPrim("symbol");
|
|
493
594
|
case ts.SyntaxKind.AnyKeyword:
|
|
494
595
|
case ts.SyntaxKind.UnknownKeyword:
|
|
495
596
|
case ts.SyntaxKind.ObjectKeyword:
|
|
496
|
-
return
|
|
597
|
+
return absUnknown();
|
|
497
598
|
case ts.SyntaxKind.VoidKeyword:
|
|
498
599
|
case ts.SyntaxKind.UndefinedKeyword:
|
|
499
|
-
return
|
|
600
|
+
return absUndefLit();
|
|
500
601
|
case ts.SyntaxKind.NeverKeyword:
|
|
501
|
-
return
|
|
602
|
+
return absNever();
|
|
502
603
|
case ts.SyntaxKind.NullKeyword:
|
|
503
|
-
return
|
|
604
|
+
return absNullLit();
|
|
504
605
|
default:
|
|
505
|
-
return
|
|
606
|
+
return absUnknown();
|
|
506
607
|
}
|
|
507
608
|
}
|
|
508
609
|
function indent(level) {
|
|
@@ -513,66 +614,74 @@ function emitKey(key) {
|
|
|
513
614
|
}
|
|
514
615
|
function emitEntries(lines, record, level) {
|
|
515
616
|
for (const [key, value] of Object.entries(record)) {
|
|
516
|
-
lines.push(`${indent(level)}${emitKey(key)}: ${
|
|
617
|
+
lines.push(`${indent(level)}${emitKey(key)}: ${emitAbs(value, /* @__PURE__ */ new Set())},`);
|
|
517
618
|
}
|
|
518
619
|
}
|
|
519
|
-
function
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (tv.value === null) return "T.null";
|
|
523
|
-
if (tv.value === void 0) return "T.undefined";
|
|
524
|
-
return `T.literal(${JSON.stringify(tv.value)})`;
|
|
525
|
-
case "primitive":
|
|
526
|
-
return `T.${tv.type}`;
|
|
527
|
-
case "unknown":
|
|
528
|
-
return "T.unknown";
|
|
620
|
+
function emitAbs(a, expanding) {
|
|
621
|
+
const s = a.shape;
|
|
622
|
+
switch (s.k) {
|
|
529
623
|
case "never":
|
|
530
|
-
return "
|
|
531
|
-
case "
|
|
532
|
-
|
|
624
|
+
return "absNever";
|
|
625
|
+
case "unknown":
|
|
626
|
+
if (a.term?.op === "lit") {
|
|
627
|
+
const v = a.term.value;
|
|
628
|
+
if (v === null) return `makeAbs({ k: "unknown" }, { op: "lit", value: null }, undefined, "exact")`;
|
|
629
|
+
if (v === void 0) return `makeAbs({ k: "unknown" }, { op: "lit", value: undefined }, undefined, "exact")`;
|
|
630
|
+
if (typeof v === "number") return `numLit(${JSON.stringify(v)})`;
|
|
631
|
+
if (typeof v === "boolean") return `boolLit(${v})`;
|
|
632
|
+
if (typeof v === "string") return `strLit(${JSON.stringify(v)})`;
|
|
633
|
+
}
|
|
634
|
+
return "absUnknown";
|
|
635
|
+
case "any":
|
|
636
|
+
return "absUnknown";
|
|
637
|
+
case "prim": {
|
|
638
|
+
if (a.term?.op === "lit") {
|
|
639
|
+
const v = a.term.value;
|
|
640
|
+
if (typeof v === "number") return `numLit(${JSON.stringify(v)})`;
|
|
641
|
+
if (typeof v === "boolean") return `boolLit(${v})`;
|
|
642
|
+
if (typeof v === "string") return `strLit(${JSON.stringify(v)})`;
|
|
643
|
+
}
|
|
644
|
+
if (s.type === "number") return "num()";
|
|
645
|
+
if (s.type === "string") return "str()";
|
|
646
|
+
if (s.type === "boolean") return "bool()";
|
|
647
|
+
return "absUnknown";
|
|
648
|
+
}
|
|
649
|
+
case "arr":
|
|
650
|
+
return `makeAbs({ k: "arr", element: ${emitAbs(s.element, expanding)} }, undefined, undefined, "exact")`;
|
|
533
651
|
case "tuple":
|
|
534
|
-
return `
|
|
535
|
-
case "
|
|
536
|
-
return `
|
|
537
|
-
case "
|
|
538
|
-
const entries = Object.entries(
|
|
539
|
-
([key,
|
|
652
|
+
return `makeAbs({ k: "tuple", elements: [${s.elements.map((e) => emitAbs(e, expanding)).join(", ")}] }, undefined, undefined, "exact")`;
|
|
653
|
+
case "eff":
|
|
654
|
+
return `makeAbs({ k: "eff", eff: ${JSON.stringify(s.eff)}, inner: ${emitAbs(s.inner, expanding)} }, undefined, undefined, "exact")`;
|
|
655
|
+
case "obj": {
|
|
656
|
+
const entries = Object.entries(s.slots).map(
|
|
657
|
+
([key, slot]) => `${emitKey(key)}: { value: ${emitAbs(slot.value, expanding)} }`
|
|
540
658
|
);
|
|
541
|
-
return `
|
|
659
|
+
return `objOf({ ${entries.join(", ")} })`;
|
|
542
660
|
}
|
|
543
|
-
case "
|
|
544
|
-
if (expanding.has(
|
|
545
|
-
return `
|
|
661
|
+
case "brand": {
|
|
662
|
+
if (expanding.has(s.name)) {
|
|
663
|
+
return `makeAbs({ k: "brand", name: ${JSON.stringify(s.name)}, shape: absUnknown }, undefined, undefined, "path")`;
|
|
546
664
|
}
|
|
547
|
-
expanding.add(
|
|
665
|
+
expanding.add(s.name);
|
|
548
666
|
try {
|
|
549
|
-
|
|
550
|
-
([key, value]) => `${emitKey(key)}: ${emitType(value, expanding)}`
|
|
551
|
-
);
|
|
552
|
-
return `T.instanceOf(${JSON.stringify(tv.className)}, { ${entries.join(", ")} })`;
|
|
667
|
+
return `makeAbs({ k: "brand", name: ${JSON.stringify(s.name)}, shape: ${emitAbs(s.shape, expanding)} }, undefined, undefined, "path")`;
|
|
553
668
|
} finally {
|
|
554
|
-
expanding.delete(
|
|
669
|
+
expanding.delete(s.name);
|
|
555
670
|
}
|
|
556
671
|
}
|
|
557
|
-
case "
|
|
558
|
-
if (
|
|
559
|
-
if (
|
|
560
|
-
return `
|
|
672
|
+
case "sum": {
|
|
673
|
+
if (s.members.length === 0) return "absNever";
|
|
674
|
+
if (s.members.length === 1) return emitAbs(s.members[0], expanding);
|
|
675
|
+
return `makeAbs({ k: "sum", members: [${s.members.map((m) => emitAbs(m, expanding)).join(", ")}] }, undefined, undefined, "exact")`;
|
|
561
676
|
}
|
|
562
|
-
case "
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
if (sig.throwsType && sig.throwsType.kind !== "never") {
|
|
568
|
-
return `T.fnSig([${params}], ${ret}, ${emitType(sig.throwsType, expanding)})`;
|
|
569
|
-
}
|
|
570
|
-
return `T.fnSig([${params}], ${ret})`;
|
|
677
|
+
case "fn": {
|
|
678
|
+
const pts = s.paramTypes ?? [];
|
|
679
|
+
const params = pts.map((p) => emitAbs(p, expanding)).join(", ");
|
|
680
|
+
const ret = s.returnType ? emitAbs(s.returnType, expanding) : "absUnknown";
|
|
681
|
+
return `relationFn([${params}], ${ret}, { conf: "exact" })`;
|
|
571
682
|
}
|
|
572
|
-
case "refined":
|
|
573
|
-
return emitType(tv.base, expanding);
|
|
574
683
|
default:
|
|
575
|
-
return "
|
|
684
|
+
return "absUnknown";
|
|
576
685
|
}
|
|
577
686
|
}
|
|
578
687
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nudojs/harvester",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=20"
|
|
6
|
+
},
|
|
4
7
|
"description": "Harvests TypeScript .d.ts declarations into Nudo env definitions",
|
|
5
8
|
"type": "module",
|
|
6
9
|
"license": "MIT",
|
|
@@ -27,7 +30,7 @@
|
|
|
27
30
|
},
|
|
28
31
|
"dependencies": {
|
|
29
32
|
"typescript": "^5.8.0",
|
|
30
|
-
"@nudojs/core": "0.
|
|
33
|
+
"@nudojs/core": "1.0.1"
|
|
31
34
|
},
|
|
32
35
|
"scripts": {
|
|
33
36
|
"build": "tsup src/index.ts --format esm --dts"
|