@valkyrjaio/sindri 26.6.64 → 26.6.66

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.
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
33
  // node_modules/@ts-morph/common/dist/typescript.js
34
34
  var require_typescript = __commonJS({
35
35
  "node_modules/@ts-morph/common/dist/typescript.js"(exports2, module2) {
36
- var ts12 = {};
36
+ var ts13 = {};
37
37
  ((module3) => {
38
38
  "use strict";
39
39
  var __defProp2 = Object.defineProperty;
@@ -137157,9 +137157,9 @@ ${lanes.join("\n")}
137157
137157
  /*ignoreCase*/
137158
137158
  false
137159
137159
  )) {
137160
- const basename2 = getBaseFileName(a.fileName);
137161
- if (basename2 === "lib.d.ts" || basename2 === "lib.es6.d.ts") return 0;
137162
- const name = removeSuffix(removePrefix(basename2, "lib."), ".d.ts");
137160
+ const basename3 = getBaseFileName(a.fileName);
137161
+ if (basename3 === "lib.d.ts" || basename3 === "lib.es6.d.ts") return 0;
137162
+ const name = removeSuffix(removePrefix(basename3, "lib."), ".d.ts");
137163
137163
  const index = libs.indexOf(name);
137164
137164
  if (index !== -1) return index + 1;
137165
137165
  }
@@ -201085,8 +201085,8 @@ ${options.prefix}` : "\n" : options.prefix
201085
201085
  }
201086
201086
  };
201087
201087
  for (const file of files) {
201088
- const basename2 = getBaseFileName(file);
201089
- if (basename2 === "package.json" || basename2 === "bower.json") {
201088
+ const basename3 = getBaseFileName(file);
201089
+ if (basename3 === "package.json" || basename3 === "bower.json") {
201090
201090
  createProjectWatcher(
201091
201091
  file,
201092
201092
  "FileWatcher"
@@ -204770,8 +204770,8 @@ All files are: ${JSON.stringify(names)}`,
204770
204770
  var _a;
204771
204771
  const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
204772
204772
  if (!fileOrDirectoryPath) return;
204773
- const basename2 = getBaseFileName(fileOrDirectoryPath);
204774
- if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a.size) && (basename2 === "package.json" || basename2 === "node_modules")) {
204773
+ const basename3 = getBaseFileName(fileOrDirectoryPath);
204774
+ if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a.size) && (basename3 === "package.json" || basename3 === "node_modules")) {
204775
204775
  result.affectedModuleSpecifierCacheProjects.forEach((project) => {
204776
204776
  var _a2;
204777
204777
  (_a2 = project.getModuleSpecifierCache()) == null ? void 0 : _a2.clear();
@@ -211530,9 +211530,9 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
211530
211530
  };
211531
211531
  }
211532
211532
  })({ get exports() {
211533
- return ts12;
211533
+ return ts13;
211534
211534
  }, set exports(v) {
211535
- ts12 = v;
211535
+ ts13 = v;
211536
211536
  if (typeof module2 !== "undefined" && module2.exports) {
211537
211537
  module2.exports = v;
211538
211538
  }
@@ -213742,7 +213742,7 @@ var require_path_browserify = __commonJS({
213742
213742
  if (hasRoot && end === 1) return "//";
213743
213743
  return path6.slice(0, end);
213744
213744
  },
213745
- basename: function basename2(path6, ext) {
213745
+ basename: function basename3(path6, ext) {
213746
213746
  if (ext !== void 0 && typeof ext !== "string") throw new TypeError('"ext" argument must be a string');
213747
213747
  assertPath(path6);
213748
213748
  var start = 0;
@@ -216527,7 +216527,7 @@ var require_dist2 = __commonJS({
216527
216527
  var require_ts_morph_common = __commonJS({
216528
216528
  "node_modules/@ts-morph/common/dist/ts-morph-common.js"(exports2) {
216529
216529
  "use strict";
216530
- var ts12 = require_typescript();
216530
+ var ts13 = require_typescript();
216531
216531
  var minimatch = require_commonjs3();
216532
216532
  var path$1 = require_path_browserify();
216533
216533
  var fs$1 = require("node:fs");
@@ -216557,7 +216557,7 @@ var require_ts_morph_common = __commonJS({
216557
216557
  n.default = e;
216558
216558
  return Object.freeze(n);
216559
216559
  }
216560
- var ts__namespace = /* @__PURE__ */ _interopNamespaceCompat(ts12);
216560
+ var ts__namespace = /* @__PURE__ */ _interopNamespaceCompat(ts13);
216561
216561
  var minimatch__namespace = /* @__PURE__ */ _interopNamespaceCompat(minimatch);
216562
216562
  var path__default = /* @__PURE__ */ _interopDefaultCompat(path$1);
216563
216563
  var fs__namespace = /* @__PURE__ */ _interopNamespaceCompat(fs$1);
@@ -219667,85 +219667,85 @@ ${nodeLocation}` : message;
219667
219667
  Object.defineProperty(exports2, "DiagnosticCategory", {
219668
219668
  enumerable: true,
219669
219669
  get: function() {
219670
- return ts12.DiagnosticCategory;
219670
+ return ts13.DiagnosticCategory;
219671
219671
  }
219672
219672
  });
219673
219673
  Object.defineProperty(exports2, "EmitHint", {
219674
219674
  enumerable: true,
219675
219675
  get: function() {
219676
- return ts12.EmitHint;
219676
+ return ts13.EmitHint;
219677
219677
  }
219678
219678
  });
219679
219679
  Object.defineProperty(exports2, "LanguageVariant", {
219680
219680
  enumerable: true,
219681
219681
  get: function() {
219682
- return ts12.LanguageVariant;
219682
+ return ts13.LanguageVariant;
219683
219683
  }
219684
219684
  });
219685
219685
  Object.defineProperty(exports2, "ModuleKind", {
219686
219686
  enumerable: true,
219687
219687
  get: function() {
219688
- return ts12.ModuleKind;
219688
+ return ts13.ModuleKind;
219689
219689
  }
219690
219690
  });
219691
219691
  Object.defineProperty(exports2, "ModuleResolutionKind", {
219692
219692
  enumerable: true,
219693
219693
  get: function() {
219694
- return ts12.ModuleResolutionKind;
219694
+ return ts13.ModuleResolutionKind;
219695
219695
  }
219696
219696
  });
219697
219697
  Object.defineProperty(exports2, "NewLineKind", {
219698
219698
  enumerable: true,
219699
219699
  get: function() {
219700
- return ts12.NewLineKind;
219700
+ return ts13.NewLineKind;
219701
219701
  }
219702
219702
  });
219703
219703
  Object.defineProperty(exports2, "NodeFlags", {
219704
219704
  enumerable: true,
219705
219705
  get: function() {
219706
- return ts12.NodeFlags;
219706
+ return ts13.NodeFlags;
219707
219707
  }
219708
219708
  });
219709
219709
  Object.defineProperty(exports2, "ObjectFlags", {
219710
219710
  enumerable: true,
219711
219711
  get: function() {
219712
- return ts12.ObjectFlags;
219712
+ return ts13.ObjectFlags;
219713
219713
  }
219714
219714
  });
219715
219715
  Object.defineProperty(exports2, "ScriptKind", {
219716
219716
  enumerable: true,
219717
219717
  get: function() {
219718
- return ts12.ScriptKind;
219718
+ return ts13.ScriptKind;
219719
219719
  }
219720
219720
  });
219721
219721
  Object.defineProperty(exports2, "ScriptTarget", {
219722
219722
  enumerable: true,
219723
219723
  get: function() {
219724
- return ts12.ScriptTarget;
219724
+ return ts13.ScriptTarget;
219725
219725
  }
219726
219726
  });
219727
219727
  Object.defineProperty(exports2, "SymbolFlags", {
219728
219728
  enumerable: true,
219729
219729
  get: function() {
219730
- return ts12.SymbolFlags;
219730
+ return ts13.SymbolFlags;
219731
219731
  }
219732
219732
  });
219733
219733
  Object.defineProperty(exports2, "SyntaxKind", {
219734
219734
  enumerable: true,
219735
219735
  get: function() {
219736
- return ts12.SyntaxKind;
219736
+ return ts13.SyntaxKind;
219737
219737
  }
219738
219738
  });
219739
219739
  Object.defineProperty(exports2, "TypeFlags", {
219740
219740
  enumerable: true,
219741
219741
  get: function() {
219742
- return ts12.TypeFlags;
219742
+ return ts13.TypeFlags;
219743
219743
  }
219744
219744
  });
219745
219745
  Object.defineProperty(exports2, "TypeFormatFlags", {
219746
219746
  enumerable: true,
219747
219747
  get: function() {
219748
- return ts12.TypeFormatFlags;
219748
+ return ts13.TypeFormatFlags;
219749
219749
  }
219750
219750
  });
219751
219751
  exports2.ts = ts__namespace;
@@ -242861,17 +242861,54 @@ var AstReader = class _AstReader {
242861
242861
  names.add(node.text);
242862
242862
  return names;
242863
242863
  }
242864
- if (import_ts_morph.ts.isPropertyAccessExpression(node)) {
242865
- return this.collectReferencedIdentifiers(node.expression, names);
242864
+ if (import_ts_morph.ts.isBindingElement(node)) {
242865
+ if (node.propertyName !== void 0 && import_ts_morph.ts.isComputedPropertyName(node.propertyName)) {
242866
+ this.collectReferencedIdentifiers(node.propertyName.expression, names);
242867
+ }
242868
+ this.collectReferencedIdentifiers(node.name, names);
242869
+ return node.initializer === void 0 ? names : this.collectReferencedIdentifiers(node.initializer, names);
242866
242870
  }
242867
- if (import_ts_morph.ts.isPropertyAssignment(node)) {
242868
- return this.collectReferencedIdentifiers(node.initializer, names);
242871
+ const slotName = "name" in node && node.name !== void 0 && import_ts_morph.ts.isIdentifier(node.name) && !import_ts_morph.ts.isShorthandPropertyAssignment(node) ? node.name : void 0;
242872
+ import_ts_morph.ts.forEachChild(node, (child) => {
242873
+ if (child !== slotName) {
242874
+ this.collectReferencedIdentifiers(child, names);
242875
+ }
242876
+ });
242877
+ return names;
242878
+ }
242879
+ /**
242880
+ * The names the provider file declares anywhere in itself, less the file's own base name, which
242881
+ * is the name the generated data file imports the provider by.
242882
+ */
242883
+ collectFileNames(sourceFile, filePath) {
242884
+ const names = this.collectDeclaredNames(sourceFile.compilerNode);
242885
+ names.delete(path.basename(filePath, ".ts"));
242886
+ return names;
242887
+ }
242888
+ /**
242889
+ * The names a node declares, such as the parameters of an inline handler.
242890
+ *
242891
+ * A name any part of an expression declares counts as declared throughout it, which reads a
242892
+ * shadowed name as declared rather than stopping on it.
242893
+ */
242894
+ collectDeclaredNames(node, names = /* @__PURE__ */ new Set()) {
242895
+ if (_AstReader.declaresName(node) && node.name !== void 0 && import_ts_morph.ts.isIdentifier(node.name)) {
242896
+ names.add(node.name.text);
242869
242897
  }
242870
242898
  import_ts_morph.ts.forEachChild(node, (child) => {
242871
- this.collectReferencedIdentifiers(child, names);
242899
+ this.collectDeclaredNames(child, names);
242872
242900
  });
242873
242901
  return names;
242874
242902
  }
242903
+ /**
242904
+ * Whether a node's `name` declares a binding rather than naming one.
242905
+ *
242906
+ * A property access, a shorthand property and an object-literal key all carry a `name` that
242907
+ * references or keys instead of declaring, so the kind decides rather than the slot.
242908
+ */
242909
+ static declaresName(node) {
242910
+ return import_ts_morph.ts.isParameter(node) || import_ts_morph.ts.isVariableDeclaration(node) || import_ts_morph.ts.isBindingElement(node) || import_ts_morph.ts.isFunctionDeclaration(node) || import_ts_morph.ts.isFunctionExpression(node) || import_ts_morph.ts.isClassDeclaration(node) || import_ts_morph.ts.isClassExpression(node) || import_ts_morph.ts.isEnumDeclaration(node) || import_ts_morph.ts.isModuleDeclaration(node);
242911
+ }
242875
242912
  /**
242876
242913
  * Extract service ID strings from keys of an object-returning method.
242877
242914
  *
@@ -244010,8 +244047,8 @@ var Header = class extends Message {
244010
244047
 
244011
244048
  // src/Sindri/Constant/SindriInfo.ts
244012
244049
  var SindriInfo = class {
244013
- static VERSION = "26.6.64";
244014
- static VERSION_BUILD_DATE_TIME = "October 10 2026 10:39:52 MST";
244050
+ static VERSION = "26.6.66";
244051
+ static VERSION_BUILD_DATE_TIME = "October 12 2026 14:34:58 MST";
244015
244052
  static ICON = ` \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
244016
244053
  \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588
244017
244054
  \u2588\u2588\u2588\u2588
@@ -245487,10 +245524,16 @@ var ListenerData = class {
245487
245524
 
245488
245525
  // src/Sindri/Ast/Data/Result/ListenerAttributeResult.ts
245489
245526
  var ListenerAttributeResult = class {
245490
- constructor(listeners = {}) {
245527
+ /**
245528
+ * @param listeners A Map, because an object reorders a key that reads as an integer
245529
+ * @param importMap Class short name → absolute file path for the handler imports
245530
+ */
245531
+ constructor(listeners = /* @__PURE__ */ new Map(), importMap = {}) {
245491
245532
  this.listeners = listeners;
245533
+ this.importMap = importMap;
245492
245534
  }
245493
245535
  listeners;
245536
+ importMap;
245494
245537
  };
245495
245538
 
245496
245539
  // src/Sindri/Ast/ListenerAttributeReader.ts
@@ -245502,22 +245545,46 @@ var ListenerAttributeReader = class _ListenerAttributeReader extends AstReader {
245502
245545
  return new ListenerAttributeResult();
245503
245546
  }
245504
245547
  const { classDecl, useMap, currentClass } = context;
245505
- const listeners = {};
245548
+ const listeners = /* @__PURE__ */ new Map();
245549
+ const listenerData = [];
245506
245550
  for (const decorator of this.findDecoratorsOnNode(classDecl, "Listener", useMap, filePath)) {
245507
245551
  const data = this.buildListenerData(decorator, useMap, filePath, currentClass, classDecl, void 0);
245508
245552
  if (data !== null) {
245509
- listeners[data.name] = this.buildListenerExpr(data);
245553
+ listeners.set(data.name, this.buildListenerExpr(data));
245554
+ listenerData.push(data);
245510
245555
  }
245511
245556
  }
245512
245557
  for (const method of classDecl.getMethods()) {
245513
245558
  for (const decorator of this.findDecoratorsOnNode(method, "Listener", useMap, filePath)) {
245514
245559
  const data = this.buildListenerData(decorator, useMap, filePath, currentClass, classDecl, method);
245515
245560
  if (data !== null) {
245516
- listeners[data.name] = this.buildListenerExpr(data);
245561
+ listeners.set(data.name, this.buildListenerExpr(data));
245562
+ listenerData.push(data);
245517
245563
  }
245518
245564
  }
245519
245565
  }
245520
- return new ListenerAttributeResult(listeners);
245566
+ return new ListenerAttributeResult(
245567
+ listeners,
245568
+ this.buildImportMap(listenerData, useMap, filePath, currentClass)
245569
+ );
245570
+ }
245571
+ /**
245572
+ * Build the class-name → absolute-file-path map for every handler class the generated data
245573
+ * cache references.
245574
+ */
245575
+ buildImportMap(listenerData, useMap, currentFilePath, currentClass) {
245576
+ const importMap = {};
245577
+ for (const data of listenerData) {
245578
+ if (data.handler === null) {
245579
+ continue;
245580
+ }
245581
+ const shortName = data.handler.class.slice(data.handler.class.lastIndexOf("\\") + 1);
245582
+ const filePath = shortName === currentClass ? currentFilePath : this.resolveClassToFilePath(shortName, useMap, currentFilePath);
245583
+ if (filePath !== "") {
245584
+ importMap[shortName] = filePath;
245585
+ }
245586
+ }
245587
+ return importMap;
245521
245588
  }
245522
245589
  buildListenerData(decorator, useMap, currentFilePath, currentClass, classDecl, method) {
245523
245590
  const eventId = this.extractStringArg(decorator, 0, useMap, currentFilePath, currentClass);
@@ -245563,22 +245630,44 @@ var ListenerAttributeReader = class _ListenerAttributeReader extends AstReader {
245563
245630
  }
245564
245631
  };
245565
245632
 
245633
+ // src/Sindri/Ast/ListenerProviderReader.ts
245634
+ var import_ts_morph7 = __toESM(require_ts_morph(), 1);
245635
+
245566
245636
  // src/Sindri/Ast/Data/Result/ListenerProviderResult.ts
245567
245637
  var ListenerProviderResult = class _ListenerProviderResult {
245568
- constructor(listenerClasses = [], listeners = []) {
245638
+ /**
245639
+ * @param listenerImports Local name → absolute file path for every class the `listeners`
245640
+ * expressions reference
245641
+ */
245642
+ constructor(listenerClasses = [], listeners = [], listenerImports = {}) {
245569
245643
  this.listenerClasses = listenerClasses;
245570
245644
  this.listeners = listeners;
245645
+ this.listenerImports = listenerImports;
245571
245646
  }
245572
245647
  listenerClasses;
245573
245648
  listeners;
245649
+ listenerImports;
245574
245650
  merge(other) {
245575
245651
  return new _ListenerProviderResult(
245576
245652
  [.../* @__PURE__ */ new Set([...this.listenerClasses, ...other.listenerClasses])],
245577
- [...this.listeners, ...other.listeners]
245653
+ [...this.listeners, ...other.listeners],
245654
+ { ...this.listenerImports, ...other.listenerImports }
245578
245655
  );
245579
245656
  }
245580
245657
  };
245581
245658
 
245659
+ // src/Sindri/Throwable/Exception/Abstract/SindriInvalidArgumentException.ts
245660
+ var SindriInvalidArgumentException = class extends ValkyrjaInvalidArgumentException {
245661
+ };
245662
+
245663
+ // src/Sindri/Ast/Throwable/Exception/Abstract/AstInvalidArgumentException.ts
245664
+ var AstInvalidArgumentException = class extends SindriInvalidArgumentException {
245665
+ };
245666
+
245667
+ // src/Sindri/Ast/Throwable/Exception/AstUnreadableListenerException.ts
245668
+ var AstUnreadableListenerException = class extends AstInvalidArgumentException {
245669
+ };
245670
+
245582
245671
  // src/Sindri/Ast/ListenerProviderReader.ts
245583
245672
  var ListenerProviderReader = class _ListenerProviderReader extends AstReader {
245584
245673
  static METHOD_LISTENER_CLASSES = "getListenerClasses";
@@ -245591,18 +245680,62 @@ var ListenerProviderReader = class _ListenerProviderReader extends AstReader {
245591
245680
  }
245592
245681
  const useMap = this.buildUseMap(sourceFile);
245593
245682
  const methods = this.indexMethods(classDecl);
245683
+ const listeners = this.extractListeners(methods[_ListenerProviderReader.METHOD_LISTENERS]);
245594
245684
  return new ListenerProviderResult(
245595
245685
  this.extractClassListFromValues(methods[_ListenerProviderReader.METHOD_LISTENER_CLASSES], useMap, filePath),
245596
- this.extractListeners(methods[_ListenerProviderReader.METHOD_LISTENERS], useMap, filePath)
245686
+ listeners,
245687
+ this.extractListenerImports(listeners, useMap, filePath, this.collectFileNames(sourceFile, filePath))
245597
245688
  );
245598
245689
  }
245599
- extractListeners(_method, _useMap, _filePath) {
245600
- return [];
245690
+ /**
245691
+ * Extract the listeners a provider's `getListeners()` method returns, which the generator
245692
+ * emits verbatim.
245693
+ */
245694
+ extractListeners(method) {
245695
+ if (method === void 0) {
245696
+ return [];
245697
+ }
245698
+ const array = this.findReturnedArray(method);
245699
+ if (array === void 0) {
245700
+ return [];
245701
+ }
245702
+ return array.elements.filter((element) => this.isConstructedListener(element));
245703
+ }
245704
+ /** Whether an expression declares a listener through a construction, with or without a chain. */
245705
+ isConstructedListener(expression) {
245706
+ let current = this.unwrapTypeAssertions(expression);
245707
+ while (import_ts_morph7.ts.isCallExpression(current) && import_ts_morph7.ts.isPropertyAccessExpression(current.expression)) {
245708
+ current = this.unwrapTypeAssertions(current.expression.expression);
245709
+ }
245710
+ return import_ts_morph7.ts.isNewExpression(current);
245711
+ }
245712
+ /**
245713
+ * Resolve every class the listener expressions reference to its absolute file path, so the
245714
+ * generated data cache can import them.
245715
+ */
245716
+ extractListenerImports(listeners, useMap, filePath, fileNames) {
245717
+ const imports = {};
245718
+ for (const listener of listeners) {
245719
+ const declaredNames = this.collectDeclaredNames(listener);
245720
+ for (const name of this.collectReferencedIdentifiers(listener)) {
245721
+ const resolved = this.resolveImportToFilePath(name, useMap, filePath);
245722
+ if (resolved !== "") {
245723
+ imports[name] = resolved;
245724
+ continue;
245725
+ }
245726
+ if (fileNames.has(name) && !declaredNames.has(name)) {
245727
+ throw new AstUnreadableListenerException(
245728
+ `Cannot read the listener '${listener.getText()}': the generated data cannot import '${name}', which the provider declares for itself.`
245729
+ );
245730
+ }
245731
+ }
245732
+ }
245733
+ return imports;
245601
245734
  }
245602
245735
  };
245603
245736
 
245604
245737
  // src/Sindri/Ast/RouteProviderReader.ts
245605
- var import_ts_morph7 = __toESM(require_ts_morph(), 1);
245738
+ var import_ts_morph8 = __toESM(require_ts_morph(), 1);
245606
245739
 
245607
245740
  // src/Sindri/Ast/Data/Result/RouteProviderResult.ts
245608
245741
  var RouteProviderResult = class _RouteProviderResult {
@@ -245628,6 +245761,10 @@ var RouteProviderResult = class _RouteProviderResult {
245628
245761
  }
245629
245762
  };
245630
245763
 
245764
+ // src/Sindri/Ast/Throwable/Exception/AstUnreadableRouteException.ts
245765
+ var AstUnreadableRouteException = class extends AstInvalidArgumentException {
245766
+ };
245767
+
245631
245768
  // src/Sindri/Ast/RouteProviderReader.ts
245632
245769
  var RouteProviderReader = class _RouteProviderReader extends AstReader {
245633
245770
  static METHOD_CONTROLLER_CLASSES = "getControllerClasses";
@@ -245641,19 +245778,17 @@ var RouteProviderReader = class _RouteProviderReader extends AstReader {
245641
245778
  const useMap = this.buildUseMap(sourceFile);
245642
245779
  const methods = this.indexMethods(classDecl);
245643
245780
  const routes = this.extractRoutes(methods[_RouteProviderReader.METHOD_ROUTES], useMap, filePath);
245781
+ const routeImports = this.extractRouteImports(routes, useMap, filePath);
245782
+ this.validateRouteImports(routes, routeImports, useMap, this.collectFileNames(sourceFile, filePath));
245644
245783
  return new RouteProviderResult(
245645
245784
  this.extractClassListFromValues(methods[_RouteProviderReader.METHOD_CONTROLLER_CLASSES], useMap, filePath),
245646
245785
  routes,
245647
- this.extractRouteImports(routes, useMap, filePath)
245786
+ routeImports
245648
245787
  );
245649
245788
  }
245650
245789
  /**
245651
- * Resolve every class the imperative route expressions reference to its
245652
- * absolute file path, so the generated data cache can import them.
245653
- *
245654
- * Names that are not imported by the provider file — locals, globals, and
245655
- * the provider's own class (which the generator imports separately) — have
245656
- * no entry in the use map and are skipped.
245790
+ * Resolve every class the imperative route expressions reference to its absolute file path, so
245791
+ * the generated data cache can import them.
245657
245792
  */
245658
245793
  extractRouteImports(routes, useMap, filePath) {
245659
245794
  const imports = {};
@@ -245667,6 +245802,27 @@ var RouteProviderReader = class _RouteProviderReader extends AstReader {
245667
245802
  }
245668
245803
  return imports;
245669
245804
  }
245805
+ /** Stop on a name a route references that the generated data file, in another module, cannot reach. */
245806
+ validateRouteImports(routes, routeImports, useMap, fileNames) {
245807
+ for (const route2 of routes) {
245808
+ const declaredNames = this.collectDeclaredNames(route2);
245809
+ for (const name of this.collectReferencedIdentifiers(route2)) {
245810
+ if (routeImports[name] !== void 0 || declaredNames.has(name)) {
245811
+ continue;
245812
+ }
245813
+ if (fileNames.has(name)) {
245814
+ throw new AstUnreadableRouteException(
245815
+ `Cannot read the route '${route2.getText()}': the generated data cannot import '${name}', which the provider declares for itself.`
245816
+ );
245817
+ }
245818
+ if (useMap[name] !== void 0) {
245819
+ throw new AstUnreadableRouteException(
245820
+ `Cannot read the route '${route2.getText()}': the import of '${name}' resolves to no TypeScript file.`
245821
+ );
245822
+ }
245823
+ }
245824
+ }
245825
+ }
245670
245826
  /**
245671
245827
  * Extract the route objects returned by a provider's `getRoutes()` method.
245672
245828
  *
@@ -245686,12 +245842,12 @@ var RouteProviderReader = class _RouteProviderReader extends AstReader {
245686
245842
  if (array === void 0) {
245687
245843
  return [];
245688
245844
  }
245689
- return array.elements.filter((element) => import_ts_morph7.ts.isNewExpression(element));
245845
+ return array.elements.filter((element) => import_ts_morph8.ts.isNewExpression(element));
245690
245846
  }
245691
245847
  };
245692
245848
 
245693
245849
  // src/Sindri/Ast/ServiceProviderReader.ts
245694
- var import_ts_morph8 = __toESM(require_ts_morph(), 1);
245850
+ var import_ts_morph9 = __toESM(require_ts_morph(), 1);
245695
245851
 
245696
245852
  // src/Sindri/Ast/Data/Result/ServiceProviderResult.ts
245697
245853
  var ServiceProviderResult = class _ServiceProviderResult {
@@ -245744,7 +245900,7 @@ var ServiceProviderReader = class _ServiceProviderReader extends AstReader {
245744
245900
  }
245745
245901
  const map = {};
245746
245902
  for (const prop of obj.properties) {
245747
- if (!import_ts_morph8.ts.isPropertyAssignment(prop)) {
245903
+ if (!import_ts_morph9.ts.isPropertyAssignment(prop)) {
245748
245904
  continue;
245749
245905
  }
245750
245906
  const serviceId = this.resolvePropertyKeyToString(prop.name, useMap, filePath);
@@ -245765,8 +245921,8 @@ var ServiceProviderReader = class _ServiceProviderReader extends AstReader {
245765
245921
  * Handles: `ProviderClass.publishMethod` and `[ProviderClass, 'method']`.
245766
245922
  */
245767
245923
  extractHandlerFromValue(node, useMap, filePath, currentClass) {
245768
- if (import_ts_morph8.ts.isPropertyAccessExpression(node)) {
245769
- const className = import_ts_morph8.ts.isIdentifier(node.expression) ? node.expression.text : void 0;
245924
+ if (import_ts_morph9.ts.isPropertyAccessExpression(node)) {
245925
+ const className = import_ts_morph9.ts.isIdentifier(node.expression) ? node.expression.text : void 0;
245770
245926
  if (className === void 0) {
245771
245927
  return void 0;
245772
245928
  }
@@ -245774,7 +245930,7 @@ var ServiceProviderReader = class _ServiceProviderReader extends AstReader {
245774
245930
  const resolvedClass = className === "self" || className === "this" ? currentClass : className;
245775
245931
  return [resolvedClass, methodName];
245776
245932
  }
245777
- if (import_ts_morph8.ts.isArrayLiteralExpression(node) && node.elements.length === 2) {
245933
+ if (import_ts_morph9.ts.isArrayLiteralExpression(node) && node.elements.length === 2) {
245778
245934
  const raw = this.extractHandlerFromTsArray(node, useMap, filePath, currentClass);
245779
245935
  if (raw !== void 0) {
245780
245936
  return [raw.class, raw.method];
@@ -245785,7 +245941,7 @@ var ServiceProviderReader = class _ServiceProviderReader extends AstReader {
245785
245941
  };
245786
245942
 
245787
245943
  // src/Sindri/Generator/Ast/Cli/AstCliDataFileGenerator.ts
245788
- var import_ts_morph9 = __toESM(require_ts_morph(), 1);
245944
+ var import_ts_morph10 = __toESM(require_ts_morph(), 1);
245789
245945
  var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGenerator {
245790
245946
  /** The framework classes every generated CLI data file imports as values. */
245791
245947
  static FRAMEWORK_IMPORTS = {
@@ -245803,13 +245959,13 @@ var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGene
245803
245959
  RouteContract: "@valkyrjaio/valkyrja/Cli/Routing/Data/Contract/RouteContract.ts"
245804
245960
  };
245805
245961
  classImportMap = {};
245806
- printer = import_ts_morph9.ts.createPrinter({ newLine: import_ts_morph9.ts.NewLineKind.LineFeed });
245807
- dummySourceFile = import_ts_morph9.ts.createSourceFile(
245962
+ printer = import_ts_morph10.ts.createPrinter({ newLine: import_ts_morph10.ts.NewLineKind.LineFeed });
245963
+ dummySourceFile = import_ts_morph10.ts.createSourceFile(
245808
245964
  "_dummy.ts",
245809
245965
  "",
245810
- import_ts_morph9.ts.ScriptTarget.ESNext,
245966
+ import_ts_morph10.ts.ScriptTarget.ESNext,
245811
245967
  false,
245812
- import_ts_morph9.ts.ScriptKind.TS
245968
+ import_ts_morph10.ts.ScriptKind.TS
245813
245969
  );
245814
245970
  generateFile(directory, className, namespace, routes) {
245815
245971
  const userImportsBlock = this.buildUserImportsBlock(this.classImportMap, [
@@ -245849,7 +246005,7 @@ var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGene
245849
246005
  generateMergedFile(directory, className, namespace, routes, routeExprs) {
245850
246006
  const merged = { ...routes };
245851
246007
  for (const expr of routeExprs) {
245852
- if (!import_ts_morph9.ts.isNewExpression(expr)) {
246008
+ if (!import_ts_morph10.ts.isNewExpression(expr)) {
245853
246009
  continue;
245854
246010
  }
245855
246011
  const key = this.routeKey((expr.arguments ?? [])[0]);
@@ -245873,10 +246029,10 @@ var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGene
245873
246029
  if (nameArg === void 0) {
245874
246030
  return void 0;
245875
246031
  }
245876
- if (import_ts_morph9.ts.isStringLiteral(nameArg)) {
246032
+ if (import_ts_morph10.ts.isStringLiteral(nameArg)) {
245877
246033
  return nameArg.text;
245878
246034
  }
245879
- if (import_ts_morph9.ts.isPropertyAccessExpression(nameArg) && import_ts_morph9.ts.isIdentifier(nameArg.expression)) {
246035
+ if (import_ts_morph10.ts.isPropertyAccessExpression(nameArg) && import_ts_morph10.ts.isIdentifier(nameArg.expression)) {
245880
246036
  return `${nameArg.expression.text}::${nameArg.name.text}`;
245881
246037
  }
245882
246038
  return void 0;
@@ -245889,7 +246045,7 @@ var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGene
245889
246045
  const lines = [];
245890
246046
  for (const [key, valueExpr] of entries) {
245891
246047
  const printedValue = this.printExpr(valueExpr);
245892
- const formattedKey = key.includes("::") ? `[${this.printer.printNode(import_ts_morph9.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(key), this.dummySourceFile)}]` : `['${key}']`;
246048
+ const formattedKey = key.includes("::") ? `[${this.printer.printNode(import_ts_morph10.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(key), this.dummySourceFile)}]` : `['${key}']`;
245893
246049
  lines.push(` ${formattedKey}: (): RouteContract => ${printedValue},`);
245894
246050
  }
245895
246051
  return ["super({", ...lines, " });"].join("\n ");
@@ -245900,12 +246056,12 @@ var AstCliDataFileGenerator = class _AstCliDataFileGenerator extends AstFileGene
245900
246056
  * carry no source positions) are emitted through the printer.
245901
246057
  */
245902
246058
  printExpr(expr) {
245903
- return expr.pos >= 0 ? expr.getText() : this.printer.printNode(import_ts_morph9.ts.EmitHint.Unspecified, expr, this.dummySourceFile);
246059
+ return expr.pos >= 0 ? expr.getText() : this.printer.printNode(import_ts_morph10.ts.EmitHint.Unspecified, expr, this.dummySourceFile);
245904
246060
  }
245905
246061
  };
245906
246062
 
245907
246063
  // src/Sindri/Generator/Ast/Container/AstContainerDataFileGenerator.ts
245908
- var import_ts_morph10 = __toESM(require_ts_morph(), 1);
246064
+ var import_ts_morph11 = __toESM(require_ts_morph(), 1);
245909
246065
  var AstContainerDataFileGenerator = class _AstContainerDataFileGenerator extends AstFileGenerator {
245910
246066
  /** The framework class every generated container data file imports as a value. */
245911
246067
  static FRAMEWORK_IMPORTS = {
@@ -245916,13 +246072,13 @@ var AstContainerDataFileGenerator = class _AstContainerDataFileGenerator extends
245916
246072
  ContainerContract: "@valkyrjaio/valkyrja/Container/Manager/Contract/ContainerContract.ts"
245917
246073
  };
245918
246074
  classImportMap = {};
245919
- printer = import_ts_morph10.ts.createPrinter({ newLine: import_ts_morph10.ts.NewLineKind.LineFeed });
245920
- dummySourceFile = import_ts_morph10.ts.createSourceFile(
246075
+ printer = import_ts_morph11.ts.createPrinter({ newLine: import_ts_morph11.ts.NewLineKind.LineFeed });
246076
+ dummySourceFile = import_ts_morph11.ts.createSourceFile(
245921
246077
  "_dummy.ts",
245922
246078
  "",
245923
- import_ts_morph10.ts.ScriptTarget.ESNext,
246079
+ import_ts_morph11.ts.ScriptTarget.ESNext,
245924
246080
  false,
245925
- import_ts_morph10.ts.ScriptKind.TS
246081
+ import_ts_morph11.ts.ScriptKind.TS
245926
246082
  );
245927
246083
  generateFile(directory, className, namespace, publishers) {
245928
246084
  const userImportsBlock = this.buildUserImportsBlock(this.classImportMap, [
@@ -245953,7 +246109,7 @@ var AstContainerDataFileGenerator = class _AstContainerDataFileGenerator extends
245953
246109
  const lines = [];
245954
246110
  for (const [serviceId, [providerClass, methodName]] of entries) {
245955
246111
  const shortProviderClass = providerClass.slice(providerClass.lastIndexOf("\\") + 1);
245956
- const formattedKey = serviceId.includes("::") ? `[${this.printer.printNode(import_ts_morph10.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(serviceId), this.dummySourceFile)}]` : `['${serviceId}']`;
246112
+ const formattedKey = serviceId.includes("::") ? `[${this.printer.printNode(import_ts_morph11.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(serviceId), this.dummySourceFile)}]` : `['${serviceId}']`;
245957
246113
  lines.push(
245958
246114
  ` ${formattedKey}: (container: ContainerContract) => ${shortProviderClass}.${methodName}(container),`
245959
246115
  );
@@ -245965,7 +246121,17 @@ var AstContainerDataFileGenerator = class _AstContainerDataFileGenerator extends
245965
246121
  };
245966
246122
 
245967
246123
  // src/Sindri/Generator/Ast/Event/AstEventDataFileGenerator.ts
245968
- var import_ts_morph11 = __toESM(require_ts_morph(), 1);
246124
+ var import_ts_morph12 = __toESM(require_ts_morph(), 1);
246125
+
246126
+ // src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorInvalidArgumentException.ts
246127
+ var GeneratorInvalidArgumentException = class extends SindriInvalidArgumentException {
246128
+ };
246129
+
246130
+ // src/Sindri/Generator/Throwable/Exception/GeneratorUnreadableListenerException.ts
246131
+ var GeneratorUnreadableListenerException = class extends GeneratorInvalidArgumentException {
246132
+ };
246133
+
246134
+ // src/Sindri/Generator/Ast/Event/AstEventDataFileGenerator.ts
245969
246135
  var AstEventDataFileGenerator = class _AstEventDataFileGenerator extends AstFileGenerator {
245970
246136
  /** The framework class every generated event data file imports as a value. */
245971
246137
  static FRAMEWORK_IMPORTS = {
@@ -245979,23 +246145,58 @@ var AstEventDataFileGenerator = class _AstEventDataFileGenerator extends AstFile
245979
246145
  static LISTENER_TYPE_IMPORTS = {
245980
246146
  ListenerContract: "@valkyrjaio/valkyrja/Event/Data/Contract/ListenerContract.ts"
245981
246147
  };
246148
+ /** The builders `ListenerContract` declares. */
246149
+ static LISTENER_BUILDERS = ["withEventId", "withName", "withHandler"];
246150
+ /** The builder that replaces a listener's event id. */
246151
+ static BUILDER_EVENT_ID = "withEventId";
246152
+ /** The builder that replaces a listener's name. */
246153
+ static BUILDER_NAME = "withName";
246154
+ /** The position of the event id in a `Listener` construction. */
246155
+ static ARGUMENT_EVENT_ID = 0;
246156
+ /** The position of the listener name in a `Listener` construction. */
246157
+ static ARGUMENT_NAME = 1;
245982
246158
  classImportMap = {};
245983
- printer = import_ts_morph11.ts.createPrinter({ newLine: import_ts_morph11.ts.NewLineKind.LineFeed });
245984
- dummySourceFile = import_ts_morph11.ts.createSourceFile(
246159
+ printer = import_ts_morph12.ts.createPrinter({ newLine: import_ts_morph12.ts.NewLineKind.LineFeed });
246160
+ dummySourceFile = import_ts_morph12.ts.createSourceFile(
245985
246161
  "_dummy.ts",
245986
246162
  "",
245987
- import_ts_morph11.ts.ScriptTarget.ESNext,
246163
+ import_ts_morph12.ts.ScriptTarget.ESNext,
245988
246164
  false,
245989
- import_ts_morph11.ts.ScriptKind.TS
246165
+ import_ts_morph12.ts.ScriptKind.TS
245990
246166
  );
245991
246167
  generateFile(directory, className, namespace, listeners) {
246168
+ return this.generateMergedFile(directory, className, namespace, listeners, []);
246169
+ }
246170
+ /**
246171
+ * Generate the event data file from the decorated listeners and the listeners a provider
246172
+ * declares by hand.
246173
+ */
246174
+ generateMergedFile(directory, className, namespace, listeners, listenerExprs) {
246175
+ const factories = /* @__PURE__ */ new Map();
246176
+ const events = /* @__PURE__ */ new Map();
246177
+ for (const [name, listener] of listeners) {
246178
+ this.fileListener(
246179
+ factories,
246180
+ events,
246181
+ this.stringSource(name),
246182
+ this.readListenerKeys(listener).eventId,
246183
+ listener
246184
+ );
246185
+ }
246186
+ for (const listener of listenerExprs) {
246187
+ const keys = this.readListenerKeys(listener);
246188
+ if (keys.name === void 0 || keys.eventId === void 0) {
246189
+ continue;
246190
+ }
246191
+ this.fileListener(factories, events, keys.name, keys.eventId, listener);
246192
+ }
245992
246193
  const userImportsBlock = this.buildUserImportsBlock(this.classImportMap, [
245993
246194
  ...Object.keys(_AstEventDataFileGenerator.FRAMEWORK_IMPORTS),
245994
246195
  ...Object.keys(_AstEventDataFileGenerator.LISTENER_IMPORTS),
245995
246196
  ...Object.keys(_AstEventDataFileGenerator.LISTENER_TYPE_IMPORTS)
245996
246197
  ]);
245997
- const contents = this.generateClassContents(listeners);
245998
- const listenerImports = Object.keys(listeners).length > 0 ? [
246198
+ const contents = this.generateClassContents(factories, events);
246199
+ const listenerImports = factories.size > 0 ? [
245999
246200
  ...this.buildFrameworkImportLines(_AstEventDataFileGenerator.LISTENER_IMPORTS),
246000
246201
  ...this.buildFrameworkImportLines(_AstEventDataFileGenerator.LISTENER_TYPE_IMPORTS, true)
246001
246202
  ] : [];
@@ -246014,24 +246215,187 @@ var AstEventDataFileGenerator = class _AstEventDataFileGenerator extends AstFile
246014
246215
  ].join("\n");
246015
246216
  return this.writeFile(directory, className, data);
246016
246217
  }
246017
- generateClassContents(listeners) {
246018
- const entries = Object.entries(listeners);
246019
- if (entries.length === 0) {
246218
+ generateClassContents(factories, events) {
246219
+ if (factories.size === 0) {
246020
246220
  return "super();";
246021
246221
  }
246022
- const lines = [];
246023
- for (const [key, valueExpr] of entries) {
246024
- const printed = this.printer.printNode(import_ts_morph11.ts.EmitHint.Unspecified, valueExpr, this.dummySourceFile);
246025
- lines.push(` ['${key}']: (): ListenerContract => ${printed},`);
246222
+ return [
246223
+ "super(",
246224
+ ...this.wrapMapLines(this.buildEventIndexLines(events)),
246225
+ ...this.wrapMapLines(this.buildListenerLines(factories)),
246226
+ " );"
246227
+ ].join("\n");
246228
+ }
246229
+ /**
246230
+ * File one listener into the listener map and the event index, the way
246231
+ * `ListenerCollection.addListener` files it.
246232
+ *
246233
+ * @param name The source text of the key the listener map files the listener under
246234
+ * @param eventId The source text of the key the event index files the name under, or nothing
246235
+ * when the listener names no event id a key can read
246236
+ */
246237
+ fileListener(factories, events, name, eventId, listener) {
246238
+ factories.set(name, listener);
246239
+ if (eventId === void 0) {
246240
+ return;
246026
246241
  }
246027
- return ["super(", " {},", " {", ...lines, " },", " );"].join(
246028
- "\n "
246242
+ const names = events.get(eventId);
246243
+ if (names === void 0) {
246244
+ events.set(eventId, [name]);
246245
+ return;
246246
+ }
246247
+ if (!names.includes(name)) {
246248
+ names.push(name);
246249
+ }
246250
+ }
246251
+ /**
246252
+ * Read the event id and the name the listener an expression declares ends up with.
246253
+ *
246254
+ * The chain is walked from the outermost call inward, so the first `withEventId` and the first
246255
+ * `withName` it reaches are the last ones the framework applies.
246256
+ */
246257
+ readListenerKeys(listener) {
246258
+ let eventIdArgument = void 0;
246259
+ let nameArgument = void 0;
246260
+ let eventIdReplaced = false;
246261
+ let nameReplaced = false;
246262
+ this.requireNoTypeBinding(listener);
246263
+ let current = this.readValueExpression(listener);
246264
+ while (import_ts_morph12.ts.isCallExpression(current) && import_ts_morph12.ts.isPropertyAccessExpression(current.expression)) {
246265
+ const builder = current.expression.name.text;
246266
+ if (!_AstEventDataFileGenerator.LISTENER_BUILDERS.includes(builder)) {
246267
+ throw new GeneratorUnreadableListenerException(
246268
+ `Cannot read the listener '${this.printExpr(current)}': '${builder}' is not a listener builder.`
246269
+ );
246270
+ }
246271
+ if (builder === _AstEventDataFileGenerator.BUILDER_EVENT_ID && !eventIdReplaced) {
246272
+ eventIdReplaced = true;
246273
+ eventIdArgument = current.arguments[0];
246274
+ }
246275
+ if (builder === _AstEventDataFileGenerator.BUILDER_NAME && !nameReplaced) {
246276
+ nameReplaced = true;
246277
+ nameArgument = current.arguments[0];
246278
+ }
246279
+ current = this.readValueExpression(current.expression.expression);
246280
+ }
246281
+ if (!import_ts_morph12.ts.isNewExpression(current)) {
246282
+ return { eventId: void 0, name: void 0 };
246283
+ }
246284
+ const args = current.arguments ?? [];
246285
+ if (!eventIdReplaced) {
246286
+ eventIdArgument = args[_AstEventDataFileGenerator.ARGUMENT_EVENT_ID];
246287
+ }
246288
+ if (!nameReplaced) {
246289
+ nameArgument = args[_AstEventDataFileGenerator.ARGUMENT_NAME];
246290
+ }
246291
+ return { eventId: this.keySource(eventIdArgument), name: this.keySource(nameArgument) };
246292
+ }
246293
+ /**
246294
+ * Read the source text of one key an argument names, which is nothing when the generated file
246295
+ * cannot name that key before the application runs.
246296
+ */
246297
+ keySource(argument) {
246298
+ if (argument === void 0) {
246299
+ return void 0;
246300
+ }
246301
+ const value = this.readValueExpression(argument);
246302
+ if (import_ts_morph12.ts.isStringLiteral(value)) {
246303
+ return this.stringSource(value.text);
246304
+ }
246305
+ if (!import_ts_morph12.ts.isPropertyAccessExpression(value) || !import_ts_morph12.ts.isIdentifier(value.expression)) {
246306
+ return void 0;
246307
+ }
246308
+ if (!Object.hasOwn(this.classImportMap, value.expression.text)) {
246309
+ throw new GeneratorUnreadableListenerException(
246310
+ `Cannot read the listener key '${this.printExpr(value)}': the generated data imports no '${value.expression.text}'.`
246311
+ );
246312
+ }
246313
+ return this.printExpr(value);
246314
+ }
246315
+ /** Build the lines of the event index, which files each listener name under its event id. */
246316
+ buildEventIndexLines(events) {
246317
+ return [...events].map(([eventId, names]) => ` [${eventId}]: [${names.join(", ")}],`);
246318
+ }
246319
+ /** Build the lines of the listener map, which holds a factory for each listener name. */
246320
+ buildListenerLines(factories) {
246321
+ return [...factories].map(
246322
+ ([name, listener]) => ` [${name}]: (): ListenerContract => ${this.printExpr(listener)},`
246323
+ );
246324
+ }
246325
+ /** Wrap the lines of one generated map in its braces, and collapse an empty map to `{}`. */
246326
+ wrapMapLines(lines) {
246327
+ if (lines.length === 0) {
246328
+ return [" {},"];
246329
+ }
246330
+ return [" {", ...lines, " },"];
246331
+ }
246332
+ /** Render a string as the source text of a string literal, with the escapes it needs. */
246333
+ stringSource(value) {
246334
+ return this.printer.printNode(
246335
+ import_ts_morph12.ts.EmitHint.Unspecified,
246336
+ import_ts_morph12.ts.factory.createStringLiteral(value, true),
246337
+ this.dummySourceFile
246029
246338
  );
246030
246339
  }
246340
+ /** Print an expression to source. */
246341
+ printExpr(expr) {
246342
+ return this.printNodeText(expr);
246343
+ }
246344
+ /** Print a node to source, through its own text when it carries a source position. */
246345
+ printNodeText(node) {
246346
+ return node.pos >= 0 ? node.getText() : this.printer.printNode(import_ts_morph12.ts.EmitHint.Unspecified, node, this.dummySourceFile);
246347
+ }
246348
+ /** Reach the value node a wrapped expression holds, through the parentheses and the casts. */
246349
+ readValueExpression(expression) {
246350
+ if (import_ts_morph12.ts.isParenthesizedExpression(expression) || import_ts_morph12.ts.isAsExpression(expression) || import_ts_morph12.ts.isSatisfiesExpression(expression)) {
246351
+ return this.readValueExpression(expression.expression);
246352
+ }
246353
+ return expression;
246354
+ }
246355
+ /**
246356
+ * Stop when any part of a listener names a binding in a type, which the generated file carries
246357
+ * no import for.
246358
+ */
246359
+ requireNoTypeBinding(listener, node = listener) {
246360
+ if (import_ts_morph12.ts.isTypeNode(node) && this.namesBinding(node)) {
246361
+ throw new GeneratorUnreadableListenerException(
246362
+ `Cannot read the listener '${this.printNodeText(listener)}': the generated data cannot import the type '${this.printNodeText(node)}'; declare the listener without it.`
246363
+ );
246364
+ }
246365
+ import_ts_morph12.ts.forEachChild(node, (child) => {
246366
+ this.requireNoTypeBinding(listener, child);
246367
+ });
246368
+ }
246369
+ /**
246370
+ * Whether a type names a binding that the file holding it has to resolve. `const` is a reserved
246371
+ * word, so it names none.
246372
+ */
246373
+ namesBinding(node) {
246374
+ if (import_ts_morph12.ts.isImportTypeNode(node) || import_ts_morph12.ts.isQualifiedName(node)) {
246375
+ return true;
246376
+ }
246377
+ if (import_ts_morph12.ts.isIdentifier(node)) {
246378
+ return node.text !== "const";
246379
+ }
246380
+ const declaredName = this.declaredName(node);
246381
+ let names = false;
246382
+ import_ts_morph12.ts.forEachChild(node, (child) => {
246383
+ names = names || child !== declaredName && this.namesBinding(child);
246384
+ });
246385
+ return names;
246386
+ }
246387
+ /**
246388
+ * The name a declaration spells out as one identifier, which declares a binding rather than
246389
+ * naming one. Every other name form can hold an expression, so it is read.
246390
+ */
246391
+ declaredName(node) {
246392
+ const name = "name" in node ? node.name : void 0;
246393
+ return name !== void 0 && import_ts_morph12.ts.isIdentifier(name) ? name : void 0;
246394
+ }
246031
246395
  };
246032
246396
 
246033
246397
  // src/Sindri/Generator/Ast/Http/AstHttpDataFileGenerator.ts
246034
- var import_ts_morph12 = __toESM(require_ts_morph(), 1);
246398
+ var import_ts_morph13 = __toESM(require_ts_morph(), 1);
246035
246399
 
246036
246400
  // node_modules/@valkyrjaio/valkyrja/src/Valkyrja/Http/Message/Enum/RequestMethod.ts
246037
246401
  function allRequestMethods() {
@@ -246514,13 +246878,13 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246514
246878
  };
246515
246879
  classImportMap = {};
246516
246880
  processor;
246517
- printer = import_ts_morph12.ts.createPrinter({ newLine: import_ts_morph12.ts.NewLineKind.LineFeed });
246518
- dummySourceFile = import_ts_morph12.ts.createSourceFile(
246881
+ printer = import_ts_morph13.ts.createPrinter({ newLine: import_ts_morph13.ts.NewLineKind.LineFeed });
246882
+ dummySourceFile = import_ts_morph13.ts.createSourceFile(
246519
246883
  "_dummy.ts",
246520
246884
  "",
246521
- import_ts_morph12.ts.ScriptTarget.ESNext,
246885
+ import_ts_morph13.ts.ScriptTarget.ESNext,
246522
246886
  false,
246523
- import_ts_morph12.ts.ScriptKind.TS
246887
+ import_ts_morph13.ts.ScriptKind.TS
246524
246888
  );
246525
246889
  constructor(processor = new Processor()) {
246526
246890
  super();
@@ -246668,24 +247032,24 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246668
247032
  const innerProps = [];
246669
247033
  for (const [innerKey, value] of Object.entries(innerMap)) {
246670
247034
  innerProps.push(
246671
- import_ts_morph12.ts.factory.createPropertyAssignment(
246672
- import_ts_morph12.ts.factory.createStringLiteral(innerKey),
246673
- import_ts_morph12.ts.factory.createStringLiteral(value)
247035
+ import_ts_morph13.ts.factory.createPropertyAssignment(
247036
+ import_ts_morph13.ts.factory.createStringLiteral(innerKey),
247037
+ import_ts_morph13.ts.factory.createStringLiteral(value)
246674
247038
  )
246675
247039
  );
246676
247040
  }
246677
247041
  outerProps.push(
246678
- import_ts_morph12.ts.factory.createPropertyAssignment(
246679
- import_ts_morph12.ts.factory.createStringLiteral(outerKey),
246680
- import_ts_morph12.ts.factory.createObjectLiteralExpression(innerProps, true)
247042
+ import_ts_morph13.ts.factory.createPropertyAssignment(
247043
+ import_ts_morph13.ts.factory.createStringLiteral(outerKey),
247044
+ import_ts_morph13.ts.factory.createObjectLiteralExpression(innerProps, true)
246681
247045
  )
246682
247046
  );
246683
247047
  }
246684
- return import_ts_morph12.ts.factory.createObjectLiteralExpression(outerProps, true);
247048
+ return import_ts_morph13.ts.factory.createObjectLiteralExpression(outerProps, true);
246685
247049
  }
246686
247050
  printNestedObject(data) {
246687
247051
  return this.printer.printNode(
246688
- import_ts_morph12.ts.EmitHint.Unspecified,
247052
+ import_ts_morph13.ts.EmitHint.Unspecified,
246689
247053
  this.buildNestedStringArrayExpr(data),
246690
247054
  this.dummySourceFile
246691
247055
  );
@@ -246751,8 +247115,8 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246751
247115
  for (const [key, routeExpr] of Object.entries(routes)) {
246752
247116
  const data = routeData[key] ?? null;
246753
247117
  const expr = data !== null ? this.injectRegex(routeExpr, data) : routeExpr;
246754
- const printedRoute = this.printer.printNode(import_ts_morph12.ts.EmitHint.Unspecified, expr, this.dummySourceFile);
246755
- const formattedKey = key.includes("::") ? `[${this.printer.printNode(import_ts_morph12.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(key), this.dummySourceFile)}]` : `['${key}']`;
247118
+ const printedRoute = this.printer.printNode(import_ts_morph13.ts.EmitHint.Unspecified, expr, this.dummySourceFile);
247119
+ const formattedKey = key.includes("::") ? `[${this.printer.printNode(import_ts_morph13.ts.EmitHint.Unspecified, this.buildEnumCaseExpr(key), this.dummySourceFile)}]` : `['${key}']`;
246756
247120
  lines.push(` ${formattedKey}: (): RouteContract => ${printedRoute},`);
246757
247121
  }
246758
247122
  return lines;
@@ -246764,13 +247128,13 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246764
247128
  * `Processor` and computes the real value here.
246765
247129
  */
246766
247130
  injectRegex(expr, data) {
246767
- if (!(data.isDynamic && import_ts_morph12.ts.isNewExpression(expr))) {
247131
+ if (!(data.isDynamic && import_ts_morph13.ts.isNewExpression(expr))) {
246768
247132
  return expr;
246769
247133
  }
246770
247134
  const computedRegex = data.parameters.length > 0 ? this.computeRegex(data) : "";
246771
- const original = expr.arguments ?? import_ts_morph12.ts.factory.createNodeArray();
246772
- const args = original.map((arg, index) => index === 2 ? import_ts_morph12.ts.factory.createStringLiteral(computedRegex) : arg);
246773
- return import_ts_morph12.ts.factory.createNewExpression(expr.expression, expr.typeArguments, args);
247135
+ const original = expr.arguments ?? import_ts_morph13.ts.factory.createNodeArray();
247136
+ const args = original.map((arg, index) => index === 2 ? import_ts_morph13.ts.factory.createStringLiteral(computedRegex) : arg);
247137
+ return import_ts_morph13.ts.factory.createNewExpression(expr.expression, expr.typeArguments, args);
246774
247138
  }
246775
247139
  // -------------------------------------------------------------------------
246776
247140
  // Imperative `getRoutes()` support
@@ -246782,11 +247146,11 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246782
247146
  * DynamicRoute(path, name, regex, parameters, handler, requestMethods?)
246783
247147
  */
246784
247148
  extractRouteMeta(expr) {
246785
- if (!import_ts_morph12.ts.isNewExpression(expr) || !import_ts_morph12.ts.isIdentifier(expr.expression)) {
247149
+ if (!import_ts_morph13.ts.isNewExpression(expr) || !import_ts_morph13.ts.isIdentifier(expr.expression)) {
246786
247150
  return void 0;
246787
247151
  }
246788
247152
  const isDynamic = expr.expression.text === "DynamicRoute";
246789
- const args = expr.arguments ?? import_ts_morph12.ts.factory.createNodeArray();
247153
+ const args = expr.arguments ?? import_ts_morph13.ts.factory.createNodeArray();
246790
247154
  const path6 = this.stringArg(args[0]);
246791
247155
  const name = this.stringArg(args[1]);
246792
247156
  if (name === void 0 || path6 === void 0) {
@@ -246798,7 +247162,7 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246798
247162
  return { expr, name, path: path6, isDynamic, regex, methods };
246799
247163
  }
246800
247164
  stringArg(node) {
246801
- return node !== void 0 && import_ts_morph12.ts.isStringLiteral(node) ? node.text : void 0;
247165
+ return node !== void 0 && import_ts_morph13.ts.isStringLiteral(node) ? node.text : void 0;
246802
247166
  }
246803
247167
  /**
246804
247168
  * Resolve a `[RequestMethod.GET, ...]` argument to method-name strings,
@@ -246806,12 +247170,12 @@ var AstHttpDataFileGenerator = class _AstHttpDataFileGenerator extends AstFileGe
246806
247170
  * and expanding `RequestMethod.ANY` to every request method.
246807
247171
  */
246808
247172
  extractMethodNamesFromArg(node) {
246809
- if (node === void 0 || !import_ts_morph12.ts.isArrayLiteralExpression(node)) {
247173
+ if (node === void 0 || !import_ts_morph13.ts.isArrayLiteralExpression(node)) {
246810
247174
  return ["HEAD" /* HEAD */, "GET" /* GET */];
246811
247175
  }
246812
247176
  const methods = [];
246813
247177
  for (const element of node.elements) {
246814
- if (!import_ts_morph12.ts.isPropertyAccessExpression(element)) {
247178
+ if (!import_ts_morph13.ts.isPropertyAccessExpression(element)) {
246815
247179
  continue;
246816
247180
  }
246817
247181
  const method = element.name.text;
@@ -247018,27 +247382,39 @@ var GenerateDataFromAst = class extends GenerateFromAst {
247018
247382
  }
247019
247383
  generateEventData(listenerProviders, config, output) {
247020
247384
  output = output.withAddedMessages(new Message("Generating Event Data..........................")).writeMessages();
247021
- const allListeners = {};
247385
+ const allListeners = /* @__PURE__ */ new Map();
247386
+ const imperativeListeners = [];
247387
+ const importMap = {};
247022
247388
  for (const providerClass of listenerProviders) {
247023
247389
  const filePath = this.fqnToFilePath(providerClass, config.namespace, config.dir);
247024
247390
  if (filePath === "" || !fs4.existsSync(filePath)) {
247025
247391
  continue;
247026
247392
  }
247027
247393
  const providerResult = this.listenerProviderReader.readFile(filePath);
247394
+ if (providerResult.listeners.length > 0) {
247395
+ imperativeListeners.push(...providerResult.listeners);
247396
+ importMap[path5.basename(filePath, ".ts")] = this.importSpecifier(config.dataPath, filePath);
247397
+ this.mergeReaderImports(importMap, providerResult.listenerImports, config);
247398
+ }
247028
247399
  for (const listenerClass of providerResult.listenerClasses) {
247029
247400
  const listenerPath = this.fqnToFilePath(listenerClass, config.namespace, config.dir);
247030
247401
  if (listenerPath === "" || !fs4.existsSync(listenerPath)) {
247031
247402
  continue;
247032
247403
  }
247033
247404
  const attrResult = this.listenerAttributeReader.readFile(listenerPath);
247034
- Object.assign(allListeners, attrResult.listeners);
247405
+ for (const [name, listener] of attrResult.listeners) {
247406
+ allListeners.set(name, listener);
247407
+ }
247408
+ this.mergeReaderImports(importMap, attrResult.importMap, config);
247035
247409
  }
247036
247410
  }
247037
- const status = this.eventGenerator.generateFile(
247411
+ this.eventGenerator.classImportMap = importMap;
247412
+ const status = this.eventGenerator.generateMergedFile(
247038
247413
  config.dataPath,
247039
247414
  "AppEventData",
247040
247415
  config.dataNamespace,
247041
- allListeners
247416
+ allListeners,
247417
+ imperativeListeners
247042
247418
  );
247043
247419
  return this.addMessagesForGenerateStatus(output, status).withAddedMessages(new NewLine()).writeMessages();
247044
247420
  }
@@ -247122,12 +247498,8 @@ var GenerateDataFromAst = class extends GenerateFromAst {
247122
247498
  return this.addMessagesForGenerateStatus(output, status).withAddedMessages(new NewLine()).writeMessages();
247123
247499
  }
247124
247500
  /**
247125
- * Merge the class-name → absolute-file-path imports a route attribute reader
247126
- * resolved (handler/help-text/middleware classes) into the generated data
247127
- * file's import map, converting each absolute path to the specifier the
247128
- * generated file imports it by — relative to the output directory for
247129
- * application source, or the owning package's own specifier for a class an
247130
- * installed package exposes.
247501
+ * Merge the class-name → absolute-file-path imports a reader resolved into the generated data
247502
+ * file's import map, by the specifier that file imports each one by.
247131
247503
  */
247132
247504
  mergeReaderImports(importMap, readerImportMap, config) {
247133
247505
  for (const [name, absolutePath] of Object.entries(readerImportMap)) {