@514labs/moose-lsp 0.1.0-dev.11.3.1

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 (104) hide show
  1. package/dist/clickhouseData.d.ts +78 -0
  2. package/dist/clickhouseData.js +111 -0
  3. package/dist/clickhouseData.js.map +1 -0
  4. package/dist/clickhouseData.test.d.ts +2 -0
  5. package/dist/clickhouseData.test.js +92 -0
  6. package/dist/clickhouseData.test.js.map +1 -0
  7. package/dist/clickhouseVersion.d.ts +49 -0
  8. package/dist/clickhouseVersion.js +148 -0
  9. package/dist/clickhouseVersion.js.map +1 -0
  10. package/dist/clickhouseVersion.test.d.ts +2 -0
  11. package/dist/clickhouseVersion.test.js +113 -0
  12. package/dist/clickhouseVersion.test.js.map +1 -0
  13. package/dist/codeActions.d.ts +27 -0
  14. package/dist/codeActions.js +172 -0
  15. package/dist/codeActions.js.map +1 -0
  16. package/dist/codeActions.test.d.ts +2 -0
  17. package/dist/codeActions.test.js +206 -0
  18. package/dist/codeActions.test.js.map +1 -0
  19. package/dist/completions.d.ts +22 -0
  20. package/dist/completions.js +227 -0
  21. package/dist/completions.js.map +1 -0
  22. package/dist/completions.test.d.ts +2 -0
  23. package/dist/completions.test.js +282 -0
  24. package/dist/completions.test.js.map +1 -0
  25. package/dist/data/clickhouse-25.6.json +30772 -0
  26. package/dist/data/clickhouse-25.8.json +31872 -0
  27. package/dist/diagnostics.d.ts +18 -0
  28. package/dist/diagnostics.js +53 -0
  29. package/dist/diagnostics.js.map +1 -0
  30. package/dist/diagnostics.test.d.ts +2 -0
  31. package/dist/diagnostics.test.js +109 -0
  32. package/dist/diagnostics.test.js.map +1 -0
  33. package/dist/formatting.d.ts +36 -0
  34. package/dist/formatting.js +69 -0
  35. package/dist/formatting.js.map +1 -0
  36. package/dist/formatting.test.d.ts +2 -0
  37. package/dist/formatting.test.js +92 -0
  38. package/dist/formatting.test.js.map +1 -0
  39. package/dist/hover.d.ts +44 -0
  40. package/dist/hover.js +209 -0
  41. package/dist/hover.js.map +1 -0
  42. package/dist/hover.test.d.ts +2 -0
  43. package/dist/hover.test.js +354 -0
  44. package/dist/hover.test.js.map +1 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/index.js +25 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/node_modules/@514labs/moose-sql-validator-wasm/dist/index.js +56 -0
  49. package/dist/node_modules/@514labs/moose-sql-validator-wasm/dist/index.js.map +1 -0
  50. package/dist/node_modules/@514labs/moose-sql-validator-wasm/dist/index.test.js +185 -0
  51. package/dist/node_modules/@514labs/moose-sql-validator-wasm/dist/index.test.js.map +1 -0
  52. package/dist/node_modules/@514labs/moose-sql-validator-wasm/package.json +40 -0
  53. package/dist/node_modules/@514labs/moose-sql-validator-wasm/pkg/package.json +11 -0
  54. package/dist/node_modules/@514labs/moose-sql-validator-wasm/pkg/sql_validator.js +176 -0
  55. package/dist/node_modules/@514labs/moose-sql-validator-wasm/pkg/sql_validator_bg.wasm +0 -0
  56. package/dist/projectDetector.d.ts +21 -0
  57. package/dist/projectDetector.js +162 -0
  58. package/dist/projectDetector.js.map +1 -0
  59. package/dist/projectDetector.test.d.ts +2 -0
  60. package/dist/projectDetector.test.js +303 -0
  61. package/dist/projectDetector.test.js.map +1 -0
  62. package/dist/pythonService.d.ts +40 -0
  63. package/dist/pythonService.js +121 -0
  64. package/dist/pythonService.js.map +1 -0
  65. package/dist/pythonService.test.d.ts +2 -0
  66. package/dist/pythonService.test.js +208 -0
  67. package/dist/pythonService.test.js.map +1 -0
  68. package/dist/pythonSqlExtractor.d.ts +25 -0
  69. package/dist/pythonSqlExtractor.js +258 -0
  70. package/dist/pythonSqlExtractor.js.map +1 -0
  71. package/dist/pythonSqlExtractor.test.d.ts +2 -0
  72. package/dist/pythonSqlExtractor.test.js +227 -0
  73. package/dist/pythonSqlExtractor.test.js.map +1 -0
  74. package/dist/server.d.ts +2 -0
  75. package/dist/server.integration.test.d.ts +2 -0
  76. package/dist/server.integration.test.js +189 -0
  77. package/dist/server.integration.test.js.map +1 -0
  78. package/dist/server.js +228412 -0
  79. package/dist/server.js.map +1 -0
  80. package/dist/serverLogic.d.ts +40 -0
  81. package/dist/serverLogic.js +61 -0
  82. package/dist/serverLogic.js.map +1 -0
  83. package/dist/serverLogic.test.d.ts +2 -0
  84. package/dist/serverLogic.test.js +263 -0
  85. package/dist/serverLogic.test.js.map +1 -0
  86. package/dist/sqlExtractor.d.ts +15 -0
  87. package/dist/sqlExtractor.js +105 -0
  88. package/dist/sqlExtractor.js.map +1 -0
  89. package/dist/sqlExtractor.test.d.ts +2 -0
  90. package/dist/sqlExtractor.test.js +267 -0
  91. package/dist/sqlExtractor.test.js.map +1 -0
  92. package/dist/sqlLocations.d.ts +31 -0
  93. package/dist/sqlLocations.js +51 -0
  94. package/dist/sqlLocations.js.map +1 -0
  95. package/dist/sqlLocations.test.d.ts +2 -0
  96. package/dist/sqlLocations.test.js +94 -0
  97. package/dist/sqlLocations.test.js.map +1 -0
  98. package/dist/typescriptService.d.ts +29 -0
  99. package/dist/typescriptService.js +137 -0
  100. package/dist/typescriptService.js.map +1 -0
  101. package/dist/typescriptService.test.d.ts +2 -0
  102. package/dist/typescriptService.test.js +200 -0
  103. package/dist/typescriptService.test.js.map +1 -0
  104. package/package.json +49 -0
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var import_node_assert = __toESM(require("node:assert"));
25
+ var fs = __toESM(require("node:fs"));
26
+ var os = __toESM(require("node:os"));
27
+ var path = __toESM(require("node:path"));
28
+ var import_node_test = require("node:test");
29
+ var import_typescript = __toESM(require("typescript"));
30
+ var import_sqlExtractor = require("./sqlExtractor");
31
+ function createTestProgram(files) {
32
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sql-extractor-test-"));
33
+ const mooseLibDir = path.join(
34
+ tmpDir,
35
+ "node_modules",
36
+ "@514labs",
37
+ "moose-lib"
38
+ );
39
+ fs.mkdirSync(mooseLibDir, { recursive: true });
40
+ fs.writeFileSync(
41
+ path.join(mooseLibDir, "index.d.ts"),
42
+ `export declare function sql(strings: TemplateStringsArray, ...values: any[]): string;`
43
+ );
44
+ fs.writeFileSync(
45
+ path.join(mooseLibDir, "index.js"),
46
+ `module.exports.sql = function sql(strings, ...values) { return strings.join(''); };`
47
+ );
48
+ fs.writeFileSync(
49
+ path.join(mooseLibDir, "package.json"),
50
+ JSON.stringify({
51
+ name: "@514labs/moose-lib",
52
+ main: "index.js",
53
+ types: "index.d.ts"
54
+ })
55
+ );
56
+ for (const [fileName, content] of Object.entries(files)) {
57
+ const filePath = path.join(tmpDir, fileName);
58
+ const dir = path.dirname(filePath);
59
+ fs.mkdirSync(dir, { recursive: true });
60
+ fs.writeFileSync(filePath, content);
61
+ }
62
+ const tsconfigPath = path.join(tmpDir, "tsconfig.json");
63
+ fs.writeFileSync(
64
+ tsconfigPath,
65
+ JSON.stringify({
66
+ compilerOptions: {
67
+ target: "ES2020",
68
+ module: "commonjs",
69
+ strict: true,
70
+ esModuleInterop: true,
71
+ moduleResolution: "node",
72
+ baseUrl: ".",
73
+ paths: {
74
+ "@514labs/moose-lib": ["node_modules/@514labs/moose-lib"]
75
+ }
76
+ },
77
+ include: ["src/**/*"]
78
+ })
79
+ );
80
+ const configFile = import_typescript.default.readConfigFile(tsconfigPath, import_typescript.default.sys.readFile);
81
+ const parsed = import_typescript.default.parseJsonConfigFileContent(
82
+ configFile.config,
83
+ import_typescript.default.sys,
84
+ tmpDir
85
+ );
86
+ const program = import_typescript.default.createProgram({
87
+ rootNames: parsed.fileNames,
88
+ options: parsed.options
89
+ });
90
+ return { program, tmpDir };
91
+ }
92
+ function cleanupTestProject(dir) {
93
+ fs.rmSync(dir, { recursive: true, force: true });
94
+ }
95
+ (0, import_node_test.describe)("sqlExtractor", () => {
96
+ (0, import_node_test.describe)("extractSqlLocations", () => {
97
+ (0, import_node_test.it)("extracts sql template from file with moose-lib import", () => {
98
+ const { program, tmpDir } = createTestProgram({
99
+ "src/index.ts": `
100
+ import { sql } from '@514labs/moose-lib';
101
+
102
+ const query = sql\`SELECT * FROM users\`;
103
+ `
104
+ });
105
+ try {
106
+ const sourceFile = program.getSourceFile(
107
+ path.join(tmpDir, "src/index.ts")
108
+ );
109
+ import_node_assert.default.ok(sourceFile, "Source file should exist");
110
+ const typeChecker = program.getTypeChecker();
111
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
112
+ import_node_assert.default.strictEqual(locations.length, 1);
113
+ import_node_assert.default.strictEqual(locations[0].templateText, "SELECT * FROM users");
114
+ import_node_assert.default.strictEqual(locations[0].line, 4);
115
+ } finally {
116
+ cleanupTestProject(tmpDir);
117
+ }
118
+ });
119
+ (0, import_node_test.it)("extracts multiple sql templates from same file", () => {
120
+ const { program, tmpDir } = createTestProgram({
121
+ "src/index.ts": `
122
+ import { sql } from '@514labs/moose-lib';
123
+
124
+ const query1 = sql\`SELECT * FROM users\`;
125
+ const query2 = sql\`SELECT * FROM orders\`;
126
+ const query3 = sql\`SELECT * FROM products\`;
127
+ `
128
+ });
129
+ try {
130
+ const sourceFile = program.getSourceFile(
131
+ path.join(tmpDir, "src/index.ts")
132
+ );
133
+ import_node_assert.default.ok(sourceFile);
134
+ const typeChecker = program.getTypeChecker();
135
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
136
+ import_node_assert.default.strictEqual(locations.length, 3);
137
+ import_node_assert.default.strictEqual(locations[0].templateText, "SELECT * FROM users");
138
+ import_node_assert.default.strictEqual(locations[1].templateText, "SELECT * FROM orders");
139
+ import_node_assert.default.strictEqual(locations[2].templateText, "SELECT * FROM products");
140
+ } finally {
141
+ cleanupTestProject(tmpDir);
142
+ }
143
+ });
144
+ (0, import_node_test.it)("handles template with substitutions", () => {
145
+ const { program, tmpDir } = createTestProgram({
146
+ "src/index.ts": `
147
+ import { sql } from '@514labs/moose-lib';
148
+
149
+ const tableName = 'users';
150
+ const column = 'id';
151
+ const query = sql\`SELECT \${column} FROM \${tableName} WHERE active = \${true}\`;
152
+ `
153
+ });
154
+ try {
155
+ const sourceFile = program.getSourceFile(
156
+ path.join(tmpDir, "src/index.ts")
157
+ );
158
+ import_node_assert.default.ok(sourceFile);
159
+ const typeChecker = program.getTypeChecker();
160
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
161
+ import_node_assert.default.strictEqual(locations.length, 1);
162
+ import_node_assert.default.strictEqual(
163
+ locations[0].templateText,
164
+ "SELECT ${...} FROM ${...} WHERE active = ${...}"
165
+ );
166
+ } finally {
167
+ cleanupTestProject(tmpDir);
168
+ }
169
+ });
170
+ (0, import_node_test.it)("returns empty array for file without sql templates", () => {
171
+ const { program, tmpDir } = createTestProgram({
172
+ "src/index.ts": `
173
+ const x = 1;
174
+ const y = 2;
175
+ console.log(x + y);
176
+ `
177
+ });
178
+ try {
179
+ const sourceFile = program.getSourceFile(
180
+ path.join(tmpDir, "src/index.ts")
181
+ );
182
+ import_node_assert.default.ok(sourceFile);
183
+ const typeChecker = program.getTypeChecker();
184
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
185
+ import_node_assert.default.strictEqual(locations.length, 0);
186
+ } finally {
187
+ cleanupTestProject(tmpDir);
188
+ }
189
+ });
190
+ (0, import_node_test.it)("extracts sql tag even when symbol cannot be resolved (fallback behavior)", () => {
191
+ const { program, tmpDir } = createTestProgram({
192
+ "src/index.ts": `
193
+ // Define our own sql function (not from moose-lib)
194
+ function sql(strings: TemplateStringsArray, ...values: any[]) {
195
+ return strings.join('');
196
+ }
197
+
198
+ const query = sql\`SELECT * FROM users\`;
199
+ `
200
+ });
201
+ try {
202
+ const sourceFile = program.getSourceFile(
203
+ path.join(tmpDir, "src/index.ts")
204
+ );
205
+ import_node_assert.default.ok(sourceFile);
206
+ const typeChecker = program.getTypeChecker();
207
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
208
+ import_node_assert.default.strictEqual(locations.length, 1);
209
+ } finally {
210
+ cleanupTestProject(tmpDir);
211
+ }
212
+ });
213
+ (0, import_node_test.it)("extracts correct line and column positions", () => {
214
+ const { program, tmpDir } = createTestProgram({
215
+ "src/index.ts": `import { sql } from '@514labs/moose-lib';
216
+
217
+ const query = sql\`SELECT * FROM users\`;
218
+ `
219
+ });
220
+ try {
221
+ const sourceFile = program.getSourceFile(
222
+ path.join(tmpDir, "src/index.ts")
223
+ );
224
+ import_node_assert.default.ok(sourceFile);
225
+ const typeChecker = program.getTypeChecker();
226
+ const locations = (0, import_sqlExtractor.extractSqlLocations)(sourceFile, typeChecker);
227
+ import_node_assert.default.strictEqual(locations.length, 1);
228
+ import_node_assert.default.strictEqual(locations[0].line, 3);
229
+ import_node_assert.default.ok(locations[0].column > 0);
230
+ } finally {
231
+ cleanupTestProject(tmpDir);
232
+ }
233
+ });
234
+ });
235
+ (0, import_node_test.describe)("extractAllSqlLocations", () => {
236
+ (0, import_node_test.it)("extracts sql from multiple source files", () => {
237
+ const { program, tmpDir } = createTestProgram({
238
+ "src/queries/users.ts": `
239
+ import { sql } from '@514labs/moose-lib';
240
+ export const getUsersQuery = sql\`SELECT * FROM users\`;
241
+ `,
242
+ "src/queries/orders.ts": `
243
+ import { sql } from '@514labs/moose-lib';
244
+ export const getOrdersQuery = sql\`SELECT * FROM orders\`;
245
+ `,
246
+ "src/index.ts": `
247
+ export * from './queries/users';
248
+ export * from './queries/orders';
249
+ `
250
+ });
251
+ try {
252
+ const typeChecker = program.getTypeChecker();
253
+ const sourceFiles = program.getSourceFiles().filter(
254
+ (sf) => !sf.isDeclarationFile && !sf.fileName.includes("node_modules")
255
+ );
256
+ const locations = (0, import_sqlExtractor.extractAllSqlLocations)(sourceFiles, typeChecker);
257
+ import_node_assert.default.strictEqual(locations.length, 2);
258
+ const templates = locations.map((l) => l.templateText);
259
+ import_node_assert.default.ok(templates.includes("SELECT * FROM users"));
260
+ import_node_assert.default.ok(templates.includes("SELECT * FROM orders"));
261
+ } finally {
262
+ cleanupTestProject(tmpDir);
263
+ }
264
+ });
265
+ });
266
+ });
267
+ //# sourceMappingURL=sqlExtractor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlExtractor.test.ts"],"sourcesContent":["import assert from 'node:assert';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { describe, it } from 'node:test';\nimport ts from 'typescript';\nimport { extractAllSqlLocations, extractSqlLocations } from './sqlExtractor';\n\n/**\n * Creates a TypeScript program from source code strings for testing.\n * Simulates moose-lib by providing a mock sql function declaration.\n */\nfunction createTestProgram(files: Record<string, string>): {\n program: ts.Program;\n tmpDir: string;\n} {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sql-extractor-test-'));\n\n // Create a mock moose-lib module with sql function\n const mooseLibDir = path.join(\n tmpDir,\n 'node_modules',\n '@514labs',\n 'moose-lib',\n );\n fs.mkdirSync(mooseLibDir, { recursive: true });\n fs.writeFileSync(\n path.join(mooseLibDir, 'index.d.ts'),\n `export declare function sql(strings: TemplateStringsArray, ...values: any[]): string;`,\n );\n fs.writeFileSync(\n path.join(mooseLibDir, 'index.js'),\n `module.exports.sql = function sql(strings, ...values) { return strings.join(''); };`,\n );\n fs.writeFileSync(\n path.join(mooseLibDir, 'package.json'),\n JSON.stringify({\n name: '@514labs/moose-lib',\n main: 'index.js',\n types: 'index.d.ts',\n }),\n );\n\n // Write test files\n for (const [fileName, content] of Object.entries(files)) {\n const filePath = path.join(tmpDir, fileName);\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n\n // Create tsconfig\n const tsconfigPath = path.join(tmpDir, 'tsconfig.json');\n fs.writeFileSync(\n tsconfigPath,\n JSON.stringify({\n compilerOptions: {\n target: 'ES2020',\n module: 'commonjs',\n strict: true,\n esModuleInterop: true,\n moduleResolution: 'node',\n baseUrl: '.',\n paths: {\n '@514labs/moose-lib': ['node_modules/@514labs/moose-lib'],\n },\n },\n include: ['src/**/*'],\n }),\n );\n\n const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n const parsed = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n tmpDir,\n );\n\n const program = ts.createProgram({\n rootNames: parsed.fileNames,\n options: parsed.options,\n });\n\n return { program, tmpDir };\n}\n\nfunction cleanupTestProject(dir: string): void {\n fs.rmSync(dir, { recursive: true, force: true });\n}\n\ndescribe('sqlExtractor', () => {\n describe('extractSqlLocations', () => {\n it('extracts sql template from file with moose-lib import', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `\nimport { sql } from '@514labs/moose-lib';\n\nconst query = sql\\`SELECT * FROM users\\`;\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile, 'Source file should exist');\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n assert.strictEqual(locations.length, 1);\n assert.strictEqual(locations[0].templateText, 'SELECT * FROM users');\n assert.strictEqual(locations[0].line, 4);\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n\n it('extracts multiple sql templates from same file', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `\nimport { sql } from '@514labs/moose-lib';\n\nconst query1 = sql\\`SELECT * FROM users\\`;\nconst query2 = sql\\`SELECT * FROM orders\\`;\nconst query3 = sql\\`SELECT * FROM products\\`;\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile);\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n assert.strictEqual(locations.length, 3);\n assert.strictEqual(locations[0].templateText, 'SELECT * FROM users');\n assert.strictEqual(locations[1].templateText, 'SELECT * FROM orders');\n assert.strictEqual(locations[2].templateText, 'SELECT * FROM products');\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n\n it('handles template with substitutions', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `\nimport { sql } from '@514labs/moose-lib';\n\nconst tableName = 'users';\nconst column = 'id';\nconst query = sql\\`SELECT \\${column} FROM \\${tableName} WHERE active = \\${true}\\`;\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile);\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n assert.strictEqual(locations.length, 1);\n // Substitutions should be replaced with ${...}\n assert.strictEqual(\n locations[0].templateText,\n 'SELECT ${...} FROM ${...} WHERE active = ${...}',\n );\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n\n it('returns empty array for file without sql templates', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `\nconst x = 1;\nconst y = 2;\nconsole.log(x + y);\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile);\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n assert.strictEqual(locations.length, 0);\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n\n it('extracts sql tag even when symbol cannot be resolved (fallback behavior)', () => {\n // When TypeScript can't resolve the sql symbol (e.g., mock setup issues),\n // we fall back to accepting it (better to have false positives than miss real sql queries)\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `\n// Define our own sql function (not from moose-lib)\nfunction sql(strings: TemplateStringsArray, ...values: any[]) {\n return strings.join('');\n}\n\nconst query = sql\\`SELECT * FROM users\\`;\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile);\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n // With fallback behavior, we accept sql tags even when we can't verify\n // they come from moose-lib (better to have false positives)\n assert.strictEqual(locations.length, 1);\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n\n it('extracts correct line and column positions', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/index.ts': `import { sql } from '@514labs/moose-lib';\n\nconst query = sql\\`SELECT * FROM users\\`;\n`,\n });\n\n try {\n const sourceFile = program.getSourceFile(\n path.join(tmpDir, 'src/index.ts'),\n );\n assert.ok(sourceFile);\n\n const typeChecker = program.getTypeChecker();\n const locations = extractSqlLocations(sourceFile, typeChecker);\n\n assert.strictEqual(locations.length, 1);\n assert.strictEqual(locations[0].line, 3);\n // Column should point to the start of the template literal\n assert.ok(locations[0].column > 0);\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n });\n\n describe('extractAllSqlLocations', () => {\n it('extracts sql from multiple source files', () => {\n const { program, tmpDir } = createTestProgram({\n 'src/queries/users.ts': `\nimport { sql } from '@514labs/moose-lib';\nexport const getUsersQuery = sql\\`SELECT * FROM users\\`;\n`,\n 'src/queries/orders.ts': `\nimport { sql } from '@514labs/moose-lib';\nexport const getOrdersQuery = sql\\`SELECT * FROM orders\\`;\n`,\n 'src/index.ts': `\nexport * from './queries/users';\nexport * from './queries/orders';\n`,\n });\n\n try {\n const typeChecker = program.getTypeChecker();\n const sourceFiles = program\n .getSourceFiles()\n .filter(\n (sf) =>\n !sf.isDeclarationFile && !sf.fileName.includes('node_modules'),\n );\n\n const locations = extractAllSqlLocations(sourceFiles, typeChecker);\n\n assert.strictEqual(locations.length, 2);\n\n const templates = locations.map((l) => l.templateText);\n assert.ok(templates.includes('SELECT * FROM users'));\n assert.ok(templates.includes('SELECT * FROM orders'));\n } finally {\n cleanupTestProject(tmpDir);\n }\n });\n });\n});\n"],"mappings":"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","names":["ts","assert"]}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Represents a SQL template literal location from .moose/sql-locations.json
3
+ */
4
+ interface SqlLocation {
5
+ id: string;
6
+ file: string;
7
+ line: number;
8
+ column: number;
9
+ endLine: number;
10
+ endColumn: number;
11
+ templateText: string;
12
+ }
13
+ /**
14
+ * The manifest format for .moose/sql-locations.json
15
+ */
16
+ interface SqlLocationManifest {
17
+ version: number;
18
+ sqlLocations: SqlLocation[];
19
+ }
20
+ /**
21
+ * Parses sql-locations.json content and returns the manifest.
22
+ * Returns empty locations on parse error (graceful degradation).
23
+ */
24
+ declare function loadSqlLocations(jsonContent: string): SqlLocationManifest;
25
+ /**
26
+ * Prepares template text for SQL validation by replacing ${...} placeholders
27
+ * with valid SQL identifiers that won't cause parse errors.
28
+ */
29
+ declare function prepareSqlForValidation(templateText: string): string;
30
+
31
+ export { type SqlLocation, type SqlLocationManifest, loadSqlLocations, prepareSqlForValidation };
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var sqlLocations_exports = {};
20
+ __export(sqlLocations_exports, {
21
+ loadSqlLocations: () => loadSqlLocations,
22
+ prepareSqlForValidation: () => prepareSqlForValidation
23
+ });
24
+ module.exports = __toCommonJS(sqlLocations_exports);
25
+ function loadSqlLocations(jsonContent) {
26
+ try {
27
+ const parsed = JSON.parse(jsonContent);
28
+ return {
29
+ version: parsed.version ?? 1,
30
+ sqlLocations: Array.isArray(parsed.sqlLocations) ? parsed.sqlLocations : []
31
+ };
32
+ } catch {
33
+ return {
34
+ version: 1,
35
+ sqlLocations: []
36
+ };
37
+ }
38
+ }
39
+ function prepareSqlForValidation(templateText) {
40
+ let counter = 0;
41
+ return templateText.replace(/\$\{\.\.\.\}/g, () => {
42
+ counter++;
43
+ return `_ph_${counter}`;
44
+ });
45
+ }
46
+ // Annotate the CommonJS export names for ESM import in node:
47
+ 0 && (module.exports = {
48
+ loadSqlLocations,
49
+ prepareSqlForValidation
50
+ });
51
+ //# sourceMappingURL=sqlLocations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlLocations.ts"],"sourcesContent":["/**\n * Represents a SQL template literal location from .moose/sql-locations.json\n */\nexport interface SqlLocation {\n id: string;\n file: string;\n line: number;\n column: number;\n endLine: number;\n endColumn: number;\n templateText: string;\n}\n\n/**\n * The manifest format for .moose/sql-locations.json\n */\nexport interface SqlLocationManifest {\n version: number;\n sqlLocations: SqlLocation[];\n}\n\n/**\n * Parses sql-locations.json content and returns the manifest.\n * Returns empty locations on parse error (graceful degradation).\n */\nexport function loadSqlLocations(jsonContent: string): SqlLocationManifest {\n try {\n const parsed = JSON.parse(jsonContent);\n return {\n version: parsed.version ?? 1,\n sqlLocations: Array.isArray(parsed.sqlLocations)\n ? parsed.sqlLocations\n : [],\n };\n } catch {\n // Graceful degradation - return empty manifest on parse error\n return {\n version: 1,\n sqlLocations: [],\n };\n }\n}\n\n/**\n * Prepares template text for SQL validation by replacing ${...} placeholders\n * with valid SQL identifiers that won't cause parse errors.\n */\nexport function prepareSqlForValidation(templateText: string): string {\n // Replace ${...} with a placeholder identifier that's valid in SQL\n // Using '_ph_N' pattern to create unique, valid identifiers\n let counter = 0;\n return templateText.replace(/\\$\\{\\.\\.\\.\\}/g, () => {\n counter++;\n return `_ph_${counter}`;\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBO,SAAS,iBAAiB,aAA0C;AACzE,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,WAAW;AACrC,WAAO;AAAA,MACL,SAAS,OAAO,WAAW;AAAA,MAC3B,cAAc,MAAM,QAAQ,OAAO,YAAY,IAC3C,OAAO,eACP,CAAC;AAAA,IACP;AAAA,EACF,QAAQ;AAEN,WAAO;AAAA,MACL,SAAS;AAAA,MACT,cAAc,CAAC;AAAA,IACjB;AAAA,EACF;AACF;AAMO,SAAS,wBAAwB,cAA8B;AAGpE,MAAI,UAAU;AACd,SAAO,aAAa,QAAQ,iBAAiB,MAAM;AACjD;AACA,WAAO,OAAO,OAAO;AAAA,EACvB,CAAC;AACH;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var import_node_assert = __toESM(require("node:assert"));
25
+ var import_node_test = require("node:test");
26
+ var import_sqlLocations = require("./sqlLocations");
27
+ (0, import_node_test.test)("loadSqlLocations Tests", async (t) => {
28
+ await t.test("parses valid sql-locations.json content", () => {
29
+ const manifest = {
30
+ version: 1,
31
+ sqlLocations: [
32
+ {
33
+ id: "app/apis/bar.ts:54:22",
34
+ file: "/project/app/apis/bar.ts",
35
+ line: 54,
36
+ column: 22,
37
+ endLine: 61,
38
+ endColumn: 6,
39
+ templateText: "\n SELECT \n ${...},\n ${...}\n FROM ${...}\n "
40
+ }
41
+ ]
42
+ };
43
+ const result = (0, import_sqlLocations.loadSqlLocations)(JSON.stringify(manifest));
44
+ import_node_assert.default.strictEqual(result.version, 1);
45
+ import_node_assert.default.strictEqual(result.sqlLocations.length, 1);
46
+ import_node_assert.default.strictEqual(result.sqlLocations[0].file, "/project/app/apis/bar.ts");
47
+ import_node_assert.default.strictEqual(result.sqlLocations[0].line, 54);
48
+ });
49
+ await t.test("returns empty locations for invalid JSON", () => {
50
+ const result = (0, import_sqlLocations.loadSqlLocations)("not valid json");
51
+ import_node_assert.default.strictEqual(result.version, 1);
52
+ import_node_assert.default.strictEqual(result.sqlLocations.length, 0);
53
+ });
54
+ await t.test("returns empty locations for missing sqlLocations field", () => {
55
+ const result = (0, import_sqlLocations.loadSqlLocations)('{"version": 1}');
56
+ import_node_assert.default.strictEqual(result.sqlLocations.length, 0);
57
+ });
58
+ });
59
+ (0, import_node_test.test)("prepareSqlForValidation Tests", async (t) => {
60
+ await t.test("replaces ${...} placeholders with valid identifiers", () => {
61
+ const templateText = "SELECT ${...} FROM ${...}";
62
+ const result = (0, import_sqlLocations.prepareSqlForValidation)(templateText);
63
+ import_node_assert.default.ok(!result.includes("${...}"));
64
+ import_node_assert.default.ok(result.includes("SELECT"));
65
+ import_node_assert.default.ok(result.includes("FROM"));
66
+ });
67
+ await t.test("preserves SQL keywords and structure", () => {
68
+ const templateText = "SELECT ${...} as col FROM ${...} WHERE x > 1";
69
+ const result = (0, import_sqlLocations.prepareSqlForValidation)(templateText);
70
+ import_node_assert.default.ok(result.includes("SELECT"));
71
+ import_node_assert.default.ok(result.includes("as col"));
72
+ import_node_assert.default.ok(result.includes("FROM"));
73
+ import_node_assert.default.ok(result.includes("WHERE x > 1"));
74
+ });
75
+ await t.test("handles template with SLECT typo", () => {
76
+ const templateText = "SLECT ${...} FROM ${...}";
77
+ const result = (0, import_sqlLocations.prepareSqlForValidation)(templateText);
78
+ import_node_assert.default.ok(result.includes("SLECT"));
79
+ });
80
+ await t.test("handles multi-line templates", () => {
81
+ const templateText = `
82
+ SELECT
83
+ \${...},
84
+ \${...}
85
+ FROM \${...}
86
+ ORDER BY \${...} DESC
87
+ `;
88
+ const result = (0, import_sqlLocations.prepareSqlForValidation)(templateText);
89
+ import_node_assert.default.ok(result.includes("SELECT"));
90
+ import_node_assert.default.ok(result.includes("FROM"));
91
+ import_node_assert.default.ok(result.includes("ORDER BY"));
92
+ });
93
+ });
94
+ //# sourceMappingURL=sqlLocations.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlLocations.test.ts"],"sourcesContent":["import assert from 'node:assert';\nimport { test } from 'node:test';\nimport {\n loadSqlLocations,\n prepareSqlForValidation,\n type SqlLocationManifest,\n} from './sqlLocations';\n\ntest('loadSqlLocations Tests', async (t) => {\n await t.test('parses valid sql-locations.json content', () => {\n const manifest: SqlLocationManifest = {\n version: 1,\n sqlLocations: [\n {\n id: 'app/apis/bar.ts:54:22',\n file: '/project/app/apis/bar.ts',\n line: 54,\n column: 22,\n endLine: 61,\n endColumn: 6,\n templateText:\n '\\n SELECT \\n ${...},\\n ${...}\\n FROM ${...}\\n ',\n },\n ],\n };\n\n const result = loadSqlLocations(JSON.stringify(manifest));\n\n assert.strictEqual(result.version, 1);\n assert.strictEqual(result.sqlLocations.length, 1);\n assert.strictEqual(result.sqlLocations[0].file, '/project/app/apis/bar.ts');\n assert.strictEqual(result.sqlLocations[0].line, 54);\n });\n\n await t.test('returns empty locations for invalid JSON', () => {\n const result = loadSqlLocations('not valid json');\n\n assert.strictEqual(result.version, 1);\n assert.strictEqual(result.sqlLocations.length, 0);\n });\n\n await t.test('returns empty locations for missing sqlLocations field', () => {\n const result = loadSqlLocations('{\"version\": 1}');\n\n assert.strictEqual(result.sqlLocations.length, 0);\n });\n});\n\ntest('prepareSqlForValidation Tests', async (t) => {\n await t.test('replaces ${...} placeholders with valid identifiers', () => {\n const templateText = 'SELECT ${...} FROM ${...}';\n const result = prepareSqlForValidation(templateText);\n\n // Should replace ${...} with something the SQL parser can handle\n assert.ok(!result.includes('${...}'));\n // The result should be valid SQL structure\n assert.ok(result.includes('SELECT'));\n assert.ok(result.includes('FROM'));\n });\n\n await t.test('preserves SQL keywords and structure', () => {\n const templateText = 'SELECT ${...} as col FROM ${...} WHERE x > 1';\n const result = prepareSqlForValidation(templateText);\n\n assert.ok(result.includes('SELECT'));\n assert.ok(result.includes('as col'));\n assert.ok(result.includes('FROM'));\n assert.ok(result.includes('WHERE x > 1'));\n });\n\n await t.test('handles template with SLECT typo', () => {\n const templateText = 'SLECT ${...} FROM ${...}';\n const result = prepareSqlForValidation(templateText);\n\n // The typo should be preserved\n assert.ok(result.includes('SLECT'));\n });\n\n await t.test('handles multi-line templates', () => {\n const templateText = `\n SELECT \n \\${...},\n \\${...}\n FROM \\${...}\n ORDER BY \\${...} DESC\n `;\n const result = prepareSqlForValidation(templateText);\n\n assert.ok(result.includes('SELECT'));\n assert.ok(result.includes('FROM'));\n assert.ok(result.includes('ORDER BY'));\n });\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,yBAAmB;AACnB,uBAAqB;AACrB,0BAIO;AAAA,IAEP,uBAAK,0BAA0B,OAAO,MAAM;AAC1C,QAAM,EAAE,KAAK,2CAA2C,MAAM;AAC5D,UAAM,WAAgC;AAAA,MACpC,SAAS;AAAA,MACT,cAAc;AAAA,QACZ;AAAA,UACE,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,WAAW;AAAA,UACX,cACE;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAS,sCAAiB,KAAK,UAAU,QAAQ,CAAC;AAExD,uBAAAA,QAAO,YAAY,OAAO,SAAS,CAAC;AACpC,uBAAAA,QAAO,YAAY,OAAO,aAAa,QAAQ,CAAC;AAChD,uBAAAA,QAAO,YAAY,OAAO,aAAa,CAAC,EAAE,MAAM,0BAA0B;AAC1E,uBAAAA,QAAO,YAAY,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE;AAAA,EACpD,CAAC;AAED,QAAM,EAAE,KAAK,4CAA4C,MAAM;AAC7D,UAAM,aAAS,sCAAiB,gBAAgB;AAEhD,uBAAAA,QAAO,YAAY,OAAO,SAAS,CAAC;AACpC,uBAAAA,QAAO,YAAY,OAAO,aAAa,QAAQ,CAAC;AAAA,EAClD,CAAC;AAED,QAAM,EAAE,KAAK,0DAA0D,MAAM;AAC3E,UAAM,aAAS,sCAAiB,gBAAgB;AAEhD,uBAAAA,QAAO,YAAY,OAAO,aAAa,QAAQ,CAAC;AAAA,EAClD,CAAC;AACH,CAAC;AAAA,IAED,uBAAK,iCAAiC,OAAO,MAAM;AACjD,QAAM,EAAE,KAAK,uDAAuD,MAAM;AACxE,UAAM,eAAe;AACrB,UAAM,aAAS,6CAAwB,YAAY;AAGnD,uBAAAA,QAAO,GAAG,CAAC,OAAO,SAAS,QAAQ,CAAC;AAEpC,uBAAAA,QAAO,GAAG,OAAO,SAAS,QAAQ,CAAC;AACnC,uBAAAA,QAAO,GAAG,OAAO,SAAS,MAAM,CAAC;AAAA,EACnC,CAAC;AAED,QAAM,EAAE,KAAK,wCAAwC,MAAM;AACzD,UAAM,eAAe;AACrB,UAAM,aAAS,6CAAwB,YAAY;AAEnD,uBAAAA,QAAO,GAAG,OAAO,SAAS,QAAQ,CAAC;AACnC,uBAAAA,QAAO,GAAG,OAAO,SAAS,QAAQ,CAAC;AACnC,uBAAAA,QAAO,GAAG,OAAO,SAAS,MAAM,CAAC;AACjC,uBAAAA,QAAO,GAAG,OAAO,SAAS,aAAa,CAAC;AAAA,EAC1C,CAAC;AAED,QAAM,EAAE,KAAK,oCAAoC,MAAM;AACrD,UAAM,eAAe;AACrB,UAAM,aAAS,6CAAwB,YAAY;AAGnD,uBAAAA,QAAO,GAAG,OAAO,SAAS,OAAO,CAAC;AAAA,EACpC,CAAC;AAED,QAAM,EAAE,KAAK,gCAAgC,MAAM;AACjD,UAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOrB,UAAM,aAAS,6CAAwB,YAAY;AAEnD,uBAAAA,QAAO,GAAG,OAAO,SAAS,QAAQ,CAAC;AACnC,uBAAAA,QAAO,GAAG,OAAO,SAAS,MAAM,CAAC;AACjC,uBAAAA,QAAO,GAAG,OAAO,SAAS,UAAU,CAAC;AAAA,EACvC,CAAC;AACH,CAAC;","names":["assert"]}
@@ -0,0 +1,29 @@
1
+ import ts from 'typescript';
2
+
3
+ /**
4
+ * Service that manages a TypeScript Program lifecycle for SQL extraction.
5
+ * Holds the Program and TypeChecker in memory for fast incremental updates.
6
+ */
7
+ interface TypeScriptService {
8
+ /** Initialize with tsconfig.json path. Builds initial Program. */
9
+ initialize(tsconfigPath: string): void;
10
+ /** Update file content, rebuild program incrementally. */
11
+ updateFile(filePath: string, content: string): void;
12
+ /** Get TypeChecker for symbol resolution. */
13
+ getTypeChecker(): ts.TypeChecker;
14
+ /** Get all source files (for initial scan). Excludes declaration files and node_modules. */
15
+ getSourceFiles(): readonly ts.SourceFile[];
16
+ /** Get specific source file by path. */
17
+ getSourceFile(filePath: string): ts.SourceFile | undefined;
18
+ /** Check if service is initialized and healthy. */
19
+ isHealthy(): boolean;
20
+ /** Get initialization error if any. */
21
+ getError(): string | null;
22
+ }
23
+ /**
24
+ * Creates a TypeScript service that manages Program lifecycle.
25
+ * Uses incremental compilation for fast updates on file changes.
26
+ */
27
+ declare function createTypeScriptService(): TypeScriptService;
28
+
29
+ export { type TypeScriptService, createTypeScriptService };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var typescriptService_exports = {};
30
+ __export(typescriptService_exports, {
31
+ createTypeScriptService: () => createTypeScriptService
32
+ });
33
+ module.exports = __toCommonJS(typescriptService_exports);
34
+ var path = __toESM(require("node:path"));
35
+ var import_typescript = __toESM(require("typescript"));
36
+ function createTypeScriptService() {
37
+ let program = null;
38
+ let compilerOptions = {};
39
+ let rootFiles = [];
40
+ const fileContents = /* @__PURE__ */ new Map();
41
+ let error = null;
42
+ const createCompilerHost = () => {
43
+ const defaultHost = import_typescript.default.createCompilerHost(compilerOptions);
44
+ return {
45
+ ...defaultHost,
46
+ getSourceFile: (fileName, languageVersion, onError) => {
47
+ const normalizedPath = path.normalize(fileName);
48
+ const cached = fileContents.get(normalizedPath);
49
+ if (cached !== void 0) {
50
+ return import_typescript.default.createSourceFile(fileName, cached, languageVersion);
51
+ }
52
+ return defaultHost.getSourceFile(fileName, languageVersion, onError);
53
+ },
54
+ fileExists: (fileName) => {
55
+ const normalizedPath = path.normalize(fileName);
56
+ if (fileContents.has(normalizedPath)) return true;
57
+ return defaultHost.fileExists(fileName);
58
+ },
59
+ readFile: (fileName) => {
60
+ const normalizedPath = path.normalize(fileName);
61
+ const cached = fileContents.get(normalizedPath);
62
+ if (cached !== void 0) return cached;
63
+ return defaultHost.readFile(fileName);
64
+ }
65
+ };
66
+ };
67
+ return {
68
+ initialize(tsconfigPath) {
69
+ try {
70
+ const configFile = import_typescript.default.readConfigFile(tsconfigPath, import_typescript.default.sys.readFile);
71
+ if (configFile.error) {
72
+ error = import_typescript.default.flattenDiagnosticMessageText(
73
+ configFile.error.messageText,
74
+ "\n"
75
+ );
76
+ return;
77
+ }
78
+ const projectRoot = path.dirname(tsconfigPath);
79
+ const parsed = import_typescript.default.parseJsonConfigFileContent(
80
+ configFile.config,
81
+ import_typescript.default.sys,
82
+ projectRoot
83
+ );
84
+ if (parsed.errors.length > 0) {
85
+ error = parsed.errors.map((e) => import_typescript.default.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
86
+ return;
87
+ }
88
+ compilerOptions = parsed.options;
89
+ rootFiles = parsed.fileNames;
90
+ program = import_typescript.default.createProgram({
91
+ rootNames: rootFiles,
92
+ options: compilerOptions,
93
+ host: createCompilerHost()
94
+ });
95
+ error = null;
96
+ } catch (e) {
97
+ error = e instanceof Error ? e.message : String(e);
98
+ }
99
+ },
100
+ updateFile(filePath, content) {
101
+ if (!program) return;
102
+ const normalizedPath = path.normalize(filePath);
103
+ fileContents.set(normalizedPath, content);
104
+ program = import_typescript.default.createProgram({
105
+ rootNames: rootFiles,
106
+ options: compilerOptions,
107
+ host: createCompilerHost(),
108
+ oldProgram: program
109
+ });
110
+ },
111
+ getTypeChecker() {
112
+ if (!program) throw new Error("TypeScript service not initialized");
113
+ return program.getTypeChecker();
114
+ },
115
+ getSourceFiles() {
116
+ if (!program) return [];
117
+ return program.getSourceFiles().filter((sf) => {
118
+ return !sf.isDeclarationFile && !sf.fileName.includes("node_modules");
119
+ });
120
+ },
121
+ getSourceFile(filePath) {
122
+ if (!program) return void 0;
123
+ return program.getSourceFile(path.normalize(filePath));
124
+ },
125
+ isHealthy() {
126
+ return program !== null && error === null;
127
+ },
128
+ getError() {
129
+ return error;
130
+ }
131
+ };
132
+ }
133
+ // Annotate the CommonJS export names for ESM import in node:
134
+ 0 && (module.exports = {
135
+ createTypeScriptService
136
+ });
137
+ //# sourceMappingURL=typescriptService.js.map