@atscript/typescript 0.1.51 → 0.1.52

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/cli.cjs CHANGED
@@ -1500,6 +1500,132 @@ const QUERY_OP_MAP = {
1500
1500
  "not exists": "$exists"
1501
1501
  };
1502
1502
  var JsRenderer = class extends BaseRenderer {
1503
+ /**
1504
+ * Override base `unused` to subtract symbols that the JS output references
1505
+ * transitively through `extends`-resolved parent prop trees. Without this,
1506
+ * cross-file `extends` strips the imports needed by inherited `.refTo()` calls.
1507
+ */ get unused() {
1508
+ if (this._unusedJs) return this._unusedJs;
1509
+ const base = new Set(this.doc.getUnusedTokens().map((t) => t.text));
1510
+ for (const ref of this.getExtendsRefs().keys()) if (ref.id) base.delete(ref.id);
1511
+ return this._unusedJs = base;
1512
+ }
1513
+ getExtendsRefs() {
1514
+ if (this._extendsRefs) return this._extendsRefs;
1515
+ const out = new Map();
1516
+ const visitedInterfaces = new Set();
1517
+ for (const node of this.doc.nodes) if ((0, __atscript_core.isInterface)(node) && node.hasExtends) this.walkExtendsParents(node, this.doc, out, visitedInterfaces);
1518
+ return this._extendsRefs = out;
1519
+ }
1520
+ walkRefs(node, visited, visit) {
1521
+ if (!node || visited.has(node)) return;
1522
+ visited.add(node);
1523
+ if ((0, __atscript_core.isRef)(node)) {
1524
+ visit(node);
1525
+ return;
1526
+ }
1527
+ if ((0, __atscript_core.isGroup)(node)) {
1528
+ for (const item of node.unwrap()) this.walkRefs(item, visited, visit);
1529
+ return;
1530
+ }
1531
+ if ((0, __atscript_core.isArray)(node) || (0, __atscript_core.isProp)(node)) this.walkRefs(node.getDefinition(), visited, visit);
1532
+ }
1533
+ walkExtendsParents(iface, doc, out, visited) {
1534
+ if (visited.has(iface)) return;
1535
+ visited.add(iface);
1536
+ const visitedNodes = new Set();
1537
+ for (const token of iface.extendsTokens) {
1538
+ const unwound = doc.unwindType(token.text);
1539
+ if (!unwound?.def || !(0, __atscript_core.isInterface)(unwound.def)) continue;
1540
+ const parentInterface = unwound.def;
1541
+ const parentDoc = unwound.doc;
1542
+ this.walkRefs(parentInterface.getDefinition(), visitedNodes, (ref) => {
1543
+ if (!out.has(ref)) out.set(ref, parentDoc);
1544
+ });
1545
+ if (parentInterface.hasExtends) this.walkExtendsParents(parentInterface, parentDoc, out, visited);
1546
+ }
1547
+ }
1548
+ computeSynthesizedImports() {
1549
+ if (this._synthComputed) return;
1550
+ this._synthComputed = true;
1551
+ const refToOriginDoc = this.getExtendsRefs();
1552
+ if (refToOriginDoc.size === 0) return;
1553
+ const taken = new Set(this.doc.registry.definitions.keys());
1554
+ const allocated = new Map();
1555
+ const synthPathCache = new Map();
1556
+ for (const [refNode, originDoc] of refToOriginDoc) {
1557
+ const refId = refNode.id;
1558
+ if (!refId) continue;
1559
+ const ownerInfo = this.resolveOwner(originDoc, refId);
1560
+ if (!ownerInfo?.doc || ownerInfo.doc === this.doc) continue;
1561
+ if (ownerInfo.node && (0, __atscript_core.isPrimitive)(ownerInfo.node)) continue;
1562
+ const ownerDoc = ownerInfo.doc;
1563
+ let synthPath;
1564
+ if (synthPathCache.has(ownerDoc)) synthPath = synthPathCache.get(ownerDoc);
1565
+ else {
1566
+ synthPath = this.computeSynthPath(ownerDoc);
1567
+ synthPathCache.set(ownerDoc, synthPath);
1568
+ }
1569
+ if (!synthPath) continue;
1570
+ const allocKey = `${synthPath}::${refId}`;
1571
+ let info = allocated.get(allocKey);
1572
+ if (!info) {
1573
+ info = this.allocateSynthInfo(refId, synthPath, ownerInfo, taken);
1574
+ allocated.set(allocKey, info);
1575
+ }
1576
+ this._refSynthInfo.set(refNode, info);
1577
+ }
1578
+ }
1579
+ resolveOwner(fromDoc, refId) {
1580
+ const key = `${fromDoc.id}::${refId}`;
1581
+ let v = this._ownerCache.get(key);
1582
+ if (v === undefined && !this._ownerCache.has(key)) {
1583
+ v = fromDoc.getDeclarationOwnerNode(refId);
1584
+ this._ownerCache.set(key, v);
1585
+ }
1586
+ return v;
1587
+ }
1588
+ allocateSynthInfo(refId, synthPath, ownerInfo, taken) {
1589
+ const ownerDoc = ownerInfo.doc;
1590
+ const ownerNode = ownerInfo.node;
1591
+ const existing = this.doc.importedDefs.get(refId);
1592
+ if (existing?.text === synthPath) return {
1593
+ alias: refId,
1594
+ ownerDoc,
1595
+ ownerNode
1596
+ };
1597
+ const alias = this.allocAlias(refId, taken);
1598
+ let group = this._synthImports.get(synthPath);
1599
+ if (!group) {
1600
+ group = [];
1601
+ this._synthImports.set(synthPath, group);
1602
+ }
1603
+ group.push({
1604
+ name: refId,
1605
+ alias
1606
+ });
1607
+ return {
1608
+ alias,
1609
+ ownerDoc,
1610
+ ownerNode
1611
+ };
1612
+ }
1613
+ allocAlias(name, taken) {
1614
+ if (!taken.has(name)) {
1615
+ taken.add(name);
1616
+ return name;
1617
+ }
1618
+ let n = 1;
1619
+ while (taken.has(`${name}_${n}`)) n++;
1620
+ const alias = `${name}_${n}`;
1621
+ taken.add(alias);
1622
+ return alias;
1623
+ }
1624
+ computeSynthPath(ownerDoc) {
1625
+ if ((0, __atscript_core.isBareId)(ownerDoc.id)) return ownerDoc.id.slice("bare:".length, -".as".length);
1626
+ if (!ownerDoc.id.startsWith("file://")) return undefined;
1627
+ return (0, __atscript_core.getRelPath)(this.doc.id, ownerDoc.id);
1628
+ }
1503
1629
  pre() {
1504
1630
  this.writeln("// prettier-ignore-start");
1505
1631
  this.writeln("/* eslint-disable */");
@@ -1523,6 +1649,11 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
1523
1649
  if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
1524
1650
  if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
1525
1651
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
1652
+ this.computeSynthesizedImports();
1653
+ for (const [synthPath, names] of this._synthImports) {
1654
+ const list = names.map((n) => n.alias === n.name ? n.name : `${n.name} as ${n.alias}`).join(", ");
1655
+ this.writeln(`import { ${list} } from "${this.transformFromPath(synthPath)}"`);
1656
+ }
1526
1657
  }
1527
1658
  buildAdHocMap(annotateNodes) {
1528
1659
  const map = new Map();
@@ -1801,7 +1932,7 @@ else handle.prop(prop.id, propHandle.$type);
1801
1932
  const ref = node;
1802
1933
  const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
1803
1934
  if ((0, __atscript_core.isPrimitive)(decl)) {
1804
- const ownerDecl$1 = this.doc.getDeclarationOwnerNode(ref.id);
1935
+ const ownerDecl$1 = this.resolveOwner(this.doc, ref.id);
1805
1936
  if (!ownerDecl$1?.node || ownerDecl$1.node.entity !== "type" && ownerDecl$1.node.entity !== "interface") {
1806
1937
  this.annotateType(decl, name);
1807
1938
  return this;
@@ -1816,9 +1947,14 @@ else handle.prop(prop.id, propHandle.$type);
1816
1947
  }
1817
1948
  }
1818
1949
  const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
1819
- const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
1820
- const isImported = ownerDecl ? ownerDecl.doc !== this.doc : false;
1821
- const refExpr = isImported ? `() => ${ref.id}` : ref.id;
1950
+ const synth = this._refSynthInfo.get(ref);
1951
+ const ownerDecl = synth ? {
1952
+ doc: synth.ownerDoc,
1953
+ node: synth.ownerNode
1954
+ } : this.resolveOwner(this.doc, ref.id);
1955
+ const refName = synth?.alias ?? ref.id;
1956
+ const isImported = !!synth || (ownerDecl ? ownerDecl.doc !== this.doc : false);
1957
+ const refExpr = isImported ? `() => ${refName}` : refName;
1822
1958
  this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${refExpr}${chain})`);
1823
1959
  if (!ref.hasChain) {
1824
1960
  if (ownerDecl?.node) {
@@ -2233,7 +2369,7 @@ else {
2233
2369
  return [];
2234
2370
  }
2235
2371
  constructor(doc, opts) {
2236
- super(doc), _define_property$3(this, "opts", void 0), _define_property$3(this, "postAnnotate", void 0), _define_property$3(this, "_adHocAnnotations", void 0), _define_property$3(this, "_propPath", void 0), _define_property$3(this, "typeIds", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map();
2372
+ super(doc), _define_property$3(this, "opts", void 0), _define_property$3(this, "postAnnotate", void 0), _define_property$3(this, "_adHocAnnotations", void 0), _define_property$3(this, "_propPath", void 0), _define_property$3(this, "typeIds", void 0), _define_property$3(this, "_unusedJs", void 0), _define_property$3(this, "_extendsRefs", void 0), _define_property$3(this, "_refSynthInfo", void 0), _define_property$3(this, "_synthImports", void 0), _define_property$3(this, "_synthComputed", void 0), _define_property$3(this, "_ownerCache", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map(), this._refSynthInfo = new Map(), this._synthImports = new Map(), this._synthComputed = false, this._ownerCache = new Map();
2237
2373
  }
2238
2374
  };
2239
2375
 
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
- const require_plugin = require('./plugin-cY7VLpmN.cjs');
2
+ const require_plugin = require('./plugin-otL5yA8s.cjs');
3
3
  require('./json-schema-BgW_S2sP.cjs');
4
4
 
5
5
  exports.default = require_plugin.tsPlugin
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { tsPlugin } from "./plugin-D96fH7Va.mjs";
1
+ import { tsPlugin } from "./plugin-C_5DTxz9.mjs";
2
2
  import "./json-schema-DrJMwvm1.mjs";
3
3
 
4
4
  export { tsPlugin as default, tsPlugin };
@@ -1,6 +1,6 @@
1
1
  import { buildJsonSchema, defineAnnotatedType } from "./json-schema-DrJMwvm1.mjs";
2
2
  import path from "path";
3
- import { DEFAULT_FORMAT, flattenInterfaceNode, hasNavPropAnnotation, isArray, isConst, isGroup, isInterface, isPrimitive, isQueryLogical, isRef, isStructure } from "@atscript/core";
3
+ import { DEFAULT_FORMAT, flattenInterfaceNode, getRelPath, hasNavPropAnnotation, isArray, isBareId, isConst, isGroup, isInterface, isPrimitive, isProp, isQueryLogical, isRef, isStructure } from "@atscript/core";
4
4
 
5
5
  //#region packages/typescript/src/codegen/code-printer.ts
6
6
  function _define_property$3(obj, key, value) {
@@ -671,6 +671,132 @@ const QUERY_OP_MAP = {
671
671
  "not exists": "$exists"
672
672
  };
673
673
  var JsRenderer = class extends BaseRenderer {
674
+ /**
675
+ * Override base `unused` to subtract symbols that the JS output references
676
+ * transitively through `extends`-resolved parent prop trees. Without this,
677
+ * cross-file `extends` strips the imports needed by inherited `.refTo()` calls.
678
+ */ get unused() {
679
+ if (this._unusedJs) return this._unusedJs;
680
+ const base = new Set(this.doc.getUnusedTokens().map((t) => t.text));
681
+ for (const ref of this.getExtendsRefs().keys()) if (ref.id) base.delete(ref.id);
682
+ return this._unusedJs = base;
683
+ }
684
+ getExtendsRefs() {
685
+ if (this._extendsRefs) return this._extendsRefs;
686
+ const out = new Map();
687
+ const visitedInterfaces = new Set();
688
+ for (const node of this.doc.nodes) if (isInterface(node) && node.hasExtends) this.walkExtendsParents(node, this.doc, out, visitedInterfaces);
689
+ return this._extendsRefs = out;
690
+ }
691
+ walkRefs(node, visited, visit) {
692
+ if (!node || visited.has(node)) return;
693
+ visited.add(node);
694
+ if (isRef(node)) {
695
+ visit(node);
696
+ return;
697
+ }
698
+ if (isGroup(node)) {
699
+ for (const item of node.unwrap()) this.walkRefs(item, visited, visit);
700
+ return;
701
+ }
702
+ if (isArray(node) || isProp(node)) this.walkRefs(node.getDefinition(), visited, visit);
703
+ }
704
+ walkExtendsParents(iface, doc, out, visited) {
705
+ if (visited.has(iface)) return;
706
+ visited.add(iface);
707
+ const visitedNodes = new Set();
708
+ for (const token of iface.extendsTokens) {
709
+ const unwound = doc.unwindType(token.text);
710
+ if (!unwound?.def || !isInterface(unwound.def)) continue;
711
+ const parentInterface = unwound.def;
712
+ const parentDoc = unwound.doc;
713
+ this.walkRefs(parentInterface.getDefinition(), visitedNodes, (ref) => {
714
+ if (!out.has(ref)) out.set(ref, parentDoc);
715
+ });
716
+ if (parentInterface.hasExtends) this.walkExtendsParents(parentInterface, parentDoc, out, visited);
717
+ }
718
+ }
719
+ computeSynthesizedImports() {
720
+ if (this._synthComputed) return;
721
+ this._synthComputed = true;
722
+ const refToOriginDoc = this.getExtendsRefs();
723
+ if (refToOriginDoc.size === 0) return;
724
+ const taken = new Set(this.doc.registry.definitions.keys());
725
+ const allocated = new Map();
726
+ const synthPathCache = new Map();
727
+ for (const [refNode, originDoc] of refToOriginDoc) {
728
+ const refId = refNode.id;
729
+ if (!refId) continue;
730
+ const ownerInfo = this.resolveOwner(originDoc, refId);
731
+ if (!ownerInfo?.doc || ownerInfo.doc === this.doc) continue;
732
+ if (ownerInfo.node && isPrimitive(ownerInfo.node)) continue;
733
+ const ownerDoc = ownerInfo.doc;
734
+ let synthPath;
735
+ if (synthPathCache.has(ownerDoc)) synthPath = synthPathCache.get(ownerDoc);
736
+ else {
737
+ synthPath = this.computeSynthPath(ownerDoc);
738
+ synthPathCache.set(ownerDoc, synthPath);
739
+ }
740
+ if (!synthPath) continue;
741
+ const allocKey = `${synthPath}::${refId}`;
742
+ let info = allocated.get(allocKey);
743
+ if (!info) {
744
+ info = this.allocateSynthInfo(refId, synthPath, ownerInfo, taken);
745
+ allocated.set(allocKey, info);
746
+ }
747
+ this._refSynthInfo.set(refNode, info);
748
+ }
749
+ }
750
+ resolveOwner(fromDoc, refId) {
751
+ const key = `${fromDoc.id}::${refId}`;
752
+ let v = this._ownerCache.get(key);
753
+ if (v === undefined && !this._ownerCache.has(key)) {
754
+ v = fromDoc.getDeclarationOwnerNode(refId);
755
+ this._ownerCache.set(key, v);
756
+ }
757
+ return v;
758
+ }
759
+ allocateSynthInfo(refId, synthPath, ownerInfo, taken) {
760
+ const ownerDoc = ownerInfo.doc;
761
+ const ownerNode = ownerInfo.node;
762
+ const existing = this.doc.importedDefs.get(refId);
763
+ if (existing?.text === synthPath) return {
764
+ alias: refId,
765
+ ownerDoc,
766
+ ownerNode
767
+ };
768
+ const alias = this.allocAlias(refId, taken);
769
+ let group = this._synthImports.get(synthPath);
770
+ if (!group) {
771
+ group = [];
772
+ this._synthImports.set(synthPath, group);
773
+ }
774
+ group.push({
775
+ name: refId,
776
+ alias
777
+ });
778
+ return {
779
+ alias,
780
+ ownerDoc,
781
+ ownerNode
782
+ };
783
+ }
784
+ allocAlias(name, taken) {
785
+ if (!taken.has(name)) {
786
+ taken.add(name);
787
+ return name;
788
+ }
789
+ let n = 1;
790
+ while (taken.has(`${name}_${n}`)) n++;
791
+ const alias = `${name}_${n}`;
792
+ taken.add(alias);
793
+ return alias;
794
+ }
795
+ computeSynthPath(ownerDoc) {
796
+ if (isBareId(ownerDoc.id)) return ownerDoc.id.slice("bare:".length, -".as".length);
797
+ if (!ownerDoc.id.startsWith("file://")) return undefined;
798
+ return getRelPath(this.doc.id, ownerDoc.id);
799
+ }
674
800
  pre() {
675
801
  this.writeln("// prettier-ignore-start");
676
802
  this.writeln("/* eslint-disable */");
@@ -694,6 +820,11 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
694
820
  if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
695
821
  if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
696
822
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
823
+ this.computeSynthesizedImports();
824
+ for (const [synthPath, names] of this._synthImports) {
825
+ const list = names.map((n) => n.alias === n.name ? n.name : `${n.name} as ${n.alias}`).join(", ");
826
+ this.writeln(`import { ${list} } from "${this.transformFromPath(synthPath)}"`);
827
+ }
697
828
  }
698
829
  buildAdHocMap(annotateNodes) {
699
830
  const map = new Map();
@@ -972,7 +1103,7 @@ else handle.prop(prop.id, propHandle.$type);
972
1103
  const ref = node;
973
1104
  const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
974
1105
  if (isPrimitive(decl)) {
975
- const ownerDecl$1 = this.doc.getDeclarationOwnerNode(ref.id);
1106
+ const ownerDecl$1 = this.resolveOwner(this.doc, ref.id);
976
1107
  if (!ownerDecl$1?.node || ownerDecl$1.node.entity !== "type" && ownerDecl$1.node.entity !== "interface") {
977
1108
  this.annotateType(decl, name);
978
1109
  return this;
@@ -987,9 +1118,14 @@ else handle.prop(prop.id, propHandle.$type);
987
1118
  }
988
1119
  }
989
1120
  const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
990
- const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
991
- const isImported = ownerDecl ? ownerDecl.doc !== this.doc : false;
992
- const refExpr = isImported ? `() => ${ref.id}` : ref.id;
1121
+ const synth = this._refSynthInfo.get(ref);
1122
+ const ownerDecl = synth ? {
1123
+ doc: synth.ownerDoc,
1124
+ node: synth.ownerNode
1125
+ } : this.resolveOwner(this.doc, ref.id);
1126
+ const refName = synth?.alias ?? ref.id;
1127
+ const isImported = !!synth || (ownerDecl ? ownerDecl.doc !== this.doc : false);
1128
+ const refExpr = isImported ? `() => ${refName}` : refName;
993
1129
  this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${refExpr}${chain})`);
