sqlstack 3.4.0 → 3.5.0-dev.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 (83) hide show
  1. package/dist/cjs/codegen/generateManifest.d.ts +3 -1
  2. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -1
  3. package/dist/cjs/codegen/generateManifest.js +195 -3
  4. package/dist/cjs/codegen/generateManifest.js.map +1 -1
  5. package/dist/cjs/core/errors.d.ts +9 -0
  6. package/dist/cjs/core/errors.d.ts.map +1 -1
  7. package/dist/cjs/core/errors.js +10 -0
  8. package/dist/cjs/core/errors.js.map +1 -1
  9. package/dist/cjs/core/fileResolution.d.ts +7 -0
  10. package/dist/cjs/core/fileResolution.d.ts.map +1 -1
  11. package/dist/cjs/core/fileResolution.js +53 -14
  12. package/dist/cjs/core/fileResolution.js.map +1 -1
  13. package/dist/cjs/core/metadata.d.ts +5 -0
  14. package/dist/cjs/core/metadata.d.ts.map +1 -1
  15. package/dist/cjs/core/metadata.js.map +1 -1
  16. package/dist/cjs/core/resources.d.ts +36 -0
  17. package/dist/cjs/core/resources.d.ts.map +1 -0
  18. package/dist/cjs/core/resources.js +98 -0
  19. package/dist/cjs/core/resources.js.map +1 -0
  20. package/dist/cjs/core/sourceScanResolver.d.ts +8 -14
  21. package/dist/cjs/core/sourceScanResolver.d.ts.map +1 -1
  22. package/dist/cjs/core/sourceScanResolver.js +8 -20
  23. package/dist/cjs/core/sourceScanResolver.js.map +1 -1
  24. package/dist/cjs/decorators/query.d.ts +14 -0
  25. package/dist/cjs/decorators/query.d.ts.map +1 -1
  26. package/dist/cjs/decorators/query.js +208 -40
  27. package/dist/cjs/decorators/query.js.map +1 -1
  28. package/dist/cjs/family.d.ts.map +1 -1
  29. package/dist/cjs/family.js +3 -1
  30. package/dist/cjs/family.js.map +1 -1
  31. package/dist/cjs/index.d.ts +3 -0
  32. package/dist/cjs/index.d.ts.map +1 -1
  33. package/dist/cjs/index.js +6 -2
  34. package/dist/cjs/index.js.map +1 -1
  35. package/dist/cjs/run.d.ts +180 -6
  36. package/dist/cjs/run.d.ts.map +1 -1
  37. package/dist/cjs/run.js +158 -17
  38. package/dist/cjs/run.js.map +1 -1
  39. package/dist/cjs/runtime.d.ts +14 -0
  40. package/dist/cjs/runtime.d.ts.map +1 -1
  41. package/dist/cjs/runtime.js +30 -0
  42. package/dist/cjs/runtime.js.map +1 -1
  43. package/dist/cjs/sql.d.ts +19 -0
  44. package/dist/cjs/sql.d.ts.map +1 -1
  45. package/dist/cjs/sql.js +66 -28
  46. package/dist/cjs/sql.js.map +1 -1
  47. package/dist/cjs/stack.d.ts +14 -0
  48. package/dist/cjs/stack.d.ts.map +1 -1
  49. package/dist/cjs/stack.js +20 -0
  50. package/dist/cjs/stack.js.map +1 -1
  51. package/dist/cjs/transactions.d.ts +60 -0
  52. package/dist/cjs/transactions.d.ts.map +1 -1
  53. package/dist/cjs/transactions.js +575 -3
  54. package/dist/cjs/transactions.js.map +1 -1
  55. package/dist/esm/codegen/generateManifest.js +195 -3
  56. package/dist/esm/codegen/generateManifest.js.map +1 -1
  57. package/dist/esm/core/errors.js +10 -0
  58. package/dist/esm/core/errors.js.map +1 -1
  59. package/dist/esm/core/fileResolution.js +52 -14
  60. package/dist/esm/core/fileResolution.js.map +1 -1
  61. package/dist/esm/core/metadata.js.map +1 -1
  62. package/dist/esm/core/resources.js +91 -0
  63. package/dist/esm/core/resources.js.map +1 -0
  64. package/dist/esm/core/sourceScanResolver.js +8 -19
  65. package/dist/esm/core/sourceScanResolver.js.map +1 -1
  66. package/dist/esm/decorators/query.js +214 -46
  67. package/dist/esm/decorators/query.js.map +1 -1
  68. package/dist/esm/family.js +3 -1
  69. package/dist/esm/family.js.map +1 -1
  70. package/dist/esm/index.js +3 -1
  71. package/dist/esm/index.js.map +1 -1
  72. package/dist/esm/run.js +153 -18
  73. package/dist/esm/run.js.map +1 -1
  74. package/dist/esm/runtime.js +28 -0
  75. package/dist/esm/runtime.js.map +1 -1
  76. package/dist/esm/sql.js +63 -27
  77. package/dist/esm/sql.js.map +1 -1
  78. package/dist/esm/stack.js +21 -1
  79. package/dist/esm/stack.js.map +1 -1
  80. package/dist/esm/transactions.js +571 -3
  81. package/dist/esm/transactions.js.map +1 -1
  82. package/package.json +1 -1
  83. package/readme.md +201 -171
