@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 CHANGED
@@ -1,12 +1,12 @@
1
- import { TypeValue } from '@nudojs/core';
1
+ import { Abs } from '@nudojs/core';
2
2
 
3
3
  /**
4
- * The result of harvesting a set of `.d.ts` files: a Nudo env shaped exactly
5
- * like `EnvDefinition` (`{ globals, modules }`), plus harvest statistics.
4
+ * Harvested env:Abs 原生(与 EnvDefinition 同形)。
5
+ * 收集与物化全程 Abs,不再经 TypeValue 桥。
6
6
  */
7
7
  type HarvestedEnv = {
8
- globals: Record<string, TypeValue>;
9
- modules: Record<string, Record<string, TypeValue>>;
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 { typeValueEquals, getFnSig, T } from "@nudojs/core";
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, TypeValue> = {`);
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
- if (constLines.length > 0) {
82
- lines.push('import { type TypeValue, T } from "@nudojs/core";');
83
- } else {
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 = getFnSig(value);
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.kind !== "unknown") returns.push(ret);
380
+ if (!isPlainUnknown(ret)) returns.push(ret);
283
381
  }
284
- sig.returnType = returns.length > 0 ? returns.reduce((acc, r) => typeValueEquals(acc, r) ? acc : T.union(acc, r)) : T.unknown;
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) : T.unknown;
293
- if (mapped.kind === "unknown") {
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) : T.unknown;
308
- if (param.questionToken) type = T.union(type, T.undefined);
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] = T.fnSig(params, instanceFor(ctx, p.lookup ?? 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] = T.unknown;
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 T.unknown;
441
+ if (!decl) return absUnknown();
344
442
  if (ctx.expanding.has(key)) {
345
- return T.instanceOf(decl.name?.text ?? key, {});
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) : T.unknown;
358
- if (member.questionToken) type = T.union(type, T.undefined);
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 = T.instanceOf(decl.name?.text ?? key, properties);
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 ? T.array(mapType(ctx, inner, 0)) : T.unknown;
480
+ type = inner ? absArr(mapType(ctx, inner, 0)) : absUnknown();
383
481
  } else {
384
- type = param.type ? mapType(ctx, param.type, 0) : T.unknown;
482
+ type = param.type ? mapType(ctx, param.type, 0) : absUnknown();
385
483
  }
386
- if (param.questionToken && !param.dotDotDotToken) type = T.union(type, T.undefined);
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) : T.unknown;
390
- return T.fnSig(paramTypes, returnType);
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) : T.unknown;
399
- if (member.questionToken) type = T.union(type, T.undefined);
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 T.array(mapType(ctx, args[0], depth));
511
+ return absArr(mapType(ctx, args[0], depth));
414
512
  }
415
513
  if (name === "Promise" && args.length >= 1) {
416
- return T.promise(mapType(ctx, args[0], depth));
514
+ return absPromise(mapType(ctx, args[0], depth));
417
515
  }
418
516
  if (name === "Record") {
419
- return T.object({});
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 T.unknown;
524
+ return absUnknown();
427
525
  }
428
526
  function mapType(ctx, node, depth) {
429
- if (!node || depth > MAX_ALIAS_DEPTH) return T.unknown;
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 T.array(mapType(ctx, node.elementType, depth));
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 T.array(mapType(ctx, inner, depth));
534
+ return absArr(mapType(ctx, inner, depth));
437
535
  }
438
- return T.unknown;
536
+ return absUnknown();
439
537
  }
440
538
  if (ts.isUnionTypeNode(node)) {
441
- return T.union(...node.types.map((t) => mapType(ctx, t, depth)));
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.kind === "object")) {
543
+ if (members.length > 0 && members.every((m) => m.shape.k === "obj")) {
446
544
  const properties = {};
447
545
  for (const member of members) {
448
- Object.assign(properties, member.properties);
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 T.object(properties);
551
+ return absObj(properties);
451
552
  }
452
- return members[0] ?? T.unknown;
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 T.literal(lit.text);
457
- if (ts.isNumericLiteral(lit)) return T.literal(Number(lit.text));
458
- if (lit.kind === ts.SyntaxKind.TrueKeyword) return T.literal(true);
459
- if (lit.kind === ts.SyntaxKind.FalseKeyword) return T.literal(false);
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 T.literal(-Number(lit.operand.text));
562
+ return absLit(-Number(lit.operand.text));
462
563
  }
463
- return T.unknown;
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) : T.unknown;
472
- if (param.questionToken) type = T.union(type, T.undefined);
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 T.fnSig(params, ctor.type ? mapType(ctx, ctor.type, depth) : T.unknown);
576
+ return absFnSig(params, ctor.type ? mapType(ctx, ctor.type, depth) : absUnknown());
476
577
  }
477
- return T.object(mapTypeMembers(ctx, node.members, depth));
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) : T.unknown;
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 T.string;
585
+ return absPrim("string");
485
586
  case ts.SyntaxKind.NumberKeyword:
486
- return T.number;
587
+ return absPrim("number");
487
588
  case ts.SyntaxKind.BooleanKeyword:
488
- return T.boolean;
589
+ return absPrim("boolean");
489
590
  case ts.SyntaxKind.BigIntKeyword:
490
- return T.bigint;
591
+ return absPrim("bigint");
491
592
  case ts.SyntaxKind.SymbolKeyword:
492
- return T.symbol;
593
+ return absPrim("symbol");
493
594
  case ts.SyntaxKind.AnyKeyword:
494
595
  case ts.SyntaxKind.UnknownKeyword:
495
596
  case ts.SyntaxKind.ObjectKeyword:
496
- return T.unknown;
597
+ return absUnknown();
497
598
  case ts.SyntaxKind.VoidKeyword:
498
599
  case ts.SyntaxKind.UndefinedKeyword:
499
- return T.undefined;
600
+ return absUndefLit();
500
601
  case ts.SyntaxKind.NeverKeyword:
501
- return T.never;
602
+ return absNever();
502
603
  case ts.SyntaxKind.NullKeyword:
503
- return T.null;
604
+ return absNullLit();
504
605
  default:
505
- return T.unknown;
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)}: ${emitType(value, /* @__PURE__ */ new Set())},`);
617
+ lines.push(`${indent(level)}${emitKey(key)}: ${emitAbs(value, /* @__PURE__ */ new Set())},`);
517
618
  }