994
1130
  if (!ref.hasChain) {
995
1131
  if (ownerDecl?.node) {
@@ -1404,7 +1540,7 @@ else {
1404
1540
  return [];
1405
1541
  }
1406
1542
  constructor(doc, opts) {
1407
- super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), _define_property(this, "typeIds", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map();
1543
+ super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), _define_property(this, "typeIds", void 0), _define_property(this, "_unusedJs", void 0), _define_property(this, "_extendsRefs", void 0), _define_property(this, "_refSynthInfo", void 0), _define_property(this, "_synthImports", void 0), _define_property(this, "_synthComputed", void 0), _define_property(this, "_ownerCache", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map(), this._refSynthInfo = new Map(), this._synthImports = new Map(), this._synthComputed = false, this._ownerCache = new Map();
1408
1544
  }
1409
1545
  };
1410
1546
 
@@ -695,6 +695,132 @@ const QUERY_OP_MAP = {
695
695
  "not exists": "$exists"
696
696
  };
697
697
  var JsRenderer = class extends BaseRenderer {
698
+ /**
699
+ * Override base `unused` to subtract symbols that the JS output references
700
+ * transitively through `extends`-resolved parent prop trees. Without this,
701
+ * cross-file `extends` strips the imports needed by inherited `.refTo()` calls.
702
+ */ get unused() {
703
+ if (this._unusedJs) return this._unusedJs;
704
+ const base = new Set(this.doc.getUnusedTokens().map((t) => t.text));
705
+ for (const ref of this.getExtendsRefs().keys()) if (ref.id) base.delete(ref.id);
706
+ return this._unusedJs = base;
707
+ }
708
+ getExtendsRefs() {
709
+ if (this._extendsRefs) return this._extendsRefs;
710
+ const out = new Map();
711
+ const visitedInterfaces = new Set();
712
+ for (const node of this.doc.nodes) if ((0, __atscript_core.isInterface)(node) && node.hasExtends) this.walkExtendsParents(node, this.doc, out, visitedInterfaces);
713
+ return this._extendsRefs = out;
714
+ }
715
+ walkRefs(node, visited, visit) {
716
+ if (!node || visited.has(node)) return;
717
+ visited.add(node);
718
+ if ((0, __atscript_core.isRef)(node)) {
719
+ visit(node);
720
+ return;
721
+ }
722
+ if ((0, __atscript_core.isGroup)(node)) {
723
+ for (const item of node.unwrap()) this.walkRefs(item, visited, visit);
724
+ return;
725
+ }
726
+ if ((0, __atscript_core.isArray)(node) || (0, __atscript_core.isProp)(node)) this.walkRefs(node.getDefinition(), visited, visit);
727
+ }
728
+ walkExtendsParents(iface, doc, out, visited) {
729
+ if (visited.has(iface)) return;
730
+ visited.add(iface);
731
+ const visitedNodes = new Set();
732
+ for (const token of iface.extendsTokens) {
733
+ const unwound = doc.unwindType(token.text);
734
+ if (!unwound?.def || !(0, __atscript_core.isInterface)(unwound.def)) continue;
735
+ const parentInterface = unwound.def;
736
+ const parentDoc = unwound.doc;
737
+ this.walkRefs(parentInterface.getDefinition(), visitedNodes, (ref) => {
738
+ if (!out.has(ref)) out.set(ref, parentDoc);
739
+ });
740
+ if (parentInterface.hasExtends) this.walkExtendsParents(parentInterface, parentDoc, out, visited);
741
+ }
742
+ }
743
+ computeSynthesizedImports() {
744
+ if (this._synthComputed) return;
745
+ this._synthComputed = true;
746
+ const refToOriginDoc = this.getExtendsRefs();
747
+ if (refToOriginDoc.size === 0) return;
748
+ const taken = new Set(this.doc.registry.definitions.keys());
749
+ const allocated = new Map();
750
+ const synthPathCache = new Map();
751
+ for (const [refNode, originDoc] of refToOriginDoc) {
752
+ const refId = refNode.id;
753
+ if (!refId) continue;
754
+ const ownerInfo = this.resolveOwner(originDoc, refId);
755
+ if (!ownerInfo?.doc || ownerInfo.doc === this.doc) continue;
756
+ if (ownerInfo.node && (0, __atscript_core.isPrimitive)(ownerInfo.node)) continue;
757
+ const ownerDoc = ownerInfo.doc;
758
+ let synthPath;
759
+ if (synthPathCache.has(ownerDoc)) synthPath = synthPathCache.get(ownerDoc);
760
+ else {
761
+ synthPath = this.computeSynthPath(ownerDoc);
762
+ synthPathCache.set(ownerDoc, synthPath);
763
+ }
764
+ if (!synthPath) continue;
765
+ const allocKey = `${synthPath}::${refId}`;
766
+ let info = allocated.get(allocKey);
767
+ if (!info) {
768
+ info = this.allocateSynthInfo(refId, synthPath, ownerInfo, taken);
769
+ allocated.set(allocKey, info);
770
+ }
771
+ this._refSynthInfo.set(refNode, info);
772
+ }
773
+ }
774
+ resolveOwner(fromDoc, refId) {
775
+ const key = `${fromDoc.id}::${refId}`;
776
+ let v = this._ownerCache.get(key);
777
+ if (v === undefined && !this._ownerCache.has(key)) {
778
+ v = fromDoc.getDeclarationOwnerNode(refId);
779
+ this._ownerCache.set(key, v);
780
+ }
781
+ return v;
782
+ }
783
+ allocateSynthInfo(refId, synthPath, ownerInfo, taken) {
784
+ const ownerDoc = ownerInfo.doc;
785
+ const ownerNode = ownerInfo.node;
786
+ const existing = this.doc.importedDefs.get(refId);
787
+ if (existing?.text === synthPath) return {
788
+ alias: refId,
789
+ ownerDoc,
790
+ ownerNode
791
+ };
792
+ const alias = this.allocAlias(refId, taken);
793
+ let group = this._synthImports.get(synthPath);
794
+ if (!group) {
795
+ group = [];
796
+ this._synthImports.set(synthPath, group);
797
+ }
798
+ group.push({
799
+ name: refId,
800
+ alias
801
+ });
802
+ return {
803
+ alias,
804
+ ownerDoc,
805
+ ownerNode
806
+ };
807
+ }
808
+ allocAlias(name, taken) {
809
+ if (!taken.has(name)) {
810
+ taken.add(name);
811
+ return name;
812
+ }
813
+ let n = 1;
814
+ while (taken.has(`${name}_${n}`)) n++;
815
+ const alias = `${name}_${n}`;
816
+ taken.add(alias);
817
+ return alias;
818
+ }
819
+ computeSynthPath(ownerDoc) {
820
+ if ((0, __atscript_core.isBareId)(ownerDoc.id)) return ownerDoc.id.slice("bare:".length, -".as".length);
821
+ if (!ownerDoc.id.startsWith("file://")) return undefined;
822
+ return (0, __atscript_core.getRelPath)(this.doc.id, ownerDoc.id);
823
+ }
698
824
  pre() {
699
825
  this.writeln("// prettier-ignore-start");
700
826
  this.writeln("/* eslint-disable */");
@@ -718,6 +844,11 @@ else for (let i = 0; i < nodes.length; i++) this.typeIds.set(nodes[i], `${name}_
718
844
  if (this.opts?.exampleData) imports.push("createDataFromAnnotatedType as $e");
719
845
  if (jsonSchemaMode === false) imports.push("throwFeatureDisabled as $d");
720
846
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
847
+ this.computeSynthesizedImports();
848
+ for (const [synthPath, names] of this._synthImports) {
849
+ const list = names.map((n) => n.alias === n.name ? n.name : `${n.name} as ${n.alias}`).join(", ");
850
+ this.writeln(`import { ${list} } from "${this.transformFromPath(synthPath)}"`);
851
+ }
721
852
  }
722
853
  buildAdHocMap(annotateNodes) {
723
854
  const map = new Map();
@@ -996,7 +1127,7 @@ else handle.prop(prop.id, propHandle.$type);
996
1127
  const ref = node;
997
1128
  const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
998
1129
  if ((0, __atscript_core.isPrimitive)(decl)) {
999
- const ownerDecl$1 = this.doc.getDeclarationOwnerNode(ref.id);
1130
+ const ownerDecl$1 = this.resolveOwner(this.doc, ref.id);
1000
1131
  if (!ownerDecl$1?.node || ownerDecl$1.node.entity !== "type" && ownerDecl$1.node.entity !== "interface") {
1001
1132
  this.annotateType(decl, name);
1002
1133
  return this;
@@ -1011,9 +1142,14 @@ else handle.prop(prop.id, propHandle.$type);
1011
1142
  }
1012
1143
  }
1013
1144
  const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
1014
- const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
1015
- const isImported = ownerDecl ? ownerDecl.doc !== this.doc : false;
1016
- const refExpr = isImported ? `() => ${ref.id}` : ref.id;
1145
+ const synth = this._refSynthInfo.get(ref);
1146
+ const ownerDecl = synth ? {
1147
+ doc: synth.ownerDoc,
1148
+ node: synth.ownerNode
1149
+ } : this.resolveOwner(this.doc, ref.id);
1150
+ const refName = synth?.alias ?? ref.id;
1151
+ const isImported = !!synth || (ownerDecl ? ownerDecl.doc !== this.doc : false);
1152
+ const refExpr = isImported ? `() => ${refName}` : refName;
1017
1153
  this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${refExpr}${chain})`);
1018
1154
  if (!ref.hasChain) {
1019
1155
  if (ownerDecl?.node) {
@@ -1428,7 +1564,7 @@ else {
1428
1564
  return [];
1429
1565
  }
1430
1566
  constructor(doc, opts) {
1431
- super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), _define_property(this, "typeIds", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map();
1567
+ super(doc), _define_property(this, "opts", void 0), _define_property(this, "postAnnotate", void 0), _define_property(this, "_adHocAnnotations", void 0), _define_property(this, "_propPath", void 0), _define_property(this, "typeIds", void 0), _define_property(this, "_unusedJs", void 0), _define_property(this, "_extendsRefs", void 0), _define_property(this, "_refSynthInfo", void 0), _define_property(this, "_synthImports", void 0), _define_property(this, "_synthComputed", void 0), _define_property(this, "_ownerCache", void 0), this.opts = opts, this.postAnnotate = [], this._adHocAnnotations = null, this._propPath = [], this.typeIds = new Map(), this._refSynthInfo = new Map(), this._synthImports = new Map(), this._synthComputed = false, this._ownerCache = new Map();
1432
1568
  }
1433
1569
  };
1434
1570
 
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const require_plugin = require('./plugin-cY7VLpmN.cjs');
2
+ const require_plugin = require('./plugin-otL5yA8s.cjs');
3
3
  require('./json-schema-BgW_S2sP.cjs');
4
4
  const path = require_plugin.__toESM(require("path"));
5
5
  const __atscript_core = require_plugin.__toESM(require("@atscript/core"));
@@ -1,4 +1,4 @@
1
- import { tsPlugin } from "./plugin-D96fH7Va.mjs";
1
+ import { tsPlugin } from "./plugin-C_5DTxz9.mjs";
2
2
  import "./json-schema-DrJMwvm1.mjs";
3
3
  import path from "path";
4
4
  import { build } from "@atscript/core";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/typescript",
3
- "version": "0.1.51",
3
+ "version": "0.1.52",
4
4
  "description": "Atscript: typescript-gen support.",
5
5
  "keywords": [
6
6
  "annotations",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@atscript/db": "^0.1.48",
76
- "@atscript/core": "^0.1.51"
76
+ "@atscript/core": "^0.1.52"
77
77
  },
78
78
  "peerDependenciesMeta": {
79
79
  "@atscript/db": {