@soda-gql/builder 0.7.0 → 0.8.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.
package/dist/index.cjs CHANGED
@@ -25,8 +25,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
- let node_crypto = require("node:crypto");
29
28
  let node_fs = require("node:fs");
29
+ let node_fs_promises = require("node:fs/promises");
30
+ let neverthrow = require("neverthrow");
31
+ let zod = require("zod");
32
+ let node_crypto = require("node:crypto");
30
33
  let node_path = require("node:path");
31
34
  let node_vm = require("node:vm");
32
35
  let __soda_gql_common = require("@soda-gql/common");
@@ -39,14 +42,452 @@ __soda_gql_core_runtime = __toESM(__soda_gql_core_runtime);
39
42
  let __soda_gql_runtime = require("@soda-gql/runtime");
40
43
  __soda_gql_runtime = __toESM(__soda_gql_runtime);
41
44
  let __swc_core = require("@swc/core");
42
- let neverthrow = require("neverthrow");
43
- let node_fs_promises = require("node:fs/promises");
44
- let zod = require("zod");
45
45
  let typescript = require("typescript");
46
46
  typescript = __toESM(typescript);
47
47
  let fast_glob = require("fast-glob");
48
48
  fast_glob = __toESM(fast_glob);
49
49
 
50
+ //#region packages/builder/src/schemas/artifact.ts
51
+ const BuilderArtifactElementMetadataSchema = zod.z.object({
52
+ sourcePath: zod.z.string(),
53
+ contentHash: zod.z.string()
54
+ });
55
+ const BuilderArtifactOperationSchema = zod.z.object({
56
+ id: zod.z.string(),
57
+ type: zod.z.literal("operation"),
58
+ metadata: BuilderArtifactElementMetadataSchema,
59
+ prebuild: zod.z.object({
60
+ operationType: zod.z.enum([
61
+ "query",
62
+ "mutation",
63
+ "subscription"
64
+ ]),
65
+ operationName: zod.z.string(),
66
+ document: zod.z.unknown(),
67
+ variableNames: zod.z.array(zod.z.string())
68
+ })
69
+ });
70
+ const BuilderArtifactFragmentSchema = zod.z.object({
71
+ id: zod.z.string(),
72
+ type: zod.z.literal("fragment"),
73
+ metadata: BuilderArtifactElementMetadataSchema,
74
+ prebuild: zod.z.object({ typename: zod.z.string() })
75
+ });
76
+ const BuilderArtifactElementSchema = zod.z.discriminatedUnion("type", [BuilderArtifactOperationSchema, BuilderArtifactFragmentSchema]);
77
+ const BuilderArtifactMetaSchema = zod.z.object({
78
+ version: zod.z.string(),
79
+ createdAt: zod.z.string()
80
+ });
81
+ const BuilderArtifactSchema = zod.z.object({
82
+ meta: BuilderArtifactMetaSchema.optional(),
83
+ elements: zod.z.record(zod.z.string(), BuilderArtifactElementSchema),
84
+ report: zod.z.object({
85
+ durationMs: zod.z.number(),
86
+ warnings: zod.z.array(zod.z.string()),
87
+ stats: zod.z.object({
88
+ hits: zod.z.number(),
89
+ misses: zod.z.number(),
90
+ skips: zod.z.number()
91
+ })
92
+ })
93
+ });
94
+
95
+ //#endregion
96
+ //#region packages/builder/src/artifact/loader.ts
97
+ /**
98
+ * Load a pre-built artifact from a JSON file asynchronously.
99
+ *
100
+ * @param path - Absolute path to the artifact JSON file
101
+ * @returns Result with the parsed artifact or an error
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const result = await loadArtifact("/path/to/artifact.json");
106
+ * if (result.isOk()) {
107
+ * const artifact = result.value;
108
+ * // Use artifact...
109
+ * }
110
+ * ```
111
+ */
112
+ const loadArtifact = async (path) => {
113
+ if (!(0, node_fs.existsSync)(path)) {
114
+ return (0, neverthrow.err)({
115
+ code: "ARTIFACT_NOT_FOUND",
116
+ message: `Artifact file not found: ${path}`,
117
+ filePath: path
118
+ });
119
+ }
120
+ let content;
121
+ try {
122
+ content = await (0, node_fs_promises.readFile)(path, "utf-8");
123
+ } catch (error) {
124
+ return (0, neverthrow.err)({
125
+ code: "ARTIFACT_NOT_FOUND",
126
+ message: `Failed to read artifact file: ${error instanceof Error ? error.message : String(error)}`,
127
+ filePath: path
128
+ });
129
+ }
130
+ return parseAndValidateArtifact(content, path);
131
+ };
132
+ /**
133
+ * Load a pre-built artifact from a JSON file synchronously.
134
+ *
135
+ * @param path - Absolute path to the artifact JSON file
136
+ * @returns Result with the parsed artifact or an error
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const result = loadArtifactSync("/path/to/artifact.json");
141
+ * if (result.isOk()) {
142
+ * const artifact = result.value;
143
+ * // Use artifact...
144
+ * }
145
+ * ```
146
+ */
147
+ const loadArtifactSync = (path) => {
148
+ if (!(0, node_fs.existsSync)(path)) {
149
+ return (0, neverthrow.err)({
150
+ code: "ARTIFACT_NOT_FOUND",
151
+ message: `Artifact file not found: ${path}`,
152
+ filePath: path
153
+ });
154
+ }
155
+ let content;
156
+ try {
157
+ content = (0, node_fs.readFileSync)(path, "utf-8");
158
+ } catch (error) {
159
+ return (0, neverthrow.err)({
160
+ code: "ARTIFACT_NOT_FOUND",
161
+ message: `Failed to read artifact file: ${error instanceof Error ? error.message : String(error)}`,
162
+ filePath: path
163
+ });
164
+ }
165
+ return parseAndValidateArtifact(content, path);
166
+ };
167
+ /**
168
+ * Parse JSON content and validate against BuilderArtifactSchema.
169
+ */
170
+ function parseAndValidateArtifact(content, filePath) {
171
+ let parsed;
172
+ try {
173
+ parsed = JSON.parse(content);
174
+ } catch (error) {
175
+ return (0, neverthrow.err)({
176
+ code: "ARTIFACT_PARSE_ERROR",
177
+ message: `Invalid JSON in artifact file: ${error instanceof Error ? error.message : String(error)}`,
178
+ filePath
179
+ });
180
+ }
181
+ const validated = BuilderArtifactSchema.safeParse(parsed);
182
+ if (!validated.success) {
183
+ return (0, neverthrow.err)({
184
+ code: "ARTIFACT_VALIDATION_ERROR",
185
+ message: `Invalid artifact structure: ${validated.error.message}`,
186
+ filePath
187
+ });
188
+ }
189
+ return (0, neverthrow.ok)(validated.data);
190
+ }
191
+
192
+ //#endregion
193
+ //#region packages/builder/src/errors/formatter.ts
194
+ /**
195
+ * Hints for each error code to help users understand and fix issues.
196
+ */
197
+ const errorHints = {
198
+ ELEMENT_EVALUATION_FAILED: "Check if all imported fragments are properly exported and included in entry patterns.",
199
+ GRAPH_CIRCULAR_DEPENDENCY: "Break the circular import by extracting shared types to a common module.",
200
+ GRAPH_MISSING_IMPORT: "Verify the import path exists and the module is included in entry patterns.",
201
+ RUNTIME_MODULE_LOAD_FAILED: "Ensure the module can be imported and all dependencies are installed.",
202
+ CONFIG_NOT_FOUND: "Create a soda-gql.config.ts file in your project root.",
203
+ CONFIG_INVALID: "Check your configuration file for syntax errors or invalid options.",
204
+ ENTRY_NOT_FOUND: "Verify the entry pattern matches your file structure.",
205
+ INTERNAL_INVARIANT: "This is an internal error. Please report it at https://github.com/soda-gql/soda-gql/issues"
206
+ };
207
+ /**
208
+ * Format a BuilderError into a structured FormattedError object.
209
+ */
210
+ const formatBuilderErrorStructured = (error) => {
211
+ const base = {
212
+ code: error.code,
213
+ message: error.message,
214
+ hint: errorHints[error.code],
215
+ cause: "cause" in error ? error.cause : undefined
216
+ };
217
+ switch (error.code) {
218
+ case "ELEMENT_EVALUATION_FAILED": return {
219
+ ...base,
220
+ location: {
221
+ modulePath: error.modulePath,
222
+ astPath: error.astPath || undefined
223
+ }
224
+ };
225
+ case "RUNTIME_MODULE_LOAD_FAILED": return {
226
+ ...base,
227
+ location: {
228
+ modulePath: error.filePath,
229
+ astPath: error.astPath
230
+ }
231
+ };
232
+ case "GRAPH_MISSING_IMPORT": return {
233
+ ...base,
234
+ relatedFiles: [error.importer, error.importee]
235
+ };
236
+ case "GRAPH_CIRCULAR_DEPENDENCY": return {
237
+ ...base,
238
+ relatedFiles: error.chain
239
+ };
240
+ case "CONFIG_NOT_FOUND":
241
+ case "CONFIG_INVALID": return {
242
+ ...base,
243
+ location: { modulePath: error.path }
244
+ };
245
+ case "FINGERPRINT_FAILED": return {
246
+ ...base,
247
+ location: { modulePath: error.filePath }
248
+ };
249
+ case "DISCOVERY_IO_ERROR": return {
250
+ ...base,
251
+ location: { modulePath: error.path }
252
+ };
253
+ default: return base;
254
+ }
255
+ };
256
+ /**
257
+ * Format a BuilderError for CLI/stderr output with human-readable formatting.
258
+ * Includes location, hint, and related files when available.
259
+ */
260
+ const formatBuilderErrorForCLI = (error) => {
261
+ const formatted = formatBuilderErrorStructured(error);
262
+ const lines = [];
263
+ lines.push(`Error [${formatted.code}]: ${formatted.message}`);
264
+ if (formatted.location) {
265
+ lines.push(` at ${formatted.location.modulePath}`);
266
+ if (formatted.location.astPath) {
267
+ lines.push(` in ${formatted.location.astPath}`);
268
+ }
269
+ }
270
+ if (formatted.hint) {
271
+ lines.push("");
272
+ lines.push(` Hint: ${formatted.hint}`);
273
+ }
274
+ if (formatted.relatedFiles && formatted.relatedFiles.length > 0) {
275
+ lines.push("");
276
+ lines.push(" Related files:");
277
+ for (const file of formatted.relatedFiles) {
278
+ lines.push(` - ${file}`);
279
+ }
280
+ }
281
+ return lines.join("\n");
282
+ };
283
+
284
+ //#endregion
285
+ //#region packages/builder/src/errors.ts
286
+ /**
287
+ * Error constructor helpers for concise error creation.
288
+ */
289
+ const builderErrors = {
290
+ entryNotFound: (entry, message) => ({
291
+ code: "ENTRY_NOT_FOUND",
292
+ message: message ?? `Entry not found: ${entry}`,
293
+ entry
294
+ }),
295
+ configNotFound: (path, message) => ({
296
+ code: "CONFIG_NOT_FOUND",
297
+ message: message ?? `Config file not found: ${path}`,
298
+ path
299
+ }),
300
+ configInvalid: (path, message, cause) => ({
301
+ code: "CONFIG_INVALID",
302
+ message,
303
+ path,
304
+ cause
305
+ }),
306
+ discoveryIOError: (path, message, errno, cause) => ({
307
+ code: "DISCOVERY_IO_ERROR",
308
+ message,
309
+ path,
310
+ errno,
311
+ cause
312
+ }),
313
+ fingerprintFailed: (filePath, message, cause) => ({
314
+ code: "FINGERPRINT_FAILED",
315
+ message,
316
+ filePath,
317
+ cause
318
+ }),
319
+ unsupportedAnalyzer: (analyzer, message) => ({
320
+ code: "UNSUPPORTED_ANALYZER",
321
+ message: message ?? `Unsupported analyzer: ${analyzer}`,
322
+ analyzer
323
+ }),
324
+ canonicalPathInvalid: (path, reason) => ({
325
+ code: "CANONICAL_PATH_INVALID",
326
+ message: `Invalid canonical path: ${path}${reason ? ` (${reason})` : ""}`,
327
+ path,
328
+ reason
329
+ }),
330
+ canonicalScopeMismatch: (expected, actual) => ({
331
+ code: "CANONICAL_SCOPE_MISMATCH",
332
+ message: `Scope mismatch: expected ${expected}, got ${actual}`,
333
+ expected,
334
+ actual
335
+ }),
336
+ graphCircularDependency: (chain) => ({
337
+ code: "GRAPH_CIRCULAR_DEPENDENCY",
338
+ message: `Circular dependency detected: ${chain.join(" → ")}`,
339
+ chain
340
+ }),
341
+ graphMissingImport: (importer, importee) => ({
342
+ code: "GRAPH_MISSING_IMPORT",
343
+ message: `Missing import: "${importer}" imports "${importee}" but it's not in the graph`,
344
+ importer,
345
+ importee
346
+ }),
347
+ docDuplicate: (name, sources) => ({
348
+ code: "DOC_DUPLICATE",
349
+ message: `Duplicate document name: ${name} found in ${sources.length} files`,
350
+ name,
351
+ sources
352
+ }),
353
+ writeFailed: (outPath, message, cause) => ({
354
+ code: "WRITE_FAILED",
355
+ message,
356
+ outPath,
357
+ cause
358
+ }),
359
+ cacheCorrupted: (message, cachePath, cause) => ({
360
+ code: "CACHE_CORRUPTED",
361
+ message,
362
+ cachePath,
363
+ cause
364
+ }),
365
+ runtimeModuleLoadFailed: (filePath, astPath, message, cause) => ({
366
+ code: "RUNTIME_MODULE_LOAD_FAILED",
367
+ message,
368
+ filePath,
369
+ astPath,
370
+ cause
371
+ }),
372
+ artifactRegistrationFailed: (elementId, reason) => ({
373
+ code: "ARTIFACT_REGISTRATION_FAILED",
374
+ message: `Failed to register artifact element ${elementId}: ${reason}`,
375
+ elementId,
376
+ reason
377
+ }),
378
+ elementEvaluationFailed: (modulePath, astPath, message, cause) => ({
379
+ code: "ELEMENT_EVALUATION_FAILED",
380
+ message,
381
+ modulePath,
382
+ astPath,
383
+ cause
384
+ }),
385
+ internalInvariant: (message, context, cause) => ({
386
+ code: "INTERNAL_INVARIANT",
387
+ message: `Internal invariant violated: ${message}`,
388
+ context,
389
+ cause
390
+ })
391
+ };
392
+ /**
393
+ * Convenience helper to create an err Result from BuilderError.
394
+ */
395
+ const builderErr = (error) => (0, neverthrow.err)(error);
396
+ /**
397
+ * Type guard for BuilderError.
398
+ */
399
+ const isBuilderError = (error) => {
400
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string";
401
+ };
402
+ /**
403
+ * Format BuilderError for console output (human-readable).
404
+ */
405
+ const formatBuilderError = (error) => {
406
+ const lines = [];
407
+ lines.push(`Error [${error.code}]: ${error.message}`);
408
+ switch (error.code) {
409
+ case "ENTRY_NOT_FOUND":
410
+ lines.push(` Entry: ${error.entry}`);
411
+ break;
412
+ case "CONFIG_NOT_FOUND":
413
+ case "CONFIG_INVALID":
414
+ lines.push(` Path: ${error.path}`);
415
+ if (error.code === "CONFIG_INVALID" && error.cause) {
416
+ lines.push(` Cause: ${error.cause}`);
417
+ }
418
+ break;
419
+ case "DISCOVERY_IO_ERROR":
420
+ lines.push(` Path: ${error.path}`);
421
+ if (error.errno !== undefined) {
422
+ lines.push(` Errno: ${error.errno}`);
423
+ }
424
+ break;
425
+ case "FINGERPRINT_FAILED":
426
+ lines.push(` File: ${error.filePath}`);
427
+ break;
428
+ case "CANONICAL_PATH_INVALID":
429
+ lines.push(` Path: ${error.path}`);
430
+ if (error.reason) {
431
+ lines.push(` Reason: ${error.reason}`);
432
+ }
433
+ break;
434
+ case "CANONICAL_SCOPE_MISMATCH":
435
+ lines.push(` Expected: ${error.expected}`);
436
+ lines.push(` Actual: ${error.actual}`);
437
+ break;
438
+ case "GRAPH_CIRCULAR_DEPENDENCY":
439
+ lines.push(` Chain: ${error.chain.join(" → ")}`);
440
+ break;
441
+ case "GRAPH_MISSING_IMPORT":
442
+ lines.push(` Importer: ${error.importer}`);
443
+ lines.push(` Importee: ${error.importee}`);
444
+ break;
445
+ case "DOC_DUPLICATE":
446
+ lines.push(` Name: ${error.name}`);
447
+ lines.push(` Sources:\n ${error.sources.join("\n ")}`);
448
+ break;
449
+ case "WRITE_FAILED":
450
+ lines.push(` Output path: ${error.outPath}`);
451
+ break;
452
+ case "CACHE_CORRUPTED":
453
+ if (error.cachePath) {
454
+ lines.push(` Cache path: ${error.cachePath}`);
455
+ }
456
+ break;
457
+ case "RUNTIME_MODULE_LOAD_FAILED":
458
+ lines.push(` File: ${error.filePath}`);
459
+ lines.push(` AST path: ${error.astPath}`);
460
+ break;
461
+ case "ARTIFACT_REGISTRATION_FAILED":
462
+ lines.push(` Element ID: ${error.elementId}`);
463
+ lines.push(` Reason: ${error.reason}`);
464
+ break;
465
+ case "ELEMENT_EVALUATION_FAILED":
466
+ lines.push(` at ${error.modulePath}`);
467
+ if (error.astPath) {
468
+ lines.push(` in ${error.astPath}`);
469
+ }
470
+ break;
471
+ case "INTERNAL_INVARIANT":
472
+ if (error.context) {
473
+ lines.push(` Context: ${error.context}`);
474
+ }
475
+ break;
476
+ }
477
+ if ("cause" in error && error.cause && !["CONFIG_INVALID"].includes(error.code)) {
478
+ lines.push(` Caused by: ${error.cause}`);
479
+ }
480
+ return lines.join("\n");
481
+ };
482
+ /**
483
+ * Assert unreachable code path (for exhaustiveness checks).
484
+ * This is the ONLY acceptable throw in builder code.
485
+ */
486
+ const assertUnreachable = (value, context) => {
487
+ throw new Error(`Unreachable code path${context ? ` in ${context}` : ""}: received ${JSON.stringify(value)}`);
488
+ };
489
+
490
+ //#endregion
50
491
  //#region packages/builder/src/scheduler/effects.ts
