sqlstack 2.0.0 → 3.0.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.
Files changed (132) hide show
  1. package/dist/cjs/codegen/generateManifest.d.ts +12 -0
  2. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -1
  3. package/dist/cjs/codegen/generateManifest.js +21 -11
  4. package/dist/cjs/codegen/generateManifest.js.map +1 -1
  5. package/dist/cjs/core/resolver.d.ts +25 -12
  6. package/dist/cjs/core/resolver.d.ts.map +1 -1
  7. package/dist/cjs/core/resolver.js +66 -20
  8. package/dist/cjs/core/resolver.js.map +1 -1
  9. package/dist/cjs/core/sourceScanResolver.d.ts +25 -0
  10. package/dist/cjs/core/sourceScanResolver.d.ts.map +1 -0
  11. package/dist/cjs/core/sourceScanResolver.js +56 -0
  12. package/dist/cjs/core/sourceScanResolver.js.map +1 -0
  13. package/dist/cjs/decorators/query.d.ts.map +1 -1
  14. package/dist/cjs/decorators/query.js +29 -16
  15. package/dist/cjs/decorators/query.js.map +1 -1
  16. package/dist/cjs/families/sqliteFamily.d.ts +26 -0
  17. package/dist/cjs/families/sqliteFamily.d.ts.map +1 -0
  18. package/dist/cjs/families/sqliteFamily.js +187 -0
  19. package/dist/cjs/families/sqliteFamily.js.map +1 -0
  20. package/dist/cjs/family.d.ts +69 -0
  21. package/dist/cjs/family.d.ts.map +1 -0
  22. package/dist/cjs/family.js +206 -0
  23. package/dist/cjs/family.js.map +1 -0
  24. package/dist/cjs/familyBinding.d.ts +22 -0
  25. package/dist/cjs/familyBinding.d.ts.map +1 -0
  26. package/dist/cjs/familyBinding.js +22 -0
  27. package/dist/cjs/familyBinding.js.map +1 -0
  28. package/dist/cjs/index.d.ts +9 -1
  29. package/dist/cjs/index.d.ts.map +1 -1
  30. package/dist/cjs/index.js +14 -2
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/ioc.d.ts +22 -0
  33. package/dist/cjs/ioc.d.ts.map +1 -0
  34. package/dist/cjs/ioc.js +35 -0
  35. package/dist/cjs/ioc.js.map +1 -0
  36. package/dist/cjs/runtime.d.ts +25 -0
  37. package/dist/cjs/runtime.d.ts.map +1 -0
  38. package/dist/cjs/runtime.js +133 -0
  39. package/dist/cjs/runtime.js.map +1 -0
  40. package/dist/cjs/stack.d.ts +101 -0
  41. package/dist/cjs/stack.d.ts.map +1 -0
  42. package/dist/cjs/stack.js +288 -0
  43. package/dist/cjs/stack.js.map +1 -0
  44. package/dist/cjs/testing/builder.d.ts +29 -0
  45. package/dist/cjs/testing/builder.d.ts.map +1 -0
  46. package/dist/cjs/testing/builder.js +131 -0
  47. package/dist/cjs/testing/builder.js.map +1 -0
  48. package/dist/cjs/testing/index.d.ts +10 -0
  49. package/dist/cjs/testing/index.d.ts.map +1 -0
  50. package/dist/cjs/testing/index.js +18 -0
  51. package/dist/cjs/testing/index.js.map +1 -0
  52. package/dist/cjs/testing/postgres/allocator.d.ts +17 -0
  53. package/dist/cjs/testing/postgres/allocator.d.ts.map +1 -0
  54. package/dist/cjs/testing/postgres/allocator.js +54 -0
  55. package/dist/cjs/testing/postgres/allocator.js.map +1 -0
  56. package/dist/cjs/testing/postgres/database.d.ts +21 -0
  57. package/dist/cjs/testing/postgres/database.d.ts.map +1 -0
  58. package/dist/cjs/testing/postgres/database.js +39 -0
  59. package/dist/cjs/testing/postgres/database.js.map +1 -0
  60. package/dist/cjs/testing/postgres/loadData.d.ts +31 -0
  61. package/dist/cjs/testing/postgres/loadData.d.ts.map +1 -0
  62. package/dist/cjs/testing/postgres/loadData.js +184 -0
  63. package/dist/cjs/testing/postgres/loadData.js.map +1 -0
  64. package/dist/cjs/testing/postgres/server.d.ts +19 -0
  65. package/dist/cjs/testing/postgres/server.d.ts.map +1 -0
  66. package/dist/cjs/testing/postgres/server.js +78 -0
  67. package/dist/cjs/testing/postgres/server.js.map +1 -0
  68. package/dist/cjs/testing/schema/ddl.d.ts +14 -0
  69. package/dist/cjs/testing/schema/ddl.d.ts.map +1 -0
  70. package/dist/cjs/testing/schema/ddl.js +54 -0
  71. package/dist/cjs/testing/schema/ddl.js.map +1 -0
  72. package/dist/cjs/testing/schema/normalize.d.ts +7 -0
  73. package/dist/cjs/testing/schema/normalize.d.ts.map +1 -0
  74. package/dist/cjs/testing/schema/normalize.js +202 -0
  75. package/dist/cjs/testing/schema/normalize.js.map +1 -0
  76. package/dist/cjs/testing/schema/parser.d.ts +9 -0
  77. package/dist/cjs/testing/schema/parser.d.ts.map +1 -0
  78. package/dist/cjs/testing/schema/parser.js +80 -0
  79. package/dist/cjs/testing/schema/parser.js.map +1 -0
  80. package/dist/cjs/testing/schema/types.d.ts +82 -0
  81. package/dist/cjs/testing/schema/types.d.ts.map +1 -0
  82. package/dist/cjs/testing/schema/types.js +10 -0
  83. package/dist/cjs/testing/schema/types.js.map +1 -0
  84. package/dist/cjs/transactions.d.ts +14 -5
  85. package/dist/cjs/transactions.d.ts.map +1 -1
  86. package/dist/cjs/transactions.js +40 -24
  87. package/dist/cjs/transactions.js.map +1 -1
  88. package/dist/esm/codegen/generateManifest.js +20 -11
  89. package/dist/esm/codegen/generateManifest.js.map +1 -1
  90. package/dist/esm/core/resolver.js +59 -19
  91. package/dist/esm/core/resolver.js.map +1 -1
  92. package/dist/esm/core/sourceScanResolver.js +51 -0
  93. package/dist/esm/core/sourceScanResolver.js.map +1 -0
  94. package/dist/esm/decorators/query.js +31 -18
  95. package/dist/esm/decorators/query.js.map +1 -1
  96. package/dist/esm/families/sqliteFamily.js +151 -0
  97. package/dist/esm/families/sqliteFamily.js.map +1 -0
  98. package/dist/esm/family.js +202 -0
  99. package/dist/esm/family.js.map +1 -0
  100. package/dist/esm/familyBinding.js +18 -0
  101. package/dist/esm/familyBinding.js.map +1 -0
  102. package/dist/esm/index.js +8 -1
  103. package/dist/esm/index.js.map +1 -1
  104. package/dist/esm/ioc.js +32 -0
  105. package/dist/esm/ioc.js.map +1 -0
  106. package/dist/esm/runtime.js +94 -0
  107. package/dist/esm/runtime.js.map +1 -0
  108. package/dist/esm/stack.js +251 -0
  109. package/dist/esm/stack.js.map +1 -0
  110. package/dist/esm/testing/builder.js +95 -0
  111. package/dist/esm/testing/builder.js.map +1 -0
  112. package/dist/esm/testing/index.js +7 -0
  113. package/dist/esm/testing/index.js.map +1 -0
  114. package/dist/esm/testing/postgres/allocator.js +49 -0
  115. package/dist/esm/testing/postgres/allocator.js.map +1 -0
  116. package/dist/esm/testing/postgres/database.js +36 -0
  117. package/dist/esm/testing/postgres/database.js.map +1 -0
  118. package/dist/esm/testing/postgres/loadData.js +176 -0
  119. package/dist/esm/testing/postgres/loadData.js.map +1 -0
  120. package/dist/esm/testing/postgres/server.js +69 -0
  121. package/dist/esm/testing/postgres/server.js.map +1 -0
  122. package/dist/esm/testing/schema/ddl.js +49 -0
  123. package/dist/esm/testing/schema/ddl.js.map +1 -0
  124. package/dist/esm/testing/schema/normalize.js +164 -0
  125. package/dist/esm/testing/schema/normalize.js.map +1 -0
  126. package/dist/esm/testing/schema/parser.js +43 -0
  127. package/dist/esm/testing/schema/parser.js.map +1 -0
  128. package/dist/esm/testing/schema/types.js +9 -0
  129. package/dist/esm/testing/schema/types.js.map +1 -0
  130. package/dist/esm/transactions.js +39 -24
  131. package/dist/esm/transactions.js.map +1 -1
  132. package/package.json +18 -2
