@soda-gql/builder 0.11.10 → 0.11.11

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.
@@ -1509,35 +1509,66 @@ const createGraphqlSystemIdentifyHelper = (config) => {
1509
1509
  };
1510
1510
  };
1511
1511
 
1512
+ //#endregion
1513
+ //#region packages/builder/src/artifact/canonical-id-utils.ts
1514
+ /**
1515
+ * Parse a canonical ID with validation.
1516
+ * Returns a Result with parsed components or a BuilderError.
1517
+ *
1518
+ * @param canonicalId - The canonical ID to parse
1519
+ * @returns Result with {filePath, astPath} or BuilderError
1520
+ */
1521
+ const parseCanonicalIdSafe = (canonicalId) => {
1522
+ const validation = (0, __soda_gql_common.validateCanonicalId)(canonicalId);
1523
+ if (!validation.isValid) {
1524
+ return (0, neverthrow.err)(builderErrors.canonicalPathInvalid(canonicalId, validation.reason));
1525
+ }
1526
+ return (0, neverthrow.ok)((0, __soda_gql_common.parseCanonicalId)(canonicalId));
1527
+ };
1528
+ /**
1529
+ * Extract file path from canonical ID with validation.
1530
+ * Returns a Result with the file path or a BuilderError.
1531
+ *
1532
+ * @param canonicalId - The canonical ID to extract from
1533
+ * @returns Result with filePath or BuilderError
1534
+ */
1535
+ const extractFilePathSafe = (canonicalId) => {
1536
+ return parseCanonicalIdSafe(canonicalId).map(({ filePath }) => filePath);
1537
+ };
1538
+
1512
1539
  //#endregion
1513
1540
  //#region packages/builder/src/artifact/aggregate.ts
1514
- const canonicalToFilePath$1 = (canonicalId) => canonicalId.split("::")[0] ?? canonicalId;
1515
1541
  const computeContentHash = (prebuild) => {
1516
1542
  const hash = (0, node_crypto.createHash)("sha1");
1517
1543
  hash.update(JSON.stringify(prebuild));
1518
1544
  return hash.digest("hex");
1519
1545
  };