@@ -48,7 +48,9 @@ type DiscoveredMethod = {
48
48
  * Regex-based discovery: each @Query method is attributed to the nearest
49
49
  * preceding `class` declaration in the same file. Inline queries are detected
50
50
  * by a `sql:` property in the decorator arguments (see docs/codegen.md for the
51
- * documented limitations of this heuristic).
51
+ * documented limitations of this heuristic). Comments and string/template/
52
+ * regex literal contents are masked first (positions preserved), so prose
53
+ * cannot declare classes or @Query methods.
52
54
  */
53
55
  export declare function scanSourceForQueryMethods(source: string, sourcePath: string): DiscoveredMethod[];
54
56
  /**
@@ -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,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"}
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;AAsLF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA0BhG;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"}
@@ -55,21 +55,213 @@ function walkSourceFiles(rootDir, exclude) {
55
55
  }
56
56
  const CLASS_RE = /(?:^|[\s;{}(])class\s+([A-Za-z_$][\w$]*)/g;
57
57
  const QUERY_RE = /@Query\s*(?:\(([^)]*)\))?\s*(?:public\s+|private\s+|protected\s+)?(?:async\s+)?([A-Za-z_$][\w$]*)\s*[(<]/g;
58
+ /** Punctuators after which a `/` starts a regex literal rather than division. */
59
+ const REGEX_AFTER_PUNCT = new Set('(,=:[!&|?{};+-*%<>~^'.split(''));
60
+ /** Keywords after which a `/` starts a regex literal rather than division. */
61
+ const REGEX_AFTER_KEYWORD = new Set([
62
+ 'return', 'typeof', 'instanceof', 'in', 'of', 'new', 'delete', 'void',
63
+ 'throw', 'case', 'do', 'else', 'yield', 'await',
64
+ ]);
65
+ const IDENT_CHAR = /[A-Za-z0-9_$]/;
66
+ /**
67
+ * Returns `source` with comments and the contents of string, template and
68
+ * regex literals replaced by spaces (newlines kept), so every index still
69
+ * points at the same position in the original text. Literal delimiters are
70
+ * kept, so decorator arguments such as `{ sql: '...' }` keep their shape and
71
+ * the `sql:` key stays detectable, while prose like "the same class with" or
72
+ * "@Query() foo(" inside a comment or string can no longer match CLASS_RE or
73
+ * QUERY_RE. Lexical heuristic only (no TS compiler dependency).
74
+ */
75
+ function maskNonCode(source) {
76
+ const n = source.length;
77
+ const out = source.split('');
78
+ const blank = (from, to) => {
79
+ for (let k = from; k < to; k++) {
80
+ const c = source[k];
81
+ if (c !== '\n' && c !== '\r')
82
+ out[k] = ' ';
83
+ }
84
+ };
85
+ const lineEnd = (from) => {
86
+ const at = source.indexOf('\n', from);
87
+ return at < 0 ? n : at;
88
+ };
89
+ const blockEnd = (from) => {
90
+ const at = source.indexOf('*/', from + 2);
91
+ return at < 0 ? n : at + 2;
92
+ };
93
+ /** Index after the closing quote (closed) or at the newline/EOF (unterminated). */
94
+ const stringEnd = (from) => {
95
+ const quote = source[from];
96
+ let j = from + 1;
97
+ while (j < n) {
98
+ const c = source[j];
99
+ if (c === '\\') {
100
+ j += 2;
101
+ continue;
102
+ }
103
+ if (c === quote)
104
+ return { end: j + 1, closed: true };
105
+ if (c === '\n')
106
+ return { end: j, closed: false };
107
+ j++;
108
+ }
109
+ return { end: n, closed: false };
110
+ };
111
+ const templateEnd = (from) => {
112
+ let j = from + 1;
113
+ while (j < n) {
114
+ const c = source[j];
115
+ if (c === '\\') {
116
+ j += 2;
117
+ continue;
118
+ }
119
+ if (c === '`')
120
+ return { end: j + 1, closed: true };
121
+ if (c === '$' && source[j + 1] === '{') {
122
+ j = expressionEnd(j + 2);
123
+ continue;
124
+ }
125
+ j++;
126
+ }
127
+ return { end: n, closed: false };
128
+ };
129
+ /** Skips a `${ ... }` substitution body (nested literals/comments aware). */
130
+ const expressionEnd = (from) => {
131
+ let depth = 1;
132
+ let j = from;
133
+ while (j < n) {
134
+ const c = source[j];
135
+ const next = source[j + 1];
136
+ if (c === '/' && next === '/') {
137
+ j = lineEnd(j);
138
+ continue;
139
+ }
140
+ if (c === '/' && next === '*') {
141
+ j = blockEnd(j);
142
+ continue;
143
+ }
144
+ if (c === '\'' || c === '"') {
145
+ j = stringEnd(j).end;
146
+ continue;
147
+ }
148
+ if (c === '`') {
149
+ j = templateEnd(j).end;
150
+ continue;
151
+ }
152
+ if (c === '{')
153
+ depth++;
154
+ else if (c === '}' && --depth === 0)
155
+ return j + 1;
156
+ j++;
157
+ }
158
+ return n;
159
+ };
160
+ /** Regex literal starting at `from`, or null when it is not a single-line regex. */
161
+ const regexEnd = (from) => {
162
+ let inClass = false;
163
+ let j = from + 1;
164
+ while (j < n) {
165
+ const c = source[j];
166
+ if (c === '\n' || c === '\r')
167
+ return null;
168
+ if (c === '\\') {
169
+ j += 2;
170
+ continue;
171
+ }
172
+ if (inClass) {
173
+ if (c === ']')
174
+ inClass = false;
175
+ }
176
+ else if (c === '[') {
177
+ inClass = true;
178
+ }
179
+ else if (c === '/') {
180
+ let k = j + 1;
181
+ while (k < n && /[A-Za-z]/.test(source[k]))
182
+ k++;
183
+ return { bodyEnd: j, end: k };
184
+ }
185
+ j++;
186
+ }
187
+ return null;
188
+ };
189
+ // Last significant token: a punctuator char, 'value' after a literal or
190
+ // identifier, or '' at start of input; lastWord holds the identifier text.
191
+ let last = '';
192
+ let lastWord = '';
193
+ let i = 0;
194
+ while (i < n) {
195
+ const c = source[i];
196
+ const next = source[i + 1];
197
+ if (c === '/' && next === '/') {
198
+ const end = lineEnd(i);
199
+ blank(i, end);
200
+ i = end;
201
+ continue;
202
+ }
203
+ if (c === '/' && next === '*') {
204
+ const end = blockEnd(i);
205
+ blank(i, end);
206
+ i = end;
207
+ continue;
208
+ }
209
+ if (c === '\'' || c === '"' || c === '`') {
210
+ const { end, closed } = c === '`' ? templateEnd(i) : stringEnd(i);
211
+ blank(i + 1, closed ? end - 1 : end);
212
+ i = end;
213
+ last = 'value';
214
+ lastWord = '';
215
+ continue;
216
+ }
217
+ if (c === '/') {
218
+ const regexAllowed = last === '' || REGEX_AFTER_PUNCT.has(last) || (last === 'value' && REGEX_AFTER_KEYWORD.has(lastWord));
219
+ const re = regexAllowed ? regexEnd(i) : null;
220
+ if (re) {
221
+ blank(i + 1, re.bodyEnd);
222
+ i = re.end;
223
+ last = 'value';
224
+ lastWord = '';
225
+ continue;
226
+ }
227
+ }
228
+ if (/\s/.test(c)) {
229
+ i++;
230
+ continue;
231
+ }
232
+ if (IDENT_CHAR.test(c)) {
233
+ let j = i + 1;
234
+ while (j < n && IDENT_CHAR.test(source[j]))
235
+ j++;
236
+ lastWord = source.slice(i, j);
237
+ last = 'value';
238
+ i = j;
239
+ continue;
240
+ }
241
+ last = c;
242
+ lastWord = '';
243
+ i++;
244
+ }
245
+ return out.join('');
246
+ }
58
247
  /**
59
248
  * Regex-based discovery: each @Query method is attributed to the nearest
60
249
  * preceding `class` declaration in the same file. Inline queries are detected
61
250
  * by a `sql:` property in the decorator arguments (see docs/codegen.md for the
62
- * documented limitations of this heuristic).
251
+ * documented limitations of this heuristic). Comments and string/template/
252
+ * regex literal contents are masked first (positions preserved), so prose
253
+ * cannot declare classes or @Query methods.
63
254
  */