@@ -56,5 +56,17 @@ export declare function scanSourceForQueryMethods(source: string, sourcePath: st
56
56
  * callable from application build pipelines.
57
57
  */
58
58
  export declare function generateSqlManifest(options: GenerateSqlManifestOptions): Promise<GenerateSqlManifestResult>;
59
+ export type ScanSqlManifestResult = {
60
+ manifest: Record<string, string>;
61
+ entries: SqlManifestEntry[];
62
+ missing: MissingSqlMethod[];
63
+ };
64
+ /**
65
+ * Synchronous scan core: discover @Query methods under rootDir and inline
66
+ * their sibling .sql files into a Contract A manifest. Shared by the
67
+ * build-time generator above and the runtime SourceScanResolver (bare
68
+ * @Query() with no resolver installed).
69
+ */
70
+ export declare function scanSqlManifestSync(rootDir: string, excludeExtra?: string[]): ScanSqlManifestResult;
59
71
  export {};
60
72
  //# sourceMappingURL=generateManifest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateManifest.d.ts","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,0BAA0B,GAAG;IACvC,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,6FAA6F;IAC7F,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAyBF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAyBhG;AAyBD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAwEpC"}
1
+ {"version":3,"file":"generateManifest.d.ts","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,0BAA0B,GAAG;IACvC,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,6FAA6F;IAC7F,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAyBF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAyBhG;AAyBD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAcpC;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,qBAAqB,CA6DnG"}
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.scanSourceForQueryMethods = scanSourceForQueryMethods;
7
7
  exports.generateSqlManifest = generateSqlManifest;
8
+ exports.scanSqlManifestSync = scanSqlManifestSync;
8
9
  const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const resolver_1 = require("../core/resolver");
@@ -112,10 +113,28 @@ function renderModule(manifest, entries, format, rootDir) {
112
113
  */
113
114
  async function generateSqlManifest(options) {
114
115
  const rootDir = path_1.default.resolve(options.rootDir);
116
+ const { manifest, entries, missing } = scanSqlManifestSync(rootDir, options.exclude);
117
+ const outFile = path_1.default.resolve(options.outFile ?? path_1.default.join(rootDir, 'sql-manifest.mjs'));
118
+ const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');
119
+ const code = renderModule(manifest, entries, format, rootDir);
120
+ if (options.write !== false) {
121
+ fs_1.default.mkdirSync(path_1.default.dirname(outFile), { recursive: true });
122
+ fs_1.default.writeFileSync(outFile, code);
123
+ return { manifest, entries, missing, code, outFile };
124
+ }
125
+ return { manifest, entries, missing, code };
126
+ }
127
+ /**
128
+ * Synchronous scan core: discover @Query methods under rootDir and inline
129
+ * their sibling .sql files into a Contract A manifest. Shared by the
130
+ * build-time generator above and the runtime SourceScanResolver (bare
131
+ * @Query() with no resolver installed).
132
+ */
133
+ function scanSqlManifestSync(rootDir, excludeExtra) {
115
134
  if (!fs_1.default.existsSync(rootDir) || !fs_1.default.statSync(rootDir).isDirectory()) {
116
135
  throw new Error(`sqlstack-codegen: rootDir is not a directory: ${rootDir}`);
117
136
  }
118
- const exclude = new Set([...DEFAULT_EXCLUDES, ...(options.exclude ?? [])]);
137
+ const exclude = new Set([...DEFAULT_EXCLUDES, ...(excludeExtra ?? [])]);
119
138
  // 1) discover @Query methods
120
139
  const discovered = [];
121
140
  for (const file of walkSourceFiles(rootDir, exclude)) {
@@ -167,15 +186,6 @@ async function generateSqlManifest(options) {
167
186
  if (!matched)
168
187
  missing.push({ className: d.className, methodName: d.methodName, sourcePath: d.sourcePath });
169
188
  }
170
- // 4) emit
171
- const outFile = path_1.default.resolve(options.outFile ?? path_1.default.join(rootDir, 'sql-manifest.mjs'));
172
- const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');
173
- const code = renderModule(manifest, entries, format, rootDir);
174
- if (options.write !== false) {
175
- fs_1.default.mkdirSync(path_1.default.dirname(outFile), { recursive: true });
176
- fs_1.default.writeFileSync(outFile, code);
177
- return { manifest, entries, missing, code, outFile };
178
- }
179
- return { manifest, entries, missing, code };
189
+ return { manifest, entries, missing };
180
190
  }
181
191
  //# sourceMappingURL=generateManifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateManifest.js","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":";;;;;AA6GA,8DAyBC;AA6BD,kDA0EC;AA7OD,4CAAoB;AACpB,gDAAwB;AACxB,+CAAwD;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1F,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAqDxF,SAAS,eAAe,CAAC,OAAe,EAAE,OAAoB;IAC5D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,YAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBACrE,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC1C,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YAC3C,GAAG,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,QAAQ,GAAG,2CAA2C,CAAC;AAC7D,MAAM,QAAQ,GACZ,2GAA2G,CAAC;AAE9G;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,MAAc,EAAE,UAAkB;IAC1E,MAAM,OAAO,GAAsC,EAAE,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACxB,IAAI,KAAyB,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE;gBAAE,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;;gBAC5B,MAAM;QACb,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,CAAC,CAAC,CAAC,CAAE;YACjB,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CACnB,QAAgC,EAChC,OAA2B,EAC3B,MAAoB,EACpB,OAAe;IAEf,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,KAAK,GAAa;QACtB,gDAAgD;QAChD,kEAAkE;QAClE,MAAM,KAAK,IAAI;YACb,CAAC,CAAC,sDAAsD;YACxD,CAAC,CAAC,8BAA8B;KACnC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,cAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,mBAAmB,CACvC,OAAmC;IAEnC,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,iDAAiD,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAE3E,6BAA6B;IAC7B,MAAM,UAAU,GAAuB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACrD,UAAU,CAAC,IAAI,CAAC,GAAG,yBAAyB,CAAC,YAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,mEAAmE;IACnE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC7E,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACrF,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,qGAAqG;YACnG,UAAU;iBACP,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;iBACzF,IAAI,CAAC,IAAI,CAAC,CAChB,CAAC;IACJ,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,MAAM;YAAE,SAAS;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEb,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC;QAC1D,IAAI,YAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC,EAAE,CAAC,GAAG,YAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YAClG,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC,EAAE,CAAC;YACtD,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,GAAG,MAAM,CAAC,CAAC;YACjE,IAAI,YAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC;gBAC3B,QAAQ,CAAC,GAAG,CAAC,GAAG,YAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC/G,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7G,CAAC;IAED,UAAU;IACV,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACxF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC5B,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { MANIFEST_DIALECT_EXT } from '../core/resolver';\n\n/**\n * Build-time SQL manifest generation (Contract A).\n *\n * Scans a source tree for @Query-decorated class methods, pairs each with its\n * sibling `.sql` files (same directory as the declaring source file, filename =\n * method name, optional dialect suffix), and emits a generated module:\n *\n * export const sqlManifest = {\n * '<ClassName>.<methodName>.<dialectExt>': '<sql>',\n * '<ClassName>.<methodName>': '<sql>',\n * };\n *\n * The `.sql` files on disk remain the source of truth — the generated module\n * inlines their text and is never hand-edited.\n *\n * Requirements policed here:\n * - Class names must be unique across the scanned tree (manifest keys are\n * class-name scoped) — duplicates are a build error.\n * - Consumers must not minify class names away (esbuild `keepNames`,\n * terser `keep_classnames`) — documented in docs/codegen.md.\n */\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs']);\nconst DEFAULT_EXCLUDES = new Set(['node_modules', 'dist', 'build', 'coverage', '.git']);\n\nexport type GenerateSqlManifestOptions = {\n /** Directory to scan recursively for @Query classes and sibling .sql files. */\n rootDir: string;\n /**\n * Output path for the generated module. Default: `<rootDir>/sql-manifest.mjs`.\n * Extension selects the format when `format` is not given (.ts → ts, else mjs).\n */\n outFile?: string;\n /** 'mjs' (default) emits an ES module; 'ts' emits a typed TS source variant. */\n format?: 'mjs' | 'ts';\n /** Write the generated module to outFile. Default true; false = dry run. */\n write?: boolean;\n /** Directory names to skip while walking. Defaults to node_modules/dist/build/coverage/.git. */\n exclude?: string[];\n};\n\nexport type SqlManifestEntry = {\n key: string;\n className: string;\n methodName: string;\n /** pg | mysql | sqlite for dialect-specific entries; undefined for generic. */\n dialectExt?: string;\n /** Absolute path of the .sql source file. */\n sqlPath: string;\n};\n\nexport type MissingSqlMethod = {\n className: string;\n methodName: string;\n /** Source file that declares the @Query method. */\n sourcePath: string;\n};\n\nexport type GenerateSqlManifestResult = {\n manifest: Record<string, string>;\n entries: SqlManifestEntry[];\n /** Non-inline @Query methods with no sibling .sql file (assertion will catch at startup). */\n missing: MissingSqlMethod[];\n /** The generated module source. */\n code: string;\n /** Absolute path written to (present when write !== false). */\n outFile?: string;\n};\n\ntype DiscoveredMethod = {\n className: string;\n methodName: string;\n inline: boolean;\n sourcePath: string;\n};\n\nfunction walkSourceFiles(rootDir: string, exclude: Set<string>): string[] {\n const out: string[] = [];\n const stack = [rootDir];\n while (stack.length) {\n const dir = stack.pop()!;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!exclude.has(entry.name)) stack.push(path.join(dir, entry.name));\n continue;\n }\n const ext = path.extname(entry.name);\n if (!SOURCE_EXTENSIONS.has(ext)) continue;\n if (entry.name.endsWith('.d.ts')) continue;\n out.push(path.join(dir, entry.name));\n }\n }\n return out.sort();\n}\n\nconst CLASS_RE = /(?:^|[\\s;{}(])class\\s+([A-Za-z_$][\\w$]*)/g;\nconst QUERY_RE =\n /@Query\\s*(?:\\(([^)]*)\\))?\\s*(?:public\\s+|private\\s+|protected\\s+)?(?:async\\s+)?([A-Za-z_$][\\w$]*)\\s*[(<]/g;\n\n/**\n * Regex-based discovery: each @Query method is attributed to the nearest\n * preceding `class` declaration in the same file. Inline queries are detected\n * by a `sql:` property in the decorator arguments (see docs/codegen.md for the\n * documented limitations of this heuristic).\n */\nexport function scanSourceForQueryMethods(source: string, sourcePath: string): DiscoveredMethod[] {\n const classes: { name: string; index: number }[] = [];\n for (const m of source.matchAll(CLASS_RE)) {\n classes.push({ name: m[1]!, index: m.index ?? 0 });\n }\n if (!classes.length) return [];\n\n const found: DiscoveredMethod[] = [];\n for (const m of source.matchAll(QUERY_RE)) {\n const at = m.index ?? 0;\n let owner: string | undefined;\n for (const c of classes) {\n if (c.index < at) owner = c.name;\n else break;\n }\n if (!owner) continue;\n const args = m[1] ?? '';\n found.push({\n className: owner,\n methodName: m[2]!,\n inline: /\\bsql\\s*:/.test(args),\n sourcePath,\n });\n }\n return found;\n}\n\nfunction renderModule(\n manifest: Record<string, string>,\n entries: SqlManifestEntry[],\n format: 'mjs' | 'ts',\n rootDir: string\n): string {\n const byKey = new Map(entries.map((e) => [e.key, e]));\n const lines: string[] = [\n '// GENERATED by sqlstack-codegen. DO NOT EDIT.',\n '// Source of truth: the .sql files referenced beside each entry.',\n format === 'ts'\n ? 'export const sqlManifest: Record<string, string> = {'\n : 'export const sqlManifest = {',\n ];\n for (const key of Object.keys(manifest).sort()) {\n const entry = byKey.get(key);\n const from = entry ? path.relative(rootDir, entry.sqlPath) : '';\n lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(manifest[key])},${from ? ` // ${from}` : ''}`);\n }\n lines.push('};', '');\n return lines.join('\\n');\n}\n\n/**\n * Programmatic entry point — also used by the CLI (`sqlstack-codegen`) and\n * callable from application build pipelines.\n */\nexport async function generateSqlManifest(\n options: GenerateSqlManifestOptions\n): Promise<GenerateSqlManifestResult> {\n const rootDir = path.resolve(options.rootDir);\n if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {\n throw new Error(`sqlstack-codegen: rootDir is not a directory: ${rootDir}`);\n }\n const exclude = new Set([...DEFAULT_EXCLUDES, ...(options.exclude ?? [])]);\n\n // 1) discover @Query methods\n const discovered: DiscoveredMethod[] = [];\n for (const file of walkSourceFiles(rootDir, exclude)) {\n discovered.push(...scanSourceForQueryMethods(fs.readFileSync(file, 'utf8'), file));\n }\n\n // 2) police duplicate class names (manifest keys are class-scoped)\n const filesByClass = new Map<string, Set<string>>();\n for (const d of discovered) {\n if (!filesByClass.has(d.className)) filesByClass.set(d.className, new Set());\n filesByClass.get(d.className)!.add(d.sourcePath);\n }\n const duplicates = [...filesByClass.entries()].filter(([, files]) => files.size > 1);\n if (duplicates.length) {\n throw new Error(\n 'sqlstack-codegen: duplicate @Query class names (manifest keys are class-name scoped; rename one):\\n' +\n duplicates\n .map(([name, files]) => ` - ${name}:\\n${[...files].map((f) => ` ${f}`).join('\\n')}`)\n .join('\\n')\n );\n }\n\n // 3) pair each non-inline method with sibling .sql files\n const manifest: Record<string, string> = {};\n const entries: SqlManifestEntry[] = [];\n const missing: MissingSqlMethod[] = [];\n const seen = new Set<string>();\n for (const d of discovered) {\n if (d.inline) continue;\n const id = `${d.className}.${d.methodName}`;\n if (seen.has(id)) continue;\n seen.add(id);\n\n const dir = path.dirname(d.sourcePath);\n let matched = false;\n\n const genericPath = path.join(dir, `${d.methodName}.sql`);\n if (fs.existsSync(genericPath)) {\n manifest[id] = fs.readFileSync(genericPath, 'utf8');\n entries.push({ key: id, className: d.className, methodName: d.methodName, sqlPath: genericPath });\n matched = true;\n }\n for (const ext of Object.values(MANIFEST_DIALECT_EXT)) {\n const dialectPath = path.join(dir, `${d.methodName}.${ext}.sql`);\n if (fs.existsSync(dialectPath)) {\n const key = `${id}.${ext}`;\n manifest[key] = fs.readFileSync(dialectPath, 'utf8');\n entries.push({ key, className: d.className, methodName: d.methodName, dialectExt: ext, sqlPath: dialectPath });\n matched = true;\n }\n }\n if (!matched) missing.push({ className: d.className, methodName: d.methodName, sourcePath: d.sourcePath });\n }\n\n // 4) emit\n const outFile = path.resolve(options.outFile ?? path.join(rootDir, 'sql-manifest.mjs'));\n const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');\n const code = renderModule(manifest, entries, format, rootDir);\n\n if (options.write !== false) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\n fs.writeFileSync(outFile, code);\n return { manifest, entries, missing, code, outFile };\n }\n return { manifest, entries, missing, code };\n}\n"]}
1
+ {"version":3,"file":"generateManifest.js","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":";;;;;AA6GA,8DAyBC;AA6BD,kDAgBC;AAcD,kDA6DC;AA9PD,4CAAoB;AACpB,gDAAwB;AACxB,+CAAwD;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1F,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAqDxF,SAAS,eAAe,CAAC,OAAe,EAAE,OAAoB;IAC5D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,YAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBACrE,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC1C,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YAC3C,GAAG,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,QAAQ,GAAG,2CAA2C,CAAC;AAC7D,MAAM,QAAQ,GACZ,2GAA2G,CAAC;AAE9G;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,MAAc,EAAE,UAAkB;IAC1E,MAAM,OAAO,GAAsC,EAAE,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACxB,IAAI,KAAyB,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE;gBAAE,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;;gBAC5B,MAAM;QACb,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,CAAC,CAAC,CAAC,CAAE;YACjB,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CACnB,QAAgC,EAChC,OAA2B,EAC3B,MAAoB,EACpB,OAAe;IAEf,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,KAAK,GAAa;QACtB,gDAAgD;QAChD,kEAAkE;QAClE,MAAM,KAAK,IAAI;YACb,CAAC,CAAC,sDAAsD;YACxD,CAAC,CAAC,8BAA8B;KACnC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,cAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,mBAAmB,CACvC,OAAmC;IAEnC,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAErF,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACxF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC5B,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC;AAQD;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,OAAe,EAAE,YAAuB;IAC1E,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,iDAAiD,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAExE,6BAA6B;IAC7B,MAAM,UAAU,GAAuB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACrD,UAAU,CAAC,IAAI,CAAC,GAAG,yBAAyB,CAAC,YAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,mEAAmE;IACnE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC7E,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACrF,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,qGAAqG;YACnG,UAAU;iBACP,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;iBACzF,IAAI,CAAC,IAAI,CAAC,CAChB,CAAC;IACJ,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,MAAM;YAAE,SAAS;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEb,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC;QAC1D,IAAI,YAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC,EAAE,CAAC,GAAG,YAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YAClG,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC,EAAE,CAAC;YACtD,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,GAAG,MAAM,CAAC,CAAC;YACjE,IAAI,YAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC;gBAC3B,QAAQ,CAAC,GAAG,CAAC,GAAG,YAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC/G,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7G,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACxC,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { MANIFEST_DIALECT_EXT } from '../core/resolver';\n\n/**\n * Build-time SQL manifest generation (Contract A).\n *\n * Scans a source tree for @Query-decorated class methods, pairs each with its\n * sibling `.sql` files (same directory as the declaring source file, filename =\n * method name, optional dialect suffix), and emits a generated module:\n *\n * export const sqlManifest = {\n * '<ClassName>.<methodName>.<dialectExt>': '<sql>',\n * '<ClassName>.<methodName>': '<sql>',\n * };\n *\n * The `.sql` files on disk remain the source of truth — the generated module\n * inlines their text and is never hand-edited.\n *\n * Requirements policed here:\n * - Class names must be unique across the scanned tree (manifest keys are\n * class-name scoped) — duplicates are a build error.\n * - Consumers must not minify class names away (esbuild `keepNames`,\n * terser `keep_classnames`) — documented in docs/codegen.md.\n */\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs']);\nconst DEFAULT_EXCLUDES = new Set(['node_modules', 'dist', 'build', 'coverage', '.git']);\n\nexport type GenerateSqlManifestOptions = {\n /** Directory to scan recursively for @Query classes and sibling .sql files. */\n rootDir: string;\n /**\n * Output path for the generated module. Default: `<rootDir>/sql-manifest.mjs`.\n * Extension selects the format when `format` is not given (.ts → ts, else mjs).\n */\n outFile?: string;\n /** 'mjs' (default) emits an ES module; 'ts' emits a typed TS source variant. */\n format?: 'mjs' | 'ts';\n /** Write the generated module to outFile. Default true; false = dry run. */\n write?: boolean;\n /** Directory names to skip while walking. Defaults to node_modules/dist/build/coverage/.git. */\n exclude?: string[];\n};\n\nexport type SqlManifestEntry = {\n key: string;\n className: string;\n methodName: string;\n /** pg | mysql | sqlite for dialect-specific entries; undefined for generic. */\n dialectExt?: string;\n /** Absolute path of the .sql source file. */\n sqlPath: string;\n};\n\nexport type MissingSqlMethod = {\n className: string;\n methodName: string;\n /** Source file that declares the @Query method. */\n sourcePath: string;\n};\n\nexport type GenerateSqlManifestResult = {\n manifest: Record<string, string>;\n entries: SqlManifestEntry[];\n /** Non-inline @Query methods with no sibling .sql file (assertion will catch at startup). */\n missing: MissingSqlMethod[];\n /** The generated module source. */\n code: string;\n /** Absolute path written to (present when write !== false). */\n outFile?: string;\n};\n\ntype DiscoveredMethod = {\n className: string;\n methodName: string;\n inline: boolean;\n sourcePath: string;\n};\n\nfunction walkSourceFiles(rootDir: string, exclude: Set<string>): string[] {\n const out: string[] = [];\n const stack = [rootDir];\n while (stack.length) {\n const dir = stack.pop()!;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!exclude.has(entry.name)) stack.push(path.join(dir, entry.name));\n continue;\n }\n const ext = path.extname(entry.name);\n if (!SOURCE_EXTENSIONS.has(ext)) continue;\n if (entry.name.endsWith('.d.ts')) continue;\n out.push(path.join(dir, entry.name));\n }\n }\n return out.sort();\n}\n\nconst CLASS_RE = /(?:^|[\\s;{}(])class\\s+([A-Za-z_$][\\w$]*)/g;\nconst QUERY_RE =\n /@Query\\s*(?:\\(([^)]*)\\))?\\s*(?:public\\s+|private\\s+|protected\\s+)?(?:async\\s+)?([A-Za-z_$][\\w$]*)\\s*[(<]/g;\n\n/**\n * Regex-based discovery: each @Query method is attributed to the nearest\n * preceding `class` declaration in the same file. Inline queries are detected\n * by a `sql:` property in the decorator arguments (see docs/codegen.md for the\n * documented limitations of this heuristic).\n */\nexport function scanSourceForQueryMethods(source: string, sourcePath: string): DiscoveredMethod[] {\n const classes: { name: string; index: number }[] = [];\n for (const m of source.matchAll(CLASS_RE)) {\n classes.push({ name: m[1]!, index: m.index ?? 0 });\n }\n if (!classes.length) return [];\n\n const found: DiscoveredMethod[] = [];\n for (const m of source.matchAll(QUERY_RE)) {\n const at = m.index ?? 0;\n let owner: string | undefined;\n for (const c of classes) {\n if (c.index < at) owner = c.name;\n else break;\n }\n if (!owner) continue;\n const args = m[1] ?? '';\n found.push({\n className: owner,\n methodName: m[2]!,\n inline: /\\bsql\\s*:/.test(args),\n sourcePath,\n });\n }\n return found;\n}\n\nfunction renderModule(\n manifest: Record<string, string>,\n entries: SqlManifestEntry[],\n format: 'mjs' | 'ts',\n rootDir: string\n): string {\n const byKey = new Map(entries.map((e) => [e.key, e]));\n const lines: string[] = [\n '// GENERATED by sqlstack-codegen. DO NOT EDIT.',\n '// Source of truth: the .sql files referenced beside each entry.',\n format === 'ts'\n ? 'export const sqlManifest: Record<string, string> = {'\n : 'export const sqlManifest = {',\n ];\n for (const key of Object.keys(manifest).sort()) {\n const entry = byKey.get(key);\n const from = entry ? path.relative(rootDir, entry.sqlPath) : '';\n lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(manifest[key])},${from ? ` // ${from}` : ''}`);\n }\n lines.push('};', '');\n return lines.join('\\n');\n}\n\n/**\n * Programmatic entry point — also used by the CLI (`sqlstack-codegen`) and\n * callable from application build pipelines.\n */\nexport async function generateSqlManifest(\n options: GenerateSqlManifestOptions\n): Promise<GenerateSqlManifestResult> {\n const rootDir = path.resolve(options.rootDir);\n const { manifest, entries, missing } = scanSqlManifestSync(rootDir, options.exclude);\n\n const outFile = path.resolve(options.outFile ?? path.join(rootDir, 'sql-manifest.mjs'));\n const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');\n const code = renderModule(manifest, entries, format, rootDir);\n\n if (options.write !== false) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\n fs.writeFileSync(outFile, code);\n return { manifest, entries, missing, code, outFile };\n }\n return { manifest, entries, missing, code };\n}\n\nexport type ScanSqlManifestResult = {\n manifest: Record<string, string>;\n entries: SqlManifestEntry[];\n missing: MissingSqlMethod[];\n};\n\n/**\n * Synchronous scan core: discover @Query methods under rootDir and inline\n * their sibling .sql files into a Contract A manifest. Shared by the\n * build-time generator above and the runtime SourceScanResolver (bare\n * @Query() with no resolver installed).\n */\nexport function scanSqlManifestSync(rootDir: string, excludeExtra?: string[]): ScanSqlManifestResult {\n if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {\n throw new Error(`sqlstack-codegen: rootDir is not a directory: ${rootDir}`);\n }\n const exclude = new Set([...DEFAULT_EXCLUDES, ...(excludeExtra ?? [])]);\n\n // 1) discover @Query methods\n const discovered: DiscoveredMethod[] = [];\n for (const file of walkSourceFiles(rootDir, exclude)) {\n discovered.push(...scanSourceForQueryMethods(fs.readFileSync(file, 'utf8'), file));\n }\n\n // 2) police duplicate class names (manifest keys are class-scoped)\n const filesByClass = new Map<string, Set<string>>();\n for (const d of discovered) {\n if (!filesByClass.has(d.className)) filesByClass.set(d.className, new Set());\n filesByClass.get(d.className)!.add(d.sourcePath);\n }\n const duplicates = [...filesByClass.entries()].filter(([, files]) => files.size > 1);\n if (duplicates.length) {\n throw new Error(\n 'sqlstack-codegen: duplicate @Query class names (manifest keys are class-name scoped; rename one):\\n' +\n duplicates\n .map(([name, files]) => ` - ${name}:\\n${[...files].map((f) => ` ${f}`).join('\\n')}`)\n .join('\\n')\n );\n }\n\n // 3) pair each non-inline method with sibling .sql files\n const manifest: Record<string, string> = {};\n const entries: SqlManifestEntry[] = [];\n const missing: MissingSqlMethod[] = [];\n const seen = new Set<string>();\n for (const d of discovered) {\n if (d.inline) continue;\n const id = `${d.className}.${d.methodName}`;\n if (seen.has(id)) continue;\n seen.add(id);\n\n const dir = path.dirname(d.sourcePath);\n let matched = false;\n\n const genericPath = path.join(dir, `${d.methodName}.sql`);\n if (fs.existsSync(genericPath)) {\n manifest[id] = fs.readFileSync(genericPath, 'utf8');\n entries.push({ key: id, className: d.className, methodName: d.methodName, sqlPath: genericPath });\n matched = true;\n }\n for (const ext of Object.values(MANIFEST_DIALECT_EXT)) {\n const dialectPath = path.join(dir, `${d.methodName}.${ext}.sql`);\n if (fs.existsSync(dialectPath)) {\n const key = `${id}.${ext}`;\n manifest[key] = fs.readFileSync(dialectPath, 'utf8');\n entries.push({ key, className: d.className, methodName: d.methodName, dialectExt: ext, sqlPath: dialectPath });\n matched = true;\n }\n }\n if (!matched) missing.push({ className: d.className, methodName: d.methodName, sourcePath: d.sourcePath });\n }\n\n return { manifest, entries, missing };\n}\n"]}
@@ -56,26 +56,39 @@ export declare class ManifestResolver implements SqlResolver {
56
56
  /** True when the manifest has a generic or any dialect-specific entry. */
57
57
  hasEntryFor(className: string, methodName: string): boolean;
58
58
  }
59
- type DecoratedMethod = {
59
+ export type DecoratedMethod = {
60
60
  className: string;
61
61
  methodName: string;
62
62
  inline: boolean;
63
63
  };
64
64
  /** @internal Called by the @Query decorator at class-definition time. */
65
+ export declare function recordQueryMethodOnClass(proto: any, entry: DecoratedMethod): void;
66
+ /** @Query-decorated methods declared by the given classes (own + inherited). */
67
+ export declare function queryMethodsOf(classes: ReadonlyArray<abstract new (...args: any[]) => any>): DecoratedMethod[];
68
+ /** @internal Called by the @Query decorator at class-definition time. */
65
69
  export declare function registerDecoratedMethod(entry: DecoratedMethod): void;
66
70
  /** @internal Read by the @Query call path. */
67
71
  export declare function getActiveResolver(): SqlResolver | undefined;
68
72
  /**
69
- * Resolver registration surface (Contract A):
70
- * SqlStack.useResolver(new ManifestResolver(sqlManifest))
71
- * Call at app startup, after repository classes have been imported
72
- * (decoration populates the coverage check).
73
- * With no resolver registered, @Query resolves via the filesystem exactly
74
- * as in v1.
73
+ * Environment-local manifest coverage check: validates only the explicitly
74
+ * supplied classes, from their immutable class metadata. Deterministic
75
+ * regardless of what else the process happened to import.
75
76
  */
76
- export declare const SqlStack: {
77
- useResolver(resolver: SqlResolver): void;
78
- clearResolver(): void;
79
- };
80
- export {};
77
+ export declare function assertManifestCoversClasses(resolver: ManifestResolver, classes: ReadonlyArray<abstract new (...args: any[]) => any>): void;
78
+ /**
79
+ * @deprecated Process-global resolver registration (legacy v2 surface,
80
+ * previously `SqlStack.useResolver(...)`). The canonical path is a per-root
81
+ * resolver on the SqlStack instance (see src/stack.ts); this global is only
82
+ * consulted when no IoC environment is active. Reached via the deprecated
83
+ * static `SqlStack.useResolver(...)` forwards during migration.
84
+ */
85
+ export declare function setGlobalResolver(resolver: SqlResolver): void;
86
+ /** @deprecated See setGlobalResolver. */
87
+ export declare function clearGlobalResolver(): void;
88
+ /**
89
+ * @internal
90
+ * @deprecated Coverage check against the process-global decorated list; the
91
+ * canonical path is assertManifestCoversClasses with an explicit catalog.
92
+ */
93
+ export declare function assertManifestCoverage(resolver: ManifestResolver): void;
81
94
  //# sourceMappingURL=resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAIxD,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;CAC5D;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC5C,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAIpF;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAEhD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,OAAO,EAAE,uBAAuB;gBADxB,QAAQ,EAAE,WAAW,EAC7B,OAAO,GAAE,uBAA4B;IAGhD,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAQrF,0EAA0E;IAC1E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;CAK5D;AAED,KAAK,eAAe,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAclF,yEAAyE;AACzE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAEpE;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,IAAI,WAAW,GAAG,SAAS,CAE3D;AAiBD;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ;0BACG,WAAW,GAAG,IAAI;qBAMvB,IAAI;CAGtB,CAAC"}
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAIxD,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;CAC5D;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC5C,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAIpF;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAEhD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,OAAO,EAAE,uBAAuB;gBADxB,QAAQ,EAAE,WAAW,EAC7B,OAAO,GAAE,uBAA4B;IAGhD,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;IAQrF,0EAA0E;IAC1E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;CAK5D;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAQzF,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAKjF;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,eAAe,EAAE,CAY9G;AAcD,yEAAyE;AACzE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAEpE;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,IAAI,WAAW,GAAG,SAAS,CAE3D;AAiBD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,aAAa,CAAC,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAC3D,IAAI,CAEN;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAK7D;AAED,yCAAyC;AACzC,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAEvE"}
@@ -1,8 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SqlStack = exports.ManifestResolver = exports.FsResolver = exports.MANIFEST_DIALECT_EXT = void 0;
3
+ exports.ManifestResolver = exports.FsResolver = exports.MANIFEST_DIALECT_EXT = void 0;
4
+ exports.recordQueryMethodOnClass = recordQueryMethodOnClass;
5
+ exports.queryMethodsOf = queryMethodsOf;
4
6
  exports.registerDecoratedMethod = registerDecoratedMethod;
5
7
  exports.getActiveResolver = getActiveResolver;
8
+ exports.assertManifestCoversClasses = assertManifestCoversClasses;
9
+ exports.setGlobalResolver = setGlobalResolver;
10
+ exports.clearGlobalResolver = clearGlobalResolver;
11
+ exports.assertManifestCoverage = assertManifestCoverage;
6
12
  const fileResolution_1 = require("./fileResolution");
7
13
  /**
8
14
  * Dialect → manifest key suffix. Mirrors the on-disk file convention
@@ -51,6 +57,32 @@ class ManifestResolver {
51
57
  }
52
58
  }
53
59
  exports.ManifestResolver = ManifestResolver;
60
+ // Immutable per-class record of @Query-decorated methods, written at
61
+ // class-definition time onto the prototype. Unlike the process-global list
62
+ // below, this cannot be polluted by unrelated imports/tests: coverage checks
63
+ // derive from the classes explicitly supplied to them (repo spec 19 §10).
64
+ const QUERY_METHODS = Symbol.for('sqlstack:queryMethods');
65
+ /** @internal Called by the @Query decorator at class-definition time. */
66
+ function recordQueryMethodOnClass(proto, entry) {
67
+ if (!Object.prototype.hasOwnProperty.call(proto, QUERY_METHODS)) {
68
+ Object.defineProperty(proto, QUERY_METHODS, { value: [], enumerable: false });
69
+ }
70
+ proto[QUERY_METHODS].push(entry);
71
+ }
72
+ /** @Query-decorated methods declared by the given classes (own + inherited). */
73
+ function queryMethodsOf(classes) {
74
+ const out = [];
75
+ for (const cls of classes) {
76
+ let proto = cls.prototype;
77
+ while (proto && proto !== Object.prototype) {
78
+ if (Object.prototype.hasOwnProperty.call(proto, QUERY_METHODS)) {
79
+ out.push(...proto[QUERY_METHODS]);
80
+ }
81
+ proto = Object.getPrototypeOf(proto);
82
+ }
83
+ }
84
+ return out;
85
+ }
54
86
  // Single shared state across module copies (same pattern as SqlStackDB).
55
87
  const g = globalThis;
56
88
  if (!g.__SQLSTACK_RESOLVER_STATE__) {
@@ -65,8 +97,8 @@ function registerDecoratedMethod(entry) {
65
97
  function getActiveResolver() {
66
98
  return state.resolver;
67
99
  }
68
- function assertManifestCovers(resolver) {
69
- const missing = state.decorated
100
+ function assertMissing(resolver, decorated) {
101
+ const missing = decorated
70
102
  .filter((m) => !m.inline)
71
103
  .filter((m) => !resolver.hasEntryFor(m.className, m.methodName))
72
104
  .map((m) => `${m.className}.${m.methodName}`);
@@ -78,22 +110,36 @@ function assertManifestCovers(resolver) {
78
110
  }
79
111
  }
80
112
  /**
81
- * Resolver registration surface (Contract A):
82
- * SqlStack.useResolver(new ManifestResolver(sqlManifest))
83
- * Call at app startup, after repository classes have been imported
84
- * (decoration populates the coverage check).
85
- * With no resolver registered, @Query resolves via the filesystem exactly
86
- * as in v1.
113
+ * Environment-local manifest coverage check: validates only the explicitly
114
+ * supplied classes, from their immutable class metadata. Deterministic
115
+ * regardless of what else the process happened to import.
87
116
  */
88
- exports.SqlStack = {
89
- useResolver(resolver) {
90
- if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {
91
- assertManifestCovers(resolver);
92
- }
93
- state.resolver = resolver;
94
- },
95
- clearResolver() {
96
- state.resolver = undefined;
97
- },
98
- };
117
+ function assertManifestCoversClasses(resolver, classes) {
118
+ assertMissing(resolver, queryMethodsOf(classes));
119
+ }
120
+ /**
121
+ * @deprecated Process-global resolver registration (legacy v2 surface,
122
+ * previously `SqlStack.useResolver(...)`). The canonical path is a per-root
123
+ * resolver on the SqlStack instance (see src/stack.ts); this global is only
124
+ * consulted when no IoC environment is active. Reached via the deprecated
125
+ * static `SqlStack.useResolver(...)` forwards during migration.
126
+ */
127
+ function setGlobalResolver(resolver) {
128
+ if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {
129
+ assertMissing(resolver, state.decorated);
130
+ }
131
+ state.resolver = resolver;
132
+ }
133
+ /** @deprecated See setGlobalResolver. */
134
+ function clearGlobalResolver() {
135
+ state.resolver = undefined;
136
+ }
137
+ /**
138
+ * @internal
139
+ * @deprecated Coverage check against the process-global decorated list; the
140
+ * canonical path is assertManifestCoversClasses with an explicit catalog.
141
+ */
142
+ function assertManifestCoverage(resolver) {
143
+ assertMissing(resolver, state.decorated);
144
+ }
99
145
  //# sourceMappingURL=resolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Dialect } from '../registry';\nimport { resolveSqlFromFs } from './fileResolution';\n\n/**\n * Dialect → manifest key suffix. Mirrors the on-disk file convention\n * (`findByEmail.pg.sql` → key `UsersRepo.findByEmail.pg`).\n */\nexport const MANIFEST_DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\n/**\n * Generated SQL manifest shape (see docs/resolver_architecture.md, Contract A):\n * { '<ClassName>.<methodName>.<dialectExt>': '<sql>', '<ClassName>.<methodName>': '<sql>' }\n */\nexport type SqlManifest = Record<string, string>;\n\nexport type SqlResolutionRequest = {\n className: string;\n methodName: string;\n dialect: Dialect;\n /** Present when the @Query decorator resolved a filesystem root (Node only). */\n rootDir?: string;\n};\n\n/**\n * Strategy for turning a decorated @Query method into a SQL string.\n * The public @Query API is identical under every resolver.\n */\nexport interface SqlResolver {\n /** Return the SQL for the request, or undefined when this resolver has none. */\n resolve(request: SqlResolutionRequest): string | undefined;\n}\n\n/**\n * Node filesystem resolution — the v1 behavior, unchanged: dialect-specific\n * `<method>.<ext>.sql` first, then generic `<method>.sql`, from the rootDir\n * the decorator captured (explicit argument or stack-based directory guess).\n */\nexport class FsResolver implements SqlResolver {\n resolve({ rootDir, methodName, dialect }: SqlResolutionRequest): string | undefined {\n if (!rootDir) return undefined;\n return resolveSqlFromFs(rootDir, methodName, dialect).sql;\n }\n}\n\nexport type ManifestResolverOptions = {\n /**\n * Validate at registration time that every decorated @Query method has a\n * manifest entry (fail fast, earlier than v1's lazy fs lookup).\n * Default true. Set false when some @Query methods build their SQL by\n * returning a SqlFragment from the method body — those never consult the\n * manifest and cannot be distinguished statically.\n */\n assert?: boolean;\n};\n\n/**\n * Build-time manifest resolution — bundling-proof (Cloudflare Workers).\n * Lookup order per Contract A:\n * 1. `${className}.${methodName}.${dialectExt}`\n * 2. `${className}.${methodName}` (generic fallback)\n */\nexport class ManifestResolver implements SqlResolver {\n constructor(\n private readonly manifest: SqlManifest,\n readonly options: ManifestResolverOptions = {}\n ) {}\n\n resolve({ className, methodName, dialect }: SqlResolutionRequest): string | undefined {\n const ext = MANIFEST_DIALECT_EXT[dialect];\n return (\n this.manifest[`${className}.${methodName}.${ext}`] ??\n this.manifest[`${className}.${methodName}`]\n );\n }\n\n /** True when the manifest has a generic or any dialect-specific entry. */\n hasEntryFor(className: string, methodName: string): boolean {\n const generic = `${className}.${methodName}`;\n if (generic in this.manifest) return true;\n return Object.values(MANIFEST_DIALECT_EXT).some((ext) => `${generic}.${ext}` in this.manifest);\n }\n}\n\ntype DecoratedMethod = { className: string; methodName: string; inline: boolean };\n\ntype ResolverState = {\n resolver: SqlResolver | undefined;\n decorated: DecoratedMethod[];\n};\n\n// Single shared state across module copies (same pattern as SqlStackDB).\nconst g = globalThis as any;\nif (!g.__SQLSTACK_RESOLVER_STATE__) {\n g.__SQLSTACK_RESOLVER_STATE__ = { resolver: undefined, decorated: [] } as ResolverState;\n}\nconst state: ResolverState = g.__SQLSTACK_RESOLVER_STATE__;\n\n/** @internal Called by the @Query decorator at class-definition time. */\nexport function registerDecoratedMethod(entry: DecoratedMethod): void {\n state.decorated.push(entry);\n}\n\n/** @internal Read by the @Query call path. */\nexport function getActiveResolver(): SqlResolver | undefined {\n return state.resolver;\n}\n\nfunction assertManifestCovers(resolver: ManifestResolver): void {\n const missing = state.decorated\n .filter((m) => !m.inline)\n .filter((m) => !resolver.hasEntryFor(m.className, m.methodName))\n .map((m) => `${m.className}.${m.methodName}`);\n if (missing.length) {\n throw new Error(\n 'sqlstack: ManifestResolver has no SQL for these @Query methods:\\n' +\n missing.map((k) => ` - ${k}`).join('\\n') +\n '\\nRegenerate the manifest (see docs/codegen.md), or pass ' +\n '{ assert: false } if these methods return a SqlFragment from their body.'\n );\n }\n}\n\n/**\n * Resolver registration surface (Contract A):\n * SqlStack.useResolver(new ManifestResolver(sqlManifest))\n * Call at app startup, after repository classes have been imported\n * (decoration populates the coverage check).\n * With no resolver registered, @Query resolves via the filesystem exactly\n * as in v1.\n */\nexport const SqlStack = {\n useResolver(resolver: SqlResolver): void {\n if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {\n assertManifestCovers(resolver);\n }\n state.resolver = resolver;\n },\n clearResolver(): void {\n state.resolver = undefined;\n },\n};\n"]}
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":";;;AAgGA,4DAKC;AAGD,wCAYC;AAeD,0DAEC;AAGD,8CAEC;AAsBD,kEAKC;AASD,8CAKC;AAGD,kDAEC;AAOD,wDAEC;AAhMD,qDAAoD;AAEpD;;;GAGG;AACU,QAAA,oBAAoB,GAA4B;IAC3D,QAAQ,EAAE,IAAI;IACd,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;CACjB,CAAC;AAyBF;;;;GAIG;AACH,MAAa,UAAU;IACrB,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAwB;QAC5D,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,OAAO,IAAA,iCAAgB,EAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC;IAC5D,CAAC;CACF;AALD,gCAKC;AAaD;;;;;GAKG;AACH,MAAa,gBAAgB;IAC3B,YACmB,QAAqB,EAC7B,UAAmC,EAAE;QAD7B,aAAQ,GAAR,QAAQ,CAAa;QAC7B,YAAO,GAAP,OAAO,CAA8B;IAC7C,CAAC;IAEJ,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAwB;QAC9D,MAAM,GAAG,GAAG,4BAAoB,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,GAAG,SAAS,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;YAClD,IAAI,CAAC,QAAQ,CAAC,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC,CAC5C,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,WAAW,CAAC,SAAiB,EAAE,UAAkB;QAC/C,MAAM,OAAO,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;QAC7C,IAAI,OAAO,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,MAAM,CAAC,MAAM,CAAC,4BAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjG,CAAC;CACF;AApBD,4CAoBC;AAID,qEAAqE;AACrE,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAE1D,yEAAyE;AACzE,SAAgB,wBAAwB,CAAC,KAAU,EAAE,KAAsB;IACzE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,gFAAgF;AAChF,SAAgB,cAAc,CAAC,OAA4D;IACzF,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC;QAC1B,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;YACpC,CAAC;YACD,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAOD,yEAAyE;AACzE,MAAM,CAAC,GAAG,UAAiB,CAAC;AAC5B,IAAI,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAC;IACnC,CAAC,CAAC,2BAA2B,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAmB,CAAC;AAC1F,CAAC;AACD,MAAM,KAAK,GAAkB,CAAC,CAAC,2BAA2B,CAAC;AAE3D,yEAAyE;AACzE,SAAgB,uBAAuB,CAAC,KAAsB;IAC5D,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,8CAA8C;AAC9C,SAAgB,iBAAiB;IAC/B,OAAO,KAAK,CAAC,QAAQ,CAAC;AACxB,CAAC;AAED,SAAS,aAAa,CAAC,QAA0B,EAAE,SAA4B;IAC7E,MAAM,OAAO,GAAG,SAAS;SACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;SAC/D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IAChD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,mEAAmE;YACjE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACzC,2DAA2D;YAC3D,0EAA0E,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,2BAA2B,CACzC,QAA0B,EAC1B,OAA4D;IAE5D,aAAa,CAAC,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,QAAqB;IACrD,IAAI,QAAQ,YAAY,gBAAgB,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC9E,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IACD,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC5B,CAAC;AAED,yCAAyC;AACzC,SAAgB,mBAAmB;IACjC,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAAC,QAA0B;IAC/D,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["import type { Dialect } from '../registry';\nimport { resolveSqlFromFs } from './fileResolution';\n\n/**\n * Dialect → manifest key suffix. Mirrors the on-disk file convention\n * (`findByEmail.pg.sql` → key `UsersRepo.findByEmail.pg`).\n */\nexport const MANIFEST_DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\n/**\n * Generated SQL manifest shape (see docs/resolver_architecture.md, Contract A):\n * { '<ClassName>.<methodName>.<dialectExt>': '<sql>', '<ClassName>.<methodName>': '<sql>' }\n */\nexport type SqlManifest = Record<string, string>;\n\nexport type SqlResolutionRequest = {\n className: string;\n methodName: string;\n dialect: Dialect;\n /** Present when the @Query decorator resolved a filesystem root (Node only). */\n rootDir?: string;\n};\n\n/**\n * Strategy for turning a decorated @Query method into a SQL string.\n * The public @Query API is identical under every resolver.\n */\nexport interface SqlResolver {\n /** Return the SQL for the request, or undefined when this resolver has none. */\n resolve(request: SqlResolutionRequest): string | undefined;\n}\n\n/**\n * Node filesystem resolution — the v1 behavior, unchanged: dialect-specific\n * `<method>.<ext>.sql` first, then generic `<method>.sql`, from the rootDir\n * the decorator captured (explicit argument or stack-based directory guess).\n */\nexport class FsResolver implements SqlResolver {\n resolve({ rootDir, methodName, dialect }: SqlResolutionRequest): string | undefined {\n if (!rootDir) return undefined;\n return resolveSqlFromFs(rootDir, methodName, dialect).sql;\n }\n}\n\nexport type ManifestResolverOptions = {\n /**\n * Validate at registration time that every decorated @Query method has a\n * manifest entry (fail fast, earlier than v1's lazy fs lookup).\n * Default true. Set false when some @Query methods build their SQL by\n * returning a SqlFragment from the method body — those never consult the\n * manifest and cannot be distinguished statically.\n */\n assert?: boolean;\n};\n\n/**\n * Build-time manifest resolution — bundling-proof (Cloudflare Workers).\n * Lookup order per Contract A:\n * 1. `${className}.${methodName}.${dialectExt}`\n * 2. `${className}.${methodName}` (generic fallback)\n */\nexport class ManifestResolver implements SqlResolver {\n constructor(\n private readonly manifest: SqlManifest,\n readonly options: ManifestResolverOptions = {}\n ) {}\n\n resolve({ className, methodName, dialect }: SqlResolutionRequest): string | undefined {\n const ext = MANIFEST_DIALECT_EXT[dialect];\n return (\n this.manifest[`${className}.${methodName}.${ext}`] ??\n this.manifest[`${className}.${methodName}`]\n );\n }\n\n /** True when the manifest has a generic or any dialect-specific entry. */\n hasEntryFor(className: string, methodName: string): boolean {\n const generic = `${className}.${methodName}`;\n if (generic in this.manifest) return true;\n return Object.values(MANIFEST_DIALECT_EXT).some((ext) => `${generic}.${ext}` in this.manifest);\n }\n}\n\nexport type DecoratedMethod = { className: string; methodName: string; inline: boolean };\n\n// Immutable per-class record of @Query-decorated methods, written at\n// class-definition time onto the prototype. Unlike the process-global list\n// below, this cannot be polluted by unrelated imports/tests: coverage checks\n// derive from the classes explicitly supplied to them (repo spec 19 §10).\nconst QUERY_METHODS = Symbol.for('sqlstack:queryMethods');\n\n/** @internal Called by the @Query decorator at class-definition time. */\nexport function recordQueryMethodOnClass(proto: any, entry: DecoratedMethod): void {\n if (!Object.prototype.hasOwnProperty.call(proto, QUERY_METHODS)) {\n Object.defineProperty(proto, QUERY_METHODS, { value: [], enumerable: false });\n }\n proto[QUERY_METHODS].push(entry);\n}\n\n/** @Query-decorated methods declared by the given classes (own + inherited). */\nexport function queryMethodsOf(classes: ReadonlyArray<abstract new (...args: any[]) => any>): DecoratedMethod[] {\n const out: DecoratedMethod[] = [];\n for (const cls of classes) {\n let proto = cls.prototype;\n while (proto && proto !== Object.prototype) {\n if (Object.prototype.hasOwnProperty.call(proto, QUERY_METHODS)) {\n out.push(...proto[QUERY_METHODS]);\n }\n proto = Object.getPrototypeOf(proto);\n }\n }\n return out;\n}\n\ntype ResolverState = {\n resolver: SqlResolver | undefined;\n decorated: DecoratedMethod[];\n};\n\n// Single shared state across module copies (same pattern as SqlStackDB).\nconst g = globalThis as any;\nif (!g.__SQLSTACK_RESOLVER_STATE__) {\n g.__SQLSTACK_RESOLVER_STATE__ = { resolver: undefined, decorated: [] } as ResolverState;\n}\nconst state: ResolverState = g.__SQLSTACK_RESOLVER_STATE__;\n\n/** @internal Called by the @Query decorator at class-definition time. */\nexport function registerDecoratedMethod(entry: DecoratedMethod): void {\n state.decorated.push(entry);\n}\n\n/** @internal Read by the @Query call path. */\nexport function getActiveResolver(): SqlResolver | undefined {\n return state.resolver;\n}\n\nfunction assertMissing(resolver: ManifestResolver, decorated: DecoratedMethod[]): void {\n const missing = decorated\n .filter((m) => !m.inline)\n .filter((m) => !resolver.hasEntryFor(m.className, m.methodName))\n .map((m) => `${m.className}.${m.methodName}`);\n if (missing.length) {\n throw new Error(\n 'sqlstack: ManifestResolver has no SQL for these @Query methods:\\n' +\n missing.map((k) => ` - ${k}`).join('\\n') +\n '\\nRegenerate the manifest (see docs/codegen.md), or pass ' +\n '{ assert: false } if these methods return a SqlFragment from their body.'\n );\n }\n}\n\n/**\n * Environment-local manifest coverage check: validates only the explicitly\n * supplied classes, from their immutable class metadata. Deterministic\n * regardless of what else the process happened to import.\n */\nexport function assertManifestCoversClasses(\n resolver: ManifestResolver,\n classes: ReadonlyArray<abstract new (...args: any[]) => any>\n): void {\n assertMissing(resolver, queryMethodsOf(classes));\n}\n\n/**\n * @deprecated Process-global resolver registration (legacy v2 surface,\n * previously `SqlStack.useResolver(...)`). The canonical path is a per-root\n * resolver on the SqlStack instance (see src/stack.ts); this global is only\n * consulted when no IoC environment is active. Reached via the deprecated\n * static `SqlStack.useResolver(...)` forwards during migration.\n */\nexport function setGlobalResolver(resolver: SqlResolver): void {\n if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {\n assertMissing(resolver, state.decorated);\n }\n state.resolver = resolver;\n}\n\n/** @deprecated See setGlobalResolver. */\nexport function clearGlobalResolver(): void {\n state.resolver = undefined;\n}\n\n/**\n * @internal\n * @deprecated Coverage check against the process-global decorated list; the\n * canonical path is assertManifestCoversClasses with an explicit catalog.\n */\nexport function assertManifestCoverage(resolver: ManifestResolver): void {\n assertMissing(resolver, state.decorated);\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { SqlResolver, SqlResolutionRequest } from './resolver';
2
+ /**
3
+ * Zero-config Node resolution for bare @Query(): lazily scans the project
4
+ * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
5
+ * sibling .sql files, then answers Contract A lookups from the in-memory
6
+ * manifest. The scan runs once, on the first bare-@Query execution.
7
+ *
8
+ * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
9
+ * or the deprecated global) always take precedence, and bundled runtimes
10
+ * (Cloudflare Workers) never reach it because their entrypoints install a
11
+ * ManifestResolver.
12
+ */
13
+ export declare class SourceScanResolver implements SqlResolver {
14
+ #private;
15
+ private readonly rootDir?;
16
+ constructor(rootDir?: string | undefined);
17
+ resolve(request: SqlResolutionRequest): string | undefined;
18
+ }
19
+ /**
20
+ * @internal Process-wide default used by the @Query call path when no
21
+ * resolver is installed and the decorator captured no filesystem root.
22
+ * Node-only: returns undefined where the filesystem is unavailable.
23
+ */
24
+ export declare function defaultSourceScanResolver(): SourceScanResolver | undefined;
25
+ //# sourceMappingURL=sourceScanResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceScanResolver.d.ts","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIpE;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,WAAW;;IAGxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAR,OAAO,CAAC,EAAE,MAAM,YAAA;IAE7C,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAO3D;AAID;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,GAAG,SAAS,CAG1E"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _SourceScanResolver_inner;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SourceScanResolver = void 0;
16
+ exports.defaultSourceScanResolver = defaultSourceScanResolver;
17
+ const resolver_1 = require("./resolver");
18
+ const generateManifest_1 = require("../codegen/generateManifest");
19
+ /**
20
+ * Zero-config Node resolution for bare @Query(): lazily scans the project
21
+ * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
22
+ * sibling .sql files, then answers Contract A lookups from the in-memory
23
+ * manifest. The scan runs once, on the first bare-@Query execution.
24
+ *
25
+ * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
26
+ * or the deprecated global) always take precedence, and bundled runtimes
27
+ * (Cloudflare Workers) never reach it because their entrypoints install a
28
+ * ManifestResolver.
29
+ */
30
+ class SourceScanResolver {
31
+ constructor(rootDir) {
32
+ this.rootDir = rootDir;
33
+ _SourceScanResolver_inner.set(this, void 0);
34
+ }
35
+ resolve(request) {
36
+ if (!__classPrivateFieldGet(this, _SourceScanResolver_inner, "f")) {
37
+ const { manifest } = (0, generateManifest_1.scanSqlManifestSync)(this.rootDir ?? process.cwd());
38
+ __classPrivateFieldSet(this, _SourceScanResolver_inner, new resolver_1.ManifestResolver(manifest, { assert: false }), "f");
39
+ }
40
+ return __classPrivateFieldGet(this, _SourceScanResolver_inner, "f").resolve(request);
41
+ }
42
+ }
43
+ exports.SourceScanResolver = SourceScanResolver;
44
+ _SourceScanResolver_inner = new WeakMap();
45
+ let defaultInstance;
46
+ /**
47
+ * @internal Process-wide default used by the @Query call path when no
48
+ * resolver is installed and the decorator captured no filesystem root.
49
+ * Node-only: returns undefined where the filesystem is unavailable.
50
+ */
51
+ function defaultSourceScanResolver() {
52
+ if (typeof process === 'undefined' || typeof process.cwd !== 'function')
53
+ return undefined;
54
+ return (defaultInstance ?? (defaultInstance = new SourceScanResolver()));
55
+ }
56
+ //# sourceMappingURL=sourceScanResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAoCA,8DAGC;AAtCD,yCAA8C;AAC9C,kEAAkE;AAElE;;;;;;;;;;GAUG;AACH,MAAa,kBAAkB;IAG7B,YAA6B,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAF7C,4CAAqC;IAEW,CAAC;IAEjD,OAAO,CAAC,OAA6B;QACnC,IAAI,CAAC,uBAAA,IAAI,iCAAO,EAAE,CAAC;YACjB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,sCAAmB,EAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,2BAAgB,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAA,CAAC;QAClE,CAAC;QACD,OAAO,uBAAA,IAAI,iCAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF;AAZD,gDAYC;;AAED,IAAI,eAA+C,CAAC;AAEpD;;;;GAIG;AACH,SAAgB,yBAAyB;IACvC,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAC1F,OAAO,CAAC,eAAe,KAAf,eAAe,GAAK,IAAI,kBAAkB,EAAE,EAAC,CAAC;AACxD,CAAC","sourcesContent":["import type { SqlResolver, SqlResolutionRequest } from './resolver';\nimport { ManifestResolver } from './resolver';\nimport { scanSqlManifestSync } from '../codegen/generateManifest';\n\n/**\n * Zero-config Node resolution for bare @Query(): lazily scans the project\n * tree (process.cwd(), or an explicit rootDir) for @Query classes and their\n * sibling .sql files, then answers Contract A lookups from the in-memory\n * manifest. The scan runs once, on the first bare-@Query execution.\n *\n * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig\n * or the deprecated global) always take precedence, and bundled runtimes\n * (Cloudflare Workers) never reach it because their entrypoints install a\n * ManifestResolver.\n */\nexport class SourceScanResolver implements SqlResolver {\n #inner: ManifestResolver | undefined;\n\n constructor(private readonly rootDir?: string) {}\n\n resolve(request: SqlResolutionRequest): string | undefined {\n if (!this.#inner) {\n const { manifest } = scanSqlManifestSync(this.rootDir ?? process.cwd());\n this.#inner = new ManifestResolver(manifest, { assert: false });\n }\n return this.#inner.resolve(request);\n }\n}\n\nlet defaultInstance: SourceScanResolver | undefined;\n\n/**\n * @internal Process-wide default used by the @Query call path when no\n * resolver is installed and the decorator captured no filesystem root.\n * Node-only: returns undefined where the filesystem is unavailable.\n */\nexport function defaultSourceScanResolver(): SourceScanResolver | undefined {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') return undefined;\n return (defaultInstance ??= new SourceScanResolver());\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"AAUA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,wBA8Q/E"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"AAWA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,wBA0R/E"}
@@ -4,10 +4,11 @@ exports.Query = Query;
4
4
  const metadata_1 = require("../core/metadata");
5
5
  const errors_1 = require("../core/errors");
6
6
  const validator_1 = require("../core/validator");
7
- const registry_1 = require("../registry");
7
+ const runtime_1 = require("../runtime");
8
8
  const sqlBinder_1 = require("../binders/sqlBinder");
9
9
  const fileResolution_1 = require("../core/fileResolution");
10
10
  const resolver_1 = require("../core/resolver");
11
+ const sourceScanResolver_1 = require("../core/sourceScanResolver");
11
12
  const transactions_1 = require("../transactions");
12
13
  const sql_1 = require("../sql");
13
14
  function Query(arg) {
@@ -23,19 +24,25 @@ function Query(arg) {
23
24
  (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'inline', sql: options.sql } });
24
25
  }
25
26
  else {
26
- // FS-based resolution
27
+ // FS-based resolution: only an EXPLICIT path argument pins a directory.
28
+ // Bare @Query() resolves through the active resolver (or the default
29
+ // SourceScanResolver) — no stack-based directory guessing, which breaks
30
+ // under bundlers and test transforms.
27
31
  const { rootDir } = (0, fileResolution_1.coerceRootPath)(rootArg);
28
- const dir = rootDir ?? (0, fileResolution_1.guessDecoratorDir)();
29
- if (dir) {
30
- (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'fs', rootDir: dir } });
32
+ if (rootDir) {
33
+ (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'fs', rootDir } });
31
34
  }
32
35
  }
33
- // Record for resolver coverage checks (ManifestResolver startup assertion).
34
- (0, resolver_1.registerDecoratedMethod)({
36
+ // Record for resolver coverage checks: immutable class metadata (the
37
+ // canonical, environment-local source) plus the deprecated global list
38
+ // consulted by the legacy global-resolver path.
39
+ const decoratedEntry = {
35
40
  className: _target?.constructor?.name ?? '<anonymous>',
36
41
  methodName: String(prop),
37
42
  inline: !!options?.sql,
38
- });
43
+ };
44
+ (0, resolver_1.recordQueryMethodOnClass)(_target, decoratedEntry);
45
+ (0, resolver_1.registerDecoratedMethod)(decoratedEntry);
39
46
  const original = desc.value;
40
47
  desc.value = async function (...callArgs) {
41
48
  const labels = (0, metadata_1.getMethodLabels)(this, prop);
@@ -52,10 +59,11 @@ function Query(arg) {
52
59
  if (fragmentResult instanceof sql_1.SqlFragment) {
53
60
  const { sql: boundSql, params } = fragmentResult.toSQL();
54
61
  const dbName = labels.db ?? options?.db ?? classLabels?.db;
55
- const { name: resolvedDbName, db } = registry_1.SqlStackDB.getEntry(dbName);
62
+ const { entry } = await (0, runtime_1.resolveExecution)(dbName);
63
+ const db = entry.db;
56
64
  let out;
57
65
  try {
58
- const tx = (0, transactions_1.getActiveTransaction)(resolvedDbName);
66
+ const tx = (0, transactions_1.getActiveTransaction)(entry);
59
67
  out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);
60
68
  }
61
69
  catch (dbError) {
@@ -79,12 +87,13 @@ function Query(arg) {
79
87
  }
80
88
  // 1) prepare args with defaults
81
89
  const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array
82
- // 2) choose database and dialect
90
+ // 2) choose database and dialect via the active environment
83
91
  const dbName = labels.db ?? options?.db ?? classLabels?.db;
84
- const { name: resolvedDbName, db } = registry_1.SqlStackDB.getEntry(dbName);
92
+ const { entry, resolver: activeResolver } = await (0, runtime_1.resolveExecution)(dbName);
93
+ const db = entry.db;
85
94
  const dialect = options?.dialect ?? db.dialect ?? 'sqlite';
86
- // 3) load SQL source (inline, active resolver, or v1 fs fallback)
87
- const activeResolver = (0, resolver_1.getActiveResolver)();
95
+ // 3) load SQL source (inline, environment resolver, v1 fs fallback,
96
+ // or the zero-config source scan — bare @Query() with nothing installed)
88
97
  const sql = labels?.source?.kind === 'inline'
89
98
  ? labels.source.sql
90
99
  : activeResolver
@@ -96,7 +105,11 @@ function Query(arg) {
96
105
  })
97
106
  : labels?.source?.kind === 'fs'
98
107
  ? (0, fileResolution_1.resolveSqlFromFs)(labels.source.rootDir, String(prop), dialect).sql
99
- : undefined;
108
+ : (0, sourceScanResolver_1.defaultSourceScanResolver)()?.resolve({
109
+ className: this?.constructor?.name ?? '<anonymous>',
110
+ methodName: String(prop),
111
+ dialect,
112
+ });
100
113
  if (!sql) {
101
114
  throw new errors_1.SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);
102
115
  }
@@ -284,7 +297,7 @@ function Query(arg) {
284
297
  // 5) execute query via registry DB
285
298
  let out;
286
299
  try {
287
- const tx = (0, transactions_1.getActiveTransaction)(resolvedDbName);
300
+ const tx = (0, transactions_1.getActiveTransaction)(entry);
288
301
  out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);
289
302
  }
290
303
  catch (dbError) {