518
619
  }
519
- function emitType(tv, expanding) {
520
- switch (tv.kind) {
521
- case "literal":
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 "T.never";
531
- case "array":
532
- return `T.array(${emitType(tv.element, expanding)})`;
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 `T.tuple([${tv.elements.map((e) => emitType(e, expanding)).join(", ")}])`;
535
- case "promise":
536
- return `T.promise(${emitType(tv.value, expanding)})`;
537
- case "object": {
538
- const entries = Object.entries(tv.properties).map(
539
- ([key, value]) => `${emitKey(key)}: ${emitType(value, expanding)}`
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 `T.object({ ${entries.join(", ")} })`;
659
+ return `objOf({ ${entries.join(", ")} })`;
542
660
  }
543
- case "instance": {
544
- if (expanding.has(tv.className)) {
545
- return `T.instanceOf(${JSON.stringify(tv.className)}, {})`;
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(tv.className);
665
+ expanding.add(s.name);
548
666
  try {
549
- const entries = Object.entries(tv.properties).map(
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(tv.className);
669
+ expanding.delete(s.name);
555
670
  }
556
671
  }
557
- case "union": {
558
- if (tv.members.length === 0) return "T.never";
559
- if (tv.members.length === 1) return emitType(tv.members[0], expanding);
560
- return `T.union(${tv.members.map((m) => emitType(m, expanding)).join(", ")})`;
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 "function": {
563
- const sig = getFnSig(tv);
564
- if (!sig) return "T.unknown";
565
- const params = sig.paramTypes.map((p) => emitType(p, expanding)).join(", ");
566
- const ret = emitType(sig.returnType, expanding);
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 "T.unknown";
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.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.4.0"
33
+ "@nudojs/core": "1.0.1"
31
34
  },
32
35
  "scripts": {
33
36
  "build": "tsup src/index.ts --format esm --dts"