@soda-gql/core 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +39 -39
  2. package/dist/adapter.cjs +1 -3
  3. package/dist/adapter.cjs.map +1 -1
  4. package/dist/adapter.d.cts +3 -5
  5. package/dist/adapter.d.cts.map +1 -1
  6. package/dist/adapter.d.ts +3 -5
  7. package/dist/adapter.d.ts.map +1 -1
  8. package/dist/adapter.js +1 -3
  9. package/dist/adapter.js.map +1 -1
  10. package/dist/{index-PnGDsBZE.d.cts → index-Bdt5dpFG.d.cts} +26 -5
  11. package/dist/{index-PnGDsBZE.d.cts.map → index-Bdt5dpFG.d.cts.map} +1 -1
  12. package/dist/{index-Dl3Md53A.d.ts → index-CRWc3q9X.d.cts} +300 -626
  13. package/dist/index-CRWc3q9X.d.cts.map +1 -0
  14. package/dist/{index-CcqI7_ms.d.ts → index-D1T79XaT.d.ts} +26 -5
  15. package/dist/{index-CcqI7_ms.d.ts.map → index-D1T79XaT.d.ts.map} +1 -1
  16. package/dist/{index-Ctr8gcP8.d.cts → index-DJ-yqsXz.d.ts} +300 -626
  17. package/dist/index-DJ-yqsXz.d.ts.map +1 -0
  18. package/dist/index.cjs +609 -700
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +9 -4
  21. package/dist/index.d.cts.map +1 -1
  22. package/dist/index.d.ts +9 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +602 -696
  25. package/dist/index.js.map +1 -1
  26. package/dist/runtime.d.cts +2 -2
  27. package/dist/runtime.d.ts +2 -2
  28. package/dist/{schema-builder-B0DcWTQ-.d.ts → schema-builder-DTinHI5s.d.ts} +2 -2
  29. package/dist/{schema-builder-B0DcWTQ-.d.ts.map → schema-builder-DTinHI5s.d.ts.map} +1 -1
  30. package/dist/{schema-builder-C7bceM7O.d.cts → schema-builder-DfdeJY7k.d.cts} +2 -2
  31. package/dist/{schema-builder-C7bceM7O.d.cts.map → schema-builder-DfdeJY7k.d.cts.map} +1 -1
  32. package/package.json +1 -1
  33. package/dist/index-Ctr8gcP8.d.cts.map +0 -1
  34. package/dist/index-Dl3Md53A.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -195,7 +195,7 @@ const buildArgumentValue = (value, enumLookup) => {
195
195
  fields: Object.entries(value).map(([key, fieldValue]) => {
196
196
  let fieldTypeSpecifier = null;
197
197
  if (enumLookup.typeSpecifier?.kind === "input") {
198
- const fieldSpec = enumLookup.schema.input[enumLookup.typeSpecifier.name]?.fields[key];
198
+ const fieldSpec = (enumLookup.schema.input?.[enumLookup.typeSpecifier.name])?.fields[key];
199
199
  fieldTypeSpecifier = fieldSpec ? parseInputSpecifier(fieldSpec) : null;
200
200
  }
201
201
  const valueNode = buildArgumentValue(fieldValue, {
@@ -323,12 +323,12 @@ const isShorthand = (value) => {
323
323
  const expandShorthand = (schema, typeName, fieldName) => {
324
324
  const typeDef = schema.object[typeName];
325
325
  if (!typeDef) throw new Error(`Type "${typeName}" not found in schema`);
326
- const fieldSpec = typeDef.fields[fieldName];
327
- if (!fieldSpec) throw new Error(`Field "${fieldName}" not found on type "${typeName}"`);
326
+ const fieldDef = typeDef.fields[fieldName];
327
+ if (!fieldDef) throw new Error(`Field "${fieldName}" not found on type "${typeName}"`);
328
328
  return {
329
329
  parent: typeName,
330
330
  field: fieldName,
331
- type: fieldSpec,
331
+ type: typeof fieldDef === "string" ? fieldDef : fieldDef.spec,
332
332
  args: {},
333
333
  directives: [],
334
334
  object: null,
@@ -337,8 +337,10 @@ const expandShorthand = (schema, typeName, fieldName) => {
337
337
  };
338
338
  const buildUnionSelection = (union, schema) => {
339
339
  const { selections, __typename: hasTypenameFlag } = union;
340
- const inlineFragments = Object.entries(selections).map(([typeName, object]) => {
341
- if (!object || typeof object !== "object") return null;
340
+ const inlineFragments = Object.entries(selections).map(([typeName, member]) => {
341
+ if (!member || typeof member !== "object") return null;
342
+ const { fields, directives: memberDirectives } = member;
343
+ const builtDirectives = buildDirectives(memberDirectives, "INLINE_FRAGMENT", schema);
342
344
  return {
343
345
  kind: graphql.Kind.INLINE_FRAGMENT,
344
346
  typeCondition: {
@@ -348,9 +350,10 @@ const buildUnionSelection = (union, schema) => {
348
350
  value: typeName
349
351
  }
350
352
  },
353
+ ...builtDirectives.length > 0 ? { directives: builtDirectives } : {},
351
354
  selectionSet: {
352
355
  kind: graphql.Kind.SELECTION_SET,
353
- selections: buildField(object, schema, typeName)
356
+ selections: buildField(fields, schema, typeName)
354
357
  }
355
358
  };
356
359
  }).filter((item) => item !== null);
@@ -426,7 +429,7 @@ const buildConstValueNode = (value, enumLookup) => {
426
429
  fields: Object.entries(value).map(([key, fieldValue]) => {
427
430
  let fieldTypeSpecifier = null;
428
431
  if (enumLookup.typeSpecifier?.kind === "input") {
429
- const fieldSpec = enumLookup.schema.input[enumLookup.typeSpecifier.name]?.fields[key];
432
+ const fieldSpec = (enumLookup.schema.input?.[enumLookup.typeSpecifier.name])?.fields[key];
430
433
  fieldTypeSpecifier = fieldSpec ? parseInputSpecifier(fieldSpec) : null;
431
434
  }
432
435
  const valueNode = buildConstValueNode(fieldValue, {
@@ -470,10 +473,10 @@ const buildConstValueNode = (value, enumLookup) => {
470
473
  * followed by `[]?` or `[]!` pairs for lists.
471
474
  *
472
475
  * @example
473
- * - `"!"` `String!`
474
- * - `"?"` `String`
475
- * - `"![]!"` `[String!]!`
476
- * - `"?[]?"` `[String]`
476
+ * - `"!"` -> `String!`
477
+ * - `"?"` -> `String`
478
+ * - `"![]!"` -> `[String!]!`
479
+ * - `"?[]?"` -> `[String]`
477
480
  */
478
481
  const buildWithTypeModifier = (modifier, buildType) => {
479
482
  const baseType = buildType();
@@ -532,6 +535,10 @@ const buildWithTypeModifier = (modifier, buildType) => {
532
535
  }
533
536
  return curr.type;
534
537
  };
538
+ /**
539
+ * Builds VariableDefinitionNode[] from VarSpecifier records.
540
+ * Kept as private fallback for callers that don't provide pre-parsed nodes.
541
+ */
535
542
  const buildVariables = (variables, schema) => {
536
543
  return Object.entries(variables).map(([name, varSpec]) => {
537
544
  let defaultValue;
@@ -589,7 +596,8 @@ const buildOperationTypeNode = (operation) => {
589
596
  * @returns TypedDocumentNode with inferred input/output types
590
597
  */
591
598
  const buildDocument = (options) => {
592
- const { operationName, operationType, operationTypeName, variables, fields, schema } = options;
599
+ const { operationName, operationType, operationTypeName, variableDefinitionNodes, variables, fields, schema } = options;
600
+ const varDefs = variableDefinitionNodes ?? buildVariables(variables, schema);
593
601
  return {
594
602
  kind: graphql.Kind.DOCUMENT,
595
603
  definitions: [{
@@ -599,7 +607,7 @@ const buildDocument = (options) => {
599
607
  kind: graphql.Kind.NAME,
600
608
  value: operationName
601
609
  },
602
- variableDefinitions: buildVariables(variables, schema),
610
+ variableDefinitions: varDefs,
603
611
  selectionSet: {
604
612
  kind: graphql.Kind.SELECTION_SET,
605
613
  selections: buildField(fields, schema, operationTypeName)
@@ -620,13 +628,13 @@ const buildDocument = (options) => {
620
628
  * @example
621
629
  * ```typescript
622
630
  * // In operation definition
623
- * query.operation({
624
- * name: "GetData",
625
- * fields: ({ $ }) => $colocate({
626
- * userCard: userCardFragment.spread({ userId: $.userId }),
627
- * posts: postsFragment.spread({ userId: $.userId }),
631
+ * query("GetData")({
632
+ * variables: `($userId: ID!)`,
633
+ * fields: ({ f, $ }) => $colocate({
634
+ * userCard: { ...f("user", { id: $.userId })(() => ({ ...userCardFragment.spread() })) },
635
+ * posts: { ...f("posts", { userId: $.userId })(() => ({ ...postsFragment.spread() })) },
628
636
  * }),
629
- * });
637
+ * })({});
630
638
  *
631
639
  * // In parser definition (same labels)
632
640
  * createExecutionResultParser({
@@ -646,16 +654,6 @@ const createColocateHelper = () => {
646
654
  return $colocate;
647
655
  };
648
656
 
649
- //#endregion
650
- //#region packages/core/src/types/element/compat-spec.ts
651
- /**
652
- * Type guard to distinguish TemplateCompatSpec from CompatSpec at runtime.
653
- * Uses structural discrimination (presence of `graphqlSource` field).
654
- */
655
- const isTemplateCompatSpec = (spec) => {
656
- return "graphqlSource" in spec && !("fieldsBuilder" in spec);
657
- };
658
-
659
657
  //#endregion
660
658
  //#region packages/core/src/utils/promise.ts
661
659
  /**
@@ -884,7 +882,7 @@ var GqlDefine = class GqlDefine extends GqlElement {
884
882
  /**
885
883
  * Represents a reusable GraphQL field selection on a specific type.
886
884
  *
887
- * Fragments are created via `gql(({ fragment }) => fragment.TypeName({ ... }))`.
885
+ * Fragments are created via `gql(({ fragment }) => fragment("Name", "TypeName")\`{ ... }\`())`.
888
886
  * Use `spread()` to include the fragment's fields in an operation.
889
887
  *
890
888
  * @template TTypeName - The GraphQL type this fragment selects from
@@ -934,7 +932,7 @@ var Fragment = class Fragment extends GqlElement {
934
932
  /**
935
933
  * Represents a GraphQL operation (query, mutation, or subscription).
936
934
  *
937
- * Operations are created via `gql(({ query }) => query.operation({ ... }))`.
935
+ * Operations are created via `gql(({ query }) => query("Name")\`{ ... }\`())`.
938
936
  * Produces a TypedDocumentNode for type-safe execution with GraphQL clients.
939
937
  *
940
938
  * @template TOperationType - 'query' | 'mutation' | 'subscription'
@@ -989,42 +987,10 @@ var Operation = class Operation extends GqlElement {
989
987
  }
990
988
  };
991
989
 
992
- //#endregion
993
- //#region packages/core/src/composer/compat.ts
994
- /**
995
- * Compat composer factory for creating GraphQL operation specifications.
996
- * @module
997
- */
998
- /**
999
- * Creates a factory for composing compat operation specifications.
1000
- *
1001
- * Returns a function that creates a `GqlDefine<CompatSpec<...>>` storing
1002
- * the operation specification with unevaluated fieldsBuilder.
1003
- *
1004
- * @param schema - The GraphQL schema definition
1005
- * @param operationType - The operation type ('query' | 'mutation' | 'subscription')
1006
- * @returns Compat operation composer function
1007
- *
1008
- * @internal Used by `createGqlElementComposer`
1009
- */
1010
- const createCompatComposer = (schema, operationType) => {
1011
- if (schema.operations[operationType] === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
1012
- return (options) => {
1013
- return GqlDefine.create(() => ({
1014
- schema,
1015
- operationType,
1016
- operationName: options.name,
1017
- variables: options.variables ?? {},
1018
- fieldsBuilder: options.fields
1019
- }));
1020
- };
1021
- };
1022
-
1023
990
  //#endregion
1024
991
  //#region packages/core/src/composer/compat-tagged-template.ts
1025
992
  /**
1026
993
  * Compat tagged template function for creating deferred GraphQL operation specs.
1027
- * Callback builder compat path is in compat.ts.
1028
994
  * @module
1029
995
  */
1030
996
  /**
@@ -2231,14 +2197,14 @@ const ensureCacheMapBySchema = (schema) => {
2231
2197
  return cacheMap;
2232
2198
  };
2233
2199
  /**
2234
- * Creates field selection factories for a given object type.
2200
+ * Creates a field accessor function for a given object type.
2235
2201
  *
2236
- * Returns an object with a factory for each field defined on the type.
2202
+ * Returns a function f("fieldName", args, extras) for building field selections.
2237
2203
  * Factories are cached per schema+type to avoid recreation.
2238
2204
  *
2239
2205
  * @param schema - The GraphQL schema definition
2240
2206
  * @param typeName - The object type name to create factories for
2241
- * @returns Object mapping field names to their selection factories
2207
+ * @returns FieldAccessorFunction for building field selections
2242
2208
  *
2243
2209
  * @internal Used by operation and fragment composers
2244
2210
  */
@@ -2246,70 +2212,88 @@ const createFieldFactories = (schema, typeName) => {
2246
2212
  const cacheMap = ensureCacheMapBySchema(schema);
2247
2213
  const cached = cacheMap.get(typeName);
2248
2214
  if (cached) return cached;
2249
- const factories = createFieldFactoriesInner(schema, typeName);
2250
- cacheMap.set(typeName, factories);
2251
- return factories;
2215
+ const factory = createFieldFactoriesInner(schema, typeName);
2216
+ cacheMap.set(typeName, factory);
2217
+ return factory;
2252
2218
  };
2253
2219
  const createFieldFactoriesInner = (schema, typeName) => {
2254
2220
  const typeDef = schema.object[typeName];
2255
2221
  if (!typeDef) throw new Error(`Type ${typeName} is not defined in schema objects`);
2256
- const entries = Object.entries(typeDef.fields).map(([fieldName, typeSpecifier]) => {
2222
+ return (fieldName, fieldArgs, extras) => {
2223
+ if (fieldName === "__typename") {
2224
+ const wrap$1 = (value) => require_schema_builder.wrapByKey(extras?.alias ?? fieldName, value);
2225
+ return (() => wrap$1({
2226
+ parent: typeName,
2227
+ field: fieldName,
2228
+ type: "s|String|!",
2229
+ args: {},
2230
+ directives: extras?.directives ?? [],
2231
+ object: null,
2232
+ union: null
2233
+ }));
2234
+ }
2235
+ const fieldDef = typeDef.fields[fieldName];
2236
+ if (!fieldDef) throw new Error(`Field "${fieldName}" is not defined on type "${typeName}"`);
2237
+ const typeSpecifier = typeof fieldDef === "string" ? fieldDef : fieldDef.spec;
2257
2238
  const parsedType = parseOutputField(typeSpecifier);
2258
- const factory = (fieldArgs, extras) => {
2259
- const wrap = (value) => require_schema_builder.wrapByKey(extras?.alias ?? fieldName, value);
2260
- const directives = extras?.directives ?? [];
2261
- if (parsedType.kind === "object") {
2262
- const factoryReturn = ((nest) => {
2263
- const nestedFields = withFieldPath(appendToPath(getCurrentFieldPath(), {
2264
- field: fieldName,
2265
- parentType: typeName,
2266
- isList: isListType(parsedType.modifier)
2267
- }), () => nest({ f: createFieldFactories(schema, parsedType.name) }));
2268
- return wrap({
2269
- parent: typeName,
2270
- field: fieldName,
2271
- type: typeSpecifier,
2272
- args: fieldArgs ?? {},
2273
- directives,
2274
- object: nestedFields,
2275
- union: null
2276
- });
2239
+ const wrap = (value) => require_schema_builder.wrapByKey(extras?.alias ?? fieldName, value);
2240
+ const directives = extras?.directives ?? [];
2241
+ if (parsedType.kind === "object") {
2242
+ const factoryReturn = ((nest) => {
2243
+ const nestedFields = withFieldPath(appendToPath(getCurrentFieldPath(), {
2244
+ field: fieldName,
2245
+ parentType: typeName,
2246
+ isList: isListType(parsedType.modifier)
2247
+ }), () => nest({ f: createFieldFactories(schema, parsedType.name) }));
2248
+ return wrap({
2249
+ parent: typeName,
2250
+ field: fieldName,
2251
+ type: typeSpecifier,
2252
+ args: fieldArgs ?? {},
2253
+ directives,
2254
+ object: nestedFields,
2255
+ union: null
2277
2256
  });
2278
- return factoryReturn;
2279
- }
2280
- if (parsedType.kind === "union") {
2281
- const factoryReturn = ((nest) => {
2282
- const newPath = appendToPath(getCurrentFieldPath(), {
2283
- field: fieldName,
2284
- parentType: typeName,
2285
- isList: isListType(parsedType.modifier)
2286
- });
2287
- const typenameFlag = nest.__typename;
2288
- const selections = withFieldPath(newPath, () => {
2289
- const result = {};
2290
- for (const [memberName, builder] of Object.entries(nest)) {
2291
- if (memberName === "__typename") continue;
2292
- if (typeof builder !== "function") continue;
2293
- result[memberName] = builder({ f: createFieldFactories(schema, memberName) });
2294
- }
2295
- return result;
2296
- });
2297
- return wrap({
2298
- parent: typeName,
2299
- field: fieldName,
2300
- type: typeSpecifier,
2301
- args: fieldArgs ?? {},
2302
- directives,
2303
- object: null,
2304
- union: {
2305
- selections,
2306
- __typename: typenameFlag === true
2307
- }
2308
- });
2257
+ });
2258
+ return factoryReturn;
2259
+ }
2260
+ if (parsedType.kind === "union") {
2261
+ const factoryReturn = ((nest) => {
2262
+ const newPath = appendToPath(getCurrentFieldPath(), {
2263
+ field: fieldName,
2264
+ parentType: typeName,
2265
+ isList: isListType(parsedType.modifier)
2309
2266
  });
2310
- return factoryReturn;
2311
- }
2312
- if (parsedType.kind === "scalar" || parsedType.kind === "enum") return wrap({
2267
+ const typenameFlag = nest.__typename;
2268
+ const selections = withFieldPath(newPath, () => {
2269
+ const result = {};
2270
+ for (const [memberName, builder] of Object.entries(nest)) {
2271
+ if (memberName === "__typename") continue;
2272
+ if (typeof builder === "function") result[memberName] = {
2273
+ fields: builder({ f: createFieldFactories(schema, memberName) }),
2274
+ directives: []
2275
+ };
2276
+ else if (builder && typeof builder === "object" && "fields" in builder) result[memberName] = builder;
2277
+ }
2278
+ return result;
2279
+ });
2280
+ return wrap({
2281
+ parent: typeName,
2282
+ field: fieldName,
2283
+ type: typeSpecifier,
2284
+ args: fieldArgs ?? {},
2285
+ directives,
2286
+ object: null,
2287
+ union: {
2288
+ selections,
2289
+ __typename: typenameFlag === true
2290
+ }
2291
+ });
2292
+ });
2293
+ return factoryReturn;
2294
+ }
2295
+ if (parsedType.kind === "scalar" || parsedType.kind === "enum") {
2296
+ const factoryReturn = (() => wrap({
2313
2297
  parent: typeName,
2314
2298
  field: fieldName,
2315
2299
  type: typeSpecifier,
@@ -2317,12 +2301,11 @@ const createFieldFactoriesInner = (schema, typeName) => {
2317
2301
  directives,
2318
2302
  object: null,
2319
2303
  union: null
2320
- });
2321
- throw new Error(`Unsupported field type kind: ${parsedType.kind}`);
2322
- };
2323
- return [fieldName, factory];
2324
- });
2325
- return Object.fromEntries(entries);
2304
+ }));
2305
+ return factoryReturn;
2306
+ }
2307
+ throw new Error(`Unsupported field type kind: ${parsedType.kind}`);
2308
+ };
2326
2309
  };
2327
2310
 
2328
2311
  //#endregion
@@ -2403,220 +2386,6 @@ const createVarAssignments = (definitions, providedValues) => {
2403
2386
  */
2404
2387
  const createVarRefs = (definitions) => mapValues(definitions, (_, name) => createVarRefFromVariable(name));
2405
2388
 
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
2389
  //#endregion
2621
2390
  //#region packages/core/src/composer/merge-variable-definitions.ts
2622
2391
  /**
@@ -2641,31 +2410,180 @@ function mergeVariableDefinitions(parentVars, interpolationMap) {
2641
2410
  }
2642
2411
 
2643
2412
  //#endregion
2644
- //#region packages/core/src/composer/fragment-tagged-template.ts
2413
+ //#region packages/core/src/composer/var-ref-tools.ts
2645
2414
  /**
2646
- * Fragment tagged template function for creating GraphQL fragments from template literals.
2647
- * Supports Fragment Arguments RFC syntax for parameterized fragments.
2648
- * @module
2415
+ * Recursively checks if a NestedValue contains any VarRef.
2416
+ *
2417
+ * Used by getVarRefValue to determine if it's safe to return as ConstValue.
2418
+ * @internal
2649
2419
  */
2420
+ const hasVarRefInside = (value) => {
2421
+ if (value instanceof VarRef) return true;
2422
+ if (Array.isArray(value)) return value.some(hasVarRefInside);
2423
+ if (typeof value === "object" && value !== null) return Object.values(value).some(hasVarRefInside);
2424
+ return false;
2425
+ };
2650
2426
  /**
2651
- * Extract the argument list text from a fragment definition with Fragment Arguments syntax.
2652
- * Returns the text between parens in `fragment Name(...) on Type`, or null if no args.
2427
+ * Get the variable name from a VarRef.
2428
+ * Throws if the VarRef contains a nested-value instead of a variable reference.
2653
2429
  */
2654
- function extractFragmentArgText(rawSource) {
2655
- const match = /\bfragment\s+\w+\s*\(/.exec(rawSource);
2656
- if (!match) return null;
2657
- const openIndex = match.index + match[0].length - 1;
2658
- const closeIndex = findMatchingParen(rawSource, openIndex);
2659
- if (closeIndex === -1) return null;
2660
- if (rawSource.slice(closeIndex + 1).trimStart().startsWith("on")) return rawSource.slice(openIndex + 1, closeIndex);
2661
- return null;
2662
- }
2430
+ const getVarRefName = (varRef) => {
2431
+ const inner = VarRef.getInner(varRef);
2432
+ if (inner.type !== "variable") throw new Error("Expected variable reference, got nested-value");
2433
+ return inner.name;
2434
+ };
2663
2435
  /**
2664
- * Extract variable definitions from Fragment Arguments syntax.
2665
- * Wraps the argument list in a synthetic query to parse with graphql-js.
2436
+ * Get the const value from a VarRef.
2437
+ * Throws if the VarRef contains a variable reference instead of a nested-value,
2438
+ * or if the nested-value contains any VarRef inside.
2666
2439
  */
2667
- function extractFragmentVariables(rawSource, schemaIndex) {
2668
- const argText = extractFragmentArgText(rawSource);
2440
+ const getVarRefValue = (varRef) => {
2441
+ const inner = VarRef.getInner(varRef);
2442
+ if (inner.type !== "nested-value") throw new Error("Expected nested-value, got variable reference");
2443
+ if (hasVarRefInside(inner.value)) throw new Error("Cannot get const value: nested-value contains VarRef");
2444
+ return inner.value;
2445
+ };
2446
+ const SelectableProxyInnerRegistry = /* @__PURE__ */ new WeakMap();
2447
+ const getSelectableProxyInner = (proxy) => {
2448
+ const inner = SelectableProxyInnerRegistry.get(proxy);
2449
+ if (!inner) throw new Error(`Proxy inner not found`);
2450
+ return inner;
2451
+ };
2452
+ const createSelectableProxy = (current) => {
2453
+ const proxy = new Proxy(Object.create(null), { get(_, property) {
2454
+ if (typeof property === "symbol") throw new Error(`Prohibited property access: ${String(property)}`);
2455
+ const nextSegments = [...current.segments, property];
2456
+ if (current.varInner.type === "virtual") return createSelectableProxy({
2457
+ varInner: current.varInner,
2458
+ segments: nextSegments
2459
+ });
2460
+ if (current.varInner.type === "variable") return createSelectableProxy({
2461
+ varInner: {
2462
+ type: "virtual",
2463
+ varName: current.varInner.name,
2464
+ varSegments: nextSegments
2465
+ },
2466
+ segments: nextSegments
2467
+ });
2468
+ if (typeof current.varInner.value === "object" && current.varInner.value !== null) {
2469
+ const value = current.varInner.value[property];
2470
+ return createSelectableProxy({
2471
+ varInner: value instanceof VarRef ? VarRef.getInner(value) : {
2472
+ type: "nested-value",
2473
+ value
2474
+ },
2475
+ segments: nextSegments
2476
+ });
2477
+ }
2478
+ throw new Error(`Cannot access children of primitive value at path [${current.segments.join(".")}]`);
2479
+ } });
2480
+ SelectableProxyInnerRegistry.set(proxy, current);
2481
+ return proxy;
2482
+ };
2483
+ /**
2484
+ * Get the variable name from a VarRef at a specific path.
2485
+ *
2486
+ * @param varRef - The VarRef containing a nested-value
2487
+ * @param selector - Path builder function, e.g., p => p.user.age
2488
+ * @returns The variable name at the specified path
2489
+ * @throws If path doesn't lead to a VarRef with type "variable"
2490
+ *
2491
+ * @example
2492
+ * const ref = createVarRefFromNestedValue({
2493
+ * user: { age: someVariableRef }
2494
+ * });
2495
+ * getNameAt(ref, p => p.user.age); // returns the variable name
2496
+ */
2497
+ const getNameAt = (varRef, selector) => {
2498
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
2499
+ varInner: VarRef.getInner(varRef),
2500
+ segments: []
2501
+ })));
2502
+ if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
2503
+ if (inner.varInner.type !== "variable") throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable`);
2504
+ return inner.varInner.name;
2505
+ };
2506
+ /**
2507
+ * Get the const value from a nested-value VarRef at a specific path.
2508
+ *
2509
+ * @param varRef - The VarRef containing a nested-value
2510
+ * @param pathFn - Path builder function, e.g., p => p.user.name
2511
+ * @returns The const value at the specified path
2512
+ * @throws If path leads to a VarRef or if value contains VarRef inside
2513
+ *
2514
+ * @example
2515
+ * const ref = createVarRefFromNestedValue({
2516
+ * user: { name: "Alice", age: someVariableRef }
2517
+ * });
2518
+ * getValueAt(ref, p => p.user.name); // returns "Alice"
2519
+ */
2520
+ const getValueAt = (varRef, selector) => {
2521
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
2522
+ varInner: VarRef.getInner(varRef),
2523
+ segments: []
2524
+ })));
2525
+ if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
2526
+ if (inner.varInner.type !== "nested-value") throw new Error(`Value at path [${inner.segments.join(".")}] is not a nested-value`);
2527
+ if (hasVarRefInside(inner.varInner.value)) throw new Error(`Value at path [${inner.segments.join(".")}] contains nested VarRef`);
2528
+ return inner.varInner.value;
2529
+ };
2530
+ /**
2531
+ * Gets the full path to a variable within a nested structure.
2532
+ *
2533
+ * Returns path segments starting with `$variableName` followed by
2534
+ * property accesses within that variable's value.
2535
+ *
2536
+ * @example
2537
+ * ```typescript
2538
+ * getVariablePath($.filter, p => p.user.id)
2539
+ * // Returns: ["$filter", "user", "id"]
2540
+ * ```
2541
+ */
2542
+ const getVariablePath = (varRef, selector) => {
2543
+ const inner = getSelectableProxyInner(selector(createSelectableProxy({
2544
+ varInner: VarRef.getInner(varRef),
2545
+ segments: []
2546
+ })));
2547
+ if (inner.varInner.type === "virtual") return [`$${inner.varInner.varName}`, ...inner.segments.slice(inner.varInner.varSegments.length)];
2548
+ if (inner.varInner.type === "variable") return [`$${inner.varInner.name}`];
2549
+ throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable or inside a variable`);
2550
+ };
2551
+ /** Pre-built tools object passed as `$var` in metadata builder callbacks. */
2552
+ const varRefTools = Object.freeze({
2553
+ getName: getVarRefName,
2554
+ getValue: getVarRefValue,
2555
+ getNameAt,
2556
+ getValueAt,
2557
+ getPath: getVariablePath,
2558
+ hasVarRefInside
2559
+ });
2560
+
2561
+ //#endregion
2562
+ //#region packages/core/src/composer/fragment-tagged-template.ts
2563
+ /**
2564
+ * Fragment tagged template function for creating GraphQL fragments from template literals.
2565
+ * Supports Fragment Arguments RFC syntax for parameterized fragments.
2566
+ * @module
2567
+ */
2568
+ /**
2569
+ * Extract the argument list text from a fragment definition with Fragment Arguments syntax.
2570
+ * Returns the text between parens in `fragment Name(...) on Type`, or null if no args.
2571
+ */
2572
+ function extractFragmentArgText(rawSource) {
2573
+ const match = /\bfragment\s+\w+\s*\(/.exec(rawSource);
2574
+ if (!match) return null;
2575
+ const openIndex = match.index + match[0].length - 1;
2576
+ const closeIndex = findMatchingParen(rawSource, openIndex);
2577
+ if (closeIndex === -1) return null;
2578
+ if (rawSource.slice(closeIndex + 1).trimStart().startsWith("on")) return rawSource.slice(openIndex + 1, closeIndex);
2579
+ return null;
2580
+ }
2581
+ /**
2582
+ * Extract variable definitions from Fragment Arguments syntax.
2583
+ * Wraps the argument list in a synthetic query to parse with graphql-js.
2584
+ */
2585
+ function extractFragmentVariables(rawSource, schemaIndex) {
2586
+ const argText = extractFragmentArgText(rawSource);
2669
2587
  if (!argText?.trim()) return {};
2670
2588
  const syntheticQuery = `query _Synthetic(${argText}) { __typename }`;
2671
2589
  let syntheticDoc;
@@ -2680,6 +2598,30 @@ function extractFragmentVariables(rawSource, schemaIndex) {
2680
2598
  return buildVarSpecifiers(opDef.variableDefinitions ?? [], schemaIndex);
2681
2599
  }
2682
2600
  /**
2601
+ * Filters out named fragment spreads that cannot be resolved without an interpolation map.
2602
+ * Used when building fields from compat templates or zero-interpolation tagged templates
2603
+ * that may contain standard GraphQL `...FragmentName` spreads.
2604
+ */
2605
+ function filterUnresolvedFragmentSpreads(selectionSet, interpolationMap) {
2606
+ return {
2607
+ ...selectionSet,
2608
+ selections: selectionSet.selections.filter((sel) => {
2609
+ if (sel.kind !== graphql.Kind.FRAGMENT_SPREAD) return true;
2610
+ return interpolationMap?.has(sel.name.value) ?? false;
2611
+ }).map((sel) => {
2612
+ if (sel.kind === graphql.Kind.FIELD && sel.selectionSet) return {
2613
+ ...sel,
2614
+ selectionSet: filterUnresolvedFragmentSpreads(sel.selectionSet, interpolationMap)
2615
+ };
2616
+ if (sel.kind === graphql.Kind.INLINE_FRAGMENT && sel.selectionSet) return {
2617
+ ...sel,
2618
+ selectionSet: filterUnresolvedFragmentSpreads(sel.selectionSet, interpolationMap)
2619
+ };
2620
+ return sel;
2621
+ })
2622
+ };
2623
+ }
2624
+ /**
2683
2625
  * Builds field selections from a GraphQL AST SelectionSet by driving field factories.
2684
2626
  * Converts parsed AST selections into the AnyFieldsExtended format that the document builder expects.
2685
2627
  * Also used by typegen for static field extraction from tagged templates.
@@ -2694,27 +2636,33 @@ function buildFieldsFromSelectionSet(selectionSet, schema, typeName, varAssignme
2694
2636
  result[alias] = true;
2695
2637
  continue;
2696
2638
  }
2697
- const factory = f[fieldName];
2698
- if (!factory) throw new Error(`Field "${fieldName}" is not defined on type "${typeName}"`);
2699
2639
  const args = buildArgsFromASTArguments(selection.arguments ?? [], varAssignments);
2700
- const extras = alias !== fieldName ? { alias } : void 0;
2640
+ const directives = buildDirectivesFromAST(selection.directives, varAssignments);
2641
+ const hasAlias = alias !== fieldName;
2642
+ const extras = hasAlias || directives.length > 0 ? {
2643
+ ...hasAlias ? { alias } : {},
2644
+ ...directives.length > 0 ? { directives } : {}
2645
+ } : void 0;
2701
2646
  if (selection.selectionSet) {
2702
- const curried = factory(args, extras);
2647
+ const curried = f(fieldName, args, extras);
2703
2648
  if (typeof curried === "function") {
2704
- const fieldSpec = schema.object[typeName]?.fields[fieldName];
2705
- const parsedType = parseOutputField(fieldSpec);
2649
+ const fieldDefRaw = schema.object[typeName]?.fields[fieldName];
2650
+ const parsedType = parseOutputField(typeof fieldDefRaw === "string" ? fieldDefRaw : fieldDefRaw?.spec);
2706
2651
  if (parsedType.kind === "union") {
2707
2652
  const unionInput = {};
2708
2653
  let hasTypename = false;
2709
2654
  const unsupportedSelections = [];
2710
2655
  for (const sel of selection.selectionSet.selections) if (sel.kind === graphql.Kind.INLINE_FRAGMENT) {
2711
- if (sel.directives?.length) throw new Error("Directives on inline fragments are not supported in tagged templates");
2712
2656
  if (!sel.typeCondition) throw new Error("Inline fragments without type conditions are not supported in tagged templates");
2713
2657
  const memberName = sel.typeCondition.name.value;
2714
- if (!schema.union[parsedType.name]?.types[memberName]) throw new Error(`Type "${memberName}" is not a member of union "${parsedType.name}" in tagged template inline fragment`);
2658
+ const unionDef = schema.union[parsedType.name];
2659
+ if (!unionDef) throw new Error(`Union "${parsedType.name}" is not defined in schema`);
2660
+ if (!(memberName in unionDef.types)) throw new Error(`Type "${memberName}" is not a member of union "${parsedType.name}" in tagged template inline fragment`);
2715
2661
  if (memberName in unionInput) throw new Error(`Duplicate inline fragment for union member "${memberName}" in tagged template. Merge selections into a single "... on ${memberName} { ... }" block.`);
2716
- const memberFields = buildFieldsFromSelectionSet(sel.selectionSet, schema, memberName, varAssignments, interpolationMap);
2717
- unionInput[memberName] = ({ f: _f }) => memberFields;
2662
+ unionInput[memberName] = {
2663
+ fields: buildFieldsFromSelectionSet(sel.selectionSet, schema, memberName, varAssignments, interpolationMap),
2664
+ directives: buildDirectivesFromAST(sel.directives, varAssignments, "INLINE_FRAGMENT")
2665
+ };
2718
2666
  } else if (sel.kind === graphql.Kind.FIELD && sel.name.value === "__typename") {
2719
2667
  if (sel.alias) throw new Error("Aliases on __typename in union selections are not supported in tagged templates. Use \"__typename\" without an alias.");
2720
2668
  if (sel.directives?.length) throw new Error(`Directives on __typename in union selections are not supported in tagged templates.`);
@@ -2741,7 +2689,7 @@ function buildFieldsFromSelectionSet(selectionSet, schema, typeName, varAssignme
2741
2689
  }
2742
2690
  } else Object.assign(result, curried);
2743
2691
  } else {
2744
- const fieldResult = factory(args, extras);
2692
+ const fieldResult = f(fieldName, args, extras);
2745
2693
  if (typeof fieldResult === "function") {
2746
2694
  const emptyResult = fieldResult(() => ({}));
2747
2695
  Object.assign(result, emptyResult);
@@ -2764,6 +2712,18 @@ function buildFieldsFromSelectionSet(selectionSet, schema, typeName, varAssignme
2764
2712
  return result;
2765
2713
  }
2766
2714
  /**
2715
+ * Convert GraphQL AST DirectiveNodes to DirectiveRef instances.
2716
+ * Reuses buildArgsFromASTArguments for directive argument conversion.
2717
+ */
2718
+ function buildDirectivesFromAST(directives, varAssignments, location = "FIELD") {
2719
+ if (!directives || directives.length === 0) return [];
2720
+ return directives.map((d) => new DirectiveRef({
2721
+ name: d.name.value,
2722
+ arguments: buildArgsFromASTArguments(d.arguments ?? [], varAssignments),
2723
+ locations: [location]
2724
+ }));
2725
+ }
2726
+ /**
2767
2727
  * Build a simple args object from GraphQL AST argument nodes.
2768
2728
  * Extracts literal values from the AST for passing to field factories.
2769
2729
  */
@@ -2867,7 +2827,10 @@ function createFragmentTaggedTemplate(schema) {
2867
2827
  let metadataBuilder = null;
2868
2828
  if (options?.metadata !== void 0) {
2869
2829
  const metadata = options.metadata;
2870
- if (typeof metadata === "function") metadataBuilder = () => metadata({ $ });
2830
+ if (typeof metadata === "function") metadataBuilder = () => metadata({
2831
+ $,
2832
+ $var: varRefTools
2833
+ });
2871
2834
  else metadataBuilder = () => metadata;
2872
2835
  }
2873
2836
  recordFragmentUsage({
@@ -2883,54 +2846,179 @@ function createFragmentTaggedTemplate(schema) {
2883
2846
  }
2884
2847
 
2885
2848
  //#endregion
2886
- //#region packages/core/src/composer/operation.ts
2849
+ //#region packages/core/src/composer/operation-core.ts
2887
2850
  /**
2888
- * Operation composer factory for creating typed GraphQL operations.
2889
- * @module
2851
+ * Builds an operation artifact from the provided parameters.
2852
+ *
2853
+ * This function contains the core logic for:
2854
+ * - Creating variable refs and field factories
2855
+ * - Evaluating fields with fragment usage tracking
2856
+ * - Building the document
2857
+ * - Handling metadata (sync and async)
2858
+ * - Applying document transformations
2859
+ *
2860
+ * @param params - Operation building parameters
2861
+ * @returns Operation artifact or Promise of artifact (if async metadata)
2862
+ *
2863
+ * @internal Used by extend.ts and operation-tagged-template.ts
2890
2864
  */
2865
+ const buildOperationArtifact = (params) => {
2866
+ const { schema, operationType, operationTypeName, operationName, variables, variableDefinitionNodes, adapter, metadata: metadataBuilder, transformDocument: operationTransformDocument, adapterTransformDocument } = params;
2867
+ const $ = createVarRefs(variables);
2868
+ const { fieldsFactory } = params;
2869
+ const f = createFieldFactories(schema, operationTypeName);
2870
+ const collected = withFragmentUsageCollection(() => fieldsFactory({
2871
+ f,
2872
+ $
2873
+ }));
2874
+ const fields = collected.result;
2875
+ const fragmentUsages = collected.usages;
2876
+ const document = buildDocument({
2877
+ operationName,
2878
+ operationType,
2879
+ operationTypeName,
2880
+ variableDefinitionNodes,
2881
+ variables,
2882
+ fields,
2883
+ schema
2884
+ });
2885
+ const variableNames = Object.keys(variables);
2886
+ if (!fragmentUsages.some((u) => u.metadataBuilder) && !metadataBuilder && !adapterTransformDocument && !operationTransformDocument) return {
2887
+ operationType,
2888
+ operationName,
2889
+ schemaLabel: schema.label,
2890
+ variableNames,
2891
+ documentSource: () => fields,
2892
+ document,
2893
+ metadata: void 0
2894
+ };
2895
+ const aggregateFragmentMetadata = (resolvedFragmentMetadata) => {
2896
+ const fragmentMetaInfos = fragmentUsages.map((usage, index) => ({
2897
+ metadata: resolvedFragmentMetadata[index],
2898
+ fieldPath: usage.path
2899
+ }));
2900
+ return adapter.aggregateFragmentMetadata(fragmentMetaInfos);
2901
+ };
2902
+ const fragmentMetadataResults = fragmentUsages.map((usage) => usage.metadataBuilder ? usage.metadataBuilder() : void 0);
2903
+ const hasAsyncFragmentMetadata = fragmentMetadataResults.some((r) => isPromiseLike(r));
2904
+ const buildOperationMetadata = (aggregatedFragmentMetadata) => {
2905
+ const schemaLevel = adapter.schemaLevel;
2906
+ return metadataBuilder?.({
2907
+ $,
2908
+ $var: varRefTools,
2909
+ document,
2910
+ fragmentMetadata: aggregatedFragmentMetadata,
2911
+ schemaLevel
2912
+ });
2913
+ };
2914
+ const makeCreateArtifact = (aggregated$1) => {
2915
+ return ({ metadata }) => {
2916
+ let finalDocument = operationTransformDocument ? operationTransformDocument({
2917
+ document,
2918
+ metadata
2919
+ }) : document;
2920
+ if (adapterTransformDocument) finalDocument = adapterTransformDocument({
2921
+ document: finalDocument,
2922
+ operationName,
2923
+ operationType,
2924
+ variableNames,
2925
+ schemaLevel: adapter.schemaLevel,
2926
+ fragmentMetadata: aggregated$1
2927
+ });
2928
+ return {
2929
+ operationType,
2930
+ operationName,
2931
+ schemaLabel: schema.label,
2932
+ variableNames,
2933
+ documentSource: () => fields,
2934
+ document: finalDocument,
2935
+ metadata
2936
+ };
2937
+ };
2938
+ };
2939
+ if (hasAsyncFragmentMetadata) return Promise.all(fragmentMetadataResults).then(async (resolvedFragmentMetadata) => {
2940
+ const aggregated$1 = aggregateFragmentMetadata(resolvedFragmentMetadata);
2941
+ const operationMetadata = await buildOperationMetadata(aggregated$1);
2942
+ return makeCreateArtifact(aggregated$1)({ metadata: operationMetadata });
2943
+ });
2944
+ const aggregated = aggregateFragmentMetadata(fragmentMetadataResults);
2945
+ const createArtifact = makeCreateArtifact(aggregated);
2946
+ const operationMetadataResult = buildOperationMetadata(aggregated);
2947
+ if (isPromiseLike(operationMetadataResult)) return operationMetadataResult.then((metadata) => createArtifact({ metadata }));
2948
+ return createArtifact({ metadata: operationMetadataResult });
2949
+ };
2891
2950
  /**
2892
- * Creates a factory for composing GraphQL operations.
2951
+ * Wraps a buildOperationArtifact call into an Operation.create() invocation,
2952
+ * handling both sync and async artifact results.
2893
2953
  *
2894
- * Returns a curried function: first select operation type (query/mutation/subscription),
2895
- * then define the operation with name, variables, and fields.
2954
+ * @param artifactFactory - Factory that produces the artifact (may return Promise for async metadata)
2896
2955
  *
2897
- * Handles metadata aggregation from fragments (sync or async) and builds
2898
- * the TypedDocumentNode automatically.
2956
+ * @internal Used by extend.ts and operation-tagged-template.ts
2957
+ */
2958
+ const wrapArtifactAsOperation = (artifactFactory) => {
2959
+ return Operation.create(artifactFactory);
2960
+ };
2961
+
2962
+ //#endregion
2963
+ //#region packages/core/src/composer/extend.ts
2964
+ /**
2965
+ * Extend composer factory for creating Operations from TemplateCompatSpec.
2966
+ * @module
2967
+ */
2968
+ /**
2969
+ * Creates a factory for extending compat specs into full operations.
2970
+ *
2971
+ * The extend function takes a TemplateCompatSpec (created by `query.compat("Name")\`...\``)
2972
+ * and optional metadata/transformDocument options, then creates a full Operation.
2899
2973
  *
2900
2974
  * @param schema - The GraphQL schema definition
2901
2975
  * @param adapter - Optional metadata adapter for custom metadata handling
2902
- * @param transformDocument - Optional document transformer called after building
2903
- * @returns Operation type selector function
2976
+ * @param transformDocument - Optional document transformer
2977
+ * @returns Extend composer function
2904
2978
  *
2905
2979
  * @internal Used by `createGqlElementComposer`
2906
2980
  */
2907
- const createOperationComposerFactory = (schema, adapter, transformDocument) => {
2981
+ const createExtendComposer = (schema, adapter, transformDocument) => {
2908
2982
  const resolvedAdapter = adapter ?? defaultMetadataAdapter;
2909
- return (operationType) => {
2910
- const operationTypeName = schema.operations[operationType];
2911
- if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
2912
- return (options) => {
2913
- return Operation.create((() => buildOperationArtifact({
2914
- mode: "fieldsFactory",
2915
- schema,
2916
- operationType,
2917
- operationTypeName,
2918
- operationName: options.name,
2919
- variables: options.variables ?? {},
2920
- fieldsFactory: options.fields,
2921
- adapter: resolvedAdapter,
2922
- metadata: options.metadata,
2923
- transformDocument: options.transformDocument,
2924
- adapterTransformDocument: transformDocument
2925
- })));
2926
- };
2983
+ return (compat, options) => {
2984
+ const spec = compat.value;
2985
+ return buildOperationFromTemplateSpec(schema, spec, resolvedAdapter, options, transformDocument);
2927
2986
  };
2928
2987
  };
2988
+ /**
2989
+ * Builds an Operation from a TemplateCompatSpec by parsing the raw GraphQL source.
2990
+ * Evaluates fields via buildFieldsFromSelectionSet for correct typegen output.
2991
+ */
2992
+ const buildOperationFromTemplateSpec = (schema, spec, adapter, options, adapterTransformDocument) => {
2993
+ const { operationType, operationName, graphqlSource } = spec;
2994
+ const opDef = (0, graphql.parse)(graphqlSource).definitions.find((d) => d.kind === graphql.Kind.OPERATION_DEFINITION);
2995
+ if (!opDef) throw new Error("No operation definition found in compat template spec");
2996
+ const schemaIndex = createSchemaIndexFromSchema(spec.schema);
2997
+ const varSpecifiers = buildVarSpecifiers(opDef.variableDefinitions ?? [], schemaIndex);
2998
+ const operationTypeName = schema.operations[operationType];
2999
+ const filteredSelectionSet = filterUnresolvedFragmentSpreads(opDef.selectionSet);
3000
+ return wrapArtifactAsOperation(() => buildOperationArtifact({
3001
+ schema,
3002
+ operationType,
3003
+ operationTypeName,
3004
+ operationName,
3005
+ variables: varSpecifiers,
3006
+ variableDefinitionNodes: opDef.variableDefinitions ?? [],
3007
+ fieldsFactory: ({ $ }) => {
3008
+ return buildFieldsFromSelectionSet(filteredSelectionSet, schema, operationTypeName, $);
3009
+ },
3010
+ adapter,
3011
+ metadata: options?.metadata,
3012
+ transformDocument: options?.transformDocument,
3013
+ adapterTransformDocument
3014
+ }));
3015
+ };
2929
3016
 
2930
3017
  //#endregion
2931
3018
  //#region packages/core/src/composer/operation-tagged-template.ts
2932
3019
  /**
2933
3020
  * Operation tagged template function for creating GraphQL operations from template literals.
3021
+ * Also supports options object dispatch for callback builder path.
2934
3022
  * @module
2935
3023
  */
2936
3024
  /**
@@ -2944,9 +3032,9 @@ function buildSyntheticOperationSource(operationType, operationName, body) {
2944
3032
  * Resolves a metadata option from OperationTemplateMetadataOptions into a MetadataBuilder
2945
3033
  * compatible with buildOperationArtifact.
2946
3034
  *
2947
- * - `undefined` `undefined` (no metadata)
2948
- * - Raw value `() => value` (static metadata)
2949
- * - Callback forwarded directly (receives full pipeline context)
3035
+ * - `undefined` -> `undefined` (no metadata)
3036
+ * - Raw value -> `() => value` (static metadata)
3037
+ * - Callback -> forwarded directly (receives full pipeline context)
2950
3038
  */
2951
3039
  const resolveMetadataOption = (metadataOption) => {
2952
3040
  if (metadataOption === void 0) return void 0;
@@ -2954,8 +3042,11 @@ const resolveMetadataOption = (metadataOption) => {
2954
3042
  return () => metadataOption;
2955
3043
  };
2956
3044
  /**
2957
- * Creates a curried tagged template function for a specific operation type.
2958
- * New API: `query("name")\`($var: Type!) { fields }\`` returns TemplateResult<Operation>.
3045
+ * Creates a curried function for a specific operation type.
3046
+ * Supports both tagged template and options object dispatch.
3047
+ *
3048
+ * Tagged template: `query("name")\`($var: Type!) { fields }\`` returns TemplateResult<Operation>.
3049
+ * Options object: `query("name")({ variables, fields })` returns TemplateResult<Operation>.
2959
3050
  *
2960
3051
  * @param schema - The GraphQL schema definition
2961
3052
  * @param operationType - The operation type (query, mutation, subscription)
@@ -2965,264 +3056,99 @@ const resolveMetadataOption = (metadataOption) => {
2965
3056
  const createOperationTaggedTemplate = (schema, operationType, metadataAdapter, adapterTransformDocument) => {
2966
3057
  const schemaIndex = createSchemaIndexFromSchema(schema);
2967
3058
  return (operationName) => {
2968
- return (strings, ...values) => {
2969
- for (let i = 0; i < values.length; i++) {
2970
- const value = values[i];
2971
- if (!(value instanceof Fragment) && typeof value !== "function") throw new Error(`Tagged templates only accept Fragment instances or callback functions as interpolated values. Received ${typeof value} at position ${i}.`);
2972
- }
2973
- let body = strings[0] ?? "";
2974
- const interpolationMap = /* @__PURE__ */ new Map();
2975
- for (let i = 0; i < values.length; i++) {
2976
- const placeholderName = `__INTERPOLATION_${i}__`;
2977
- interpolationMap.set(placeholderName, values[i]);
2978
- body += placeholderName + (strings[i + 1] ?? "");
2979
- }
2980
- const source = buildSyntheticOperationSource(operationType, operationName, body);
2981
- let document;
2982
- try {
2983
- document = (0, graphql.parse)(source);
2984
- } catch (error) {
2985
- const message = error instanceof Error ? error.message : String(error);
2986
- throw new Error(`GraphQL parse error in tagged template: ${message}`);
2987
- }
2988
- const opDefs = document.definitions.filter((def) => def.kind === graphql.Kind.OPERATION_DEFINITION);
2989
- if (opDefs.length !== 1) throw new Error(`Internal error: expected exactly one operation definition in synthesized source`);
2990
- const opNode = opDefs[0];
2991
- if (opNode.kind !== graphql.Kind.OPERATION_DEFINITION) throw new Error("Unexpected definition kind");
2992
- let varSpecifiers = buildVarSpecifiers(opNode.variableDefinitions ?? [], schemaIndex);
2993
- varSpecifiers = mergeVariableDefinitions(varSpecifiers, interpolationMap);
2994
- const operationTypeName = schema.operations[operationType];
2995
- if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
2996
- const resolvedAdapter = metadataAdapter ?? defaultMetadataAdapter;
2997
- return (options) => {
2998
- 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
- return wrapArtifactAsOperation(() => buildOperationArtifact({
3013
- mode: "fieldsFactory",
3014
- schema,
3015
- operationType,
3016
- operationTypeName,
3017
- operationName,
3018
- variables: varSpecifiers,
3019
- fieldsFactory: ({ $ }) => {
3020
- return buildFieldsFromSelectionSet(opNode.selectionSet, schema, operationTypeName, $, interpolationMap);
3021
- },
3022
- adapter: resolvedAdapter,
3023
- metadata: resolvedMetadata,
3024
- adapterTransformDocument
3025
- }), false);
3026
- };
3059
+ const dispatch = (firstArg, ...rest) => {
3060
+ if ("raw" in firstArg) return handleTaggedTemplate(schema, schemaIndex, operationType, operationName, metadataAdapter, adapterTransformDocument, firstArg, rest);
3061
+ return handleOptionsObject(schema, schemaIndex, operationType, operationName, metadataAdapter, adapterTransformDocument, firstArg);
3027
3062
  };
3063
+ return dispatch;
3028
3064
  };
3029
3065
  };
3030
-
3031
- //#endregion
3032
- //#region packages/core/src/composer/var-ref-tools.ts
3033
- /**
3034
- * Recursively checks if a NestedValue contains any VarRef.
3035
- *
3036
- * Used by getVarRefValue to determine if it's safe to return as ConstValue.
3037
- * @internal
3038
- */
3039
- const hasVarRefInside = (value) => {
3040
- if (value instanceof VarRef) return true;
3041
- if (Array.isArray(value)) return value.some(hasVarRefInside);
3042
- if (typeof value === "object" && value !== null) return Object.values(value).some(hasVarRefInside);
3043
- return false;
3044
- };
3045
3066
  /**
3046
- * Get the variable name from a VarRef.
3047
- * Throws if the VarRef contains a nested-value instead of a variable reference.
3048
- */
3049
- const getVarRefName = (varRef) => {
3050
- const inner = VarRef.getInner(varRef);
3051
- if (inner.type !== "variable") throw new Error("Expected variable reference, got nested-value");
3052
- return inner.name;
3053
- };
3054
- /**
3055
- * Get the const value from a VarRef.
3056
- * Throws if the VarRef contains a variable reference instead of a nested-value,
3057
- * or if the nested-value contains any VarRef inside.
3067
+ * Handles the tagged template path.
3058
3068
  */
3059
- const getVarRefValue = (varRef) => {
3060
- const inner = VarRef.getInner(varRef);
3061
- if (inner.type !== "nested-value") throw new Error("Expected nested-value, got variable reference");
3062
- if (hasVarRefInside(inner.value)) throw new Error("Cannot get const value: nested-value contains VarRef");
3063
- return inner.value;
3064
- };
3065
- const SelectableProxyInnerRegistry = /* @__PURE__ */ new WeakMap();
3066
- const getSelectableProxyInner = (proxy) => {
3067
- const inner = SelectableProxyInnerRegistry.get(proxy);
3068
- if (!inner) throw new Error(`Proxy inner not found`);
3069
- return inner;
3070
- };
3071
- const createSelectableProxy = (current) => {
3072
- const proxy = new Proxy(Object.create(null), { get(_, property) {
3073
- if (typeof property === "symbol") throw new Error(`Prohibited property access: ${String(property)}`);
3074
- const nextSegments = [...current.segments, property];
3075
- if (current.varInner.type === "virtual") return createSelectableProxy({
3076
- varInner: current.varInner,
3077
- segments: nextSegments
3078
- });
3079
- if (current.varInner.type === "variable") return createSelectableProxy({
3080
- varInner: {
3081
- type: "virtual",
3082
- varName: current.varInner.name,
3083
- varSegments: nextSegments
3069
+ function handleTaggedTemplate(schema, schemaIndex, operationType, operationName, metadataAdapter, adapterTransformDocument, strings, values) {
3070
+ for (let i = 0; i < values.length; i++) {
3071
+ const value = values[i];
3072
+ if (!(value instanceof Fragment) && typeof value !== "function") throw new Error(`Tagged templates only accept Fragment instances or callback functions as interpolated values. Received ${typeof value} at position ${i}.`);
3073
+ }
3074
+ let body = strings[0] ?? "";
3075
+ const interpolationMap = /* @__PURE__ */ new Map();
3076
+ for (let i = 0; i < values.length; i++) {
3077
+ const placeholderName = `__INTERPOLATION_${i}__`;
3078
+ interpolationMap.set(placeholderName, values[i]);
3079
+ body += placeholderName + (strings[i + 1] ?? "");
3080
+ }
3081
+ const source = buildSyntheticOperationSource(operationType, operationName, body);
3082
+ let document;
3083
+ try {
3084
+ document = (0, graphql.parse)(source);
3085
+ } catch (error) {
3086
+ const message = error instanceof Error ? error.message : String(error);
3087
+ throw new Error(`GraphQL parse error in tagged template: ${message}`);
3088
+ }
3089
+ const opDefs = document.definitions.filter((def) => def.kind === graphql.Kind.OPERATION_DEFINITION);
3090
+ if (opDefs.length !== 1) throw new Error(`Internal error: expected exactly one operation definition in synthesized source`);
3091
+ const opNode = opDefs[0];
3092
+ if (opNode.kind !== graphql.Kind.OPERATION_DEFINITION) throw new Error("Unexpected definition kind");
3093
+ const varDefNodes = opNode.variableDefinitions ?? [];
3094
+ let varSpecifiers = buildVarSpecifiers(varDefNodes, schemaIndex);
3095
+ varSpecifiers = mergeVariableDefinitions(varSpecifiers, interpolationMap);
3096
+ const hasInterpolatedFragmentVars = [...interpolationMap.values()].some((v) => v instanceof Fragment && Object.keys(v.variableDefinitions).length > 0);
3097
+ const operationTypeName = schema.operations[operationType];
3098
+ if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
3099
+ const resolvedAdapter = metadataAdapter ?? defaultMetadataAdapter;
3100
+ return (options) => {
3101
+ const resolvedMetadata = resolveMetadataOption(options?.metadata);
3102
+ return wrapArtifactAsOperation(() => buildOperationArtifact({
3103
+ schema,
3104
+ operationType,
3105
+ operationTypeName,
3106
+ operationName,
3107
+ variables: varSpecifiers,
3108
+ variableDefinitionNodes: hasInterpolatedFragmentVars ? void 0 : varDefNodes,
3109
+ fieldsFactory: ({ $ }) => {
3110
+ return buildFieldsFromSelectionSet(filterUnresolvedFragmentSpreads(opNode.selectionSet, interpolationMap), schema, operationTypeName, $, interpolationMap);
3084
3111
  },
3085
- segments: nextSegments
3086
- });
3087
- if (typeof current.varInner.value === "object" && current.varInner.value !== null) {
3088
- const value = current.varInner.value[property];
3089
- return createSelectableProxy({
3090
- varInner: value instanceof VarRef ? VarRef.getInner(value) : {
3091
- type: "nested-value",
3092
- value
3093
- },
3094
- segments: nextSegments
3095
- });
3096
- }
3097
- throw new Error(`Cannot access children of primitive value at path [${current.segments.join(".")}]`);
3098
- } });
3099
- SelectableProxyInnerRegistry.set(proxy, current);
3100
- return proxy;
3101
- };
3102
- /**
3103
- * Get the variable name from a VarRef at a specific path.
3104
- *
3105
- * @param varRef - The VarRef containing a nested-value
3106
- * @param selector - Path builder function, e.g., p => p.user.age
3107
- * @returns The variable name at the specified path
3108
- * @throws If path doesn't lead to a VarRef with type "variable"
3109
- *
3110
- * @example
3111
- * const ref = createVarRefFromNestedValue({
3112
- * user: { age: someVariableRef }
3113
- * });
3114
- * getNameAt(ref, p => p.user.age); // returns the variable name
3115
- */
3116
- const getNameAt = (varRef, selector) => {
3117
- const inner = getSelectableProxyInner(selector(createSelectableProxy({
3118
- varInner: VarRef.getInner(varRef),
3119
- segments: []
3120
- })));
3121
- if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
3122
- if (inner.varInner.type !== "variable") throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable`);
3123
- return inner.varInner.name;
3124
- };
3125
- /**
3126
- * Get the const value from a nested-value VarRef at a specific path.
3127
- *
3128
- * @param varRef - The VarRef containing a nested-value
3129
- * @param pathFn - Path builder function, e.g., p => p.user.name
3130
- * @returns The const value at the specified path
3131
- * @throws If path leads to a VarRef or if value contains VarRef inside
3132
- *
3133
- * @example
3134
- * const ref = createVarRefFromNestedValue({
3135
- * user: { name: "Alice", age: someVariableRef }
3136
- * });
3137
- * getValueAt(ref, p => p.user.name); // returns "Alice"
3138
- */
3139
- const getValueAt = (varRef, selector) => {
3140
- const inner = getSelectableProxyInner(selector(createSelectableProxy({
3141
- varInner: VarRef.getInner(varRef),
3142
- segments: []
3143
- })));
3144
- if (inner.varInner.type === "virtual") throw new Error(`Value at path [${inner.segments.join(".")}] is inside a variable`);
3145
- if (inner.varInner.type !== "nested-value") throw new Error(`Value at path [${inner.segments.join(".")}] is not a nested-value`);
3146
- if (hasVarRefInside(inner.varInner.value)) throw new Error(`Value at path [${inner.segments.join(".")}] contains nested VarRef`);
3147
- return inner.varInner.value;
3148
- };
3149
- /**
3150
- * Gets the full path to a variable within a nested structure.
3151
- *
3152
- * Returns path segments starting with `$variableName` followed by
3153
- * property accesses within that variable's value.
3154
- *
3155
- * @example
3156
- * ```typescript
3157
- * getVariablePath($.filter, p => p.user.id)
3158
- * // Returns: ["$filter", "user", "id"]
3159
- * ```
3160
- */
3161
- const getVariablePath = (varRef, selector) => {
3162
- const inner = getSelectableProxyInner(selector(createSelectableProxy({
3163
- varInner: VarRef.getInner(varRef),
3164
- segments: []
3165
- })));
3166
- if (inner.varInner.type === "virtual") return [`$${inner.varInner.varName}`, ...inner.segments.slice(inner.varInner.varSegments.length)];
3167
- if (inner.varInner.type === "variable") return [`$${inner.varInner.name}`];
3168
- throw new Error(`Value at path [${inner.segments.join(".")}] is not a variable or inside a variable`);
3169
- };
3170
-
3171
- //#endregion
3172
- //#region packages/core/src/composer/var-builder.ts
3173
- /**
3174
- * Creates a factory function for generating schema-scoped variable methods.
3175
- * This ensures proper type inference for nested input objects by binding the schema type upfront.
3176
- *
3177
- * @example
3178
- * ```typescript
3179
- * const createMethod = createVarMethodFactory<typeof schema>();
3180
- * const inputTypeMethods = {
3181
- * Boolean: createMethod("scalar", "Boolean"),
3182
- * user_bool_exp: createMethod("input", "user_bool_exp"),
3183
- * } satisfies InputTypeMethods<typeof schema>;
3184
- * ```
3185
- */
3186
- const createVarMethodFactory = () => {
3187
- return (kind, typeName) => {
3188
- return ((modifier, extras) => ({
3189
- kind,
3190
- name: typeName,
3191
- modifier,
3192
- defaultValue: extras?.default ? { default: extras.default() } : null,
3193
- directives: extras?.directives ?? {}
3112
+ adapter: resolvedAdapter,
3113
+ metadata: resolvedMetadata,
3114
+ transformDocument: options?.transformDocument,
3115
+ adapterTransformDocument
3194
3116
  }));
3195
3117
  };
3196
- };
3118
+ }
3197
3119
  /**
3198
- * Creates a variable builder using injected input type methods.
3199
- *
3200
- * The returned builder provides type-safe variable definition methods
3201
- * for all input types in the schema. Also includes utilities for
3202
- * extracting variable names and values from VarRefs.
3203
- *
3204
- * @param inputTypeMethods - Methods for each input type (from codegen)
3205
- * @returns Variable builder with methods for all input types
3206
- *
3207
- * @internal Used by `createGqlElementComposer`
3120
+ * Handles the options object path.
3208
3121
  */
3209
- const createVarBuilder = (inputTypeMethods) => {
3210
- const varBuilder = (varName) => {
3211
- const wrappedMethods = {};
3212
- for (const [typeName, method] of Object.entries(inputTypeMethods)) Object.defineProperty(wrappedMethods, typeName, {
3213
- value: ((modifier, extras) => require_schema_builder.wrapByKey(varName, method(modifier, extras))),
3214
- writable: false,
3215
- configurable: true
3216
- });
3217
- return wrappedMethods;
3122
+ function handleOptionsObject(schema, schemaIndex, operationType, operationName, metadataAdapter, adapterTransformDocument, options) {
3123
+ let varSpecifiers = {};
3124
+ let varDefNodes = [];
3125
+ if (options.variables) {
3126
+ const opDef = (0, graphql.parse)(`query __var_parse__ ${String(options.variables).trim()} { __typename }`).definitions[0];
3127
+ if (opDef?.kind === graphql.Kind.OPERATION_DEFINITION) {
3128
+ varDefNodes = opDef.variableDefinitions ?? [];
3129
+ varSpecifiers = buildVarSpecifiers(varDefNodes, schemaIndex);
3130
+ }
3131
+ }
3132
+ const operationTypeName = schema.operations[operationType];
3133
+ if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
3134
+ const resolvedAdapter = metadataAdapter ?? defaultMetadataAdapter;
3135
+ return (step2Options) => {
3136
+ const resolvedMetadata = resolveMetadataOption(step2Options?.metadata);
3137
+ return wrapArtifactAsOperation(() => buildOperationArtifact({
3138
+ schema,
3139
+ operationType,
3140
+ operationTypeName,
3141
+ operationName,
3142
+ variables: varSpecifiers,
3143
+ variableDefinitionNodes: varDefNodes,
3144
+ fieldsFactory: options.fields,
3145
+ adapter: resolvedAdapter,
3146
+ metadata: resolvedMetadata,
3147
+ transformDocument: step2Options?.transformDocument,
3148
+ adapterTransformDocument
3149
+ }));
3218
3150
  };
3219
- varBuilder.getName = getVarRefName;
3220
- varBuilder.getValue = getVarRefValue;
3221
- varBuilder.getNameAt = getNameAt;
3222
- varBuilder.getValueAt = getValueAt;
3223
- varBuilder.getVariablePath = getVariablePath;
3224
- return varBuilder;
3225
- };
3151
+ }
3226
3152
 
3227
3153
  //#endregion
3228
3154
  //#region packages/core/src/composer/gql-composer.ts
@@ -3232,57 +3158,37 @@ const createVarBuilder = (inputTypeMethods) => {
3232
3158
  * This is the main entry point for defining GraphQL operations and fragments.
3233
3159
  * The returned function provides a context with:
3234
3160
  * - `fragment`: Tagged template function for fragment definitions
3235
- * - `query/mutation/subscription`: Operation builders
3236
- * - `$var`: Variable definition helpers
3161
+ * - `query/mutation/subscription`: Operation builders (tagged template + options object + .compat)
3237
3162
  * - `$dir`: Field directive helpers (@skip, @include)
3238
3163
  * - `$colocate`: Fragment colocation utilities
3239
3164
  *
3240
3165
  * @param schema - The GraphQL schema definition
3241
- * @param options - Configuration including input type methods and optional adapter
3166
+ * @param options - Configuration including optional adapter
3242
3167
  * @returns Element composer function
3243
3168
  *
3244
3169
  * @example
3245
3170
  * ```typescript
3246
- * const gql = createGqlElementComposer(schema, { inputTypeMethods });
3247
- *
3248
- * const GetUser = gql(({ query, $var, $dir }) =>
3249
- * query.operation({
3250
- * name: "GetUser",
3251
- * variables: { showEmail: $var("showEmail").Boolean("!") },
3252
- * fields: ({ f, $ }) => ({
3253
- * ...f.user({ id: "1" })(({ f }) => ({
3254
- * ...f.name(),
3255
- * ...f.email({}, { directives: [$dir.skip({ if: $.showEmail })] }),
3256
- * })),
3257
- * }),
3258
- * })
3171
+ * const gql = createGqlElementComposer(schema, {});
3172
+ *
3173
+ * const GetUser = gql(({ query, $dir }) =>
3174
+ * query("GetUser")`($id: ID!) {
3175
+ * user(id: $id) { name email }
3176
+ * }`()
3259
3177
  * );
3260
3178
  * ```
3261
3179
  */
3262
3180
  const createGqlElementComposer = (schema, options) => {
3263
- const { adapter, inputTypeMethods, directiveMethods } = options;
3181
+ const { adapter, directiveMethods } = options;
3264
3182
  const helpers = adapter?.helpers;
3265
3183
  const metadataAdapter = adapter?.metadata;
3266
3184
  const transformDocument = adapter?.transformDocument;
3267
- const fragment = createFragmentTaggedTemplate(schema);
3268
- const createOperationComposer = createOperationComposerFactory(schema, metadataAdapter, transformDocument);
3269
3185
  const transformedContext = require_context_transformer.applyContextTransformer({
3270
- fragment,
3271
- query: Object.assign(createOperationTaggedTemplate(schema, "query", metadataAdapter, transformDocument), {
3272
- operation: createOperationComposer("query"),
3273
- compat: createCompatTaggedTemplate(schema, "query")
3274
- }),
3275
- mutation: Object.assign(createOperationTaggedTemplate(schema, "mutation", metadataAdapter, transformDocument), {
3276
- operation: createOperationComposer("mutation"),
3277
- compat: createCompatTaggedTemplate(schema, "mutation")
3278
- }),
3279
- subscription: Object.assign(createOperationTaggedTemplate(schema, "subscription", metadataAdapter, transformDocument), {
3280
- operation: createOperationComposer("subscription"),
3281
- compat: createCompatTaggedTemplate(schema, "subscription")
3282
- }),
3186
+ fragment: createFragmentTaggedTemplate(schema),
3187
+ query: Object.assign(createOperationTaggedTemplate(schema, "query", metadataAdapter, transformDocument), { compat: createCompatTaggedTemplate(schema, "query") }),
3188
+ mutation: Object.assign(createOperationTaggedTemplate(schema, "mutation", metadataAdapter, transformDocument), { compat: createCompatTaggedTemplate(schema, "mutation") }),
3189
+ subscription: Object.assign(createOperationTaggedTemplate(schema, "subscription", metadataAdapter, transformDocument), { compat: createCompatTaggedTemplate(schema, "subscription") }),
3283
3190
  define: (factory) => GqlDefine.create(factory),
3284
3191
  extend: createExtendComposer(schema, metadataAdapter, transformDocument),
3285
- $var: createVarBuilder(inputTypeMethods),
3286
3192
  $dir: directiveMethods ?? createStandardDirectives(),
3287
3193
  $colocate: createColocateHelper(),
3288
3194
  ...helpers ?? {}
@@ -3453,15 +3359,15 @@ const calculateUnionType = (schema, union, formatters, unionTypeName) => {
3453
3359
  if (unionDef) {
3454
3360
  const allMemberNames = Object.keys(unionDef.types);
3455
3361
  for (const typeName of allMemberNames) {
3456
- const fields = selections[typeName];
3457
- if (fields && typeof fields === "object") {
3458
- const fieldsType = calculateFieldsType(schema, fields, formatters, typeName);
3362
+ const member = selections[typeName];
3363
+ if (member && typeof member === "object") {
3364
+ const fieldsType = calculateFieldsType(schema, member.fields, formatters, typeName);
3459
3365
  memberTypes.push(`${fieldsType} & { readonly __typename: "${typeName}" }`);
3460
3366
  } else memberTypes.push(`{ readonly __typename: "${typeName}" }`);
3461
3367
  }
3462
3368
  }
3463
- } else for (const [typeName, fields] of Object.entries(selections)) if (fields && typeof fields === "object") {
3464
- const memberType = calculateFieldsType(schema, fields, formatters, typeName);
3369
+ } else for (const [typeName, member] of Object.entries(selections)) if (member && typeof member === "object") {
3370
+ const memberType = calculateFieldsType(schema, member.fields, formatters, typeName);
3465
3371
  memberTypes.push(memberType);
3466
3372
  }
3467
3373
  if (memberTypes.length === 0) return "never";
@@ -3603,7 +3509,7 @@ const generateInputTypeFromSpecifiers = (schema, specifiers, options = {}) => {
3603
3509
  * Generate a TypeScript type string for input variables from VariableDefinitions.
3604
3510
  *
3605
3511
  * Unlike generateInputTypeFromSpecifiers which works with deferred specifier strings,
3606
- * this function works with VarSpecifier objects created by $var().
3512
+ * this function works with VarSpecifier objects from variable definitions.
3607
3513
  * Used for generating Fragment input types in prebuilt mode.
3608
3514
  *
3609
3515
  * @param schema - The GraphQL schema
@@ -3642,7 +3548,6 @@ exports.calculateFieldType = calculateFieldType;
3642
3548
  exports.calculateFieldsType = calculateFieldsType;
3643
3549
  exports.collectVariableUsages = collectVariableUsages;
3644
3550
  exports.createColocateHelper = createColocateHelper;
3645
- exports.createCompatComposer = createCompatComposer;
3646
3551
  exports.createCompatTaggedTemplate = createCompatTaggedTemplate;
3647
3552
  exports.createDefaultAdapter = createDefaultAdapter;
3648
3553
  exports.createDirectiveBuilder = createDirectiveBuilder;
@@ -3651,15 +3556,12 @@ exports.createExtendComposer = createExtendComposer;
3651
3556
  exports.createFieldFactories = createFieldFactories;
3652
3557
  exports.createFragmentTaggedTemplate = createFragmentTaggedTemplate;
3653
3558
  exports.createGqlElementComposer = createGqlElementComposer;
3654
- exports.createOperationComposerFactory = createOperationComposerFactory;
3655
3559
  exports.createOperationTaggedTemplate = createOperationTaggedTemplate;
3656
3560
  exports.createSchemaIndex = createSchemaIndex;
3657
3561
  exports.createSchemaIndexFromSchema = createSchemaIndexFromSchema;
3658
3562
  exports.createStandardDirectives = createStandardDirectives;
3659
3563
  exports.createTypedDirectiveMethod = createTypedDirectiveMethod;
3660
3564
  exports.createVarAssignments = createVarAssignments;
3661
- exports.createVarBuilder = createVarBuilder;
3662
- exports.createVarMethodFactory = createVarMethodFactory;
3663
3565
  exports.createVarRefFromVariable = createVarRefFromVariable;
3664
3566
  exports.createVarRefs = createVarRefs;
3665
3567
  exports.defaultMetadataAdapter = defaultMetadataAdapter;
@@ -3668,6 +3570,7 @@ exports.defineOperationRoots = require_schema_builder.defineOperationRoots;
3668
3570
  exports.defineScalar = require_schema_builder.defineScalar;
3669
3571
  exports.err = err;
3670
3572
  exports.extractFragmentVariables = extractFragmentVariables;
3573
+ exports.filterUnresolvedFragmentSpreads = filterUnresolvedFragmentSpreads;
3671
3574
  exports.generateInputObjectType = generateInputObjectType;
3672
3575
  exports.generateInputType = generateInputType;
3673
3576
  exports.generateInputTypeFromSpecifiers = generateInputTypeFromSpecifiers;
@@ -3677,14 +3580,19 @@ exports.getCurrentFieldPath = getCurrentFieldPath;
3677
3580
  exports.getEnumType = getEnumType;
3678
3581
  exports.getFieldReturnType = getFieldReturnType;
3679
3582
  exports.getInputFieldType = getInputFieldType;
3583
+ exports.getNameAt = getNameAt;
3680
3584
  exports.getScalarInputType = getScalarInputType;
3681
3585
  exports.getScalarOutputType = getScalarOutputType;
3586
+ exports.getValueAt = getValueAt;
3587
+ exports.getVarRefName = getVarRefName;
3588
+ exports.getVarRefValue = getVarRefValue;
3589
+ exports.getVariablePath = getVariablePath;
3682
3590
  exports.graphqlTypeToTypeScript = graphqlTypeToTypeScript;
3591
+ exports.hasVarRefInside = hasVarRefInside;
3683
3592
  exports.inferVariablesFromUsages = inferVariablesFromUsages;
3684
3593
  exports.isDirectiveRef = isDirectiveRef;
3685
3594
  exports.isListType = isListType;
3686
3595
  exports.isModifierAssignable = isModifierAssignable;
3687
- exports.isTemplateCompatSpec = isTemplateCompatSpec;
3688
3596
  exports.mergeModifiers = mergeModifiers;
3689
3597
  exports.mergeVariableUsages = mergeVariableUsages;
3690
3598
  exports.ok = ok;
@@ -3696,6 +3604,7 @@ exports.preprocessFragmentArgs = preprocessFragmentArgs;
3696
3604
  exports.recordFragmentUsage = recordFragmentUsage;
3697
3605
  exports.sortFragmentsByDependency = sortFragmentsByDependency;
3698
3606
  exports.transformParsedGraphql = transformParsedGraphql;
3607
+ exports.varRefTools = varRefTools;
3699
3608
  exports.withFieldPath = withFieldPath;
3700
3609
  exports.withFragmentUsageCollection = withFragmentUsageCollection;
3701
3610
  exports.wrapArtifactAsOperation = wrapArtifactAsOperation;