@nudojs/harvester 0.2.3 → 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);
@@ -308,15 +371,15 @@ function materialize(ctx) {
308
371
  if (p.t === "fn") {
309
372
  if (rec[p.name] !== void 0) continue;
310
373
  const value = signatureToFnSig(ctx, p.decls[0]);
311
- const sig = getFnSig(value);
374
+ const sig = value.shape.k === "fn" ? value.shape : void 0;
312
375
  if (sig) {
313
376
  const returns = [];
314
377
  for (const decl of p.decls) {
315
378
  if (!decl.type) continue;
316
379
  const ret = mapType(ctx, decl.type, 0);
317
- if (ret.kind !== "unknown") returns.push(ret);
380
+ if (!isPlainUnknown(ret)) returns.push(ret);
318
381
  }
319
- 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();
320
383
  }
321
384
  rec[p.name] = value;
322
385
  continue;
@@ -324,8 +387,8 @@ function materialize(ctx) {
324
387
  if (rec[p.name] !== void 0) continue;
325
388
  switch (p.t) {
326
389
  case "var": {
327
- const mapped = p.typeNode ? mapType(ctx, p.typeNode, 0) : T.unknown;
328
- if (mapped.kind === "unknown") {
390
+ const mapped = p.typeNode ? mapType(ctx, p.typeNode, 0) : absUnknown();
391
+ if (isPlainUnknown(mapped)) {
329
392
  ctx.skipped++;
330
393
  break;
331
394
  }
@@ -339,19 +402,19 @@ function materialize(ctx) {
339
402
  const params = [];
340
403
  if (ctor) {
341
404
  for (const param of ctor.parameters) {
342
- let type = param.type ? mapType(ctx, param.type, 0) : T.unknown;
343
- 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()]);
344
407
  params.push(type);
345
408
  }
346
409
  }
347
- rec[p.name] = T.fnSig(params, instanceFor(ctx, p.lookup ?? p.name));
410
+ rec[p.name] = absFnSig(params, instanceFor(ctx, p.lookup ?? p.name));
348
411
  } else {
349
412
  rec[p.name] = instanceFor(ctx, p.lookup ?? p.name);
350
413
  }
351
414
  break;
352
415
  }
353
416
  case "enum":
354
- rec[p.name] = T.unknown;
417
+ rec[p.name] = absUnknown();
355
418
  break;
356
419
  }
357
420
  }
@@ -375,9 +438,9 @@ function instanceFor(ctx, key) {
375
438
  const cached = ctx.instanceCache.get(key);
376
439
  if (cached !== void 0) return cached;
377
440
  const decl = ctx.interfaces.get(key) ?? ctx.qualifiedInterfaces.get(key);
378
- if (!decl) return T.unknown;
441
+ if (!decl) return absUnknown();
379
442
  if (ctx.expanding.has(key)) {
380
- return T.instanceOf(decl.name?.text ?? key, {});
443
+ return absBrand(decl.name?.text ?? key, {});
381
444
  }
382
445
  ctx.expanding.add(key);
383
446
  const properties = {};
@@ -389,8 +452,8 @@ function instanceFor(ctx, key) {
389
452
  if (ts.isPropertySignature(member) || ts.isPropertyDeclaration(member)) {
390
453
  const name = memberName(member);
391
454
  if (name === void 0) continue;
392
- let type = member.type ? mapType(ctx, member.type, 0) : T.unknown;
393
- 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()]);
394
457
  properties[name] = type;
395
458
  } else if (ts.isMethodSignature(member) || ts.isMethodDeclaration(member)) {
396
459
  const name = memberName(member);
@@ -405,7 +468,7 @@ function instanceFor(ctx, key) {
405
468
  } finally {
406
469
  ctx.expanding.delete(key);
407
470
  }
408
- const value = T.instanceOf(decl.name?.text ?? key, properties);
471
+ const value = absBrand(decl.name?.text ?? key, properties);
409
472
  ctx.instanceCache.set(key, value);
410
473
  return value;
411
474
  }
@@ -414,15 +477,15 @@ function signatureToFnSig(ctx, sig) {
414
477
  let type;
415
478
  if (param.dotDotDotToken) {
416
479
  const inner = param.type && ts.isArrayTypeNode(param.type) ? param.type.elementType : param.type;
417
- type = inner ? T.array(mapType(ctx, inner, 0)) : T.unknown;
480
+ type = inner ? absArr(mapType(ctx, inner, 0)) : absUnknown();
418
481
  } else {
419
- type = param.type ? mapType(ctx, param.type, 0) : T.unknown;
482
+ type = param.type ? mapType(ctx, param.type, 0) : absUnknown();
420
483
  }
421
- if (param.questionToken && !param.dotDotDotToken) type = T.union(type, T.undefined);
484
+ if (param.questionToken && !param.dotDotDotToken) type = absUnion([type, absUndefLit()]);
422
485
  return type;
423
486
  });
