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
@@ -56,6 +56,7 @@ export function guessDecoratorDir() {
56
56
  const err = new Error();
57
57
  const stack = (err.stack || '').split('\n').slice(2);
58
58
  const packageRoot = PACKAGE_ROOT_NORMALIZED;
59
+ const codeRoot = SQLSTACK_CODE_ROOT;
59
60
  // DEBUG: Uncomment to trace issues
60
61
  // console.log('[guessDecoratorDir] packageRoot:', packageRoot);
61
62
  // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));
@@ -67,26 +68,33 @@ export function guessDecoratorDir() {
67
68
  const resolved = toAbsolutePath(file);
68
69
  if (!resolved)
69
70
  continue;
70
- // Skip frames from node_modules (including sqlstack itself when used as dependency)
71
- if (resolved.includes('node_modules'))
72
- continue;
73
71
  const normalized = safeNormalize(resolved);
74
72
  if (!normalized)
75
73
  continue;
76
- // Skip frames from sqlstack's own package (when running from source)
77
- // Also skip if the path contains /sqlstack/ anywhere (linked package scenario)
78
- if (packageRoot && normalized.startsWith(packageRoot)) {
74
+ // Skip every node_modules frame (sqlstack as a dependency, decorator
75
+ // helpers such as reflect-metadata, test runners) and sqlstack's own
76
+ // src/ and dist/ under its package root (running from source or a linked
77
+ // checkout). A consumer module under a node_modules-free path that merely
78
+ // contains the word "sqlstack" — this package's own tests/fixtures — is
79
+ // a consumer and is NOT skipped.
80
+ if (normalized.includes(path.sep + 'node_modules' + path.sep))
79
81
  continue;
80
- }
81
- // Additional check: skip if this is a sqlstack path (handles linked packages with relative paths)
82
- if (isSqlstackPath(resolved)) {
82
+ if (packageRoot && isSqlstackCodePath(normalized, packageRoot))
83
83
  continue;
84
- }
85
- // Return the first valid frame - this is where @Query is defined
84
+ // Filesystem-free: sqlstack's own code root (the directory holding
85
+ // core/, decorators/, …) as the STACK names it — the only reliable
86
+ // reference on hosts without fs (workerd) or with re-rooted trees.
87
+ if (codeRoot && normalized.startsWith(codeRoot))
88
+ continue;
89
+ // Return the first consumer frame - this is where @Query is applied
86
90
  return path.dirname(resolved);
87
91
  }
88
92
  return undefined;
89
93
  }