64
255
  function scanSourceForQueryMethods(source, sourcePath) {
256
+ const code = maskNonCode(source);
65
257
  const classes = [];
66
- for (const m of source.matchAll(CLASS_RE)) {
258
+ for (const m of code.matchAll(CLASS_RE)) {
67
259
  classes.push({ name: m[1], index: m.index ?? 0 });
68
260
  }
69
261
  if (!classes.length)
70
262
  return [];
71
263
  const found = [];
72
- for (const m of source.matchAll(QUERY_RE)) {
264
+ for (const m of code.matchAll(QUERY_RE)) {
73
265
  const at = m.index ?? 0;
74
266
  let owner;
75
267
  for (const c of classes) {
@@ -1 +1 @@
1
- {"version":3,"file":"generateManifest.js","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":"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","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"]}
1
+ {"version":3,"file":"generateManifest.js","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":";;;;;AA4QA,8DA0BC;AA6BD,kDAgBC;AAcD,kDA6DC;AA9ZD,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,iFAAiF;AACjF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AACpE,8EAA8E;AAC9E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM;IACrE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;CAChD,CAAC,CAAC;AACH,MAAM,UAAU,GAAG,eAAe,CAAC;AAEnC;;;;;;;;GAQG;AACH,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE;QACzC,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;QAC/B,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACtC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;QAChC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;QAC1C,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC,CAAC;IACF,mFAAmF;IACnF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAoC,EAAE;QACnE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACrC,IAAI,CAAC,KAAK,KAAK;gBAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACrD,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YACjD,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,IAAY,EAAoC,EAAE;QACrE,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACrC,IAAI,CAAC,KAAK,GAAG;gBAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACnD,IAAI,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAAC,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC/E,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC;IACF,6EAA6E;IAC7E,MAAM,aAAa,GAAG,CAAC,IAAY,EAAU,EAAE;QAC7C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,IAAI,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC5D,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YAC7D,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBAAC,SAAS;YAAC,CAAC;YAChE,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBAAC,SAAS;YAAC,CAAC;YACpD,IAAI,CAAC,KAAK,GAAG;gBAAE,KAAK,EAAE,CAAC;iBAClB,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,KAAK,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IACF,oFAAoF;IACpF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAA2C,EAAE;QACzE,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC1C,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACrC,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,KAAK,GAAG;oBAAE,OAAO,GAAG,KAAK,CAAC;YACjC,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACrB,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;oBAAE,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;YAChC,CAAC;YACD,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,wEAAwE;IACxE,2EAA2E;IAC3E,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACvB,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACd,CAAC,GAAG,GAAG,CAAC;YACR,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACd,CAAC,GAAG,GAAG,CAAC;YACR,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAClE,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACrC,CAAC,GAAG,GAAG,CAAC;YACR,IAAI,GAAG,OAAO,CAAC;YACf,QAAQ,GAAG,EAAE,CAAC;YACd,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,MAAM,YAAY,GAChB,IAAI,KAAK,EAAE,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxG,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7C,IAAI,EAAE,EAAE,CAAC;gBACP,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;gBACzB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;gBACX,IAAI,GAAG,OAAO,CAAC;gBACf,QAAQ,GAAG,EAAE,CAAC;gBACd,SAAS;YACX,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;gBAAE,CAAC,EAAE,CAAC;YACjD,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9B,IAAI,GAAG,OAAO,CAAC;YACf,CAAC,GAAG,CAAC,CAAC;YACN,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,CAAC;QACT,QAAQ,GAAG,EAAE,CAAC;QACd,CAAC,EAAE,CAAC;IACN,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,yBAAyB,CAAC,MAAc,EAAE,UAAkB;IAC1E,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,OAAO,GAAsC,EAAE,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,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,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,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/** Punctuators after which a `/` starts a regex literal rather than division. */\nconst REGEX_AFTER_PUNCT = new Set('(,=:[!&|?{};+-*%<>~^'.split(''));\n/** Keywords after which a `/` starts a regex literal rather than division. */\nconst REGEX_AFTER_KEYWORD = new Set([\n 'return', 'typeof', 'instanceof', 'in', 'of', 'new', 'delete', 'void',\n 'throw', 'case', 'do', 'else', 'yield', 'await',\n]);\nconst IDENT_CHAR = /[A-Za-z0-9_$]/;\n\n/**\n * Returns `source` with comments and the contents of string, template and\n * regex literals replaced by spaces (newlines kept), so every index still\n * points at the same position in the original text. Literal delimiters are\n * kept, so decorator arguments such as `{ sql: '...' }` keep their shape and\n * the `sql:` key stays detectable, while prose like \"the same class with\" or\n * \"@Query() foo(\" inside a comment or string can no longer match CLASS_RE or\n * QUERY_RE. Lexical heuristic only (no TS compiler dependency).\n */\nfunction maskNonCode(source: string): string {\n const n = source.length;\n const out = source.split('');\n const blank = (from: number, to: number) => {\n for (let k = from; k < to; k++) {\n const c = source[k];\n if (c !== '\\n' && c !== '\\r') out[k] = ' ';\n }\n };\n const lineEnd = (from: number) => {\n const at = source.indexOf('\\n', from);\n return at < 0 ? n : at;\n };\n const blockEnd = (from: number) => {\n const at = source.indexOf('*/', from + 2);\n return at < 0 ? n : at + 2;\n };\n /** Index after the closing quote (closed) or at the newline/EOF (unterminated). */\n const stringEnd = (from: number): { end: number; closed: boolean } => {\n const quote = source[from];\n let j = from + 1;\n while (j < n) {\n const c = source[j];\n if (c === '\\\\') { j += 2; continue; }\n if (c === quote) return { end: j + 1, closed: true };\n if (c === '\\n') return { end: j, closed: false };\n j++;\n }\n return { end: n, closed: false };\n };\n const templateEnd = (from: number): { end: number; closed: boolean } => {\n let j = from + 1;\n while (j < n) {\n const c = source[j];\n if (c === '\\\\') { j += 2; continue; }\n if (c === '`') return { end: j + 1, closed: true };\n if (c === '$' && source[j + 1] === '{') { j = expressionEnd(j + 2); continue; }\n j++;\n }\n return { end: n, closed: false };\n };\n /** Skips a `${ ... }` substitution body (nested literals/comments aware). */\n const expressionEnd = (from: number): number => {\n let depth = 1;\n let j = from;\n while (j < n) {\n const c = source[j];\n const next = source[j + 1];\n if (c === '/' && next === '/') { j = lineEnd(j); continue; }\n if (c === '/' && next === '*') { j = blockEnd(j); continue; }\n if (c === '\\'' || c === '\"') { j = stringEnd(j).end; continue; }\n if (c === '`') { j = templateEnd(j).end; continue; }\n if (c === '{') depth++;\n else if (c === '}' && --depth === 0) return j + 1;\n j++;\n }\n return n;\n };\n /** Regex literal starting at `from`, or null when it is not a single-line regex. */\n const regexEnd = (from: number): { bodyEnd: number; end: number } | null => {\n let inClass = false;\n let j = from + 1;\n while (j < n) {\n const c = source[j];\n if (c === '\\n' || c === '\\r') return null;\n if (c === '\\\\') { j += 2; continue; }\n if (inClass) {\n if (c === ']') inClass = false;\n } else if (c === '[') {\n inClass = true;\n } else if (c === '/') {\n let k = j + 1;\n while (k < n && /[A-Za-z]/.test(source[k]!)) k++;\n return { bodyEnd: j, end: k };\n }\n j++;\n }\n return null;\n };\n\n // Last significant token: a punctuator char, 'value' after a literal or\n // identifier, or '' at start of input; lastWord holds the identifier text.\n let last = '';\n let lastWord = '';\n let i = 0;\n while (i < n) {\n const c = source[i]!;\n const next = source[i + 1];\n if (c === '/' && next === '/') {\n const end = lineEnd(i);\n blank(i, end);\n i = end;\n continue;\n }\n if (c === '/' && next === '*') {\n const end = blockEnd(i);\n blank(i, end);\n i = end;\n continue;\n }\n if (c === '\\'' || c === '\"' || c === '`') {\n const { end, closed } = c === '`' ? templateEnd(i) : stringEnd(i);\n blank(i + 1, closed ? end - 1 : end);\n i = end;\n last = 'value';\n lastWord = '';\n continue;\n }\n if (c === '/') {\n const regexAllowed =\n last === '' || REGEX_AFTER_PUNCT.has(last) || (last === 'value' && REGEX_AFTER_KEYWORD.has(lastWord));\n const re = regexAllowed ? regexEnd(i) : null;\n if (re) {\n blank(i + 1, re.bodyEnd);\n i = re.end;\n last = 'value';\n lastWord = '';\n continue;\n }\n }\n if (/\\s/.test(c)) {\n i++;\n continue;\n }\n if (IDENT_CHAR.test(c)) {\n let j = i + 1;\n while (j < n && IDENT_CHAR.test(source[j]!)) j++;\n lastWord = source.slice(i, j);\n last = 'value';\n i = j;\n continue;\n }\n last = c;\n lastWord = '';\n i++;\n }\n return out.join('');\n}\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). Comments and string/template/\n * regex literal contents are masked first (positions preserved), so prose\n * cannot declare classes or @Query methods.\n */\nexport function scanSourceForQueryMethods(source: string, sourcePath: string): DiscoveredMethod[] {\n const code = maskNonCode(source);\n const classes: { name: string; index: number }[] = [];\n for (const m of code.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 code.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"]}
@@ -19,10 +19,19 @@ export declare class ValidationError extends SqlStackError {
19
19
  constructor(details: string);
20
20
  details: string;
21
21
  }
22
+ /**
23
+ * A statement failed: the driver rejected it, or (for the `run(...)` forms
24
+ * that take arguments) the SQL could not be compiled, bound, or routed to a
25
+ * database. The original error is kept in `.cause`; when the cause carries a
26
+ * string driver code (`SQLITE_CONSTRAINT_UNIQUE`, `23505`, `ER_DUP_ENTRY`)
27
+ * it is copied to `.code` so existing `err.code` checks keep working.
28
+ */
22
29
  export declare class DatabaseError extends SqlStackError {
23
30
  constructor(message: string, sql: string, cause?: Error);
24
31
  sql: string;
25
32
  cause?: Error;
33
+ /** Driver error code copied from `cause` when it is a string. */
34
+ code?: string;
26
35
  }
27
36
  export declare class RollbackTransactionError extends SqlStackError {
28
37
  constructor(message?: string, cause?: unknown);
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,CAAC,EAAE,MAAM;CAI7B;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,WAAY,SAAQ,aAAa;;CAK7C;AAED,qBAAa,cAAe,SAAQ,aAAa;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAKD,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAUzC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;IAK3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,aAAc,SAAQ,aAAa;gBAClC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;IAMvD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAID,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,OAAO,SAA4B,EAAE,KAAK,CAAC,EAAE,OAAO;IAKhE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,CAAC,EAAE,MAAM;CAI7B;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,WAAY,SAAQ,aAAa;;CAK7C;AAED,qBAAa,cAAe,SAAQ,aAAa;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAKD,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAUzC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;IAK3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,aAAa;gBAClC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;IAQvD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,OAAO,SAA4B,EAAE,KAAK,CAAC,EAAE,OAAO;IAKhE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB"}
@@ -51,11 +51,21 @@ class ValidationError extends SqlStackError {
51
51
  }
52
52
  }
53
53
  exports.ValidationError = ValidationError;
54
+ /**
55
+ * A statement failed: the driver rejected it, or (for the `run(...)` forms
56
+ * that take arguments) the SQL could not be compiled, bound, or routed to a
57
+ * database. The original error is kept in `.cause`; when the cause carries a
58
+ * string driver code (`SQLITE_CONSTRAINT_UNIQUE`, `23505`, `ER_DUP_ENTRY`)
59
+ * it is copied to `.code` so existing `err.code` checks keep working.
60
+ */
54
61
  class DatabaseError extends SqlStackError {
55
62
  constructor(message, sql, cause) {
56
63
  super(`${message}\nSQL: ${sql}`);
57
64
  this.sql = sql;
58
65
  this.cause = cause;
66
+ const code = cause?.code;
67
+ if (typeof code === 'string')
68
+ this.code = code;
59
69
  this.name = 'DatabaseError';
60
70
  }
61
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AALD,sCAKC;AAED,MAAa,kBAAmB,SAAQ,aAAa;IACnD,YAAY,WAAmB;QAC7B,KAAK,CAAC,iCAAiC,WAAW,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,WAAY,SAAQ,aAAa;IAC5C;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AALD,kCAKC;AAED,MAAa,cAAe,SAAQ,aAAa;IAC/C,YAAY,WAAmB;QAC7B,KAAK,CAAC,yBAAyB,WAAW,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC;AAED,yEAAyE;AACzE,wEAAwE;AACxE,2DAA2D;AAC3D,MAAa,iBAAkB,SAAQ,aAAa;IAClD,YAAY,MAAc,EAAE,KAAa;QACvC,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,CACH,GAAG,SAAS,OAAO,MAAM,oEAAoE;YAC3F,2EAA2E,CAC9E,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CAGF;AAbD,8CAaC;AAED,MAAa,eAAgB,SAAQ,aAAa;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CAEF;AAPD,0CAOC;AAED,MAAa,aAAc,SAAQ,aAAa;IAC9C,YAAY,OAAe,EAAE,GAAW,EAAE,KAAa;QACrD,KAAK,CAAC,GAAG,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CAGF;AATD,sCASC;AAED,8DAA8D;AAC9D,kEAAkE;AAClE,MAAa,wBAAyB,SAAQ,aAAa;IACzD,YAAY,OAAO,GAAG,yBAAyB,EAAE,KAAe;QAC9D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CAEF;AAPD,4DAOC","sourcesContent":["export class SqlStackError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'SqlStackError';\n }\n}\n\nexport class ExactlyOneRowError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected exactly one row, got ${actualCount}`);\n this.name = 'ExactlyOneRowError';\n }\n}\n\nexport class NoRowsError extends SqlStackError {\n constructor() {\n super('Expected at least one row, got 0');\n this.name = 'NoRowsError';\n }\n}\n\nexport class RowsExistError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected no rows, got ${actualCount}`);\n this.name = 'RowsExistError';\n }\n}\n\n// A result-shape decorator (@Single/@Only/@Exist/@None) was applied to a\n// method whose statement produced no result set (a plain write). Shapes\n// require rows; use `... RETURNING` or drop the decorator.\nexport class ExpectedRowsError extends SqlStackError {\n constructor(method: string, shape: string) {\n const decorator = '@' + shape.charAt(0).toUpperCase() + shape.slice(1);\n super(\n `${decorator} on ${method} requires a result set, but the statement produced a write result ` +\n `({ rowsAffected }). Add a RETURNING clause or remove the shape decorator.`\n );\n this.method = method;\n this.shape = shape;\n this.name = 'ExpectedRowsError';\n }\n method: string;\n shape: string;\n}\n\nexport class ValidationError extends SqlStackError {\n constructor(details: string) {\n super(`Validation failed: ${details}`);\n this.details = details;\n this.name = 'ValidationError';\n }\n details: string;\n}\n\nexport class DatabaseError extends SqlStackError {\n constructor(message: string, sql: string, cause?: Error) {\n super(`${message}\\nSQL: ${sql}`);\n this.sql = sql;\n this.cause = cause;\n this.name = 'DatabaseError';\n }\n sql: string;\n cause?: Error;\n}\n\n// Signals that the current transaction should be rolled back.\n// If `cause` is provided, wrappers may rethrow it after rollback.\nexport class RollbackTransactionError extends SqlStackError {\n constructor(message = 'Transaction rolled back', cause?: unknown) {\n super(message);\n this.cause = cause;\n this.name = 'RollbackTransactionError';\n }\n cause?: unknown;\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AALD,sCAKC;AAED,MAAa,kBAAmB,SAAQ,aAAa;IACnD,YAAY,WAAmB;QAC7B,KAAK,CAAC,iCAAiC,WAAW,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,WAAY,SAAQ,aAAa;IAC5C;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AALD,kCAKC;AAED,MAAa,cAAe,SAAQ,aAAa;IAC/C,YAAY,WAAmB;QAC7B,KAAK,CAAC,yBAAyB,WAAW,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC;AAED,yEAAyE;AACzE,wEAAwE;AACxE,2DAA2D;AAC3D,MAAa,iBAAkB,SAAQ,aAAa;IAClD,YAAY,MAAc,EAAE,KAAa;QACvC,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,CACH,GAAG,SAAS,OAAO,MAAM,oEAAoE;YAC3F,2EAA2E,CAC9E,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CAGF;AAbD,8CAaC;AAED,MAAa,eAAgB,SAAQ,aAAa;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CAEF;AAPD,0CAOC;AAED;;;;;;GAMG;AACH,MAAa,aAAc,SAAQ,aAAa;IAC9C,YAAY,OAAe,EAAE,GAAW,EAAE,KAAa;QACrD,KAAK,CAAC,GAAG,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,MAAM,IAAI,GAAI,KAAwC,EAAE,IAAI,CAAC;QAC7D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CAKF;AAbD,sCAaC;AAED,8DAA8D;AAC9D,kEAAkE;AAClE,MAAa,wBAAyB,SAAQ,aAAa;IACzD,YAAY,OAAO,GAAG,yBAAyB,EAAE,KAAe;QAC9D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CAEF;AAPD,4DAOC","sourcesContent":["export class SqlStackError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'SqlStackError';\n }\n}\n\nexport class ExactlyOneRowError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected exactly one row, got ${actualCount}`);\n this.name = 'ExactlyOneRowError';\n }\n}\n\nexport class NoRowsError extends SqlStackError {\n constructor() {\n super('Expected at least one row, got 0');\n this.name = 'NoRowsError';\n }\n}\n\nexport class RowsExistError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected no rows, got ${actualCount}`);\n this.name = 'RowsExistError';\n }\n}\n\n// A result-shape decorator (@Single/@Only/@Exist/@None) was applied to a\n// method whose statement produced no result set (a plain write). Shapes\n// require rows; use `... RETURNING` or drop the decorator.\nexport class ExpectedRowsError extends SqlStackError {\n constructor(method: string, shape: string) {\n const decorator = '@' + shape.charAt(0).toUpperCase() + shape.slice(1);\n super(\n `${decorator} on ${method} requires a result set, but the statement produced a write result ` +\n `({ rowsAffected }). Add a RETURNING clause or remove the shape decorator.`\n );\n this.method = method;\n this.shape = shape;\n this.name = 'ExpectedRowsError';\n }\n method: string;\n shape: string;\n}\n\nexport class ValidationError extends SqlStackError {\n constructor(details: string) {\n super(`Validation failed: ${details}`);\n this.details = details;\n this.name = 'ValidationError';\n }\n details: string;\n}\n\n/**\n * A statement failed: the driver rejected it, or (for the `run(...)` forms\n * that take arguments) the SQL could not be compiled, bound, or routed to a\n * database. The original error is kept in `.cause`; when the cause carries a\n * string driver code (`SQLITE_CONSTRAINT_UNIQUE`, `23505`, `ER_DUP_ENTRY`)\n * it is copied to `.code` so existing `err.code` checks keep working.\n */\nexport class DatabaseError extends SqlStackError {\n constructor(message: string, sql: string, cause?: Error) {\n super(`${message}\\nSQL: ${sql}`);\n this.sql = sql;\n this.cause = cause;\n const code = (cause as { code?: unknown } | undefined)?.code;\n if (typeof code === 'string') this.code = code;\n this.name = 'DatabaseError';\n }\n sql: string;\n cause?: Error;\n /** Driver error code copied from `cause` when it is a string. */\n code?: string;\n}\n\n// Signals that the current transaction should be rolled back.\n// If `cause` is provided, wrappers may rethrow it after rollback.\nexport class RollbackTransactionError extends SqlStackError {\n constructor(message = 'Transaction rolled back', cause?: unknown) {\n super(message);\n this.cause = cause;\n this.name = 'RollbackTransactionError';\n }\n cause?: unknown;\n}\n"]}
@@ -32,4 +32,11 @@ export declare function findSqlstackFromStack(stackString: string): string | und
32
32
  * @internal Exported for testing