424
- const returnType = sig.type ? mapType(ctx, sig.type, 0) : T.unknown;
425
- return T.fnSig(paramTypes, returnType);
487
+ const returnType = sig.type ? mapType(ctx, sig.type, 0) : absUnknown();
488
+ return absFnSig(paramTypes, returnType);
426
489
  }
427
490
  function mapTypeMembers(ctx, members, depth) {
428
491
  const properties = {};
@@ -430,8 +493,8 @@ function mapTypeMembers(ctx, members, depth) {
430
493
  if (ts.isPropertySignature(member)) {
431
494
  const name = memberName(member);
432
495
  if (name === void 0) continue;
433
- let type = member.type ? mapType(ctx, member.type, depth) : T.unknown;
434
- 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()]);
435
498
  properties[name] = type;
436
499
  } else if (ts.isMethodSignature(member)) {
437
500
  const name = memberName(member);
@@ -445,57 +508,60 @@ function mapTypeRef(ctx, node, depth) {
445
508
  const name = typeNameString(node.typeName);
446
509
  const args = node.typeArguments ?? [];
447
510
  if ((name === "Array" || name === "ReadonlyArray") && args.length >= 1) {
448
- return T.array(mapType(ctx, args[0], depth));
511
+ return absArr(mapType(ctx, args[0], depth));
449
512
  }
450
513
  if (name === "Promise" && args.length >= 1) {
451
- return T.promise(mapType(ctx, args[0], depth));
514
+ return absPromise(mapType(ctx, args[0], depth));
452
515
  }
453
516
  if (name === "Record") {
454
- return T.object({});
517
+ return absObj({});
455
518
  }
456
519
  if (ctx.interfaces.has(name) || ctx.qualifiedInterfaces.has(name)) {
457
520
  return instanceFor(ctx, name);
458
521
  }
459
522
  const alias = ctx.aliases.get(name) ?? ctx.qualifiedAliases.get(name);
460
523
  if (alias) return mapType(ctx, alias.type, depth + 1);
461
- return T.unknown;
524
+ return absUnknown();
462
525
  }
463
526
  function mapType(ctx, node, depth) {
464
- if (!node || depth > MAX_ALIAS_DEPTH) return T.unknown;
527
+ if (!node || depth > MAX_ALIAS_DEPTH) return absUnknown();
465
528
  if (ts.isParenthesizedTypeNode(node)) return mapType(ctx, node.type, depth);
466
529
  if (ts.isTypeReferenceNode(node)) return mapTypeRef(ctx, node, depth);
467
- if (ts.isArrayTypeNode(node)) return T.array(mapType(ctx, node.elementType, depth));
530
+ if (ts.isArrayTypeNode(node)) return absArr(mapType(ctx, node.elementType, depth));
468
531
  if (ts.isTupleTypeNode(node)) {
469
532
  for (const element of node.elements) {
470
533
  const inner = ts.isNamedTupleMember(element) ? element.type : element;
471
- return T.array(mapType(ctx, inner, depth));
534
+ return absArr(mapType(ctx, inner, depth));
472
535
  }
473
- return T.unknown;
536
+ return absUnknown();
474
537
  }
475
538
  if (ts.isUnionTypeNode(node)) {
476
- return T.union(...node.types.map((t) => mapType(ctx, t, depth)));
539
+ return absUnion(node.types.map((t) => mapType(ctx, t, depth)));
477
540
  }
478
541
  if (ts.isIntersectionTypeNode(node)) {
479
542
  const members = node.types.map((t) => mapType(ctx, t, depth));
480
- if (members.length > 0 && members.every((m) => m.kind === "object")) {
543
+ if (members.length > 0 && members.every((m) => m.shape.k === "obj")) {
481
544
  const properties = {};
482
545
  for (const member of members) {
483
- 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
+ }
484
550
  }
485
- return T.object(properties);
551
+ return absObj(properties);
486
552
  }
487
- return members[0] ?? T.unknown;
553
+ return members[0] ?? absUnknown();
488
554
  }
489
555
  if (ts.isLiteralTypeNode(node)) {
490
556
  const lit = node.literal;
491
- if (ts.isStringLiteral(lit)) return T.literal(lit.text);
492
- if (ts.isNumericLiteral(lit)) return T.literal(Number(lit.text));
493
- if (lit.kind === ts.SyntaxKind.TrueKeyword) return T.literal(true);
494
- 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);
495
561
  if (ts.isPrefixUnaryExpression(lit) && lit.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(lit.operand)) {
496
- return T.literal(-Number(lit.operand.text));
562
+ return absLit(-Number(lit.operand.text));
497
563
  }
498
- return T.unknown;
564
+ return absUnknown();
499
565
  }
500
566
  if (ts.isFunctionTypeNode(node)) return signatureToFnSig(ctx, node);
501
567
  if (ts.isTypeLiteralNode(node)) {
@@ -503,41 +569,41 @@ function mapType(ctx, node, depth) {
503
569
  if (ctor) {
504
570
  const params = [];
505
571
  for (const param of ctor.parameters) {
506
- let type = param.type ? mapType(ctx, param.type, depth) : T.unknown;
507
- 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()]);
508
574
  params.push(type);
509
575
  }
510
- 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());
511
577
  }