51
492
  /**
52
493
  * File read effect - reads a file from the filesystem.
@@ -171,6 +612,8 @@ var OptionalFileStatEffect = class extends __soda_gql_common.Effect {
171
612
  * Supports both sync and async schedulers, enabling parallel element evaluation
172
613
  * when using async scheduler.
173
614
  *
615
+ * Wraps errors with module context for better debugging.
616
+ *
174
617
  * @example
175
618
  * yield* new ElementEvaluationEffect(element).run();
176
619
  */
@@ -179,19 +622,39 @@ var ElementEvaluationEffect = class extends __soda_gql_common.Effect {
179
622
  super();
180
623
  this.element = element;
181
624
  }
625
+ /**
626
+ * Wrap an error with element context for better debugging.
627
+ */
628
+ wrapError(error) {
629
+ const context = __soda_gql_core.GqlElement.getContext(this.element);
630
+ if (context) {
631
+ const { filePath, astPath } = (0, __soda_gql_common.parseCanonicalId)(context.canonicalId);
632
+ const message = error instanceof Error ? error.message : String(error);
633
+ throw builderErrors.elementEvaluationFailed(filePath, astPath, message, error);
634
+ }
635
+ throw error;
636
+ }
182
637
  _executeSync() {
183
- const generator = __soda_gql_core.GqlElement.createEvaluationGenerator(this.element);
184
- const result = generator.next();
185
- while (!result.done) {
186
- throw new Error("Async operation required during sync element evaluation");
638
+ try {
639
+ const generator = __soda_gql_core.GqlElement.createEvaluationGenerator(this.element);
640
+ const result = generator.next();
641
+ while (!result.done) {
642
+ throw new Error("Async operation required during sync element evaluation");
643
+ }
644
+ } catch (error) {
645
+ this.wrapError(error);
187
646
  }
188
647
  }
189
648
  async _executeAsync() {
190
- const generator = __soda_gql_core.GqlElement.createEvaluationGenerator(this.element);
191
- let result = generator.next();
192
- while (!result.done) {
193
- await result.value;
194
- result = generator.next();
649
+ try {
650
+ const generator = __soda_gql_core.GqlElement.createEvaluationGenerator(this.element);
651
+ let result = generator.next();
652
+ while (!result.done) {
653
+ await result.value;
654
+ result = generator.next();
655
+ }
656
+ } catch (error) {
657
+ this.wrapError(error);
195
658
  }
196
659
  }
197
660
  };
@@ -915,47 +1378,6 @@ const createGraphqlSystemIdentifyHelper = (config) => {
915
1378
  };
916
1379
  };
