@hey-api/codegen-core 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -283,7 +283,8 @@ var File = class {
283
283
  * Returns a debug‑friendly string representation identifying the file.
284
284
  */
285
285
  toString() {
286
- return `[File ${this._logicalFilePath}#${this.id}]`;
286
+ const finalPath = this._finalPath ? ` ${this._finalPath}` : "";
287
+ return `${`${this._finalPath ? "✓" : "~"} `}File#${this.id} ${this._logicalFilePath}${finalPath}`;
287
288
  }
288
289
  };
289
290
  //#endregion
@@ -664,17 +665,20 @@ function registerChildName(scope, name, kind) {
664
665
  //#endregion
665
666
  //#region src/planner/analyzer.ts
666
667
  var AnalysisContext = class {
668
+ /** Arbitrary project metadata. */
669
+ meta;
667
670
  /**
668
671
  * Stack of parent nodes during analysis.
669
672
  *
670
673
  * The top of the stack is the current semantic container.
671
674
  */
672
- _parentStack = [];
675
+ parentStack = [];
673
676
  scope;
674
677
  scopes = createScope();
675
678
  symbol;
676
- constructor(node) {
677
- this._parentStack.push(node);
679
+ constructor(node, meta) {
680
+ this.parentStack.push(node);
681
+ this.meta = meta;
678
682
  this.scope = this.scopes;
679
683
  this.symbol = node.symbol;
680
684
  }
@@ -682,7 +686,7 @@ var AnalysisContext = class {
682
686
  * Get the current semantic parent (top of stack).
683
687
  */
684
688
  get currentParent() {
685
- return this._parentStack[this._parentStack.length - 1];
689
+ return this.parentStack[this.parentStack.length - 1];
686
690
  }
687
691
  /**
688
692
  * Register a child node under the current parent.
@@ -708,6 +712,7 @@ var AnalysisContext = class {
708
712
  const node = fromRef(value);
709
713
  this.addChild(node, "container");
710
714
  this.pushParent(node);
715
+ node.meta = this.meta[node.language] ?? {};
711
716
  node.analyze(this);
712
717
  this.popParent();
713
718
  }
@@ -736,7 +741,7 @@ var AnalysisContext = class {
736
741
  * Call this when exiting a container node.
737
742
  */
738
743
  popParent() {
739
- this._parentStack.pop();
744
+ this.parentStack.pop();
740
745
  }
741
746
  popScope() {
742
747
  this.scope = this.scope.parent ?? this.scope;
@@ -745,7 +750,7 @@ var AnalysisContext = class {
745
750
  * Push a node as the current semantic parent.
746
751
  */
747
752
  pushParent(node) {
748
- this._parentStack.push(node);
753
+ this.parentStack.push(node);
749
754
  }
750
755
  pushScope() {
751
756
  const scope = createScope({ parent: this.scope });
@@ -763,12 +768,17 @@ var AnalysisContext = class {
763
768
  }
764
769
  };
765
770
  var Analyzer = class {
771
+ meta;
766
772
  nodeCache = /* @__PURE__ */ new WeakMap();
773
+ constructor(meta) {
774
+ this.meta = meta;
775
+ }
767
776
  analyzeNode(node) {
768
777
  const cached = this.nodeCache.get(node);
769
778
  if (cached) return cached;
770
779
  node.root = true;
771
- const ctx = new AnalysisContext(node);
780
+ node.meta = this.meta[node.language] ?? {};
781
+ const ctx = new AnalysisContext(node, this.meta);
772
782
  node.analyze(ctx);
773
783
  this.nodeCache.set(node, ctx);
774
784
  return ctx;
@@ -783,21 +793,26 @@ var Analyzer = class {
783
793
  //#endregion
784
794
  //#region src/planner/planner.ts
785
795
  const isTypeOnlyKind = (kind) => kind === "type" || kind === "interface";
786
- var Planner = class {
787
- analyzer = new Analyzer();
796
+ var Planner = class Planner {
797
+ static MAX_ALLOCATION_ROUNDS = 100;
798
+ analyzer;
788
799
  cacheResolvedNames = /* @__PURE__ */ new Set();
789
800
  project;
790
801
  constructor(project) {
802
+ this.analyzer = new Analyzer(project.meta);
791
803
  this.project = project;
792
804
  }
793
805
  /**
794
806
  * Executes the planning phase for the project.
795
807
  */
796
- plan(meta) {
808
+ plan() {
797
809
  this.cacheResolvedNames.clear();
798
- this.allocateFiles();
799
- this.assignLocalNames();
800
- this.resolveFilePaths(meta);
810
+ let rounds = 0;
811
+ while (this.allocateFiles()) {
812
+ this.assignLocalNames();
813
+ if (++rounds > Planner.MAX_ALLOCATION_ROUNDS) throw new Error(`File allocation failed to converge after ${Planner.MAX_ALLOCATION_ROUNDS} rounds`);
814
+ }
815
+ this.resolveFilePaths();
801
816
  this.planExports();
802
817
  this.planImports();
803
818
  }
@@ -806,21 +821,25 @@ var Planner = class {
806
821
  * and external dependency.
807
822
  */
808
823
  allocateFiles() {
824
+ let allocated = 0;
809
825
  this.analyzer.analyze(this.project.nodes.all(), (ctx, node) => {
810
826
  const symbol = node.symbol;
811
827
  if (!symbol) return;
812
- const file = this.project.files.register({
813
- external: false,
814
- language: node.language,
815
- logicalFilePath: symbol.getFilePath?.(symbol) || this.project.defaultFileName
816
- });
817
- file.addNode(node);
818
- symbol.setFile(file);
819
- for (const logicalFilePath of symbol.getExportFromFilePath?.(symbol) ?? []) this.project.files.register({
820
- external: false,
821
- language: file.language,
822
- logicalFilePath
823
- });
828
+ if (!symbol.file) {
829
+ const file = this.project.files.register({
830
+ external: false,
831
+ language: node.language,
832
+ logicalFilePath: symbol.getFilePath?.(symbol) || this.project.defaultFileName
833
+ });
834
+ file.addNode(node);
835
+ symbol.setFile(file);
836
+ allocated++;
837
+ for (const logicalFilePath of symbol.getExportFromFilePath?.(symbol) ?? []) this.project.files.register({
838
+ external: false,
839
+ language: file.language,
840
+ logicalFilePath
841
+ });
842
+ }
824
843
  ctx.walkScopes((dependency) => {
825
844
  const dep = fromRef(dependency);
826
845
  if (dep.external && dep.isCanonical && !dep.file) {
@@ -830,9 +849,11 @@ var Planner = class {
830
849
  logicalFilePath: dep.external
831
850
  });
832
851
  dep.setFile(file);
852
+ allocated++;
833
853
  }
834
854
  });
835
855
  });
856
+ return allocated;
836
857
  }
837
858
  /**
838
859
  * Assigns final names to all symbols.
@@ -854,7 +875,7 @@ var Planner = class {
854
875
  if (!file) return;
855
876
  ctx.walkScopes((dependency) => {
856
877
  const dep = fromRef(dependency);
857
- if (dep.file) return;
878
+ if (dep.file || dep.external) return;
858
879
  this.assignLocalName({
859
880
  ctx,
860
881
  file,
@@ -871,7 +892,7 @@ var Planner = class {
871
892
  *
872
893
  * Resolves final paths relative to the project's root directory.
873
894
  */
874
- resolveFilePaths(meta) {
895
+ resolveFilePaths() {
875
896
  for (const file of this.project.files.registered()) {
876
897
  if (file.external) {
877
898
  file.setFinalPath(file.logicalFilePath);
@@ -883,7 +904,6 @@ var Planner = class {
883
904
  if (finalPath) file.setFinalPath(path.resolve(this.project.root, finalPath));
884
905
  const ctx = {
885
906
  file,
886
- meta,
887
907
  project: this.project
888
908
  };
889
909
  const renderer = this.project.renderers.find((r) => r.supports(ctx));
@@ -1018,6 +1038,7 @@ var Planner = class {
1018
1038
  symbol: imp
1019
1039
  };
1020
1040
  fileMap.set(key, entry);
1041
+ dep.addImport(imp);
1021
1042
  }
1022
1043
  entry.kinds.add(dep.kind);
1023
1044
  dependency["~ref"] = entry.symbol;
@@ -1203,12 +1224,24 @@ var Symbol = class {
1203
1224
  */
1204
1225
  _importKind;
1205
1226
  /**
1227
+ * Per-file imported instances of this symbol.
1228
+ *
1229
+ * @default []
1230
+ */
1231
+ _imports = [];
1232
+ /**
1206
1233
  * Kind of symbol (class, type, alias, etc.).
1207
1234
  *
1208
1235
  * @default 'var'
1209
1236
  */
1210
1237
  _kind;
1211
1238
  /**
1239
+ * Registered event listeners keyed by event name.
1240
+ *
1241
+ * @default {}
1242
+ */
1243
+ _listeners = {};
1244
+ /**
1212
1245
  * Arbitrary user metadata.
1213
1246
  *
1214
1247
  * @default undefined
@@ -1313,12 +1346,24 @@ var Symbol = class {
1313
1346
  return this.canonical._importKind;
1314
1347
  }
1315
1348
  /**
1349
+ * Read-only accessor for the per-file imported instances of this symbol.
1350
+ */
1351
+ get imports() {
1352
+ return this.canonical._imports;
1353
+ }
1354
+ /**
1316
1355
  * Indicates whether this is a canonical symbol (not a stub).
1317
1356
  */
1318
1357
  get isCanonical() {
1319
1358
  return !this._canonical || this._canonical === this;
1320
1359
  }
1321
1360
  /**
1361
+ * Indicates whether this symbol was renamed during conflict resolution.
1362
+ */
1363
+ get isRenamed() {
1364
+ return Boolean(this.canonical._finalName) && this.canonical._finalName !== this.canonical._name;
1365
+ }
1366
+ /**
1322
1367
  * The symbol's kind (class, type, alias, variable, etc.).
1323
1368
  */
1324
1369
  get kind() {
@@ -1349,12 +1394,33 @@ var Symbol = class {
1349
1394
  return this.canonical._override;
1350
1395
  }
1351
1396
  /**
1397
+ * Registers a per-file imported instance of this symbol.
1398
+ *
1399
+ * @param symbol The imported instance to register.
1400
+ */
1401
+ addImport(symbol) {
1402
+ this.assertCanonical();
1403
+ this._imports.push(symbol);
1404
+ this.emit("import", { symbol });
1405
+ }
1406
+ /**
1407
+ * Registers a listener for the given symbol lifecycle event.
1408
+ *
1409
+ * @param event The event to subscribe to.
1410
+ * @param listener Callback invoked when the event is emitted.
1411
+ * @returns `this` for chaining.
1412
+ */
1413
+ on(event, listener) {
1414
+ (this.canonical._listeners[event] ??= []).push(listener);
1415
+ return this;
1416
+ }
1417
+ /**
1352
1418
  * Marks this symbol as a stub and assigns its canonical symbol.
1353
1419
  *
1354
1420
  * After calling this, all semantic queries (name, kind, file,
1355
1421
  * meta, etc.) should reflect the canonical symbol's values.
1356
1422
  *
1357
- * @param symbol The canonical symbol this stub should resolve to.
1423
+ * @param symbol The canonical symbol this stub should resolve to.
1358
1424
  */
1359
1425
  setCanonical(symbol) {
1360
1426
  this._canonical = symbol;
@@ -1362,7 +1428,7 @@ var Symbol = class {
1362
1428
  /**
1363
1429
  * Assigns the child symbol bindings associated with this symbol.
1364
1430
  *
1365
- * @param children Child bindings to associate with the symbol.
1431
+ * @param children Child bindings to associate with the symbol.
1366
1432
  */
1367
1433
  setChildren(children) {
1368
1434
  this.assertCanonical();
@@ -1371,7 +1437,7 @@ var Symbol = class {
1371
1437
  /**
1372
1438
  * Marks the symbol as exported from its file.
1373
1439
  *
1374
- * @param exported Whether the symbol is exported.
1440
+ * @param exported Whether the symbol is exported.
1375
1441
  */
1376
1442
  setExported(exported) {
1377
1443
  this.assertCanonical();
@@ -1390,6 +1456,10 @@ var Symbol = class {
1390
1456
  throw new Error(message);
1391
1457
  }
1392
1458
  this._file = file;
1459
+ this.emit("file", {
1460
+ file,
1461
+ symbol: this
1462
+ });
1393
1463
  }
1394
1464
  /**
1395
1465
  * Assigns the conflict‑resolved final local name for this symbol.
@@ -1404,11 +1474,15 @@ var Symbol = class {
1404
1474
  throw new Error(message);
1405
1475
  }
1406
1476
  this._finalName = name;
1477
+ this.emit("finalName", {
1478
+ finalName: name,
1479
+ symbol: this
1480
+ });
1407
1481
  }
1408
1482
  /**
1409
1483
  * Sets how this symbol should be imported.
1410
1484
  *
1411
- * @param kind The import strategy (named/default/namespace).
1485
+ * @param kind The import strategy (named/default/namespace).
1412
1486
  */
1413
1487
  setImportKind(kind) {
1414
1488
  this.assertCanonical();
@@ -1417,7 +1491,7 @@ var Symbol = class {
1417
1491
  /**
1418
1492
  * Sets the symbol's kind (class, type, alias, variable, etc.).
1419
1493
  *
1420
- * @param kind The new symbol kind.
1494
+ * @param kind The new symbol kind.
1421
1495
  */
1422
1496
  setKind(kind) {
1423
1497
  this.assertCanonical();
@@ -1426,7 +1500,7 @@ var Symbol = class {
1426
1500
  /**
1427
1501
  * Updates the intended user‑facing name for this symbol.
1428
1502
  *
1429
- * @param name The new name.
1503
+ * @param name The new name.
1430
1504
  */
1431
1505
  setName(name) {
1432
1506
  this.assertCanonical();
@@ -1449,7 +1523,7 @@ var Symbol = class {
1449
1523
  /**
1450
1524
  * Marks whether this symbol should be treated as an override.
1451
1525
  *
1452
- * @param override Override marker value.
1526
+ * @param override Override marker value.
1453
1527
  */
1454
1528
  setOverride(override) {
1455
1529
  this.assertCanonical();
@@ -1459,9 +1533,15 @@ var Symbol = class {
1459
1533
  * Returns a debug‑friendly string representation identifying the symbol.
1460
1534
  */
1461
1535
  toString() {
1462
- const canonical = this.canonical;
1463
- if (canonical._finalName) return `[Symbol ${canonical._name} → ${canonical._finalName}#${canonical.id}]`;
1464
- return `[Symbol ${canonical._name}#${canonical.id}] ${JSON.stringify(canonical._meta ?? {})}`;
1536
+ const c = this.canonical;
1537
+ const status = `${this._finalName ? "✓" : "~"} `;
1538
+ let renamed = "";
1539
+ let file = "";
1540
+ if (c._finalName) {
1541
+ renamed = c._finalName !== c._name ? ` → "${c._finalName}"` : "";
1542
+ file = c._file ? ` ${c._file.logicalFilePath}` : "";
1543
+ }
1544
+ return `${status}Symbol#${c.id} "${c._name}"${renamed}${file}`;
1465
1545
  }
1466
1546
  /**
1467
1547
  * Ensures this symbol is canonical before allowing mutation.
@@ -1480,6 +1560,17 @@ var Symbol = class {
1480
1560
  throw new Error(message);
1481
1561
  }
1482
1562
  }
1563
+ /**
1564
+ * Invokes all registered listeners for the given event.
1565
+ *
1566
+ * @param event The event to emit.
1567
+ * @param args Arguments forwarded to each listener.
1568
+ */
1569
+ emit(event, ...args) {
1570
+ const listeners = this._listeners[event];
1571
+ if (!listeners) return;
1572
+ for (const listener of listeners) listener(...args);
1573
+ }
1483
1574
  };
1484
1575
  //#endregion
1485
1576
  //#region src/symbols/registry.ts
@@ -1653,6 +1744,7 @@ var SymbolRegistry = class {
1653
1744
  var Project = class {
1654
1745
  _isPlanned = false;
1655
1746
  files;
1747
+ meta;
1656
1748
  nodes = new NodeRegistry();
1657
1749
  symbols = new SymbolRegistry();
1658
1750
  defaultFileName;
@@ -1664,6 +1756,7 @@ var Project = class {
1664
1756
  renderers;
1665
1757
  root;
1666
1758
  constructor(args) {
1759
+ this.meta = args.meta ?? {};
1667
1760
  const fileName = args.fileName;
1668
1761
  this.defaultFileName = args.defaultFileName ?? "main";
1669
1762
  this.defaultNameConflictResolver = args.defaultNameConflictResolver ?? simpleNameConflictResolver;
@@ -1684,18 +1777,17 @@ var Project = class {
1684
1777
  this.renderers = args.renderers ?? [];
1685
1778
  this.root = path.resolve(args.root).replace(/[/\\]+$/, "");
1686
1779
  }
1687
- plan(meta) {
1780
+ plan() {
1688
1781
  if (this._isPlanned) return;
1689
- new Planner(this).plan(meta);
1782
+ new Planner(this).plan();
1690
1783
  this._isPlanned = true;
1691
1784
  }
1692
- render(meta) {
1693
- if (!this._isPlanned) this.plan(meta);
1785
+ render() {
1786
+ if (!this._isPlanned) this.plan();
1694
1787
  const files = [];
1695
1788
  for (const file of this.files.registered()) if (!file.external && file.finalPath && file.renderer) {
1696
1789
  const content = file.renderer.render({
1697
1790
  file,
1698
- meta,
1699
1791
  project: this
1700
1792
  });
1701
1793
  files.push({
@@ -1842,6 +1934,48 @@ var StructureModel = class {
1842
1934
  }
1843
1935
  };
1844
1936
  //#endregion
1845
- export { File, Logger, Project, StructureModel, StructureNode, Symbol, defaultExtensions, defaultModuleEntryNames, defaultNameConflictResolvers, detectInteractiveSession, fromRef, fromRefs, isNode, isNodeRef, isRef, isSymbol, isSymbolRef, loadConfigFile, log, mergeConfigs, nodeBrand, pythonNameConflictResolver, ref, refs, simpleNameConflictResolver, symbolBrand, underscoreNameConflictResolver };
1937
+ //#region src/version.ts
1938
+ var Version = class Version {
1939
+ _segments;
1940
+ raw;
1941
+ constructor(version) {
1942
+ this.raw = version;
1943
+ this._segments = version.split(".").map((segment) => {
1944
+ const num = Number.parseInt(segment, 10);
1945
+ if (Number.isNaN(num)) throw new Error(`Invalid version segment "${segment}" in "${version}"`);
1946
+ return num;
1947
+ });
1948
+ }
1949
+ _compare(other) {
1950
+ const b = other instanceof Version ? other : new Version(other);
1951
+ const len = Math.max(this._segments.length, b._segments.length);
1952
+ for (let i = 0; i < len; i++) {
1953
+ const a = this._segments[i] ?? 0;
1954
+ const bSeg = b._segments[i] ?? 0;
1955
+ if (a !== bSeg) return a - bSeg;
1956
+ }
1957
+ return 0;
1958
+ }
1959
+ eq(other) {
1960
+ return this._compare(other) === 0;
1961
+ }
1962
+ gt(other) {
1963
+ return this._compare(other) > 0;
1964
+ }
1965
+ gte(other) {
1966
+ return this._compare(other) >= 0;
1967
+ }
1968
+ lt(other) {
1969
+ return this._compare(other) < 0;
1970
+ }
1971
+ lte(other) {
1972
+ return this._compare(other) <= 0;
1973
+ }
1974
+ toString() {
1975
+ return this.raw;
1976
+ }
1977
+ };
1978
+ //#endregion
1979
+ export { File, Logger, Project, StructureModel, StructureNode, Symbol, Version, defaultExtensions, defaultModuleEntryNames, defaultNameConflictResolvers, detectInteractiveSession, fromRef, fromRefs, isNode, isNodeRef, isRef, isSymbol, isSymbolRef, loadConfigFile, log, mergeConfigs, nodeBrand, pythonNameConflictResolver, ref, refs, simpleNameConflictResolver, symbolBrand, underscoreNameConflictResolver };
1846
1980
 
1847
1981
  //# sourceMappingURL=index.mjs.map