33
33
  */
34
34
  export declare function computePackageRoot(dirnameValue: string | undefined, filenameValue: string | undefined, getStack: () => string): string | undefined;
35
+ /**
36
+ * sqlstack's code root as the runtime names this module in stack traces:
37
+ * the parent of this file's directory (`src/`, `dist/cjs/`, `dist/esm/`, or
38
+ * a bundler's re-rooted copy). Needs no filesystem.
39
+ * @internal Exported for testing
40
+ */
41
+ export declare function computeCodeRoot(getStack: () => string): string | undefined;
35
42
  //# sourceMappingURL=fileResolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileResolution.d.ts","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAe3C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAgCxH;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAO7F;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAsCtD;AA8BD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CASxD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAwB7E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,QAAQ,EAAE,MAAM,MAAM,GACrB,MAAM,GAAG,SAAS,CA0BpB"}
1
+ {"version":3,"file":"fileResolution.d.ts","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAe3C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAgCxH;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAO7F;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAsCtD;AAmCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqBpE;AAUD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CASxD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAwB7E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,QAAQ,EAAE,MAAM,MAAM,GACrB,MAAM,GAAG,SAAS,CA0BpB;AAQD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1E"}
@@ -10,6 +10,7 @@ exports.findPackageRoot = findPackageRoot;
10
10
  exports.isSqlstackPath = isSqlstackPath;