1520
- const emitRegistrationError = (definition, message) => ({
1546
+ const emitRegistrationError = (filePath, astPath, message) => ({
1521
1547
  code: "RUNTIME_MODULE_LOAD_FAILED",
1522
- filePath: canonicalToFilePath$1(definition.canonicalId),
1523
- astPath: definition.astPath,
1548
+ filePath,
1549
+ astPath,
1524
1550
  message
1525
1551
  });
1526
1552
  const aggregate = ({ analyses, elements }) => {
1527
1553
  const registry = new Map();
1528
1554
  for (const analysis of analyses.values()) {
1529
1555
  for (const definition of analysis.definitions) {
1556
+ const parsedResult = parseCanonicalIdSafe(definition.canonicalId);
1557
+ if (parsedResult.isErr()) {
1558
+ return (0, neverthrow.err)(parsedResult.error);
1559
+ }
1560
+ const { filePath, astPath } = parsedResult.value;
1530
1561
  const element = elements[definition.canonicalId];
1531
1562
  if (!element) {
1532
1563
  const availableIds = Object.keys(elements).join(", ");
1533
1564
  const message = `ARTIFACT_NOT_FOUND_IN_RUNTIME_MODULE: ${definition.canonicalId}\nAvailable: ${availableIds}`;
1534
- return (0, neverthrow.err)(emitRegistrationError(definition, message));
1565
+ return (0, neverthrow.err)(emitRegistrationError(filePath, astPath, message));
1535
1566
  }
1536
1567
  if (registry.has(definition.canonicalId)) {
1537
- return (0, neverthrow.err)(emitRegistrationError(definition, `ARTIFACT_ALREADY_REGISTERED`));
1568
+ return (0, neverthrow.err)(emitRegistrationError(filePath, astPath, `ARTIFACT_ALREADY_REGISTERED`));
1538
1569
  }
1539
1570
  const metadata = {
1540
- sourcePath: analysis.filePath ?? canonicalToFilePath$1(definition.canonicalId),
1571
+ sourcePath: filePath,
1541
1572
  contentHash: ""
1542
1573
  };
1543
1574
  if (element.type === "fragment") {
@@ -1577,7 +1608,7 @@ const aggregate = ({ analyses, elements }) => {
1577
1608
  });
1578
1609
  continue;
1579
1610
  }
1580
- return (0, neverthrow.err)(emitRegistrationError(definition, "UNKNOWN_ARTIFACT_KIND"));
1611
+ return (0, neverthrow.err)(emitRegistrationError(filePath, astPath, "UNKNOWN_ARTIFACT_KIND"));
1581
1612
  }
1582
1613
  }
1583
1614
  return (0, neverthrow.ok)(registry);
@@ -1585,7 +1616,6 @@ const aggregate = ({ analyses, elements }) => {
1585
1616
 
1586
1617
  //#endregion
1587
1618
  //#region packages/builder/src/artifact/issue-handler.ts
1588
- const canonicalToFilePath = (canonicalId) => canonicalId.split("::")[0] ?? canonicalId;
1589
1619
  const checkIssues = ({ elements }) => {
1590
1620
  const operationNames = new Set();
1591
1621
  for (const [canonicalId, { type, element }] of Object.entries(elements)) {
@@ -1593,7 +1623,11 @@ const checkIssues = ({ elements }) => {
1593
1623
  continue;
1594
1624
  }
1595
1625
  if (operationNames.has(element.operationName)) {
1596
- const sources = [canonicalToFilePath(canonicalId)];
1626
+ const filePathResult = extractFilePathSafe(canonicalId);
1627
+ if (filePathResult.isErr()) {
1628
+ return (0, neverthrow.err)(filePathResult.error);
1629
+ }
1630
+ const sources = [filePathResult.value];
1597
1631
  return (0, neverthrow.err)({
1598
1632
  code: "DOC_DUPLICATE",
1599
1633
  message: `Duplicate document name: ${element.operationName}`,
@@ -1879,7 +1913,7 @@ const unwrapMethodChains$1 = (identifiers, node) => {
1879
1913
  }
1880
1914
  return unwrapMethodChains$1(identifiers, callee.object);
1881
1915
  };
1882
- const collectAllDefinitions$1 = ({ module: module$1, gqlIdentifiers, imports: _imports, exports: exports$1, source }) => {
1916
+ const collectAllDefinitions$1 = ({ module: module$1, gqlIdentifiers, imports: _imports, exports: exports$1, source, baseDir }) => {
1883
1917
  const getPropertyName$1 = (property) => {
1884
1918
  if (!property) {
1885
1919
  return null;
@@ -1897,6 +1931,7 @@ const collectAllDefinitions$1 = ({ module: module$1, gqlIdentifiers, imports: _i
1897
1931
  const exportBindings = createExportBindingsMap(exports$1);
1898
1932
  const tracker = (0, __soda_gql_common.createCanonicalTracker)({
1899
1933
  filePath: module$1.__filePath,
1934
+ baseDir,
1900
1935
  getExportName: (localName) => exportBindings.get(localName)
1901
1936
  });
1902
1937
  const anonymousCounters = new Map();
@@ -2071,7 +2106,7 @@ const collectAllDefinitions$1 = ({ module: module$1, gqlIdentifiers, imports: _i
2071
2106
  visit(statement, []);
2072
2107
  });
2073
2108
  const definitions = pending.map((item) => ({
2074
- canonicalId: (0, __soda_gql_common.createCanonicalId)(module$1.__filePath, item.astPath),
2109
+ canonicalId: (0, __soda_gql_common.createCanonicalId)(module$1.__filePath, item.astPath, { baseDir }),
2075
2110
  astPath: item.astPath,
2076
2111
  isTopLevel: item.isTopLevel,
2077
2112
  isExported: item.isExported,
@@ -2333,7 +2368,8 @@ const swcAdapter = { analyze(input, helper) {
2333
2368
  gqlIdentifiers,
2334
2369
  imports,
2335
2370
  exports: exports$1,
2336
- source: input.source
2371
+ source: input.source,
2372
+ baseDir: input.baseDir
2337
2373
  });
2338
2374
  const diagnostics = [
2339
2375
  ...collectImportDiagnostics$1(swcModule, helper),
@@ -2546,12 +2582,13 @@ const getPropertyName = (name) => {
2546
2582
  /**
2547
2583
  * Collect all gql definitions (exported, non-exported, top-level, nested)
2548
2584
  */
2549
- const collectAllDefinitions = ({ sourceFile, identifiers, exports: exports$1 }) => {
2585
+ const collectAllDefinitions = ({ sourceFile, identifiers, exports: exports$1, baseDir }) => {
2550
2586
  const pending = [];
2551
2587
  const handledCalls = [];
2552
2588
  const exportBindings = createExportBindingsMap(exports$1);
2553
2589
  const tracker = (0, __soda_gql_common.createCanonicalTracker)({
2554
2590
  filePath: sourceFile.fileName,
2591
+ baseDir,
2555
2592
  getExportName: (localName) => exportBindings.get(localName)
2556
2593
  });
2557
2594
  const anonymousCounters = new Map();
@@ -2695,7 +2732,7 @@ const collectAllDefinitions = ({ sourceFile, identifiers, exports: exports$1 })
2695
2732
  visit(statement, []);
2696
2733
  });
2697
2734
  const definitions = pending.map((item) => ({
2698
- canonicalId: (0, __soda_gql_common.createCanonicalId)(sourceFile.fileName, item.astPath),
2735
+ canonicalId: (0, __soda_gql_common.createCanonicalId)(sourceFile.fileName, item.astPath, { baseDir }),
2699
2736
  astPath: item.astPath,
2700
2737
  isTopLevel: item.isTopLevel,
2701
2738
  isExported: item.isExported,
@@ -2899,7 +2936,8 @@ const typescriptAdapter = { analyze(input, helper) {
2899
2936
  const { definitions } = collectAllDefinitions({
2900
2937
  sourceFile,
2901
2938
  identifiers: gqlIdentifiers,
2902
- exports: exports$1
2939
+ exports: exports$1,
2940
+ baseDir: input.baseDir
2903
2941
  });
2904
2942
  const diagnostics = [
2905
2943
  ...collectImportDiagnostics(sourceFile, helper),
@@ -2950,13 +2988,17 @@ const analyzeModuleCore = (input, adapter, graphqlHelper) => {
2950
2988
 
2951
2989
  //#endregion
2952
2990
  //#region packages/builder/src/ast/index.ts
2953
- const createAstAnalyzer = ({ analyzer, graphqlHelper }) => {
2991
+ const createAstAnalyzer = ({ analyzer, graphqlHelper, baseDir }) => {
2954
2992
  const analyze = (input) => {
2993
+ const inputWithBaseDir = {
2994
+ ...input,
2995
+ baseDir
2996
+ };
2955
2997
  if (analyzer === "ts") {
2956
- return analyzeModuleCore(input, typescriptAdapter, graphqlHelper);
2998
+ return analyzeModuleCore(inputWithBaseDir, typescriptAdapter, graphqlHelper);
2957
2999
  }
2958
3000
  if (analyzer === "swc") {
2959
- return analyzeModuleCore(input, swcAdapter, graphqlHelper);
3001
+ return analyzeModuleCore(inputWithBaseDir, swcAdapter, graphqlHelper);
2960
3002
  }
2961
3003
  return assertUnreachable(analyzer, "createAstAnalyzer");
2962
3004
  };
@@ -3361,22 +3403,45 @@ const createDiscoveryCache = (options) => new JsonDiscoveryCache(options);
3361
3403
  /**
3362
3404
  * Extract all unique dependencies (relative + external) from the analysis.
3363
3405
  * Resolves local specifiers immediately so discovery only traverses once.
3406
+ *
3407
+ * Resolution order:
3408
+ * 1. Relative imports → resolveRelativeImportWithExistenceCheck
3409
+ * 2. Alias imports (if aliasResolver provided) → aliasResolver.resolve
3410
+ * 3. Otherwise → mark as external
3364
3411
  */
3365
- const extractModuleDependencies = (analysis) => {
3412
+ const extractModuleDependencies = ({ analysis, aliasResolver }) => {
3366
3413
  const dependencies = new Map();
3367
3414
  const addDependency = (specifier) => {
3368
3415
  if (dependencies.has(specifier)) {
3369
3416
  return;
3370
3417
  }
3371
- const isExternal = (0, __soda_gql_common.isExternalSpecifier)(specifier);
3372
- const resolvedPath = isExternal ? null : (0, __soda_gql_common.resolveRelativeImportWithExistenceCheck)({
3373
- filePath: analysis.filePath,
3374
- specifier
3375
- });
3418
+ if (!(0, __soda_gql_common.isExternalSpecifier)(specifier)) {
3419
+ const resolvedPath = (0, __soda_gql_common.resolveRelativeImportWithExistenceCheck)({
3420
+ filePath: analysis.filePath,
3421
+ specifier
3422
+ });
3423
+ dependencies.set(specifier, {
3424
+ specifier,
3425
+ resolvedPath,
3426
+ isExternal: false
3427
+ });
3428
+ return;
3429
+ }
3430
+ if (aliasResolver) {
3431
+ const resolvedPath = aliasResolver.resolve(specifier);
3432
+ if (resolvedPath) {
3433
+ dependencies.set(specifier, {
3434
+ specifier,
3435
+ resolvedPath,
3436
+ isExternal: false
3437
+ });
3438
+ return;
3439
+ }
3440
+ }
3376
3441
  dependencies.set(specifier, {
3377
3442
  specifier,
3378
- resolvedPath,
3379
- isExternal
3443
+ resolvedPath: null,
3444
+ isExternal: true
3380
3445
  });
3381
3446
  };
3382
3447
  for (const imp of analysis.imports) {
@@ -3530,10 +3595,28 @@ function clearFingerprintCache() {
3530
3595
  //#endregion
3531
3596
  //#region packages/builder/src/discovery/discoverer.ts
3532
3597
  /**
3598
+ * JavaScript file extensions that should be treated as empty modules.
3599
+ * These files are included in the dependency graph but not parsed for definitions.
3600
+ */
3601
+ const JS_FILE_EXTENSIONS = [
3602
+ ".js",
3603
+ ".mjs",
3604
+ ".cjs",
3605
+ ".jsx"
3606
+ ];
3607
+ /**
3608
+ * Check if a file path is a JavaScript file (not TypeScript).
3609
+ * Used to skip AST analysis for JS files that are resolved as fallbacks.
3610
+ */
3611
+ const isJsFile = (filePath) => {
3612
+ const ext = (0, node_path.extname)(filePath).toLowerCase();
3613
+ return JS_FILE_EXTENSIONS.includes(ext);
3614
+ };
3615
+ /**
3533
3616
  * Generator-based module discovery that yields effects for file I/O.
3534
3617
  * This allows the discovery process to be executed with either sync or async schedulers.
3535
3618
  */
3536
- function* discoverModulesGen({ entryPaths, astAnalyzer, incremental }) {
3619
+ function* discoverModulesGen({ entryPaths, astAnalyzer, aliasResolver, incremental }) {
3537
3620
  const snapshots = new Map();
3538
3621
  const stack = [...entryPaths];
3539
3622
  const changedFiles = incremental?.changedFiles ?? new Set();
@@ -3596,12 +3679,27 @@ function* discoverModulesGen({ entryPaths, astAnalyzer, incremental }) {
3596
3679
  continue;
3597
3680
  }
3598
3681
  const signature = createSourceHash(source);
3599
- const analysis = astAnalyzer.analyze({
3600
- filePath,
3601
- source
3602
- });
3682
+ let analysis;
3683
+ if (isJsFile(filePath)) {
3684
+ analysis = {
3685
+ filePath,
3686
+ signature,
3687
+ definitions: [],
3688
+ imports: [],
3689
+ exports: [],
3690
+ diagnostics: []
3691
+ };
3692
+ } else {
3693
+ analysis = astAnalyzer.analyze({
3694
+ filePath,
3695
+ source
3696
+ });
3697
+ }
3603
3698
  cacheMisses++;
3604
- const dependencies = extractModuleDependencies(analysis);
3699
+ const dependencies = extractModuleDependencies({
3700
+ analysis,
3701
+ aliasResolver
3702
+ });
3605
3703
  for (const dep of dependencies) {
3606
3704
  if (!dep.isExternal && dep.resolvedPath && !snapshots.has(dep.resolvedPath)) {
3607
3705
  stack.push(dep.resolvedPath);
@@ -3667,12 +3765,11 @@ const discoverModulesAsync = async (options) => {
3667
3765
  //#endregion
3668
3766
  //#region packages/builder/src/utils/glob.ts
3669
3767
  /**
3670
- * Cross-runtime glob pattern matching abstraction
3671
- * Provides a unified interface for glob operations across Bun and Node.js
3768
+ * Glob pattern matching using fast-glob
3672
3769
  */
3673
3770
  /**
3674
3771
  * Scan files matching glob patterns from the given directory.
3675
- * Supports negation patterns (e.g., "!**\/excluded.ts") when using fast-glob.
3772
+ * Supports negation patterns (e.g., "!**\/excluded.ts").
3676
3773
  *
3677
3774
  * @param patterns - Glob pattern(s). Can be a single pattern or array of patterns.
3678
3775
  * @param cwd - Working directory (defaults to process.cwd())
@@ -3680,18 +3777,6 @@ const discoverModulesAsync = async (options) => {
3680
3777
  */
3681
3778
  const scanGlob = (patterns, cwd = process.cwd()) => {
3682
3779
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
3683
- const hasNegation = patternArray.some((p) => p.startsWith("!"));
3684
- if (typeof Bun !== "undefined" && Bun.Glob && !hasNegation) {
3685
- const { Glob } = Bun;
3686
- const results = new Set();
3687
- for (const pattern of patternArray) {
3688
- const glob = new Glob(pattern);
3689
- for (const match of glob.scanSync(cwd)) {
3690
- results.add(match);
3691
- }
3692
- }
3693
- return Array.from(results);
3694
- }
3695
3780
  return fast_glob.default.sync(patternArray, {
3696
3781
  cwd,
3697
3782
  dot: true,
@@ -3986,7 +4071,8 @@ const createBuilderSession = (options) => {
3986
4071
  const graphqlHelper = createGraphqlSystemIdentifyHelper(config);
3987
4072
  const ensureAstAnalyzer = (0, __soda_gql_common.cachedFn)(() => createAstAnalyzer({
3988
4073
  analyzer: config.analyzer,
3989
- graphqlHelper
4074
+ graphqlHelper,
4075
+ baseDir: config.baseDir
3990
4076
  }));
3991
4077
  const ensureDiscoveryCache = (0, __soda_gql_common.cachedFn)(() => createDiscoveryCache({
3992
4078
  factory: cacheFactory,
@@ -4033,6 +4119,7 @@ const createBuilderSession = (options) => {
4033
4119
  input: {
4034
4120
  entryPaths,
4035
4121
  astAnalyzer: ensureAstAnalyzer(),
4122
+ aliasResolver: config.tsconfigPaths ? (0, __soda_gql_common.createAliasResolver)(config.tsconfigPaths) : undefined,
4036
4123
  discoveryCache: ensureDiscoveryCache(),
4037
4124
  changedFiles,
4038
4125
  removedFiles,
@@ -4155,7 +4242,7 @@ const prepare = (input) => {
4155
4242
  * This enables single scheduler control at the root level for both sync and async execution.
4156
4243
  */
4157
4244
  function* buildGen(input) {
4158
- const { entryPaths, astAnalyzer, discoveryCache, changedFiles, removedFiles, previousModuleAdjacency, previousIntermediateModules, graphqlSystemPath, graphqlHelper } = input;
4245
+ const { entryPaths, astAnalyzer, aliasResolver, discoveryCache, changedFiles, removedFiles, previousModuleAdjacency, previousIntermediateModules, graphqlSystemPath, graphqlHelper } = input;
4159
4246
  const affectedFiles = collectAffectedFiles({
4160
4247
  changedFiles,
4161
4248
  removedFiles,
@@ -4164,6 +4251,7 @@ function* buildGen(input) {
4164
4251
  const discoveryResult = yield* discoverModulesGen({
4165
4252
  entryPaths,
4166
4253
  astAnalyzer,
4254
+ aliasResolver,
4167
4255
  incremental: {
4168
4256
  cache: discoveryCache,
4169
4257
  changedFiles,
@@ -4392,4 +4480,4 @@ Object.defineProperty(exports, 'loadArtifactSync', {
4392
4480
  return loadArtifactSync;
4393
4481
  }
4394
4482
  });
4395
- //# sourceMappingURL=service-CKlB44r5.cjs.map
4483
+ //# sourceMappingURL=service-BCL5TzS7.cjs.map