@soda-gql/core 0.13.1 → 0.13.2

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
@@ -2403,220 +2403,6 @@ const createVarAssignments = (definitions, providedValues) => {
2403
2403
  */
2404
2404
  const createVarRefs = (definitions) => mapValues(definitions, (_, name) => createVarRefFromVariable(name));
2405
2405
 
2406
- //#endregion
2407
- //#region packages/core/src/composer/operation-core.ts
2408
- /**
2409
- * Core operation building logic shared by operation and extend composers.
2410
- * @module
2411
- * @internal
2412
- */
2413
- /**
2414
- * Builds an operation artifact from the provided parameters.
2415
- *
2416
- * This function contains the core logic for:
2417
- * - Creating variable refs and field factories
2418
- * - Evaluating fields with fragment usage tracking
2419
- * - Building the document
2420
- * - Handling metadata (sync and async)
2421
- * - Applying document transformations
2422
- *
2423
- * @param params - Operation building parameters
2424
- * @returns Operation artifact or Promise of artifact (if async metadata)
2425
- *
2426
- * @internal Used by operation.ts, extend.ts, and operation-tagged-template.ts
2427
- */
2428
- const buildOperationArtifact = (params) => {
2429
- const { schema, operationType, operationTypeName, operationName, variables, adapter, metadata: metadataBuilder, transformDocument: operationTransformDocument, adapterTransformDocument } = params;
2430
- const $ = createVarRefs(variables);
2431
- let document;
2432
- let variableNames;
2433
- let fields;
2434
- let fragmentUsages;
2435
- if (params.mode === "prebuilt") {
2436
- document = params.prebuiltDocument;
2437
- variableNames = params.prebuiltVariableNames ?? Object.keys(variables);
2438
- fields = {};
2439
- fragmentUsages = [];
2440
- } else {
2441
- const { fieldsFactory } = params;
2442
- const f = createFieldFactories(schema, operationTypeName);
2443
- const collected = withFragmentUsageCollection(() => fieldsFactory({
2444
- f,
2445
- $
2446
- }));
2447
- fields = collected.result;
2448
- fragmentUsages = collected.usages;
2449
- document = buildDocument({
2450
- operationName,
2451
- operationType,
2452
- operationTypeName,
2453
- variables,
2454
- fields,
2455
- schema
2456
- });
2457
- variableNames = Object.keys(variables);
2458
- }
2459
- if (!fragmentUsages.some((u) => u.metadataBuilder) && !metadataBuilder && !adapterTransformDocument && !operationTransformDocument) return {
2460
- operationType,
2461
- operationName,
2462
- schemaLabel: schema.label,
2463
- variableNames,
2464
- documentSource: () => fields,
2465
- document,
2466
- metadata: void 0
2467
- };
2468
- const aggregateFragmentMetadata = (resolvedFragmentMetadata) => {
2469
- const fragmentMetaInfos = fragmentUsages.map((usage, index) => ({
2470
- metadata: resolvedFragmentMetadata[index],
2471
- fieldPath: usage.path
2472
- }));
2473
- return adapter.aggregateFragmentMetadata(fragmentMetaInfos);
2474
- };
2475
- const fragmentMetadataResults = fragmentUsages.map((usage) => usage.metadataBuilder ? usage.metadataBuilder() : void 0);
2476
- const hasAsyncFragmentMetadata = fragmentMetadataResults.some((r) => isPromiseLike(r));
2477
- const buildOperationMetadata = (aggregatedFragmentMetadata) => {
2478
- const schemaLevel = adapter.schemaLevel;
2479
- return metadataBuilder?.({
2480
- $,
2481
- document,
2482
- fragmentMetadata: aggregatedFragmentMetadata,
2483
- schemaLevel
2484
- });
2485
- };
2486
- const makeCreateArtifact = (aggregated$1) => {
2487
- return ({ metadata }) => {
2488
- let finalDocument = operationTransformDocument ? operationTransformDocument({
2489
- document,
2490
- metadata
2491
- }) : document;
2492
- if (adapterTransformDocument) finalDocument = adapterTransformDocument({
2493
- document: finalDocument,
2494
- operationName,
2495
- operationType,
2496
- variableNames,
2497
- schemaLevel: adapter.schemaLevel,
2498
- fragmentMetadata: aggregated$1
2499
- });
2500
- return {
2501
- operationType,
2502
- operationName,
2503
- schemaLabel: schema.label,
2504
- variableNames,
2505
- documentSource: () => fields,
2506
- document: finalDocument,
2507
- metadata
2508
- };
2509
- };
2510
- };
2511
- if (hasAsyncFragmentMetadata) return Promise.all(fragmentMetadataResults).then(async (resolvedFragmentMetadata) => {
2512
- const aggregated$1 = aggregateFragmentMetadata(resolvedFragmentMetadata);
2513
- const operationMetadata = await buildOperationMetadata(aggregated$1);
2514
- return makeCreateArtifact(aggregated$1)({ metadata: operationMetadata });
2515
- });
2516
- const aggregated = aggregateFragmentMetadata(fragmentMetadataResults);
2517
- const createArtifact = makeCreateArtifact(aggregated);
2518
- const operationMetadataResult = buildOperationMetadata(aggregated);
2519
- if (isPromiseLike(operationMetadataResult)) return operationMetadataResult.then((metadata) => createArtifact({ metadata }));
2520
- return createArtifact({ metadata: operationMetadataResult });
2521
- };
2522
- /**
2523
- * Wraps a buildOperationArtifact call into an Operation.create() invocation,
2524
- * handling both sync and async artifact results.
2525
- *
2526
- * @param artifactFactory - Factory that produces the artifact (may return Promise for async metadata)
2527
- * @param overrideDocumentSource - When true, overrides documentSource to return empty object.
2528
- * Required for pre-built document mode where fields = {} and the real documentSource is meaningless.
2529
- * Must be false for fieldsFactory mode to preserve real field selections.
2530
- *
2531
- * @internal Used by extend.ts and operation-tagged-template.ts
2532
- */
2533
- const wrapArtifactAsOperation = (artifactFactory, overrideDocumentSource) => {
2534
- return Operation.create((() => {
2535
- const artifact = artifactFactory();
2536
- if (overrideDocumentSource) {
2537
- if (isPromiseLike(artifact)) return artifact.then((a) => ({
2538
- ...a,
2539
- documentSource: () => ({})
2540
- }));
2541
- return {
2542
- ...artifact,
2543
- documentSource: () => ({})
2544
- };
2545
- }
2546
- if (isPromiseLike(artifact)) return artifact;
2547
- return artifact;
2548
- }));
2549
- };
2550
-
2551
- //#endregion
2552
- //#region packages/core/src/composer/extend.ts
2553
- /**
2554
- * Extend composer factory for creating Operations from compat specs.
2555
- * @module
2556
- */
2557
- /**
2558
- * Creates a factory for extending compat specs into full operations.
2559
- *
2560
- * The extend function takes a compat spec (created by `query.compat()`) and
2561
- * optional metadata/transformDocument options, then creates a full Operation.
2562
- *
2563
- * @param schema - The GraphQL schema definition
2564
- * @param adapter - Optional metadata adapter for custom metadata handling
2565
- * @param transformDocument - Optional document transformer
2566
- * @returns Extend composer function
2567
- *
2568
- * @internal Used by `createGqlElementComposer`
2569
- */
2570
- const createExtendComposer = (schema, adapter, transformDocument) => {
2571
- const resolvedAdapter = adapter ?? defaultMetadataAdapter;
2572
- return (compat, options) => {
2573
- const spec = compat.value;
2574
- if (isTemplateCompatSpec(spec)) return buildOperationFromTemplateSpec(schema, spec, resolvedAdapter, options, transformDocument);
2575
- const { operationType, operationName, variables, fieldsBuilder } = spec;
2576
- const operationTypeName = schema.operations[operationType];
2577
- return Operation.create((() => buildOperationArtifact({
2578
- mode: "fieldsFactory",
2579
- schema,
2580
- operationType,
2581
- operationTypeName,
2582
- operationName,
2583
- variables,
2584
- fieldsFactory: fieldsBuilder,
2585
- adapter: resolvedAdapter,
2586
- metadata: options?.metadata,
2587
- transformDocument: options?.transformDocument,
2588
- adapterTransformDocument: transformDocument
2589
- })));
2590
- };
2591
- };
2592
- /**
2593
- * Builds an Operation from a TemplateCompatSpec by parsing the raw GraphQL source.
2594
- * Delegates to buildOperationArtifact with pre-built document mode.
2595
- */
2596
- const buildOperationFromTemplateSpec = (schema, spec, adapter, options, adapterTransformDocument) => {
2597
- const { operationType, operationName, graphqlSource } = spec;
2598
- const document = (0, graphql.parse)(graphqlSource);
2599
- const opDef = document.definitions.find((d) => d.kind === graphql.Kind.OPERATION_DEFINITION);
2600
- if (!opDef) throw new Error("No operation definition found in compat template spec");
2601
- const schemaIndex = createSchemaIndexFromSchema(spec.schema);
2602
- const varSpecifiers = buildVarSpecifiers(opDef.variableDefinitions ?? [], schemaIndex);
2603
- const operationTypeName = schema.operations[operationType];
2604
- return wrapArtifactAsOperation(() => buildOperationArtifact({
2605
- mode: "prebuilt",
2606
- schema,
2607
- operationType,
2608
- operationTypeName,
2609
- operationName,
2610
- variables: varSpecifiers,
2611
- prebuiltDocument: document,
2612
- prebuiltVariableNames: Object.keys(varSpecifiers),
2613
- adapter,
2614
- metadata: options?.metadata,
2615
- transformDocument: options?.transformDocument,
2616
- adapterTransformDocument
2617
- }), true);
2618
- };
2619
-
2620
2406
  //#endregion
2621
2407
  //#region packages/core/src/composer/merge-variable-definitions.ts
2622
2408
  /**
@@ -2680,6 +2466,30 @@ function extractFragmentVariables(rawSource, schemaIndex) {
2680
2466
  return buildVarSpecifiers(opDef.variableDefinitions ?? [], schemaIndex);
2681
2467
  }
2682
2468
  /**
2469
+ * Filters out named fragment spreads that cannot be resolved without an interpolation map.
2470
+ * Used when building fields from compat templates or zero-interpolation tagged templates
2471
+ * that may contain standard GraphQL `...FragmentName` spreads.
2472
+ */
2473
+ function filterUnresolvedFragmentSpreads(selectionSet, interpolationMap) {
2474
+ return {
2475
+ ...selectionSet,
2476
+ selections: selectionSet.selections.filter((sel) => {
2477
+ if (sel.kind !== graphql.Kind.FRAGMENT_SPREAD) return true;
2478
+ return interpolationMap?.has(sel.name.value) ?? false;
2479
+ }).map((sel) => {
2480
+ if (sel.kind === graphql.Kind.FIELD && sel.selectionSet) return {
2481
+ ...sel,
2482
+ selectionSet: filterUnresolvedFragmentSpreads(sel.selectionSet, interpolationMap)
2483
+ };
2484
+ if (sel.kind === graphql.Kind.INLINE_FRAGMENT && sel.selectionSet) return {
2485
+ ...sel,
2486
+ selectionSet: filterUnresolvedFragmentSpreads(sel.selectionSet, interpolationMap)
2487
+ };
2488
+ return sel;
2489
+ })
2490
+ };
2491
+ }
2492
+ /**
2683
2493
  * Builds field selections from a GraphQL AST SelectionSet by driving field factories.
2684
2494
  * Converts parsed AST selections into the AnyFieldsExtended format that the document builder expects.
2685
2495
  * Also used by typegen for static field extraction from tagged templates.
@@ -2882,6 +2692,191 @@ function createFragmentTaggedTemplate(schema) {
2882
2692
  };
2883
2693
  }
2884
2694
 
2695
+ //#endregion
2696
+ //#region packages/core/src/composer/operation-core.ts
2697
+ /**
2698
+ * Core operation building logic shared by operation and extend composers.
2699
+ * @module
2700
+ * @internal
2701
+ */
2702
+ /**
2703
+ * Builds an operation artifact from the provided parameters.
2704
+ *
2705
+ * This function contains the core logic for:
2706
+ * - Creating variable refs and field factories
2707
+ * - Evaluating fields with fragment usage tracking
2708
+ * - Building the document
2709
+ * - Handling metadata (sync and async)
2710
+ * - Applying document transformations
2711
+ *
2712
+ * @param params - Operation building parameters
2713
+ * @returns Operation artifact or Promise of artifact (if async metadata)
2714
+ *
2715
+ * @internal Used by operation.ts, extend.ts, and operation-tagged-template.ts
2716
+ */
2717
+ const buildOperationArtifact = (params) => {
2718
+ const { schema, operationType, operationTypeName, operationName, variables, adapter, metadata: metadataBuilder, transformDocument: operationTransformDocument, adapterTransformDocument } = params;
2719
+ const $ = createVarRefs(variables);
2720
+ const { fieldsFactory } = params;
2721
+ const f = createFieldFactories(schema, operationTypeName);
2722
+ const collected = withFragmentUsageCollection(() => fieldsFactory({
2723
+ f,
2724
+ $
2725
+ }));
2726
+ const fields = collected.result;
2727
+ const fragmentUsages = collected.usages;
2728
+ const document = buildDocument({
2729
+ operationName,
2730
+ operationType,
2731
+ operationTypeName,
2732
+ variables,
2733
+ fields,
2734
+ schema
2735
+ });
2736
+ const variableNames = Object.keys(variables);
2737
+ if (!fragmentUsages.some((u) => u.metadataBuilder) && !metadataBuilder && !adapterTransformDocument && !operationTransformDocument) return {
2738
+ operationType,
2739
+ operationName,
2740
+ schemaLabel: schema.label,
2741
+ variableNames,
2742
+ documentSource: () => fields,
2743
+ document,
2744
+ metadata: void 0
2745
+ };
2746
+ const aggregateFragmentMetadata = (resolvedFragmentMetadata) => {
2747
+ const fragmentMetaInfos = fragmentUsages.map((usage, index) => ({
2748
+ metadata: resolvedFragmentMetadata[index],
2749
+ fieldPath: usage.path
2750
+ }));
2751
+ return adapter.aggregateFragmentMetadata(fragmentMetaInfos);
2752
+ };
2753
+ const fragmentMetadataResults = fragmentUsages.map((usage) => usage.metadataBuilder ? usage.metadataBuilder() : void 0);
2754
+ const hasAsyncFragmentMetadata = fragmentMetadataResults.some((r) => isPromiseLike(r));
2755
+ const buildOperationMetadata = (aggregatedFragmentMetadata) => {
2756
+ const schemaLevel = adapter.schemaLevel;
2757
+ return metadataBuilder?.({
2758
+ $,
2759
+ document,
2760
+ fragmentMetadata: aggregatedFragmentMetadata,
2761
+ schemaLevel
2762
+ });
2763
+ };
2764
+ const makeCreateArtifact = (aggregated$1) => {
2765
+ return ({ metadata }) => {
2766
+ let finalDocument = operationTransformDocument ? operationTransformDocument({
2767
+ document,
2768
+ metadata
2769
+ }) : document;
2770
+ if (adapterTransformDocument) finalDocument = adapterTransformDocument({
2771
+ document: finalDocument,
2772
+ operationName,
2773
+ operationType,
2774
+ variableNames,
2775
+ schemaLevel: adapter.schemaLevel,
2776
+ fragmentMetadata: aggregated$1
2777
+ });
2778
+ return {
2779
+ operationType,
2780
+ operationName,
2781
+ schemaLabel: schema.label,
2782
+ variableNames,
2783
+ documentSource: () => fields,
2784
+ document: finalDocument,
2785
+ metadata
2786
+ };
2787
+ };
2788
+ };
2789
+ if (hasAsyncFragmentMetadata) return Promise.all(fragmentMetadataResults).then(async (resolvedFragmentMetadata) => {
2790
+ const aggregated$1 = aggregateFragmentMetadata(resolvedFragmentMetadata);
2791
+ const operationMetadata = await buildOperationMetadata(aggregated$1);
2792
+ return makeCreateArtifact(aggregated$1)({ metadata: operationMetadata });
2793
+ });
2794
+ const aggregated = aggregateFragmentMetadata(fragmentMetadataResults);
2795
+ const createArtifact = makeCreateArtifact(aggregated);
2796
+ const operationMetadataResult = buildOperationMetadata(aggregated);
2797
+ if (isPromiseLike(operationMetadataResult)) return operationMetadataResult.then((metadata) => createArtifact({ metadata }));
2798
+ return createArtifact({ metadata: operationMetadataResult });
2799
+ };
2800
+ /**
2801
+ * Wraps a buildOperationArtifact call into an Operation.create() invocation,
2802
+ * handling both sync and async artifact results.
2803
+ *
2804
+ * @param artifactFactory - Factory that produces the artifact (may return Promise for async metadata)
2805
+ *
2806
+ * @internal Used by extend.ts and operation-tagged-template.ts
2807
+ */
2808
+ const wrapArtifactAsOperation = (artifactFactory) => {
2809
+ return Operation.create(artifactFactory);
2810
+ };
2811
+
2812
+ //#endregion
2813
+ //#region packages/core/src/composer/extend.ts
2814
+ /**
2815
+ * Extend composer factory for creating Operations from compat specs.
2816
+ * @module
2817
+ */
2818
+ /**
2819
+ * Creates a factory for extending compat specs into full operations.
2820
+ *
2821
+ * The extend function takes a compat spec (created by `query.compat()`) and
2822
+ * optional metadata/transformDocument options, then creates a full Operation.
2823
+ *
2824
+ * @param schema - The GraphQL schema definition
2825
+ * @param adapter - Optional metadata adapter for custom metadata handling
2826
+ * @param transformDocument - Optional document transformer
2827
+ * @returns Extend composer function
2828
+ *
2829
+ * @internal Used by `createGqlElementComposer`
2830
+ */
2831
+ const createExtendComposer = (schema, adapter, transformDocument) => {
2832
+ const resolvedAdapter = adapter ?? defaultMetadataAdapter;
2833
+ return (compat, options) => {
2834
+ const spec = compat.value;
2835
+ if (isTemplateCompatSpec(spec)) return buildOperationFromTemplateSpec(schema, spec, resolvedAdapter, options, transformDocument);
2836
+ const { operationType, operationName, variables, fieldsBuilder } = spec;
2837
+ const operationTypeName = schema.operations[operationType];
2838
+ return Operation.create((() => buildOperationArtifact({
2839
+ schema,
2840
+ operationType,
2841
+ operationTypeName,
2842
+ operationName,
2843
+ variables,
2844
+ fieldsFactory: fieldsBuilder,
2845
+ adapter: resolvedAdapter,
2846
+ metadata: options?.metadata,
2847
+ transformDocument: options?.transformDocument,
2848
+ adapterTransformDocument: transformDocument
2849
+ })));
2850
+ };
2851
+ };
2852
+ /**
2853
+ * Builds an Operation from a TemplateCompatSpec by parsing the raw GraphQL source.
2854
+ * Evaluates fields via buildFieldsFromSelectionSet for correct typegen output.
2855
+ */
2856
+ const buildOperationFromTemplateSpec = (schema, spec, adapter, options, adapterTransformDocument) => {
2857
+ const { operationType, operationName, graphqlSource } = spec;
2858
+ const opDef = (0, graphql.parse)(graphqlSource).definitions.find((d) => d.kind === graphql.Kind.OPERATION_DEFINITION);
2859
+ if (!opDef) throw new Error("No operation definition found in compat template spec");
2860
+ const schemaIndex = createSchemaIndexFromSchema(spec.schema);
2861
+ const varSpecifiers = buildVarSpecifiers(opDef.variableDefinitions ?? [], schemaIndex);
2862
+ const operationTypeName = schema.operations[operationType];
2863
+ const filteredSelectionSet = filterUnresolvedFragmentSpreads(opDef.selectionSet);
2864
+ return wrapArtifactAsOperation(() => buildOperationArtifact({
2865
+ schema,
2866
+ operationType,
2867
+ operationTypeName,
2868
+ operationName,
2869
+ variables: varSpecifiers,
2870
+ fieldsFactory: ({ $ }) => {
2871
+ return buildFieldsFromSelectionSet(filteredSelectionSet, schema, operationTypeName, $);
2872
+ },
2873
+ adapter,
2874
+ metadata: options?.metadata,
2875
+ transformDocument: options?.transformDocument,
2876
+ adapterTransformDocument
2877
+ }));
2878
+ };
2879
+
2885
2880
  //#endregion
2886
2881
  //#region packages/core/src/composer/operation.ts
2887
2882
  /**
@@ -2911,7 +2906,6 @@ const createOperationComposerFactory = (schema, adapter, transformDocument) => {
2911
2906
  if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
2912
2907
  return (options) => {
2913
2908
  return Operation.create((() => buildOperationArtifact({
2914
- mode: "fieldsFactory",
2915
2909
  schema,
2916
2910
  operationType,
2917
2911
  operationTypeName,
@@ -2996,33 +2990,19 @@ const createOperationTaggedTemplate = (schema, operationType, metadataAdapter, a
2996
2990
  const resolvedAdapter = metadataAdapter ?? defaultMetadataAdapter;
2997
2991
  return (options) => {
2998
2992
  const resolvedMetadata = resolveMetadataOption(options?.metadata);
2999
- if (interpolationMap.size === 0) return wrapArtifactAsOperation(() => buildOperationArtifact({
3000
- mode: "prebuilt",
3001
- schema,
3002
- operationType,
3003
- operationTypeName,
3004
- operationName,
3005
- variables: varSpecifiers,
3006
- prebuiltDocument: document,
3007
- prebuiltVariableNames: Object.keys(varSpecifiers),
3008
- adapter: resolvedAdapter,
3009
- metadata: resolvedMetadata,
3010
- adapterTransformDocument
3011
- }), true);
3012
2993
  return wrapArtifactAsOperation(() => buildOperationArtifact({
3013
- mode: "fieldsFactory",
3014
2994
  schema,
3015
2995
  operationType,
3016
2996
  operationTypeName,
3017
2997
  operationName,
3018
2998
  variables: varSpecifiers,
3019
2999
  fieldsFactory: ({ $ }) => {
3020
- return buildFieldsFromSelectionSet(opNode.selectionSet, schema, operationTypeName, $, interpolationMap);
3000
+ return buildFieldsFromSelectionSet(filterUnresolvedFragmentSpreads(opNode.selectionSet, interpolationMap), schema, operationTypeName, $, interpolationMap);
3021
3001
  },
3022
3002
  adapter: resolvedAdapter,
3023
3003
  metadata: resolvedMetadata,
3024
3004
  adapterTransformDocument
3025
- }), false);
3005
+ }));
3026
3006
  };
3027
3007
  };
3028
3008
  };
@@ -3668,6 +3648,7 @@ exports.defineOperationRoots = require_schema_builder.defineOperationRoots;
3668
3648
  exports.defineScalar = require_schema_builder.defineScalar;
3669
3649
  exports.err = err;
3670
3650
  exports.extractFragmentVariables = extractFragmentVariables;
3651
+ exports.filterUnresolvedFragmentSpreads = filterUnresolvedFragmentSpreads;
3671
3652
  exports.generateInputObjectType = generateInputObjectType;
3672
3653
  exports.generateInputType = generateInputType;
3673
3654
  exports.generateInputTypeFromSpecifiers = generateInputTypeFromSpecifiers;