11
11
  exports.findSqlstackFromStack = findSqlstackFromStack;
12
12
  exports.computePackageRoot = computePackageRoot;
13
+ exports.computeCodeRoot = computeCodeRoot;
13
14
  const fs_1 = __importDefault(require("fs"));
14
15
  const path_1 = __importDefault(require("path"));
15
16
  const url_1 = require("url");
@@ -68,6 +69,7 @@ function guessDecoratorDir() {
68
69
  const err = new Error();
69
70
  const stack = (err.stack || '').split('\n').slice(2);
70
71
  const packageRoot = PACKAGE_ROOT_NORMALIZED;
72
+ const codeRoot = SQLSTACK_CODE_ROOT;
71
73
  // DEBUG: Uncomment to trace issues
72
74
  // console.log('[guessDecoratorDir] packageRoot:', packageRoot);
73
75
  // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));
@@ -79,26 +81,33 @@ function guessDecoratorDir() {
79
81
  const resolved = toAbsolutePath(file);
80
82
  if (!resolved)
81
83
  continue;
82
- // Skip frames from node_modules (including sqlstack itself when used as dependency)
83
- if (resolved.includes('node_modules'))
84
- continue;
85
84
  const normalized = safeNormalize(resolved);
86
85
  if (!normalized)
87
86
  continue;
88
- // Skip frames from sqlstack's own package (when running from source)
89
- // Also skip if the path contains /sqlstack/ anywhere (linked package scenario)
90
- if (packageRoot && normalized.startsWith(packageRoot)) {
87
+ // Skip every node_modules frame (sqlstack as a dependency, decorator
88
+ // helpers such as reflect-metadata, test runners) and sqlstack's own
89
+ // src/ and dist/ under its package root (running from source or a linked
90
+ // checkout). A consumer module under a node_modules-free path that merely
91
+ // contains the word "sqlstack" — this package's own tests/fixtures — is
92
+ // a consumer and is NOT skipped.
93
+ if (normalized.includes(path_1.default.sep + 'node_modules' + path_1.default.sep))
91
94
  continue;
92
- }
93
- // Additional check: skip if this is a sqlstack path (handles linked packages with relative paths)
94
- if (isSqlstackPath(resolved)) {
95
+ if (packageRoot && isSqlstackCodePath(normalized, packageRoot))
95
96
  continue;
96
- }
97
- // Return the first valid frame - this is where @Query is defined
97
+ // Filesystem-free: sqlstack's own code root (the directory holding
98
+ // core/, decorators/, …) as the STACK names it — the only reliable
99
+ // reference on hosts without fs (workerd) or with re-rooted trees.
100
+ if (codeRoot && normalized.startsWith(codeRoot))
101
+ continue;
102
+ // Return the first consumer frame - this is where @Query is applied
98
103
  return path_1.default.dirname(resolved);
99
104
  }
100
105
  return undefined;
101
106
  }