512
- return T.object(mapTypeMembers(ctx, node.members, depth));
578
+ return absObj(mapTypeMembers(ctx, node.members, depth));
513
579
  }
514
580
  if (ts.isTypeOperatorNode(node)) {
515
- 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();
516
582
  }
517
583
  switch (node.kind) {
518
584
  case ts.SyntaxKind.StringKeyword:
519
- return T.string;
585
+ return absPrim("string");
520
586
  case ts.SyntaxKind.NumberKeyword:
521
- return T.number;
587
+ return absPrim("number");
522
588
  case ts.SyntaxKind.BooleanKeyword:
523
- return T.boolean;
589
+ return absPrim("boolean");
524
590
  case ts.SyntaxKind.BigIntKeyword:
525
- return T.bigint;
591
+ return absPrim("bigint");
526
592
  case ts.SyntaxKind.SymbolKeyword:
527
- return T.symbol;
593
+ return absPrim("symbol");
528
594
  case ts.SyntaxKind.AnyKeyword:
529
595
  case ts.SyntaxKind.UnknownKeyword:
530
596
  case ts.SyntaxKind.ObjectKeyword:
531
- return T.unknown;
597
+ return absUnknown();
532
598
  case ts.SyntaxKind.VoidKeyword:
533
599
  case ts.SyntaxKind.UndefinedKeyword:
534
- return T.undefined;
600
+ return absUndefLit();
535
601
  case ts.SyntaxKind.NeverKeyword:
536
- return T.never;
602
+ return absNever();
537
603
  case ts.SyntaxKind.NullKeyword:
538
- return T.null;
604
+ return absNullLit();
539
605
  default:
540
- return T.unknown;
606
+ return absUnknown();
541
607
  }
542
608
  }
543
609
  function indent(level) {
@@ -548,66 +614,74 @@ function emitKey(key) {
548
614
  }
549
615
  function emitEntries(lines, record, level) {
550
616
  for (const [key, value] of Object.entries(record)) {
551
- lines.push(`${indent(level)}${emitKey(key)}: ${emitType(value, /* @__PURE__ */ new Set())},`);
617
+ lines.push(`${indent(level)}${emitKey(key)}: ${emitAbs(value, /* @__PURE__ */ new Set())},`);
552
618
  }
553
619
  }
554
- function emitType(tv, expanding) {
555
- switch (tv.kind) {
556
- case "literal":
557
- if (tv.value === null) return "T.null";
558
- if (tv.value === void 0) return "T.undefined";
559
- return `T.literal(${JSON.stringify(tv.value)})`;
560
- case "primitive":
561
- return `T.${tv.type}`;
562
- case "unknown":
563
- return "T.unknown";
620
+ function emitAbs(a, expanding) {
621
+ const s = a.shape;
622
+ switch (s.k) {
564
623
  case "never":
565
- return "T.never";
566
- case "array":
567
- 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")`;
568
651
  case "tuple":
569
- return `T.tuple([${tv.elements.map((e) => emitType(e, expanding)).join(", ")}])`;
570
- case "promise":
571
- return `T.promise(${emitType(tv.value, expanding)})`;
572
- case "object": {
573
- const entries = Object.entries(tv.properties).map(
574
- ([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)} }`
575
658
  );
576
- return `T.object({ ${entries.join(", ")} })`;
659
+ return `objOf({ ${entries.join(", ")} })`;
577
660
  }
578
- case "instance": {
579
- if (expanding.has(tv.className)) {
580
- 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")`;
581
664
  }
582
- expanding.add(tv.className);
665
+ expanding.add(s.name);
583
666
  try {
584
- const entries = Object.entries(tv.properties).map(
585
- ([key, value]) => `${emitKey(key)}: ${emitType(value, expanding)}`
586
- );
587
- 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")`;
588
668
  } finally {
589
- expanding.delete(tv.className);
669
+ expanding.delete(s.name);
590
670
  }
591
671
  }
592
- case "union": {
593
- if (tv.members.length === 0) return "T.never";
594
- if (tv.members.length === 1) return emitType(tv.members[0], expanding);
595
- 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")`;
596
676
  }
597
- case "function": {
598
- const sig = getFnSig(tv);
599
- if (!sig) return "T.unknown";
600
- const params = sig.paramTypes.map((p) => emitType(p, expanding)).join(", ");
601
- const ret = emitType(sig.returnType, expanding);
602
- if (sig.throwsType && sig.throwsType.kind !== "never") {
603
- return `T.fnSig([${params}], ${ret}, ${emitType(sig.throwsType, expanding)})`;
604
- }
605
- 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" })`;
606
682
  }
607
- case "refined":
608
- return emitType(tv.base, expanding);
609
683
  default:
610
- return "T.unknown";
684
+ return "absUnknown";
611
685
  }
612
686
  }
613
687
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/harvester",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "typescript": "^5.8.0",
33
- "@nudojs/core": "1.0.0"
33
+ "@nudojs/core": "1.0.1"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsup src/index.ts --format esm --dts"