917
1380
 
918
- //#endregion
919
- //#region packages/builder/src/schemas/artifact.ts
920
- const BuilderArtifactElementMetadataSchema = zod.z.object({
921
- sourcePath: zod.z.string(),
922
- contentHash: zod.z.string()
923
- });
924
- const BuilderArtifactOperationSchema = zod.z.object({
925
- id: zod.z.string(),
926
- type: zod.z.literal("operation"),
927
- metadata: BuilderArtifactElementMetadataSchema,
928
- prebuild: zod.z.object({
929
- operationType: zod.z.enum([
930
- "query",
931
- "mutation",
932
- "subscription"
933
- ]),
934
- operationName: zod.z.string(),
935
- document: zod.z.unknown(),
936
- variableNames: zod.z.array(zod.z.string())
937
- })
938
- });
939
- const BuilderArtifactFragmentSchema = zod.z.object({
940
- id: zod.z.string(),
941
- type: zod.z.literal("fragment"),
942
- metadata: BuilderArtifactElementMetadataSchema,
943
- prebuild: zod.z.object({ typename: zod.z.string() })
944
- });
945
- const BuilderArtifactElementSchema = zod.z.discriminatedUnion("type", [BuilderArtifactOperationSchema, BuilderArtifactFragmentSchema]);
946
- const BuilderArtifactSchema = zod.z.object({
947
- elements: zod.z.record(zod.z.string(), BuilderArtifactElementSchema),
948
- report: zod.z.object({
949
- durationMs: zod.z.number(),
950
- warnings: zod.z.array(zod.z.string()),
951
- stats: zod.z.object({
952
- hits: zod.z.number(),
953
- misses: zod.z.number(),
954
- skips: zod.z.number()
955
- })
956
- })
957
- });
958
-
959
1381
  //#endregion