94
+ function isSqlstackCodePath(normalized, packageRoot) {
95
+ const root = process.platform === 'win32' ? packageRoot.toLowerCase() : packageRoot;
96
+ return normalized.startsWith(root + 'src' + path.sep) || normalized.startsWith(root + 'dist' + path.sep);
97
+ }
90
98
  function toAbsolutePath(file) {
91
99
  try {
92
100
  if (file.startsWith('file://')) {
@@ -119,20 +127,36 @@ function safeNormalize(p) {
119
127
  * @internal Exported for testing
120
128
  */
121
129
  export function findPackageRoot(startDir) {
130
+ // The ESM build ships a nested dist/esm/package.json ({ type: module });
131
+ // keep walking past any package.json that is not sqlstack's own so the
132
+ // root is the real package directory (whose src/ and dist/ are skipped by
133
+ // guessDecoratorDir). The first package.json found is the fallback.
122
134
  let current = startDir;
123
- for (let i = 0; i < 6; i++) {
135
+ let fallback;
136
+ for (let i = 0; i < 8; i++) {
124
137
  const candidate = path.join(current, 'package.json');
125
138
  if (fs.existsSync(candidate)) {
126
139
  const root = path.dirname(candidate);
127
140
  const normalizedRoot = safeNormalize(root);
128
- return normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);
141
+ const asRoot = normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);
142
+ if (packageNameOf(candidate) === 'sqlstack')
143
+ return asRoot;
144
+ fallback ?? (fallback = asRoot);
129
145
  }
130
146
  const parent = path.dirname(current);
131
147
  if (parent === current)
132
148
  break;
133
149
  current = parent;
134
150
  }
135
- return undefined;
151
+ return fallback;
152
+ }
153
+ function packageNameOf(packageJsonPath) {
154
+ try {
155
+ return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))?.name;
156
+ }
157
+ catch {
158
+ return undefined;
159
+ }
136
160
  }
137
161
  /**
138
162
  * Detects if a path belongs to sqlstack package.
@@ -218,4 +242,18 @@ export function computePackageRoot(dirnameValue, filenameValue, getStack) {
218
242
  return undefined;
219
243
  }
220
244
  const PACKAGE_ROOT_NORMALIZED = computePackageRoot(typeof __dirname === 'string' ? __dirname : undefined, typeof __filename === 'string' ? __filename : undefined, () => new Error().stack || '');
245
+ /**
246
+ * sqlstack's code root as the runtime names this module in stack traces:
247
+ * the parent of this file's directory (`src/`, `dist/cjs/`, `dist/esm/`, or
248
+ * a bundler's re-rooted copy). Needs no filesystem.
249
+ * @internal Exported for testing
250
+ */
251
+ export function computeCodeRoot(getStack) {
252
+ const coreDir = findSqlstackFromStack(getStack());
253
+ if (!coreDir)
254
+ return undefined;
255
+ const root = safeNormalize(path.dirname(coreDir));
256
+ return root ? ensureTrailingSep(root) : undefined;
257
+ }
258
+ const SQLSTACK_CODE_ROOT = computeCodeRoot(() => new Error().stack || '');
221
259
  //# sourceMappingURL=fileResolution.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileResolution.js","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Dialect } from '../registry';\n\nconst DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\nconst contentCache = new Map<string, string>();\nconst pathCache = new Map<string, string>();\n\nfunction key(root: string, method: string, dialect: Dialect): string {\n return `${root}::${method}::${dialect}`;\n}\n\nexport function resolveSqlFromFs(rootDir: string, methodName: string, dialect: Dialect): { sql: string; tried: string[] } {\n const k = key(rootDir, methodName, dialect);\n const tried: string[] = [];\n const ext = DIALECT_EXT[dialect];\n const dialectPath = path.join(rootDir, `${methodName}.${ext}.sql`);\n const genericPath = path.join(rootDir, `${methodName}.sql`);\n\n // Cached path\n let chosen = pathCache.get(k);\n if (!chosen) {\n if (fs.existsSync(dialectPath)) {\n chosen = dialectPath;\n } else if (fs.existsSync(genericPath)) {\n chosen = genericPath;\n }\n if (chosen) pathCache.set(k, chosen);\n }\n\n if (!chosen) {\n tried.push(dialectPath, genericPath);\n throw new Error(\n `sqlstack: SQL file not found for ${methodName}\\ntried: ${tried.join(\"\\n\")}`\n );\n }\n\n // Cached content\n let sql = contentCache.get(chosen);\n if (!sql) {\n sql = fs.readFileSync(chosen, 'utf8');\n contentCache.set(chosen, sql);\n }\n return { sql, tried: [chosen] };\n}\n\nexport function coerceRootPath(input?: string): { rootDir?: string; from?: 'file' | 'folder' } {\n if (!input) return {};\n const stat = fs.existsSync(input) ? fs.statSync(input) : undefined;\n if (stat?.isDirectory()) return { rootDir: input, from: 'folder' };\n if (stat?.isFile()) return { rootDir: path.dirname(input), from: 'file' };\n // If not found, treat as folder hint anyway\n return { rootDir: input, from: 'folder' };\n}\n\nexport function guessDecoratorDir(): string | undefined {\n const err = new Error();\n const stack = (err.stack || '').split('\\n').slice(2);\n const packageRoot = PACKAGE_ROOT_NORMALIZED;\n\n // DEBUG: Uncomment to trace issues\n // console.log('[guessDecoratorDir] packageRoot:', packageRoot);\n // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));\n\n for (const line of stack) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n\n const resolved = toAbsolutePath(file);\n if (!resolved) continue;\n\n // Skip frames from node_modules (including sqlstack itself when used as dependency)\n if (resolved.includes('node_modules')) continue;\n\n const normalized = safeNormalize(resolved);\n if (!normalized) continue;\n\n // Skip frames from sqlstack's own package (when running from source)\n // Also skip if the path contains /sqlstack/ anywhere (linked package scenario)\n if (packageRoot && normalized.startsWith(packageRoot)) {\n continue;\n }\n\n // Additional check: skip if this is a sqlstack path (handles linked packages with relative paths)\n if (isSqlstackPath(resolved)) {\n continue;\n }\n\n // Return the first valid frame - this is where @Query is defined\n return path.dirname(resolved);\n }\n return undefined;\n}\n\nfunction toAbsolutePath(file: string): string | undefined {\n try {\n if (file.startsWith('file://')) {\n return fileURLToPath(file);\n }\n // Skip Node.js internal modules and bundler internals\n if (file.startsWith('node:') || file.startsWith('webpack://')) {\n return undefined;\n }\n if (!path.isAbsolute(file)) {\n return path.resolve(file);\n }\n return file;\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSep(p: string): string {\n return p.endsWith(path.sep) ? p : p + path.sep;\n}\n\nfunction safeNormalize(p?: string): string | undefined {\n if (!p) return undefined;\n const normalized = path.normalize(p);\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized;\n}\n\n/**\n * Finds the package root from a starting directory by walking up to find package.json.\n * @internal Exported for testing\n */\nexport function findPackageRoot(startDir: string): string | undefined {\n let current = startDir;\n for (let i = 0; i < 6; i++) {\n const candidate = path.join(current, 'package.json');\n if (fs.existsSync(candidate)) {\n const root = path.dirname(candidate);\n const normalizedRoot = safeNormalize(root);\n return normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return undefined;\n}\n\n/**\n * Detects if a path belongs to sqlstack package.\n * Handles both source paths (contains 'sqlstack') and node_modules paths.\n * @internal Exported for testing\n */\nexport function isSqlstackPath(filePath: string): boolean {\n const normalized = filePath.toLowerCase();\n // Check for source development path (e.g., /path/to/sqlstack/src/...)\n if (normalized.includes(path.sep + 'sqlstack' + path.sep)) return true;\n // Check for node_modules installation\n if (normalized.includes('node_modules' + path.sep + 'sqlstack' + path.sep)) return true;\n // Check for scoped package (@noego/sqlstack or similar)\n if (normalized.includes('node_modules' + path.sep + '@') && normalized.includes('sqlstack' + path.sep)) return true;\n return false;\n}\n\n/**\n * Extracts sqlstack's location from a stack trace.\n * Handles absolute paths, file:// URLs, and relative paths (Vitest uses relative paths).\n * @internal Exported for testing\n */\nexport function findSqlstackFromStack(stackString: string): string | undefined {\n const lines = stackString.split('\\n');\n for (const line of lines) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n try {\n let resolved: string | undefined;\n if (file.startsWith('file://')) {\n resolved = fileURLToPath(file);\n } else if (path.isAbsolute(file)) {\n resolved = file;\n } else if (!file.startsWith('node:') && !file.startsWith('webpack://')) {\n // Relative path - resolve it (Vitest uses relative paths in stack traces)\n resolved = path.resolve(file);\n }\n if (resolved && resolved.includes('fileResolution')) {\n return path.dirname(resolved);\n }\n } catch {\n // Skip invalid paths\n }\n }\n return undefined;\n}\n\n/**\n * Computes the sqlstack package root directory.\n * Handles both CJS (__dirname) and ESM (stack trace) detection.\n * Validates that __dirname actually points to sqlstack (guards against Vitest injection).\n * @internal Exported for testing\n */\nexport function computePackageRoot(\n dirnameValue: string | undefined,\n filenameValue: string | undefined,\n getStack: () => string\n): string | undefined {\n const candidates: string[] = [];\n\n // CJS: use __dirname/__filename, but validate they actually point to sqlstack\n // (Vitest can inject __dirname incorrectly when transforming CJS modules)\n if (typeof dirnameValue === 'string' && isSqlstackPath(dirnameValue)) {\n candidates.push(dirnameValue);\n }\n if (typeof filenameValue === 'string' && isSqlstackPath(filenameValue)) {\n candidates.push(path.dirname(filenameValue));\n }\n\n // ESM fallback or when __dirname was incorrectly injected: parse stack trace\n if (candidates.length === 0) {\n const stackDir = findSqlstackFromStack(getStack());\n if (stackDir) {\n candidates.push(stackDir);\n }\n }\n\n // Find the package root from the first valid candidate\n for (const base of candidates) {\n const root = findPackageRoot(base);\n if (root) return root;\n }\n return undefined;\n}\n\nconst PACKAGE_ROOT_NORMALIZED = computePackageRoot(\n typeof __dirname === 'string' ? __dirname : undefined,\n typeof __filename === 'string' ? __filename : undefined,\n () => new Error().stack || ''\n);\n"]}
1
+ {"version":3,"file":"fileResolution.js","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Dialect } from '../registry';\n\nconst DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\nconst contentCache = new Map<string, string>();\nconst pathCache = new Map<string, string>();\n\nfunction key(root: string, method: string, dialect: Dialect): string {\n return `${root}::${method}::${dialect}`;\n}\n\nexport function resolveSqlFromFs(rootDir: string, methodName: string, dialect: Dialect): { sql: string; tried: string[] } {\n const k = key(rootDir, methodName, dialect);\n const tried: string[] = [];\n const ext = DIALECT_EXT[dialect];\n const dialectPath = path.join(rootDir, `${methodName}.${ext}.sql`);\n const genericPath = path.join(rootDir, `${methodName}.sql`);\n\n // Cached path\n let chosen = pathCache.get(k);\n if (!chosen) {\n if (fs.existsSync(dialectPath)) {\n chosen = dialectPath;\n } else if (fs.existsSync(genericPath)) {\n chosen = genericPath;\n }\n if (chosen) pathCache.set(k, chosen);\n }\n\n if (!chosen) {\n tried.push(dialectPath, genericPath);\n throw new Error(\n `sqlstack: SQL file not found for ${methodName}\\ntried: ${tried.join(\"\\n\")}`\n );\n }\n\n // Cached content\n let sql = contentCache.get(chosen);\n if (!sql) {\n sql = fs.readFileSync(chosen, 'utf8');\n contentCache.set(chosen, sql);\n }\n return { sql, tried: [chosen] };\n}\n\nexport function coerceRootPath(input?: string): { rootDir?: string; from?: 'file' | 'folder' } {\n if (!input) return {};\n const stat = fs.existsSync(input) ? fs.statSync(input) : undefined;\n if (stat?.isDirectory()) return { rootDir: input, from: 'folder' };\n if (stat?.isFile()) return { rootDir: path.dirname(input), from: 'file' };\n // If not found, treat as folder hint anyway\n return { rootDir: input, from: 'folder' };\n}\n\nexport function guessDecoratorDir(): string | undefined {\n const err = new Error();\n const stack = (err.stack || '').split('\\n').slice(2);\n const packageRoot = PACKAGE_ROOT_NORMALIZED;\n const codeRoot = SQLSTACK_CODE_ROOT;\n\n // DEBUG: Uncomment to trace issues\n // console.log('[guessDecoratorDir] packageRoot:', packageRoot);\n // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));\n\n for (const line of stack) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n\n const resolved = toAbsolutePath(file);\n if (!resolved) continue;\n\n const normalized = safeNormalize(resolved);\n if (!normalized) continue;\n\n // Skip every node_modules frame (sqlstack as a dependency, decorator\n // helpers such as reflect-metadata, test runners) and sqlstack's own\n // src/ and dist/ under its package root (running from source or a linked\n // checkout). A consumer module under a node_modules-free path that merely\n // contains the word \"sqlstack\" — this package's own tests/fixtures — is\n // a consumer and is NOT skipped.\n if (normalized.includes(path.sep + 'node_modules' + path.sep)) continue;\n if (packageRoot && isSqlstackCodePath(normalized, packageRoot)) continue;\n // Filesystem-free: sqlstack's own code root (the directory holding\n // core/, decorators/, …) as the STACK names it — the only reliable\n // reference on hosts without fs (workerd) or with re-rooted trees.\n if (codeRoot && normalized.startsWith(codeRoot)) continue;\n\n // Return the first consumer frame - this is where @Query is applied\n return path.dirname(resolved);\n }\n return undefined;\n}\n\nfunction isSqlstackCodePath(normalized: string, packageRoot: string): boolean {\n const root = process.platform === 'win32' ? packageRoot.toLowerCase() : packageRoot;\n return normalized.startsWith(root + 'src' + path.sep) || normalized.startsWith(root + 'dist' + path.sep);\n}\n\nfunction toAbsolutePath(file: string): string | undefined {\n try {\n if (file.startsWith('file://')) {\n return fileURLToPath(file);\n }\n // Skip Node.js internal modules and bundler internals\n if (file.startsWith('node:') || file.startsWith('webpack://')) {\n return undefined;\n }\n if (!path.isAbsolute(file)) {\n return path.resolve(file);\n }\n return file;\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSep(p: string): string {\n return p.endsWith(path.sep) ? p : p + path.sep;\n}\n\nfunction safeNormalize(p?: string): string | undefined {\n if (!p) return undefined;\n const normalized = path.normalize(p);\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized;\n}\n\n/**\n * Finds the package root from a starting directory by walking up to find package.json.\n * @internal Exported for testing\n */\nexport function findPackageRoot(startDir: string): string | undefined {\n // The ESM build ships a nested dist/esm/package.json ({ type: module });\n // keep walking past any package.json that is not sqlstack's own so the\n // root is the real package directory (whose src/ and dist/ are skipped by\n // guessDecoratorDir). The first package.json found is the fallback.\n let current = startDir;\n let fallback: string | undefined;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(current, 'package.json');\n if (fs.existsSync(candidate)) {\n const root = path.dirname(candidate);\n const normalizedRoot = safeNormalize(root);\n const asRoot = normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);\n if (packageNameOf(candidate) === 'sqlstack') return asRoot;\n fallback ??= asRoot;\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return fallback;\n}\n\nfunction packageNameOf(packageJsonPath: string): string | undefined {\n try {\n return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))?.name;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Detects if a path belongs to sqlstack package.\n * Handles both source paths (contains 'sqlstack') and node_modules paths.\n * @internal Exported for testing\n */\nexport function isSqlstackPath(filePath: string): boolean {\n const normalized = filePath.toLowerCase();\n // Check for source development path (e.g., /path/to/sqlstack/src/...)\n if (normalized.includes(path.sep + 'sqlstack' + path.sep)) return true;\n // Check for node_modules installation\n if (normalized.includes('node_modules' + path.sep + 'sqlstack' + path.sep)) return true;\n // Check for scoped package (@noego/sqlstack or similar)\n if (normalized.includes('node_modules' + path.sep + '@') && normalized.includes('sqlstack' + path.sep)) return true;\n return false;\n}\n\n/**\n * Extracts sqlstack's location from a stack trace.\n * Handles absolute paths, file:// URLs, and relative paths (Vitest uses relative paths).\n * @internal Exported for testing\n */\nexport function findSqlstackFromStack(stackString: string): string | undefined {\n const lines = stackString.split('\\n');\n for (const line of lines) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n try {\n let resolved: string | undefined;\n if (file.startsWith('file://')) {\n resolved = fileURLToPath(file);\n } else if (path.isAbsolute(file)) {\n resolved = file;\n } else if (!file.startsWith('node:') && !file.startsWith('webpack://')) {\n // Relative path - resolve it (Vitest uses relative paths in stack traces)\n resolved = path.resolve(file);\n }\n if (resolved && resolved.includes('fileResolution')) {\n return path.dirname(resolved);\n }\n } catch {\n // Skip invalid paths\n }\n }\n return undefined;\n}\n\n/**\n * Computes the sqlstack package root directory.\n * Handles both CJS (__dirname) and ESM (stack trace) detection.\n * Validates that __dirname actually points to sqlstack (guards against Vitest injection).\n * @internal Exported for testing\n */\nexport function computePackageRoot(\n dirnameValue: string | undefined,\n filenameValue: string | undefined,\n getStack: () => string\n): string | undefined {\n const candidates: string[] = [];\n\n // CJS: use __dirname/__filename, but validate they actually point to sqlstack\n // (Vitest can inject __dirname incorrectly when transforming CJS modules)\n if (typeof dirnameValue === 'string' && isSqlstackPath(dirnameValue)) {\n candidates.push(dirnameValue);\n }\n if (typeof filenameValue === 'string' && isSqlstackPath(filenameValue)) {\n candidates.push(path.dirname(filenameValue));\n }\n\n // ESM fallback or when __dirname was incorrectly injected: parse stack trace\n if (candidates.length === 0) {\n const stackDir = findSqlstackFromStack(getStack());\n if (stackDir) {\n candidates.push(stackDir);\n }\n }\n\n // Find the package root from the first valid candidate\n for (const base of candidates) {\n const root = findPackageRoot(base);\n if (root) return root;\n }\n return undefined;\n}\n\nconst PACKAGE_ROOT_NORMALIZED = computePackageRoot(\n typeof __dirname === 'string' ? __dirname : undefined,\n typeof __filename === 'string' ? __filename : undefined,\n () => new Error().stack || ''\n);\n\n/**\n * sqlstack's code root as the runtime names this module in stack traces:\n * the parent of this file's directory (`src/`, `dist/cjs/`, `dist/esm/`, or\n * a bundler's re-rooted copy). Needs no filesystem.\n * @internal Exported for testing\n */\nexport function computeCodeRoot(getStack: () => string): string | undefined {\n const coreDir = findSqlstackFromStack(getStack());\n if (!coreDir) return undefined;\n const root = safeNormalize(path.dirname(coreDir));\n return root ? ensureTrailingSep(root) : undefined;\n}\n\nconst SQLSTACK_CODE_ROOT = computeCodeRoot(() => new Error().stack || '');\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAqBzC,MAAM,UAAU,OAAO,CAAC,MAAW;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAe,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAW,EAAE,IAAqB,EAAE,KAA4B;IAC9F,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAa,EAAE,IAAqB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAS,EAAE,KAA2B;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAa;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC","sourcesContent":["const META = Symbol.for('sqlstack:meta');\n\nexport type MethodLabels = {\n defaults?: Record<string, unknown>;\n shape?: 'single' | 'only' | 'exist' | 'none';\n validateSchema?: unknown;\n source?: { kind: 'inline'; sql: string } | { kind: 'fs'; rootDir: string };\n db?: string;\n transform?: (row: any) => any;\n page?: { size: number; zeroBase?: boolean };\n};\n\nexport type ClassLabels = {\n db?: string;\n};\n\nexport type MetaShape = {\n class?: ClassLabels;\n methods: Record<string | symbol, MethodLabels>;\n};\n\nexport function getMeta(target: any): MetaShape {\n if (!target[META]) {\n target[META] = { methods: {} } as MetaShape;\n }\n return target[META];\n}\n\nexport function setMethodLabels(target: any, prop: string | symbol, patch: Partial<MethodLabels>) {\n const meta = getMeta(target);\n meta.methods[prop] = { ...(meta.methods[prop] || {}), ...patch };\n}\n\nexport function getMethodLabels(instance: any, prop: string | symbol): MethodLabels {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.methods[prop] || {};\n}\n\nexport function setClassLabels(ctor: any, patch: Partial<ClassLabels>) {\n const meta = getMeta(ctor.prototype);\n meta.class = { ...(meta.class || {}), ...patch };\n}\n\nexport function getClassLabels(instance: any): ClassLabels | undefined {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.class;\n}\n"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAyBzC,MAAM,UAAU,OAAO,CAAC,MAAW;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAe,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAW,EAAE,IAAqB,EAAE,KAA4B;IAC9F,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAa,EAAE,IAAqB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAS,EAAE,KAA2B;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAa;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC","sourcesContent":["const META = Symbol.for('sqlstack:meta');\n\nexport type MethodLabels = {\n defaults?: Record<string, unknown>;\n shape?: 'single' | 'only' | 'exist' | 'none';\n validateSchema?: unknown;\n source?:\n | { kind: 'inline'; sql: string }\n | { kind: 'fs'; rootDir: string }\n /** Bare @Query(): the directory of the decorating module, read from the stack at decoration time. */\n | { kind: 'guess'; dir: string };\n db?: string;\n transform?: (row: any) => any;\n page?: { size: number; zeroBase?: boolean };\n};\n\nexport type ClassLabels = {\n db?: string;\n};\n\nexport type MetaShape = {\n class?: ClassLabels;\n methods: Record<string | symbol, MethodLabels>;\n};\n\nexport function getMeta(target: any): MetaShape {\n if (!target[META]) {\n target[META] = { methods: {} } as MetaShape;\n }\n return target[META];\n}\n\nexport function setMethodLabels(target: any, prop: string | symbol, patch: Partial<MethodLabels>) {\n const meta = getMeta(target);\n meta.methods[prop] = { ...(meta.methods[prop] || {}), ...patch };\n}\n\nexport function getMethodLabels(instance: any, prop: string | symbol): MethodLabels {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.methods[prop] || {};\n}\n\nexport function setClassLabels(ctor: any, patch: Partial<ClassLabels>) {\n const meta = getMeta(ctor.prototype);\n meta.class = { ...(meta.class || {}), ...patch };\n}\n\nexport function getClassLabels(instance: any): ClassLabels | undefined {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.class;\n}\n"]}
@@ -0,0 +1,91 @@
1
+ const g = globalThis;
2
+ if (!g.__SQLSTACK_RESOURCES_STATE__) {
3
+ g.__SQLSTACK_RESOURCES_STATE__ = {
4
+ resources: undefined,
5
+ byKey: new Map(),
6
+ byTail: new Map(),
7
+ lookups: new Map(),
8
+ };
9
+ }
10
+ const state = g.__SQLSTACK_RESOURCES_STATE__;
11
+ const DIALECT_EXT = { postgres: 'pg', mysql: 'mysql', sqlite: 'sqlite' };
12
+ /** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */
13
+ export function normalizeResourcePath(p) {
14
+ let s = p.replace(/\\/g, '/');
15
+ if (s.startsWith('file://'))
16
+ s = s.slice('file://'.length);
17
+ s = s.replace(/^(\.\/)+/, '');
18
+ s = s.replace(/^\/+/, '');
19
+ return '/' + s;
20
+ }
21
+ function tailOf(normalized) {
22
+ const parts = normalized.split('/');
23
+ return '/' + parts.slice(-2).join('/');
24
+ }
25
+ /** Install (or clear with undefined) the process-wide packaged SQL resources. */
26
+ export function setResources(map) {
27
+ state.byKey = new Map();
28
+ state.byTail = new Map();
29
+ state.lookups = new Map();
30
+ state.resources = map;
31
+ if (!map)
32
+ return;
33
+ for (const [rawKey, sql] of Object.entries(map)) {
34
+ const key = normalizeResourcePath(rawKey);
35
+ state.byKey.set(key, sql);
36
+ const tail = tailOf(key);
37
+ const list = state.byTail.get(tail);
38
+ if (list)
39
+ list.push(key);
40
+ else
41
+ state.byTail.set(tail, [key]);
42
+ }
43
+ }
44
+ export function getResources() {
45
+ return state.resources;
46
+ }
47
+ /**
48
+ * Resolve one absolute (or module-tree) candidate path against the installed
49
+ * resources. Order: exact key; the longest key that is a path suffix of the
50
+ * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.
51
+ */
52
+ export function lookupResource(candidatePath) {
53
+ if (!state.resources)
54
+ return undefined;
55
+ const candidate = normalizeResourcePath(candidatePath);
56
+ if (state.lookups.has(candidate))
57
+ return state.lookups.get(candidate);
58
+ let found = state.byKey.get(candidate);
59
+ if (found === undefined) {
60
+ let bestLen = -1;
61
+ for (const [key, sql] of state.byKey) {
62
+ if (key.length > bestLen && candidate.endsWith(key)) {
63
+ found = sql;
64
+ bestLen = key.length;
65
+ }
66
+ }
67
+ }
68
+ if (found === undefined) {
69
+ const hits = state.byTail.get(tailOf(candidate));
70
+ if (hits && hits.length === 1)
71
+ found = state.byKey.get(hits[0]);
72
+ }
73
+ state.lookups.set(candidate, found);
74
+ return found;
75
+ }
76
+ /**
77
+ * Resolve a decorated method's SQL from the installed resources: the
78
+ * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.
79
+ * Returns the tried candidate paths so a miss can be reported precisely.
80
+ */
81
+ export function resolveSqlFromResources(dir, methodName, dialect) {
82
+ const base = normalizeResourcePath(dir).replace(/\/+$/, '');
83
+ const tried = [`${base}/${methodName}.${DIALECT_EXT[dialect]}.sql`, `${base}/${methodName}.sql`];
84
+ for (const candidate of tried) {
85
+ const sql = lookupResource(candidate);
86
+ if (sql !== undefined)
87
+ return { sql, tried };
88
+ }
89
+ return { sql: undefined, tried };
90
+ }
91
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/core/resources.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,GAAG,UAAiB,CAAC;AAC5B,IAAI,CAAC,CAAC,CAAC,4BAA4B,EAAE,CAAC;IACpC,CAAC,CAAC,4BAA4B,GAAG;QAC/B,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,OAAO,EAAE,IAAI,GAAG,EAAE;KACD,CAAC;AACtB,CAAC;AACD,MAAM,KAAK,GAAmB,CAAC,CAAC,4BAA4B,CAAC;AAE7D,MAAM,WAAW,GAA4B,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAElG,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB,CAAC,CAAS;IAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1B,OAAO,GAAG,GAAG,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,MAAM,CAAC,UAAkB;IAChC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,GAA6B;IACxD,KAAK,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IACxB,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,KAAK,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC1C,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;YACpB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,aAAqB;IAClD,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,SAAS,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtE,IAAI,KAAK,GAAuB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;QACjB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpD,KAAK,GAAG,GAAG,CAAC;gBACZ,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAW,EACX,UAAkB,EAClB,OAAgB;IAEhB,MAAM,IAAI,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,IAAI,UAAU,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,IAAI,UAAU,MAAM,CAAC,CAAC;IACjG,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC","sourcesContent":["import type { Dialect } from '../registry';\n\n/**\n * Packaged SQL resources: a path-keyed map `{ '<path>/<method>.sql': '<sql>' }`\n * installed by a bundled/packaged runtime (Electron asar, Cloudflare Worker,\n * @noego/app node runner) via `SqlStack.useResources(map)`.\n *\n * Keys are file paths — absolute, or relative to the project root (the shape\n * `import.meta.glob('/server/**\\/*.sql', { eager: true, query: '?raw' })`\n * produces). Lookups match by path suffix: the decorator's guessed directory\n * plus `<method>.sql` must END WITH a key. That makes the same map valid\n * whether modules load from `/repo/server/...`, `app.asar/out/server/...`\n * or a Worker's `modules/<project>/server/...` tree, as long as the module\n * tree is not flattened.\n */\nexport type SqlResources = Record<string, string>;\n\ntype ResourcesState = {\n resources: SqlResources | undefined;\n /** normalized key → sql */\n byKey: Map<string, string>;\n /** `<folder>/<file>` tail → normalized keys sharing that tail */\n byTail: Map<string, string[]>;\n lookups: Map<string, string | undefined>;\n};\n\nconst g = globalThis as any;\nif (!g.__SQLSTACK_RESOURCES_STATE__) {\n g.__SQLSTACK_RESOURCES_STATE__ = {\n resources: undefined,\n byKey: new Map(),\n byTail: new Map(),\n lookups: new Map(),\n } as ResourcesState;\n}\nconst state: ResourcesState = g.__SQLSTACK_RESOURCES_STATE__;\n\nconst DIALECT_EXT: Record<Dialect, string> = { postgres: 'pg', mysql: 'mysql', sqlite: 'sqlite' };\n\n/** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */\nexport function normalizeResourcePath(p: string): string {\n let s = p.replace(/\\\\/g, '/');\n if (s.startsWith('file://')) s = s.slice('file://'.length);\n s = s.replace(/^(\\.\\/)+/, '');\n s = s.replace(/^\\/+/, '');\n return '/' + s;\n}\n\nfunction tailOf(normalized: string): string {\n const parts = normalized.split('/');\n return '/' + parts.slice(-2).join('/');\n}\n\n/** Install (or clear with undefined) the process-wide packaged SQL resources. */\nexport function setResources(map: SqlResources | undefined): void {\n state.byKey = new Map();\n state.byTail = new Map();\n state.lookups = new Map();\n state.resources = map;\n if (!map) return;\n for (const [rawKey, sql] of Object.entries(map)) {\n const key = normalizeResourcePath(rawKey);\n state.byKey.set(key, sql);\n const tail = tailOf(key);\n const list = state.byTail.get(tail);\n if (list) list.push(key);\n else state.byTail.set(tail, [key]);\n }\n}\n\nexport function getResources(): SqlResources | undefined {\n return state.resources;\n}\n\n/**\n * Resolve one absolute (or module-tree) candidate path against the installed\n * resources. Order: exact key; the longest key that is a path suffix of the\n * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.\n */\nexport function lookupResource(candidatePath: string): string | undefined {\n if (!state.resources) return undefined;\n const candidate = normalizeResourcePath(candidatePath);\n if (state.lookups.has(candidate)) return state.lookups.get(candidate);\n let found: string | undefined = state.byKey.get(candidate);\n if (found === undefined) {\n let bestLen = -1;\n for (const [key, sql] of state.byKey) {\n if (key.length > bestLen && candidate.endsWith(key)) {\n found = sql;\n bestLen = key.length;\n }\n }\n }\n if (found === undefined) {\n const hits = state.byTail.get(tailOf(candidate));\n if (hits && hits.length === 1) found = state.byKey.get(hits[0]);\n }\n state.lookups.set(candidate, found);\n return found;\n}\n\n/**\n * Resolve a decorated method's SQL from the installed resources: the\n * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.\n * Returns the tried candidate paths so a miss can be reported precisely.\n */\nexport function resolveSqlFromResources(\n dir: string,\n methodName: string,\n dialect: Dialect\n): { sql: string | undefined; tried: string[] } {\n const base = normalizeResourcePath(dir).replace(/\\/+$/, '');\n const tried = [`${base}/${methodName}.${DIALECT_EXT[dialect]}.sql`, `${base}/${methodName}.sql`];\n for (const candidate of tried) {\n const sql = lookupResource(candidate);\n if (sql !== undefined) return { sql, tried };\n }\n return { sql: undefined, tried };\n}\n"]}
@@ -13,15 +13,15 @@ var _SourceScanResolver_inner;
13
13
  import { ManifestResolver } from './resolver.js';
14
14
  import { scanSqlManifestSync } from '../codegen/generateManifest.js';
15
15
  /**
16
- * Zero-config Node resolution for bare @Query(): lazily scans the project
17
- * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
18
- * sibling .sql files, then answers Contract A lookups from the in-memory
19
- * manifest. The scan runs once, on the first bare-@Query execution.
16
+ * Opt-in Node resolution that scans a project tree (process.cwd(), or an
17
+ * explicit rootDir) for @Query classes and their sibling .sql files, then
18
+ * answers Contract A lookups from the in-memory manifest. The scan runs once
19
+ * per instance, on first resolve.
20
20
  *
21
- * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
22
- * or the deprecated global) always take precedence, and bundled runtimes
23
- * (Cloudflare Workers) never reach it because their entrypoints install a
24
- * ManifestResolver.
21
+ * This is NOT a default. Bare @Query() resolves its own module directory
22
+ * (stack guess at decoration time) against `SqlStack.useResources(...)` or
23
+ * the filesystem; nothing walks the tree unless this resolver is installed
24
+ * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.
25
25
  */
26
26
  export class SourceScanResolver {
27
27
  constructor(rootDir) {
@@ -37,15 +37,4 @@ export class SourceScanResolver {
37
37
  }
38
38
  }
39
39
  _SourceScanResolver_inner = new WeakMap();
40
- let defaultInstance;
41
- /**
42
- * @internal Process-wide default used by the @Query call path when no
43
- * resolver is installed and the decorator captured no filesystem root.
44
- * Node-only: returns undefined where the filesystem is unavailable.
45
- */
46
- export function defaultSourceScanResolver() {
47
- if (typeof process === 'undefined' || typeof process.cwd !== 'function')
48
- return undefined;
49
- return (defaultInstance ?? (defaultInstance = new SourceScanResolver()));
50
- }
51
40
  //# sourceMappingURL=sourceScanResolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,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,mBAAmB,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,gBAAgB,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;;AAED,IAAI,eAA+C,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,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
+ {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,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,mBAAmB,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,gBAAgB,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","sourcesContent":["import type { SqlResolver, SqlResolutionRequest } from './resolver';\nimport { ManifestResolver } from './resolver';\nimport { scanSqlManifestSync } from '../codegen/generateManifest';\n\n/**\n * Opt-in Node resolution that scans a project tree (process.cwd(), or an\n * explicit rootDir) for @Query classes and their sibling .sql files, then\n * answers Contract A lookups from the in-memory manifest. The scan runs once\n * per instance, on first resolve.\n *\n * This is NOT a default. Bare @Query() resolves its own module directory\n * (stack guess at decoration time) against `SqlStack.useResources(...)` or\n * the filesystem; nothing walks the tree unless this resolver is installed\n * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.\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"]}