107
+ function isSqlstackCodePath(normalized, packageRoot) {
108
+ const root = process.platform === 'win32' ? packageRoot.toLowerCase() : packageRoot;
109
+ return normalized.startsWith(root + 'src' + path_1.default.sep) || normalized.startsWith(root + 'dist' + path_1.default.sep);
110
+ }
102
111
  function toAbsolutePath(file) {
103
112
  try {
104
113
  if (file.startsWith('file://')) {
@@ -131,20 +140,36 @@ function safeNormalize(p) {
131
140
  * @internal Exported for testing
132
141
  */
133
142
  function findPackageRoot(startDir) {
143
+ // The ESM build ships a nested dist/esm/package.json ({ type: module });
144
+ // keep walking past any package.json that is not sqlstack's own so the
145
+ // root is the real package directory (whose src/ and dist/ are skipped by
146
+ // guessDecoratorDir). The first package.json found is the fallback.
134
147
  let current = startDir;
135
- for (let i = 0; i < 6; i++) {
148
+ let fallback;
149
+ for (let i = 0; i < 8; i++) {
136
150
  const candidate = path_1.default.join(current, 'package.json');
137
151
  if (fs_1.default.existsSync(candidate)) {
138
152
  const root = path_1.default.dirname(candidate);
139
153
  const normalizedRoot = safeNormalize(root);
140
- return normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);
154
+ const asRoot = normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);
155
+ if (packageNameOf(candidate) === 'sqlstack')
156
+ return asRoot;
157
+ fallback ?? (fallback = asRoot);
141
158
  }
142
159
  const parent = path_1.default.dirname(current);
143
160
  if (parent === current)
144
161
  break;
145
162
  current = parent;
146
163
  }
147
- return undefined;
164
+ return fallback;
165
+ }
166
+ function packageNameOf(packageJsonPath) {
167
+ try {
168
+ return JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'))?.name;
169
+ }
170
+ catch {
171
+ return undefined;
172
+ }
148
173
  }
149
174
  /**
150
175
  * Detects if a path belongs to sqlstack package.
@@ -230,4 +255,18 @@ function computePackageRoot(dirnameValue, filenameValue, getStack) {
230
255
  return undefined;
231
256
  }
232
257
  const PACKAGE_ROOT_NORMALIZED = computePackageRoot(typeof __dirname === 'string' ? __dirname : undefined, typeof __filename === 'string' ? __filename : undefined, () => new Error().stack || '');
258
+ /**
259
+ * sqlstack's code root as the runtime names this module in stack traces:
260
+ * the parent of this file's directory (`src/`, `dist/cjs/`, `dist/esm/`, or
261
+ * a bundler's re-rooted copy). Needs no filesystem.
262
+ * @internal Exported for testing
263
+ */
264
+ function computeCodeRoot(getStack) {
265
+ const coreDir = findSqlstackFromStack(getStack());
266
+ if (!coreDir)
267
+ return undefined;
268
+ const root = safeNormalize(path_1.default.dirname(coreDir));
269
+ return root ? ensureTrailingSep(root) : undefined;
270
+ }
271
+ const SQLSTACK_CODE_ROOT = computeCodeRoot(() => new Error().stack || '');
233
272
  //# sourceMappingURL=fileResolution.js.map