960
1382
  //#region packages/builder/src/artifact/aggregate.ts
961
1383
  const canonicalToFilePath$1 = (canonicalId) => canonicalId.split("::")[0] ?? canonicalId;
@@ -1073,199 +1495,6 @@ const buildArtifact = ({ elements, analyses, stats: cache }) => {
1073
1495
  });
1074
1496
  };
1075
1497
 
1076
- //#endregion
1077
- //#region packages/builder/src/errors.ts
1078
- /**
1079
- * Error constructor helpers for concise error creation.
1080
- */
1081
- const builderErrors = {
1082
- entryNotFound: (entry, message) => ({
1083
- code: "ENTRY_NOT_FOUND",
1084
- message: message ?? `Entry not found: ${entry}`,
1085
- entry
1086
- }),
1087
- configNotFound: (path, message) => ({
1088
- code: "CONFIG_NOT_FOUND",
1089
- message: message ?? `Config file not found: ${path}`,
1090
- path
1091
- }),
1092
- configInvalid: (path, message, cause) => ({
1093
- code: "CONFIG_INVALID",
1094
- message,
1095
- path,
1096
- cause
1097
- }),
1098
- discoveryIOError: (path, message, errno, cause) => ({
1099
- code: "DISCOVERY_IO_ERROR",
1100
- message,
1101
- path,
1102
- errno,
1103
- cause
1104
- }),
1105
- fingerprintFailed: (filePath, message, cause) => ({
1106
- code: "FINGERPRINT_FAILED",
1107
- message,
1108
- filePath,
1109
- cause
1110
- }),
1111
- unsupportedAnalyzer: (analyzer, message) => ({
1112
- code: "UNSUPPORTED_ANALYZER",
1113
- message: message ?? `Unsupported analyzer: ${analyzer}`,
1114
- analyzer
1115
- }),
1116
- canonicalPathInvalid: (path, reason) => ({
1117
- code: "CANONICAL_PATH_INVALID",
1118
- message: `Invalid canonical path: ${path}${reason ? ` (${reason})` : ""}`,
1119
- path,
1120
- reason
1121
- }),
1122
- canonicalScopeMismatch: (expected, actual) => ({
1123
- code: "CANONICAL_SCOPE_MISMATCH",
1124
- message: `Scope mismatch: expected ${expected}, got ${actual}`,
1125
- expected,
1126
- actual
1127
- }),
1128
- graphCircularDependency: (chain) => ({
1129
- code: "GRAPH_CIRCULAR_DEPENDENCY",
1130
- message: `Circular dependency detected: ${chain.join(" → ")}`,
1131
- chain
1132
- }),
1133
- graphMissingImport: (importer, importee) => ({
1134
- code: "GRAPH_MISSING_IMPORT",
1135
- message: `Missing import: "${importer}" imports "${importee}" but it's not in the graph`,
1136
- importer,
1137
- importee
1138
- }),
1139
- docDuplicate: (name, sources) => ({
1140
- code: "DOC_DUPLICATE",
1141
- message: `Duplicate document name: ${name} found in ${sources.length} files`,
1142
- name,
1143
- sources
1144
- }),
1145
- writeFailed: (outPath, message, cause) => ({
1146
- code: "WRITE_FAILED",
1147
- message,
1148
- outPath,
1149
- cause
1150
- }),
1151
- cacheCorrupted: (message, cachePath, cause) => ({
1152
- code: "CACHE_CORRUPTED",
1153
- message,
1154
- cachePath,
1155
- cause
1156
- }),
1157
- runtimeModuleLoadFailed: (filePath, astPath, message, cause) => ({
1158
- code: "RUNTIME_MODULE_LOAD_FAILED",
1159
- message,
1160
- filePath,
1161
- astPath,
1162
- cause
1163
- }),
1164
- artifactRegistrationFailed: (elementId, reason) => ({
1165
- code: "ARTIFACT_REGISTRATION_FAILED",
1166
- message: `Failed to register artifact element ${elementId}: ${reason}`,
1167
- elementId,
1168
- reason
1169
- }),
1170
- internalInvariant: (message, context, cause) => ({
1171
- code: "INTERNAL_INVARIANT",
1172
- message: `Internal invariant violated: ${message}`,
1173
- context,
1174
- cause
1175
- })
1176
- };
1177
- /**
1178
- * Convenience helper to create an err Result from BuilderError.
1179
- */
1180
- const builderErr = (error) => (0, neverthrow.err)(error);
1181
- /**
1182
- * Type guard for BuilderError.
1183
- */
1184
- const isBuilderError = (error) => {
1185
- return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string";
1186
- };
1187
- /**
1188
- * Format BuilderError for console output (human-readable).
1189
- */
1190
- const formatBuilderError = (error) => {
1191
- const lines = [];
1192
- lines.push(`Error [${error.code}]: ${error.message}`);
1193
- switch (error.code) {
1194
- case "ENTRY_NOT_FOUND":
1195
- lines.push(` Entry: ${error.entry}`);
1196
- break;
1197
- case "CONFIG_NOT_FOUND":
1198
- case "CONFIG_INVALID":
1199
- lines.push(` Path: ${error.path}`);
1200
- if (error.code === "CONFIG_INVALID" && error.cause) {
1201
- lines.push(` Cause: ${error.cause}`);
1202
- }
1203
- break;
1204
- case "DISCOVERY_IO_ERROR":
1205
- lines.push(` Path: ${error.path}`);
1206
- if (error.errno !== undefined) {
1207
- lines.push(` Errno: ${error.errno}`);
1208
- }
1209
- break;
1210
- case "FINGERPRINT_FAILED":
1211
- lines.push(` File: ${error.filePath}`);
1212
- break;
1213
- case "CANONICAL_PATH_INVALID":
1214
- lines.push(` Path: ${error.path}`);
1215
- if (error.reason) {
1216
- lines.push(` Reason: ${error.reason}`);
1217
- }
1218
- break;
1219
- case "CANONICAL_SCOPE_MISMATCH":
1220
- lines.push(` Expected: ${error.expected}`);
1221
- lines.push(` Actual: ${error.actual}`);
1222
- break;
1223
- case "GRAPH_CIRCULAR_DEPENDENCY":
1224
- lines.push(` Chain: ${error.chain.join(" → ")}`);
1225
- break;
1226
- case "GRAPH_MISSING_IMPORT":
1227
- lines.push(` Importer: ${error.importer}`);
1228
- lines.push(` Importee: ${error.importee}`);
1229
- break;
1230
- case "DOC_DUPLICATE":
1231
- lines.push(` Name: ${error.name}`);
1232
- lines.push(` Sources:\n ${error.sources.join("\n ")}`);
1233
- break;
1234
- case "WRITE_FAILED":
1235
- lines.push(` Output path: ${error.outPath}`);
1236
- break;
1237
- case "CACHE_CORRUPTED":
1238
- if (error.cachePath) {
1239
- lines.push(` Cache path: ${error.cachePath}`);
1240
- }
1241
- break;
1242
- case "RUNTIME_MODULE_LOAD_FAILED":
1243
- lines.push(` File: ${error.filePath}`);
1244
- lines.push(` AST path: ${error.astPath}`);
1245
- break;
1246
- case "ARTIFACT_REGISTRATION_FAILED":
1247
- lines.push(` Element ID: ${error.elementId}`);
1248
- lines.push(` Reason: ${error.reason}`);
1249
- break;
1250
- case "INTERNAL_INVARIANT":
1251
- if (error.context) {
1252
- lines.push(` Context: ${error.context}`);
1253
- }
1254
- break;
1255
- }
1256
- if ("cause" in error && error.cause && !["CONFIG_INVALID"].includes(error.code)) {
1257
- lines.push(` Caused by: ${error.cause}`);
1258
- }
1259
- return lines.join("\n");
1260
- };
1261
- /**
1262
- * Assert unreachable code path (for exhaustiveness checks).
1263
- * This is the ONLY acceptable throw in builder code.
1264
- */
1265
- const assertUnreachable = (value, context) => {
1266
- throw new Error(`Unreachable code path${context ? ` in ${context}` : ""}: received ${JSON.stringify(value)}`);
1267
- };
1268
-
1269
1498
  //#endregion
1270
1499
  //#region packages/builder/src/ast/common/scope.ts
1271
1500
  /**
@@ -3034,7 +3263,7 @@ const createBuilderSession = (options) => {
3034
3263
  prefix: ["builder"],
3035
3264
  persistence: {
3036
3265
  enabled: true,
3037
- filePath: (0, node_path.join)(process.cwd(), ".cache", "soda-gql", "builder", "cache.json")
3266
+ filePath: (0, node_path.join)(process.cwd(), "node_modules", ".cache", "soda-gql", "builder", "cache.json")
3038
3267
  }
3039
3268
  });
3040
3269
  process.on("beforeExit", () => {
@@ -3329,4 +3558,8 @@ exports.createBuilderService = createBuilderService;
3329
3558
  exports.createBuilderSession = createBuilderSession;
3330
3559
  exports.createGraphqlSystemIdentifyHelper = createGraphqlSystemIdentifyHelper;
3331
3560
  exports.extractModuleAdjacency = extractModuleAdjacency;
3561
+ exports.formatBuilderErrorForCLI = formatBuilderErrorForCLI;
3562
+ exports.formatBuilderErrorStructured = formatBuilderErrorStructured;
3563
+ exports.loadArtifact = loadArtifact;
3564
+ exports.loadArtifactSync = loadArtifactSync;
3332
3565
  //# sourceMappingURL=index.cjs.map