@soda-gql/core 0.11.11 → 0.11.12
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-DPtgl2f4.d.ts → index-CULnRHFI.d.ts} +487 -257
- package/dist/index-CULnRHFI.d.ts.map +1 -0
- package/dist/{index-IMOOkvQf.d.cts → index-DT6mTMaZ.d.cts} +487 -257
- package/dist/index-DT6mTMaZ.d.cts.map +1 -0
- package/dist/index.cjs +717 -535
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +714 -536
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.cts +1 -1
- package/dist/runtime.d.ts +1 -1
- package/package.json +1 -1
- package/dist/index-DPtgl2f4.d.ts.map +0 -1
- package/dist/index-IMOOkvQf.d.cts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -454,541 +454,652 @@ const createColocateHelper = () => {
|
|
|
454
454
|
};
|
|
455
455
|
|
|
456
456
|
//#endregion
|
|
457
|
-
//#region packages/core/src/
|
|
457
|
+
//#region packages/core/src/utils/promise.ts
|
|
458
458
|
/**
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
* Provides type-safe methods for creating directive references that can be
|
|
462
|
-
* applied to field selections. The builder follows a similar pattern to
|
|
463
|
-
* the variable builder ($var).
|
|
464
|
-
*
|
|
459
|
+
* Promise detection utilities for cross-realm compatibility.
|
|
465
460
|
* @module
|
|
466
461
|
*/
|
|
467
462
|
/**
|
|
468
|
-
*
|
|
463
|
+
* Check if a value is Promise-like (has .then method).
|
|
469
464
|
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
465
|
+
* This function uses duck typing instead of `instanceof Promise` to work across
|
|
466
|
+
* VM sandbox boundaries where Promises created in a different realm have a
|
|
467
|
+
* different constructor.
|
|
473
468
|
*
|
|
474
469
|
* @example
|
|
475
470
|
* ```typescript
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
* ```
|
|
479
|
-
*/
|
|
480
|
-
const createDirectiveMethod = (name, locations) => {
|
|
481
|
-
return (args) => new DirectiveRef({
|
|
482
|
-
name,
|
|
483
|
-
arguments: args,
|
|
484
|
-
locations
|
|
485
|
-
});
|
|
486
|
-
};
|
|
487
|
-
/**
|
|
488
|
-
* Creates a typed directive method with argument type specifiers.
|
|
489
|
-
* Enables enum value output in directive arguments.
|
|
471
|
+
* // Works with native Promises
|
|
472
|
+
* isPromiseLike(Promise.resolve(42)); // true
|
|
490
473
|
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
* @returns A function that creates DirectiveRef instances with argument type info
|
|
474
|
+
* // Works with VM sandbox Promises (instanceof would fail)
|
|
475
|
+
* const vmPromise = vm.runInContext("Promise.resolve(42)", context);
|
|
476
|
+
* isPromiseLike(vmPromise); // true (instanceof Promise would be false)
|
|
495
477
|
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
* ["FIELD"] as const,
|
|
501
|
-
* { role: { kind: "enum", name: "Role", modifier: "!" } }
|
|
502
|
-
* );
|
|
503
|
-
* const authDirective = authMethod({ role: "ADMIN" });
|
|
478
|
+
* // Rejects non-Promises
|
|
479
|
+
* isPromiseLike({ then: "not a function" }); // false
|
|
480
|
+
* isPromiseLike(null); // false
|
|
481
|
+
* isPromiseLike(42); // false
|
|
504
482
|
* ```
|
|
505
483
|
*/
|
|
506
|
-
const
|
|
507
|
-
return
|
|
508
|
-
name,
|
|
509
|
-
arguments: args,
|
|
510
|
-
locations,
|
|
511
|
-
argumentSpecs: argSpecs
|
|
512
|
-
});
|
|
484
|
+
const isPromiseLike = (value) => {
|
|
485
|
+
return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
|
|
513
486
|
};
|
|
487
|
+
|
|
488
|
+
//#endregion
|
|
489
|
+
//#region packages/core/src/types/element/lazy-evaluator.ts
|
|
514
490
|
/**
|
|
515
|
-
*
|
|
491
|
+
* Creates a lazy evaluator with caching, async support, and dependency ordering.
|
|
492
|
+
*
|
|
493
|
+
* @param define - Factory function that produces the value
|
|
494
|
+
* @param getDeps - Optional function returning dependencies to evaluate first
|
|
495
|
+
* @param createDepGenerator - Function to create evaluation generator for a dependency
|
|
496
|
+
* @returns An executor generator function
|
|
516
497
|
*/
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
498
|
+
const createLazyEvaluator = (define, getDeps, createDepGenerator) => {
|
|
499
|
+
let cache = null;
|
|
500
|
+
let promise = null;
|
|
501
|
+
return function* execute(context) {
|
|
502
|
+
if (cache) return cache.value;
|
|
503
|
+
if (promise) {
|
|
504
|
+
yield promise;
|
|
505
|
+
return cache.value;
|
|
506
|
+
}
|
|
507
|
+
if (getDeps) for (const dep of getDeps()) yield* createDepGenerator(dep);
|
|
508
|
+
const defined = define(context);
|
|
509
|
+
if (!isPromiseLike(defined)) return (cache = { value: defined }).value;
|
|
510
|
+
promise = defined.then((value) => {
|
|
511
|
+
cache = { value };
|
|
512
|
+
promise = null;
|
|
513
|
+
});
|
|
514
|
+
yield promise;
|
|
515
|
+
return cache.value;
|
|
516
|
+
};
|
|
517
|
+
};
|
|
522
518
|
/**
|
|
523
|
-
* Creates
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
* @returns Object containing skip and include directive methods
|
|
527
|
-
*
|
|
528
|
-
* @example
|
|
529
|
-
* ```typescript
|
|
530
|
-
* const $dir = createStandardDirectives();
|
|
531
|
-
* const skipDirective = $dir.skip({ if: true });
|
|
532
|
-
* ```
|
|
519
|
+
* Creates an evaluation generator from an executor.
|
|
520
|
+
* Wraps the executor's generator and discards its return value.
|
|
533
521
|
*/
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
});
|
|
522
|
+
function* createEvaluationGenerator(executor, context) {
|
|
523
|
+
yield* executor(context);
|
|
524
|
+
}
|
|
538
525
|
/**
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
* @param customDirectives - Additional directive methods from schema (generated by codegen)
|
|
542
|
-
* @returns Combined directive builder with all available directives
|
|
543
|
-
*
|
|
544
|
-
* @internal Used by codegen to create schema-specific directive builders
|
|
526
|
+
* Executes the evaluator synchronously.
|
|
527
|
+
* Throws if async operation is encountered.
|
|
545
528
|
*/
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
};
|
|
529
|
+
const evaluateSync = (executor, context) => {
|
|
530
|
+
const result = executor(context).next();
|
|
531
|
+
if (!result.done) throw new Error("Async operation is not supported in sync evaluation.");
|
|
532
|
+
return result.value;
|
|
551
533
|
};
|
|
534
|
+
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region packages/core/src/types/element/gql-element.ts
|
|
537
|
+
const GQL_ELEMENT_FACTORY = Symbol("GQL_ELEMENT_FACTORY");
|
|
538
|
+
const GQL_ELEMENT_CONTEXT = Symbol("GQL_ELEMENT_CONTEXT");
|
|
552
539
|
/**
|
|
553
|
-
*
|
|
540
|
+
* Abstract base class for all GraphQL elements (Fragment, Operation).
|
|
554
541
|
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
542
|
+
* Uses lazy evaluation with caching - definition is computed on first access.
|
|
543
|
+
* Subclasses should not be instantiated directly; use static `create` methods.
|
|
544
|
+
*
|
|
545
|
+
* @template TDefinition - The shape of the evaluated definition
|
|
546
|
+
* @template TInfer - Type inference metadata (access via `$infer`)
|
|
557
547
|
*/
|
|
558
|
-
|
|
559
|
-
|
|
548
|
+
var GqlElement = class GqlElement {
|
|
549
|
+
[GQL_ELEMENT_FACTORY];
|
|
550
|
+
[GQL_ELEMENT_CONTEXT] = null;
|
|
551
|
+
constructor(define, getDeps) {
|
|
552
|
+
this[GQL_ELEMENT_FACTORY] = createLazyEvaluator(define, getDeps, GqlElement.createEvaluationGenerator);
|
|
553
|
+
Object.defineProperty(this, "$infer", { get() {
|
|
554
|
+
throw new Error("This property is only for type meta. Do not access this property directly.");
|
|
555
|
+
} });
|
|
556
|
+
}
|
|
557
|
+
attach(attachmentOrAttachments) {
|
|
558
|
+
const attachments = Array.isArray(attachmentOrAttachments) ? attachmentOrAttachments : [attachmentOrAttachments];
|
|
559
|
+
for (const attachment of attachments) {
|
|
560
|
+
let cache = null;
|
|
561
|
+
const self = this;
|
|
562
|
+
Object.defineProperty(this, attachment.name, { get() {
|
|
563
|
+
if (cache) return cache;
|
|
564
|
+
GqlElement.evaluateInstantly(self);
|
|
565
|
+
return cache = attachment.createValue(self);
|
|
566
|
+
} });
|
|
567
|
+
}
|
|
568
|
+
return this;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Sets the canonical context for an element. Used by the builder.
|
|
572
|
+
* @internal
|
|
573
|
+
*/
|
|
574
|
+
static setContext(element, context) {
|
|
575
|
+
element[GQL_ELEMENT_CONTEXT] = context;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Gets the canonical context of an element, if set.
|
|
579
|
+
* @internal
|
|
580
|
+
*/
|
|
581
|
+
static getContext(element) {
|
|
582
|
+
return element[GQL_ELEMENT_CONTEXT];
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Creates a generator for async evaluation. Used by the builder.
|
|
586
|
+
* @internal
|
|
587
|
+
*/
|
|
588
|
+
static createEvaluationGenerator(element) {
|
|
589
|
+
return createEvaluationGenerator(element[GQL_ELEMENT_FACTORY], element[GQL_ELEMENT_CONTEXT]);
|
|
590
|
+
}
|
|
591
|
+
static evaluateInstantly(element) {
|
|
592
|
+
return evaluateSync(element[GQL_ELEMENT_FACTORY], element[GQL_ELEMENT_CONTEXT]);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Forces synchronous evaluation. Throws if async operation is needed.
|
|
596
|
+
* @internal
|
|
597
|
+
*/
|
|
598
|
+
static evaluateSync(element) {
|
|
599
|
+
GqlElement.evaluateInstantly(element);
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Evaluates and returns the element's definition.
|
|
603
|
+
* Throws if async operation is needed.
|
|
604
|
+
* @internal
|
|
605
|
+
*/
|
|
606
|
+
static get(element) {
|
|
607
|
+
return GqlElement.evaluateInstantly(element);
|
|
608
|
+
}
|
|
560
609
|
};
|
|
561
610
|
|
|
562
611
|
//#endregion
|
|
563
|
-
//#region packages/core/src/
|
|
612
|
+
//#region packages/core/src/types/element/define.ts
|
|
564
613
|
/**
|
|
565
|
-
*
|
|
566
|
-
*
|
|
614
|
+
* Define element for storing arbitrary value factories.
|
|
615
|
+
* @module
|
|
567
616
|
*/
|
|
568
|
-
const fieldPathContext = { current: null };
|
|
569
617
|
/**
|
|
570
|
-
*
|
|
571
|
-
*
|
|
618
|
+
* Represents a factory-based value definition.
|
|
619
|
+
*
|
|
620
|
+
* Define elements are created via `gql(({ define }) => define(() => value))`.
|
|
621
|
+
* The factory is evaluated lazily and the result is cached.
|
|
622
|
+
*
|
|
623
|
+
* @template TValue - The type of value produced by the factory
|
|
572
624
|
*
|
|
573
625
|
* @example
|
|
574
626
|
* ```typescript
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
* //
|
|
578
|
-
*
|
|
579
|
-
*
|
|
627
|
+
* // Store a primitive value
|
|
628
|
+
* const myNumber = gql.default(({ define }) => define(() => 42));
|
|
629
|
+
* console.log(myNumber.value); // 42
|
|
630
|
+
*
|
|
631
|
+
* // Store a plain object
|
|
632
|
+
* const myConfig = gql.default(({ define }) => define(() => ({
|
|
633
|
+
* apiUrl: "https://api.example.com",
|
|
634
|
+
* timeout: 5000,
|
|
635
|
+
* })));
|
|
636
|
+
* console.log(myConfig.value.apiUrl); // "https://api.example.com"
|
|
580
637
|
* ```
|
|
581
638
|
*/
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
*
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
639
|
+
var GqlDefine = class GqlDefine extends GqlElement {
|
|
640
|
+
constructor(define) {
|
|
641
|
+
super(define);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* The evaluated value from the factory.
|
|
645
|
+
* Triggers lazy evaluation on first access.
|
|
646
|
+
*/
|
|
647
|
+
get value() {
|
|
648
|
+
return GqlElement.get(this).factoryResult;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Creates a new GqlDefine instance.
|
|
652
|
+
*
|
|
653
|
+
* Prefer using the `gql(({ define }) => define(() => value))` API instead.
|
|
654
|
+
*
|
|
655
|
+
* @param factory - Function that produces the value. Can be sync or async.
|
|
656
|
+
* @returns A new GqlDefine instance wrapping the factory result.
|
|
657
|
+
*
|
|
658
|
+
* @example
|
|
659
|
+
* ```typescript
|
|
660
|
+
* // Sync factory
|
|
661
|
+
* const syncDefine = GqlDefine.create(() => 42);
|
|
662
|
+
*
|
|
663
|
+
* // Async factory
|
|
664
|
+
* const asyncDefine = GqlDefine.create(async () => {
|
|
665
|
+
* const data = await fetch('/api/config');
|
|
666
|
+
* return data.json();
|
|
667
|
+
* });
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
static create(factory) {
|
|
671
|
+
return new GqlDefine((_context) => {
|
|
672
|
+
const result = factory();
|
|
673
|
+
if (isPromiseLike(result)) return result.then((value) => ({ factoryResult: value }));
|
|
674
|
+
return { factoryResult: result };
|
|
675
|
+
});
|
|
596
676
|
}
|
|
597
677
|
};
|
|
678
|
+
|
|
679
|
+
//#endregion
|
|
680
|
+
//#region packages/core/src/types/element/fragment.ts
|
|
598
681
|
/**
|
|
599
|
-
*
|
|
682
|
+
* Represents a reusable GraphQL field selection on a specific type.
|
|
600
683
|
*
|
|
601
|
-
*
|
|
684
|
+
* Fragments are created via `gql(({ fragment }) => fragment.TypeName({ ... }))`.
|
|
685
|
+
* Use `spread()` to include the fragment's fields in an operation.
|
|
686
|
+
*
|
|
687
|
+
* @template TTypeName - The GraphQL type this fragment selects from
|
|
688
|
+
* @template TVariables - Variables required when spreading
|
|
689
|
+
* @template TFields - The selected fields structure
|
|
690
|
+
* @template TOutput - Inferred output type from selected fields
|
|
602
691
|
*/
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
692
|
+
var Fragment = class Fragment extends GqlElement {
|
|
693
|
+
constructor(define) {
|
|
694
|
+
super(define);
|
|
695
|
+
}
|
|
696
|
+
/** The GraphQL type name this fragment selects from. */
|
|
697
|
+
get typename() {
|
|
698
|
+
return GqlElement.get(this).typename;
|
|
699
|
+
}
|
|
700
|
+
/** Optional unique key for prebuilt type lookup. */
|
|
701
|
+
get key() {
|
|
702
|
+
return GqlElement.get(this).key;
|
|
703
|
+
}
|
|
704
|
+
/** The schema label this fragment belongs to. */
|
|
705
|
+
get schemaLabel() {
|
|
706
|
+
return GqlElement.get(this).schemaLabel;
|
|
707
|
+
}
|
|
708
|
+
/** Variable definitions for this fragment. */
|
|
709
|
+
get variableDefinitions() {
|
|
710
|
+
return GqlElement.get(this).variableDefinitions;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Spreads this fragment's fields into a parent selection.
|
|
714
|
+
* Pass variables if the fragment defines any.
|
|
715
|
+
*/
|
|
716
|
+
get spread() {
|
|
717
|
+
return GqlElement.get(this).spread;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Creates a new Fragment instance.
|
|
721
|
+
* Prefer using the `gql(({ fragment }) => ...)` API instead.
|
|
722
|
+
* @internal
|
|
723
|
+
*/
|
|
724
|
+
static create(define) {
|
|
725
|
+
return new Fragment(define);
|
|
726
|
+
}
|
|
618
727
|
};
|
|
728
|
+
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region packages/core/src/types/element/operation.ts
|
|
619
731
|
/**
|
|
620
|
-
*
|
|
621
|
-
* Matches patterns like "Type:![]!", "Type:![]?", "Type:?[]!", etc.
|
|
732
|
+
* Represents a GraphQL operation (query, mutation, or subscription).
|
|
622
733
|
*
|
|
623
|
-
*
|
|
734
|
+
* Operations are created via `gql(({ query }) => query.operation({ ... }))`.
|
|
735
|
+
* Produces a TypedDocumentNode for type-safe execution with GraphQL clients.
|
|
736
|
+
*
|
|
737
|
+
* @template TOperationType - 'query' | 'mutation' | 'subscription'
|
|
738
|
+
* @template TOperationName - The unique operation name
|
|
739
|
+
* @template TVariableNames - Tuple of variable names
|
|
740
|
+
* @template TVariables - Variable types for the operation
|
|
741
|
+
* @template TFields - Selected fields structure
|
|
742
|
+
* @template TData - Inferred response data type
|
|
624
743
|
*/
|
|
625
|
-
|
|
626
|
-
|
|
744
|
+
var Operation = class Operation extends GqlElement {
|
|
745
|
+
constructor(define) {
|
|
746
|
+
super(define);
|
|
747
|
+
}
|
|
748
|
+
/** The operation type: 'query', 'mutation', or 'subscription'. */
|
|
749
|
+
get operationType() {
|
|
750
|
+
return GqlElement.get(this).operationType;
|
|
751
|
+
}
|
|
752
|
+
/** The unique name of this operation. */
|
|
753
|
+
get operationName() {
|
|
754
|
+
return GqlElement.get(this).operationName;
|
|
755
|
+
}
|
|
756
|
+
/** The schema label this operation belongs to. */
|
|
757
|
+
get schemaLabel() {
|
|
758
|
+
return GqlElement.get(this).schemaLabel;
|
|
759
|
+
}
|
|
760
|
+
/** List of variable names defined for this operation. */
|
|
761
|
+
get variableNames() {
|
|
762
|
+
return GqlElement.get(this).variableNames;
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Returns the field selections. Used for document reconstruction.
|
|
766
|
+
* @internal
|
|
767
|
+
*/
|
|
768
|
+
get documentSource() {
|
|
769
|
+
return GqlElement.get(this).documentSource;
|
|
770
|
+
}
|
|
771
|
+
/** The TypedDocumentNode for use with GraphQL clients. */
|
|
772
|
+
get document() {
|
|
773
|
+
return GqlElement.get(this).document;
|
|
774
|
+
}
|
|
775
|
+
/** Custom metadata attached to this operation, if any. */
|
|
776
|
+
get metadata() {
|
|
777
|
+
return GqlElement.get(this).metadata;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Creates a new Operation instance.
|
|
781
|
+
* Prefer using the `gql(({ query }) => ...)` API instead.
|
|
782
|
+
* @internal
|
|
783
|
+
*/
|
|
784
|
+
static create(define) {
|
|
785
|
+
return new Operation(define);
|
|
786
|
+
}
|
|
627
787
|
};
|
|
628
788
|
|
|
629
789
|
//#endregion
|
|
630
|
-
//#region packages/core/src/
|
|
631
|
-
function mapValues(obj, fn) {
|
|
632
|
-
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value, key)]));
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
//#endregion
|
|
636
|
-
//#region packages/core/src/composer/fields-builder.ts
|
|
637
|
-
const cacheMapBySchema = /* @__PURE__ */ new WeakMap();
|
|
638
|
-
const ensureCacheMapBySchema = (schema) => {
|
|
639
|
-
const cachedCacheMap = cacheMapBySchema.get(schema);
|
|
640
|
-
if (cachedCacheMap) return cachedCacheMap;
|
|
641
|
-
const cacheMap = /* @__PURE__ */ new Map();
|
|
642
|
-
cacheMapBySchema.set(schema, cacheMap);
|
|
643
|
-
return cacheMap;
|
|
644
|
-
};
|
|
790
|
+
//#region packages/core/src/composer/compat.ts
|
|
645
791
|
/**
|
|
646
|
-
*
|
|
792
|
+
* Compat composer factory for creating GraphQL operation specifications.
|
|
793
|
+
* @module
|
|
794
|
+
*/
|
|
795
|
+
/**
|
|
796
|
+
* Creates a factory for composing compat operation specifications.
|
|
647
797
|
*
|
|
648
|
-
* Returns
|
|
649
|
-
*
|
|
798
|
+
* Returns a function that creates a `GqlDefine<CompatSpec<...>>` storing
|
|
799
|
+
* the operation specification with unevaluated fieldsBuilder.
|
|
650
800
|
*
|
|
651
801
|
* @param schema - The GraphQL schema definition
|
|
652
|
-
* @param
|
|
653
|
-
* @returns
|
|
802
|
+
* @param operationType - The operation type ('query' | 'mutation' | 'subscription')
|
|
803
|
+
* @returns Compat operation composer function
|
|
654
804
|
*
|
|
655
|
-
* @internal Used by
|
|
805
|
+
* @internal Used by `createGqlElementComposer`
|
|
656
806
|
*/
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const entries = Object.entries(typeDef.fields).map(([fieldName, type]) => {
|
|
669
|
-
const factory = (fieldArgs, extras) => {
|
|
670
|
-
const wrap = (value) => wrapByKey(extras?.alias ?? fieldName, value);
|
|
671
|
-
const directives = extras?.directives ?? [];
|
|
672
|
-
if (type.kind === "object") {
|
|
673
|
-
const factoryReturn = ((nest) => {
|
|
674
|
-
const nestedFields = withFieldPath(appendToPath(getCurrentFieldPath(), {
|
|
675
|
-
field: fieldName,
|
|
676
|
-
parentType: typeName,
|
|
677
|
-
isList: isListType(type.modifier)
|
|
678
|
-
}), () => nest({ f: createFieldFactories(schema, type.name) }));
|
|
679
|
-
return wrap({
|
|
680
|
-
parent: typeName,
|
|
681
|
-
field: fieldName,
|
|
682
|
-
type,
|
|
683
|
-
args: fieldArgs ?? {},
|
|
684
|
-
directives,
|
|
685
|
-
object: nestedFields,
|
|
686
|
-
union: null
|
|
687
|
-
});
|
|
688
|
-
});
|
|
689
|
-
return factoryReturn;
|
|
690
|
-
}
|
|
691
|
-
if (type.kind === "union") {
|
|
692
|
-
const factoryReturn = ((nest) => {
|
|
693
|
-
const nestedUnion = withFieldPath(appendToPath(getCurrentFieldPath(), {
|
|
694
|
-
field: fieldName,
|
|
695
|
-
parentType: typeName,
|
|
696
|
-
isList: isListType(type.modifier)
|
|
697
|
-
}), () => mapValues(nest, (builder, memberName) => {
|
|
698
|
-
if (!builder) throw new Error(`Builder is undefined for member name: ${memberName}`);
|
|
699
|
-
return builder({ f: createFieldFactories(schema, memberName) });
|
|
700
|
-
}));
|
|
701
|
-
return wrap({
|
|
702
|
-
parent: typeName,
|
|
703
|
-
field: fieldName,
|
|
704
|
-
type,
|
|
705
|
-
args: fieldArgs ?? {},
|
|
706
|
-
directives,
|
|
707
|
-
object: null,
|
|
708
|
-
union: nestedUnion
|
|
709
|
-
});
|
|
710
|
-
});
|
|
711
|
-
return factoryReturn;
|
|
712
|
-
}
|
|
713
|
-
if (type.kind === "scalar" || type.kind === "enum" || type.kind === "typename") return wrap({
|
|
714
|
-
parent: typeName,
|
|
715
|
-
field: fieldName,
|
|
716
|
-
type,
|
|
717
|
-
args: fieldArgs ?? {},
|
|
718
|
-
directives,
|
|
719
|
-
object: null,
|
|
720
|
-
union: null
|
|
721
|
-
});
|
|
722
|
-
throw new Error(`Unsupported field type: ${type}`);
|
|
723
|
-
};
|
|
724
|
-
return [fieldName, factory];
|
|
725
|
-
});
|
|
726
|
-
return Object.fromEntries(entries);
|
|
807
|
+
const createCompatComposer = (schema, operationType) => {
|
|
808
|
+
if (schema.operations[operationType] === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
|
|
809
|
+
return (options) => {
|
|
810
|
+
return GqlDefine.create(() => ({
|
|
811
|
+
schema,
|
|
812
|
+
operationType,
|
|
813
|
+
operationName: options.name,
|
|
814
|
+
variables: options.variables ?? {},
|
|
815
|
+
fieldsBuilder: options.fields
|
|
816
|
+
}));
|
|
817
|
+
};
|
|
727
818
|
};
|
|
728
819
|
|
|
729
820
|
//#endregion
|
|
730
|
-
//#region packages/core/src/
|
|
821
|
+
//#region packages/core/src/composer/directive-builder.ts
|
|
731
822
|
/**
|
|
732
|
-
*
|
|
823
|
+
* Directive builder utilities for creating field-level directives.
|
|
824
|
+
*
|
|
825
|
+
* Provides type-safe methods for creating directive references that can be
|
|
826
|
+
* applied to field selections. The builder follows a similar pattern to
|
|
827
|
+
* the variable builder ($var).
|
|
828
|
+
*
|
|
733
829
|
* @module
|
|
734
830
|
*/
|
|
735
831
|
/**
|
|
736
|
-
*
|
|
832
|
+
* Creates a directive method factory for a specific directive.
|
|
737
833
|
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
834
|
+
* @param name - The directive name (without @)
|
|
835
|
+
* @param locations - Valid locations where the directive can be applied
|
|
836
|
+
* @returns A function that creates DirectiveRef instances
|
|
741
837
|
*
|
|
742
838
|
* @example
|
|
743
839
|
* ```typescript
|
|
744
|
-
*
|
|
745
|
-
*
|
|
840
|
+
* const skipMethod = createDirectiveMethod("skip", ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"] as const);
|
|
841
|
+
* const skipDirective = skipMethod({ if: true });
|
|
842
|
+
* ```
|
|
843
|
+
*/
|
|
844
|
+
const createDirectiveMethod = (name, locations) => {
|
|
845
|
+
return (args) => new DirectiveRef({
|
|
846
|
+
name,
|
|
847
|
+
arguments: args,
|
|
848
|
+
locations
|
|
849
|
+
});
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* Creates a typed directive method with argument type specifiers.
|
|
853
|
+
* Enables enum value output in directive arguments.
|
|
746
854
|
*
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
*
|
|
855
|
+
* @param name - The directive name (without @)
|
|
856
|
+
* @param locations - Valid locations where the directive can be applied
|
|
857
|
+
* @param argSpecs - Type specifiers for directive arguments
|
|
858
|
+
* @returns A function that creates DirectiveRef instances with argument type info
|
|
750
859
|
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```typescript
|
|
862
|
+
* const authMethod = createTypedDirectiveMethod(
|
|
863
|
+
* "auth",
|
|
864
|
+
* ["FIELD"] as const,
|
|
865
|
+
* { role: { kind: "enum", name: "Role", modifier: "!" } }
|
|
866
|
+
* );
|
|
867
|
+
* const authDirective = authMethod({ role: "ADMIN" });
|
|
755
868
|
* ```
|
|
756
869
|
*/
|
|
757
|
-
const
|
|
758
|
-
return
|
|
870
|
+
const createTypedDirectiveMethod = (name, locations, argSpecs) => {
|
|
871
|
+
return (args) => new DirectiveRef({
|
|
872
|
+
name,
|
|
873
|
+
arguments: args,
|
|
874
|
+
locations,
|
|
875
|
+
argumentSpecs: argSpecs
|
|
876
|
+
});
|
|
759
877
|
};
|
|
760
|
-
|
|
761
|
-
//#endregion
|
|
762
|
-
//#region packages/core/src/types/element/lazy-evaluator.ts
|
|
763
878
|
/**
|
|
764
|
-
*
|
|
879
|
+
* Standard directive locations for @skip and @include.
|
|
880
|
+
*/
|
|
881
|
+
const CONDITIONAL_DIRECTIVE_LOCATIONS = [
|
|
882
|
+
"FIELD",
|
|
883
|
+
"FRAGMENT_SPREAD",
|
|
884
|
+
"INLINE_FRAGMENT"
|
|
885
|
+
];
|
|
886
|
+
/**
|
|
887
|
+
* Creates the standard GraphQL directives (@skip, @include).
|
|
888
|
+
* These are always available regardless of schema definition.
|
|
765
889
|
*
|
|
766
|
-
* @
|
|
767
|
-
*
|
|
768
|
-
* @
|
|
769
|
-
*
|
|
890
|
+
* @returns Object containing skip and include directive methods
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```typescript
|
|
894
|
+
* const $dir = createStandardDirectives();
|
|
895
|
+
* const skipDirective = $dir.skip({ if: true });
|
|
896
|
+
* ```
|
|
770
897
|
*/
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
yield promise;
|
|
788
|
-
return cache.value;
|
|
898
|
+
const createStandardDirectives = () => ({
|
|
899
|
+
skip: createDirectiveMethod("skip", CONDITIONAL_DIRECTIVE_LOCATIONS),
|
|
900
|
+
include: createDirectiveMethod("include", CONDITIONAL_DIRECTIVE_LOCATIONS)
|
|
901
|
+
});
|
|
902
|
+
/**
|
|
903
|
+
* Creates a directive builder with standard directives and optional custom directives.
|
|
904
|
+
*
|
|
905
|
+
* @param customDirectives - Additional directive methods from schema (generated by codegen)
|
|
906
|
+
* @returns Combined directive builder with all available directives
|
|
907
|
+
*
|
|
908
|
+
* @internal Used by codegen to create schema-specific directive builders
|
|
909
|
+
*/
|
|
910
|
+
const createDirectiveBuilder = (customDirectives) => {
|
|
911
|
+
return {
|
|
912
|
+
...createStandardDirectives(),
|
|
913
|
+
...customDirectives ?? {}
|
|
789
914
|
};
|
|
790
915
|
};
|
|
791
916
|
/**
|
|
792
|
-
*
|
|
793
|
-
*
|
|
917
|
+
* Type guard to check if a value is a DirectiveRef.
|
|
918
|
+
*
|
|
919
|
+
* @param value - Value to check
|
|
920
|
+
* @returns True if value is a DirectiveRef instance
|
|
794
921
|
*/
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
}
|
|
922
|
+
const isDirectiveRef = (value) => {
|
|
923
|
+
return value instanceof DirectiveRef;
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
//#endregion
|
|
927
|
+
//#region packages/core/src/types/metadata/adapter.ts
|
|
798
928
|
/**
|
|
799
|
-
*
|
|
800
|
-
*
|
|
929
|
+
* Creates the default adapter instance.
|
|
930
|
+
* @internal
|
|
801
931
|
*/
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
932
|
+
const createDefaultAdapter = () => ({ aggregateFragmentMetadata: (fragments) => fragments.map((m) => m.metadata) });
|
|
933
|
+
/**
|
|
934
|
+
* The default adapter instance.
|
|
935
|
+
*/
|
|
936
|
+
const defaultMetadataAdapter = createDefaultAdapter();
|
|
807
937
|
|
|
808
938
|
//#endregion
|
|
809
|
-
//#region packages/core/src/
|
|
810
|
-
|
|
811
|
-
|
|
939
|
+
//#region packages/core/src/utils/map-values.ts
|
|
940
|
+
function mapValues(obj, fn) {
|
|
941
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value, key)]));
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
//#endregion
|
|
945
|
+
//#region packages/core/src/composer/field-path-context.ts
|
|
812
946
|
/**
|
|
813
|
-
*
|
|
947
|
+
* Shared mutable container for field path context.
|
|
948
|
+
* Only synchronous access is supported.
|
|
949
|
+
*/
|
|
950
|
+
const fieldPathContext = { current: null };
|
|
951
|
+
/**
|
|
952
|
+
* Get the current field path.
|
|
953
|
+
* Returns null if not in a field building context.
|
|
814
954
|
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
955
|
+
* @example
|
|
956
|
+
* ```typescript
|
|
957
|
+
* import { getCurrentFieldPath } from '@soda-gql/core';
|
|
817
958
|
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
959
|
+
* // Inside a field builder or model spread:
|
|
960
|
+
* const path = getCurrentFieldPath();
|
|
961
|
+
* console.log(path?.full); // "$.user.posts[].author"
|
|
962
|
+
* ```
|
|
820
963
|
*/
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
Object.defineProperty(this, attachment.name, { get() {
|
|
836
|
-
if (cache) return cache;
|
|
837
|
-
GqlElement.evaluateInstantly(self);
|
|
838
|
-
return cache = attachment.createValue(self);
|
|
839
|
-
} });
|
|
840
|
-
}
|
|
841
|
-
return this;
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
|
-
* Sets the canonical context for an element. Used by the builder.
|
|
845
|
-
* @internal
|
|
846
|
-
*/
|
|
847
|
-
static setContext(element, context) {
|
|
848
|
-
element[GQL_ELEMENT_CONTEXT] = context;
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* Gets the canonical context of an element, if set.
|
|
852
|
-
* @internal
|
|
853
|
-
*/
|
|
854
|
-
static getContext(element) {
|
|
855
|
-
return element[GQL_ELEMENT_CONTEXT];
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Creates a generator for async evaluation. Used by the builder.
|
|
859
|
-
* @internal
|
|
860
|
-
*/
|
|
861
|
-
static createEvaluationGenerator(element) {
|
|
862
|
-
return createEvaluationGenerator(element[GQL_ELEMENT_FACTORY], element[GQL_ELEMENT_CONTEXT]);
|
|
863
|
-
}
|
|
864
|
-
static evaluateInstantly(element) {
|
|
865
|
-
return evaluateSync(element[GQL_ELEMENT_FACTORY], element[GQL_ELEMENT_CONTEXT]);
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* Forces synchronous evaluation. Throws if async operation is needed.
|
|
869
|
-
* @internal
|
|
870
|
-
*/
|
|
871
|
-
static evaluateSync(element) {
|
|
872
|
-
GqlElement.evaluateInstantly(element);
|
|
873
|
-
}
|
|
874
|
-
/**
|
|
875
|
-
* Evaluates and returns the element's definition.
|
|
876
|
-
* Throws if async operation is needed.
|
|
877
|
-
* @internal
|
|
878
|
-
*/
|
|
879
|
-
static get(element) {
|
|
880
|
-
return GqlElement.evaluateInstantly(element);
|
|
964
|
+
const getCurrentFieldPath = () => fieldPathContext.current;
|
|
965
|
+
/**
|
|
966
|
+
* Run a function with a specific field path context.
|
|
967
|
+
* Restores the previous path after the function completes.
|
|
968
|
+
*
|
|
969
|
+
* @internal
|
|
970
|
+
*/
|
|
971
|
+
const withFieldPath = (path, fn) => {
|
|
972
|
+
const previousPath = fieldPathContext.current;
|
|
973
|
+
fieldPathContext.current = path;
|
|
974
|
+
try {
|
|
975
|
+
return fn();
|
|
976
|
+
} finally {
|
|
977
|
+
fieldPathContext.current = previousPath;
|
|
881
978
|
}
|
|
882
979
|
};
|
|
883
|
-
|
|
884
|
-
//#endregion
|
|
885
|
-
//#region packages/core/src/types/element/fragment.ts
|
|
886
980
|
/**
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
|
|
981
|
+
* Append a new segment to the current path.
|
|
982
|
+
*
|
|
983
|
+
* @internal
|
|
984
|
+
*/
|
|
985
|
+
const appendToPath = (parent, segment) => {
|
|
986
|
+
const listSuffix = segment.isList ? "[]" : "";
|
|
987
|
+
const newSegment = {
|
|
988
|
+
field: segment.field,
|
|
989
|
+
parent: segment.parentType,
|
|
990
|
+
isList: segment.isList
|
|
991
|
+
};
|
|
992
|
+
if (!parent) return {
|
|
993
|
+
full: `$.${segment.field}${listSuffix}`,
|
|
994
|
+
segments: [newSegment]
|
|
995
|
+
};
|
|
996
|
+
return {
|
|
997
|
+
full: `${parent.full}.${segment.field}${listSuffix}`,
|
|
998
|
+
segments: [...parent.segments, newSegment]
|
|
999
|
+
};
|
|
1000
|
+
};
|
|
1001
|
+
/**
|
|
1002
|
+
* Check if a type specifier represents a list type.
|
|
1003
|
+
* Matches patterns like "Type:![]!", "Type:![]?", "Type:?[]!", etc.
|
|
891
1004
|
*
|
|
892
|
-
* @
|
|
893
|
-
* @template TVariables - Variables required when spreading
|
|
894
|
-
* @template TFields - The selected fields structure
|
|
895
|
-
* @template TOutput - Inferred output type from selected fields
|
|
1005
|
+
* @internal
|
|
896
1006
|
*/
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
super(define);
|
|
900
|
-
}
|
|
901
|
-
/** The GraphQL type name this fragment selects from. */
|
|
902
|
-
get typename() {
|
|
903
|
-
return GqlElement.get(this).typename;
|
|
904
|
-
}
|
|
905
|
-
/** Optional unique key for prebuilt type lookup. */
|
|
906
|
-
get key() {
|
|
907
|
-
return GqlElement.get(this).key;
|
|
908
|
-
}
|
|
909
|
-
/** The schema label this fragment belongs to. */
|
|
910
|
-
get schemaLabel() {
|
|
911
|
-
return GqlElement.get(this).schemaLabel;
|
|
912
|
-
}
|
|
913
|
-
/** Variable definitions for this fragment. */
|
|
914
|
-
get variableDefinitions() {
|
|
915
|
-
return GqlElement.get(this).variableDefinitions;
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Spreads this fragment's fields into a parent selection.
|
|
919
|
-
* Pass variables if the fragment defines any.
|
|
920
|
-
*/
|
|
921
|
-
get spread() {
|
|
922
|
-
return GqlElement.get(this).spread;
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* Creates a new Fragment instance.
|
|
926
|
-
* Prefer using the `gql(({ fragment }) => ...)` API instead.
|
|
927
|
-
* @internal
|
|
928
|
-
*/
|
|
929
|
-
static create(define) {
|
|
930
|
-
return new Fragment(define);
|
|
931
|
-
}
|
|
1007
|
+
const isListType = (typeString) => {
|
|
1008
|
+
return typeString.includes("[]");
|
|
932
1009
|
};
|
|
933
1010
|
|
|
934
1011
|
//#endregion
|
|
935
|
-
//#region packages/core/src/
|
|
1012
|
+
//#region packages/core/src/composer/fields-builder.ts
|
|
1013
|
+
const cacheMapBySchema = /* @__PURE__ */ new WeakMap();
|
|
1014
|
+
const ensureCacheMapBySchema = (schema) => {
|
|
1015
|
+
const cachedCacheMap = cacheMapBySchema.get(schema);
|
|
1016
|
+
if (cachedCacheMap) return cachedCacheMap;
|
|
1017
|
+
const cacheMap = /* @__PURE__ */ new Map();
|
|
1018
|
+
cacheMapBySchema.set(schema, cacheMap);
|
|
1019
|
+
return cacheMap;
|
|
1020
|
+
};
|
|
936
1021
|
/**
|
|
937
|
-
*
|
|
1022
|
+
* Creates field selection factories for a given object type.
|
|
938
1023
|
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
1024
|
+
* Returns an object with a factory for each field defined on the type.
|
|
1025
|
+
* Factories are cached per schema+type to avoid recreation.
|
|
941
1026
|
*
|
|
942
|
-
* @
|
|
943
|
-
* @
|
|
944
|
-
* @
|
|
945
|
-
*
|
|
946
|
-
* @
|
|
947
|
-
* @template TData - Inferred response data type
|
|
1027
|
+
* @param schema - The GraphQL schema definition
|
|
1028
|
+
* @param typeName - The object type name to create factories for
|
|
1029
|
+
* @returns Object mapping field names to their selection factories
|
|
1030
|
+
*
|
|
1031
|
+
* @internal Used by operation and fragment composers
|
|
948
1032
|
*/
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1033
|
+
const createFieldFactories = (schema, typeName) => {
|
|
1034
|
+
const cacheMap = ensureCacheMapBySchema(schema);
|
|
1035
|
+
const cached = cacheMap.get(typeName);
|
|
1036
|
+
if (cached) return cached;
|
|
1037
|
+
const factories = createFieldFactoriesInner(schema, typeName);
|
|
1038
|
+
cacheMap.set(typeName, factories);
|
|
1039
|
+
return factories;
|
|
1040
|
+
};
|
|
1041
|
+
const createFieldFactoriesInner = (schema, typeName) => {
|
|
1042
|
+
const typeDef = schema.object[typeName];
|
|
1043
|
+
if (!typeDef) throw new Error(`Type ${typeName} is not defined in schema objects`);
|
|
1044
|
+
const entries = Object.entries(typeDef.fields).map(([fieldName, type]) => {
|
|
1045
|
+
const factory = (fieldArgs, extras) => {
|
|
1046
|
+
const wrap = (value) => wrapByKey(extras?.alias ?? fieldName, value);
|
|
1047
|
+
const directives = extras?.directives ?? [];
|
|
1048
|
+
if (type.kind === "object") {
|
|
1049
|
+
const factoryReturn = ((nest) => {
|
|
1050
|
+
const nestedFields = withFieldPath(appendToPath(getCurrentFieldPath(), {
|
|
1051
|
+
field: fieldName,
|
|
1052
|
+
parentType: typeName,
|
|
1053
|
+
isList: isListType(type.modifier)
|
|
1054
|
+
}), () => nest({ f: createFieldFactories(schema, type.name) }));
|
|
1055
|
+
return wrap({
|
|
1056
|
+
parent: typeName,
|
|
1057
|
+
field: fieldName,
|
|
1058
|
+
type,
|
|
1059
|
+
args: fieldArgs ?? {},
|
|
1060
|
+
directives,
|
|
1061
|
+
object: nestedFields,
|
|
1062
|
+
union: null
|
|
1063
|
+
});
|
|
1064
|
+
});
|
|
1065
|
+
return factoryReturn;
|
|
1066
|
+
}
|
|
1067
|
+
if (type.kind === "union") {
|
|
1068
|
+
const factoryReturn = ((nest) => {
|
|
1069
|
+
const nestedUnion = withFieldPath(appendToPath(getCurrentFieldPath(), {
|
|
1070
|
+
field: fieldName,
|
|
1071
|
+
parentType: typeName,
|
|
1072
|
+
isList: isListType(type.modifier)
|
|
1073
|
+
}), () => mapValues(nest, (builder, memberName) => {
|
|
1074
|
+
if (!builder) throw new Error(`Builder is undefined for member name: ${memberName}`);
|
|
1075
|
+
return builder({ f: createFieldFactories(schema, memberName) });
|
|
1076
|
+
}));
|
|
1077
|
+
return wrap({
|
|
1078
|
+
parent: typeName,
|
|
1079
|
+
field: fieldName,
|
|
1080
|
+
type,
|
|
1081
|
+
args: fieldArgs ?? {},
|
|
1082
|
+
directives,
|
|
1083
|
+
object: null,
|
|
1084
|
+
union: nestedUnion
|
|
1085
|
+
});
|
|
1086
|
+
});
|
|
1087
|
+
return factoryReturn;
|
|
1088
|
+
}
|
|
1089
|
+
if (type.kind === "scalar" || type.kind === "enum" || type.kind === "typename") return wrap({
|
|
1090
|
+
parent: typeName,
|
|
1091
|
+
field: fieldName,
|
|
1092
|
+
type,
|
|
1093
|
+
args: fieldArgs ?? {},
|
|
1094
|
+
directives,
|
|
1095
|
+
object: null,
|
|
1096
|
+
union: null
|
|
1097
|
+
});
|
|
1098
|
+
throw new Error(`Unsupported field type: ${type}`);
|
|
1099
|
+
};
|
|
1100
|
+
return [fieldName, factory];
|
|
1101
|
+
});
|
|
1102
|
+
return Object.fromEntries(entries);
|
|
992
1103
|
};
|
|
993
1104
|
|
|
994
1105
|
//#endregion
|
|
@@ -1063,6 +1174,142 @@ const createVarAssignments = (definitions, providedValues) => {
|
|
|
1063
1174
|
*/
|
|
1064
1175
|
const createVarRefs = (definitions) => mapValues(definitions, (_, name) => createVarRefFromVariable(name));
|
|
1065
1176
|
|
|
1177
|
+
//#endregion
|
|
1178
|
+
//#region packages/core/src/composer/operation-core.ts
|
|
1179
|
+
/**
|
|
1180
|
+
* Builds an operation artifact from the provided parameters.
|
|
1181
|
+
*
|
|
1182
|
+
* This function contains the core logic for:
|
|
1183
|
+
* - Creating variable refs and field factories
|
|
1184
|
+
* - Evaluating fields with fragment usage tracking
|
|
1185
|
+
* - Building the document
|
|
1186
|
+
* - Handling metadata (sync and async)
|
|
1187
|
+
* - Applying document transformations
|
|
1188
|
+
*
|
|
1189
|
+
* @param params - Operation building parameters
|
|
1190
|
+
* @returns Operation artifact or Promise of artifact (if async metadata)
|
|
1191
|
+
*
|
|
1192
|
+
* @internal Used by operation.ts and extend.ts
|
|
1193
|
+
*/
|
|
1194
|
+
const buildOperationArtifact = (params) => {
|
|
1195
|
+
const { schema, operationType, operationTypeName, operationName, variables, fieldsFactory, adapter, metadata: metadataBuilder, transformDocument: operationTransformDocument, adapterTransformDocument } = params;
|
|
1196
|
+
const $ = createVarRefs(variables);
|
|
1197
|
+
const f = createFieldFactories(schema, operationTypeName);
|
|
1198
|
+
const { result: fields, usages: fragmentUsages } = withFragmentUsageCollection(() => fieldsFactory({
|
|
1199
|
+
f,
|
|
1200
|
+
$
|
|
1201
|
+
}));
|
|
1202
|
+
const document = buildDocument({
|
|
1203
|
+
operationName,
|
|
1204
|
+
operationType,
|
|
1205
|
+
variables,
|
|
1206
|
+
fields,
|
|
1207
|
+
schema
|
|
1208
|
+
});
|
|
1209
|
+
const variableNames = Object.keys(variables);
|
|
1210
|
+
if (!fragmentUsages.some((u) => u.metadataBuilder) && !metadataBuilder && !adapterTransformDocument && !operationTransformDocument) return {
|
|
1211
|
+
operationType,
|
|
1212
|
+
operationName,
|
|
1213
|
+
schemaLabel: schema.label,
|
|
1214
|
+
variableNames,
|
|
1215
|
+
documentSource: () => fields,
|
|
1216
|
+
document,
|
|
1217
|
+
metadata: void 0
|
|
1218
|
+
};
|
|
1219
|
+
const aggregateFragmentMetadata = (resolvedFragmentMetadata) => {
|
|
1220
|
+
const fragmentMetaInfos = fragmentUsages.map((usage, index) => ({
|
|
1221
|
+
metadata: resolvedFragmentMetadata[index],
|
|
1222
|
+
fieldPath: usage.path
|
|
1223
|
+
}));
|
|
1224
|
+
return adapter.aggregateFragmentMetadata(fragmentMetaInfos);
|
|
1225
|
+
};
|
|
1226
|
+
const fragmentMetadataResults = fragmentUsages.map((usage) => usage.metadataBuilder ? usage.metadataBuilder() : void 0);
|
|
1227
|
+
const hasAsyncFragmentMetadata = fragmentMetadataResults.some((r) => isPromiseLike(r));
|
|
1228
|
+
const buildOperationMetadata = (aggregatedFragmentMetadata) => {
|
|
1229
|
+
const schemaLevel = adapter.schemaLevel;
|
|
1230
|
+
return metadataBuilder?.({
|
|
1231
|
+
$,
|
|
1232
|
+
document,
|
|
1233
|
+
fragmentMetadata: aggregatedFragmentMetadata,
|
|
1234
|
+
schemaLevel
|
|
1235
|
+
});
|
|
1236
|
+
};
|
|
1237
|
+
const makeCreateArtifact = (aggregated$1) => {
|
|
1238
|
+
return ({ metadata }) => {
|
|
1239
|
+
let finalDocument = operationTransformDocument ? operationTransformDocument({
|
|
1240
|
+
document,
|
|
1241
|
+
metadata
|
|
1242
|
+
}) : document;
|
|
1243
|
+
if (adapterTransformDocument) finalDocument = adapterTransformDocument({
|
|
1244
|
+
document: finalDocument,
|
|
1245
|
+
operationName,
|
|
1246
|
+
operationType,
|
|
1247
|
+
variableNames,
|
|
1248
|
+
schemaLevel: adapter.schemaLevel,
|
|
1249
|
+
fragmentMetadata: aggregated$1
|
|
1250
|
+
});
|
|
1251
|
+
return {
|
|
1252
|
+
operationType,
|
|
1253
|
+
operationName,
|
|
1254
|
+
schemaLabel: schema.label,
|
|
1255
|
+
variableNames,
|
|
1256
|
+
documentSource: () => fields,
|
|
1257
|
+
document: finalDocument,
|
|
1258
|
+
metadata
|
|
1259
|
+
};
|
|
1260
|
+
};
|
|
1261
|
+
};
|
|
1262
|
+
if (hasAsyncFragmentMetadata) return Promise.all(fragmentMetadataResults).then(async (resolvedFragmentMetadata) => {
|
|
1263
|
+
const aggregated$1 = aggregateFragmentMetadata(resolvedFragmentMetadata);
|
|
1264
|
+
const operationMetadata = await buildOperationMetadata(aggregated$1);
|
|
1265
|
+
return makeCreateArtifact(aggregated$1)({ metadata: operationMetadata });
|
|
1266
|
+
});
|
|
1267
|
+
const aggregated = aggregateFragmentMetadata(fragmentMetadataResults);
|
|
1268
|
+
const createArtifact = makeCreateArtifact(aggregated);
|
|
1269
|
+
const operationMetadataResult = buildOperationMetadata(aggregated);
|
|
1270
|
+
if (isPromiseLike(operationMetadataResult)) return operationMetadataResult.then((metadata) => createArtifact({ metadata }));
|
|
1271
|
+
return createArtifact({ metadata: operationMetadataResult });
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
//#endregion
|
|
1275
|
+
//#region packages/core/src/composer/extend.ts
|
|
1276
|
+
/**
|
|
1277
|
+
* Extend composer factory for creating Operations from compat specs.
|
|
1278
|
+
* @module
|
|
1279
|
+
*/
|
|
1280
|
+
/**
|
|
1281
|
+
* Creates a factory for extending compat specs into full operations.
|
|
1282
|
+
*
|
|
1283
|
+
* The extend function takes a compat spec (created by `query.compat()`) and
|
|
1284
|
+
* optional metadata/transformDocument options, then creates a full Operation.
|
|
1285
|
+
*
|
|
1286
|
+
* @param schema - The GraphQL schema definition
|
|
1287
|
+
* @param adapter - Optional metadata adapter for custom metadata handling
|
|
1288
|
+
* @param transformDocument - Optional document transformer
|
|
1289
|
+
* @returns Extend composer function
|
|
1290
|
+
*
|
|
1291
|
+
* @internal Used by `createGqlElementComposer`
|
|
1292
|
+
*/
|
|
1293
|
+
const createExtendComposer = (schema, adapter, transformDocument) => {
|
|
1294
|
+
const resolvedAdapter = adapter ?? defaultMetadataAdapter;
|
|
1295
|
+
return (compat, options) => {
|
|
1296
|
+
const { operationType, operationName, variables, fieldsBuilder } = compat.value;
|
|
1297
|
+
const operationTypeName = schema.operations[operationType];
|
|
1298
|
+
return Operation.create((() => buildOperationArtifact({
|
|
1299
|
+
schema,
|
|
1300
|
+
operationType,
|
|
1301
|
+
operationTypeName,
|
|
1302
|
+
operationName,
|
|
1303
|
+
variables,
|
|
1304
|
+
fieldsFactory: fieldsBuilder,
|
|
1305
|
+
adapter: resolvedAdapter,
|
|
1306
|
+
metadata: options?.metadata,
|
|
1307
|
+
transformDocument: options?.transformDocument,
|
|
1308
|
+
adapterTransformDocument: transformDocument
|
|
1309
|
+
})));
|
|
1310
|
+
};
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1066
1313
|
//#endregion
|
|
1067
1314
|
//#region packages/core/src/composer/fragment.ts
|
|
1068
1315
|
/**
|
|
@@ -1109,18 +1356,6 @@ const createGqlFragmentComposers = (schema, _adapter) => {
|
|
|
1109
1356
|
return mapValues(schema.object, (_, typename) => createFragmentComposer(typename));
|
|
1110
1357
|
};
|
|
1111
1358
|
|
|
1112
|
-
//#endregion
|
|
1113
|
-
//#region packages/core/src/types/metadata/adapter.ts
|
|
1114
|
-
/**
|
|
1115
|
-
* Creates the default adapter instance.
|
|
1116
|
-
* @internal
|
|
1117
|
-
*/
|
|
1118
|
-
const createDefaultAdapter = () => ({ aggregateFragmentMetadata: (fragments) => fragments.map((m) => m.metadata) });
|
|
1119
|
-
/**
|
|
1120
|
-
* The default adapter instance.
|
|
1121
|
-
*/
|
|
1122
|
-
const defaultMetadataAdapter = createDefaultAdapter();
|
|
1123
|
-
|
|
1124
1359
|
//#endregion
|
|
1125
1360
|
//#region packages/core/src/composer/operation.ts
|
|
1126
1361
|
/**
|
|
@@ -1149,86 +1384,18 @@ const createOperationComposerFactory = (schema, adapter, transformDocument) => {
|
|
|
1149
1384
|
const operationTypeName = schema.operations[operationType];
|
|
1150
1385
|
if (operationTypeName === null) throw new Error(`Operation type ${operationType} is not defined in schema roots`);
|
|
1151
1386
|
return (options) => {
|
|
1152
|
-
return Operation.create(() => {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
variables,
|
|
1165
|
-
fields,
|
|
1166
|
-
schema
|
|
1167
|
-
});
|
|
1168
|
-
const variableNames = Object.keys(variables);
|
|
1169
|
-
if (!fragmentUsages.some((u) => u.metadataBuilder) && !options.metadata && !transformDocument && !options.transformDocument) return {
|
|
1170
|
-
operationType,
|
|
1171
|
-
operationName,
|
|
1172
|
-
schemaLabel: schema.label,
|
|
1173
|
-
variableNames,
|
|
1174
|
-
documentSource: () => fields,
|
|
1175
|
-
document,
|
|
1176
|
-
metadata: void 0
|
|
1177
|
-
};
|
|
1178
|
-
const aggregateFragmentMetadata = (resolvedFragmentMetadata) => {
|
|
1179
|
-
const fragmentMetaInfos = fragmentUsages.map((usage, index) => ({
|
|
1180
|
-
metadata: resolvedFragmentMetadata[index],
|
|
1181
|
-
fieldPath: usage.path
|
|
1182
|
-
}));
|
|
1183
|
-
return resolvedAdapter.aggregateFragmentMetadata(fragmentMetaInfos);
|
|
1184
|
-
};
|
|
1185
|
-
const fragmentMetadataResults = fragmentUsages.map((usage) => usage.metadataBuilder ? usage.metadataBuilder() : void 0);
|
|
1186
|
-
const hasAsyncFragmentMetadata = fragmentMetadataResults.some((r) => isPromiseLike(r));
|
|
1187
|
-
const buildOperationMetadata = (aggregatedFragmentMetadata) => {
|
|
1188
|
-
const schemaLevel = resolvedAdapter.schemaLevel;
|
|
1189
|
-
return options.metadata?.({
|
|
1190
|
-
$,
|
|
1191
|
-
document,
|
|
1192
|
-
fragmentMetadata: aggregatedFragmentMetadata,
|
|
1193
|
-
schemaLevel
|
|
1194
|
-
});
|
|
1195
|
-
};
|
|
1196
|
-
const makeCreateDefinition = (aggregated$1) => {
|
|
1197
|
-
return ({ metadata }) => {
|
|
1198
|
-
let finalDocument = options.transformDocument ? options.transformDocument({
|
|
1199
|
-
document,
|
|
1200
|
-
metadata
|
|
1201
|
-
}) : document;
|
|
1202
|
-
if (transformDocument) finalDocument = transformDocument({
|
|
1203
|
-
document: finalDocument,
|
|
1204
|
-
operationName,
|
|
1205
|
-
operationType,
|
|
1206
|
-
variableNames,
|
|
1207
|
-
schemaLevel: resolvedAdapter.schemaLevel,
|
|
1208
|
-
fragmentMetadata: aggregated$1
|
|
1209
|
-
});
|
|
1210
|
-
return {
|
|
1211
|
-
operationType,
|
|
1212
|
-
operationName,
|
|
1213
|
-
schemaLabel: schema.label,
|
|
1214
|
-
variableNames,
|
|
1215
|
-
documentSource: () => fields,
|
|
1216
|
-
document: finalDocument,
|
|
1217
|
-
metadata
|
|
1218
|
-
};
|
|
1219
|
-
};
|
|
1220
|
-
};
|
|
1221
|
-
if (hasAsyncFragmentMetadata) return Promise.all(fragmentMetadataResults).then(async (resolvedFragmentMetadata) => {
|
|
1222
|
-
const aggregated$1 = aggregateFragmentMetadata(resolvedFragmentMetadata);
|
|
1223
|
-
const operationMetadata = await buildOperationMetadata(aggregated$1);
|
|
1224
|
-
return makeCreateDefinition(aggregated$1)({ metadata: operationMetadata });
|
|
1225
|
-
});
|
|
1226
|
-
const aggregated = aggregateFragmentMetadata(fragmentMetadataResults);
|
|
1227
|
-
const createDefinition = makeCreateDefinition(aggregated);
|
|
1228
|
-
const operationMetadataResult = buildOperationMetadata(aggregated);
|
|
1229
|
-
if (isPromiseLike(operationMetadataResult)) return operationMetadataResult.then((metadata) => createDefinition({ metadata }));
|
|
1230
|
-
return createDefinition({ metadata: operationMetadataResult });
|
|
1231
|
-
});
|
|
1387
|
+
return Operation.create((() => buildOperationArtifact({
|
|
1388
|
+
schema,
|
|
1389
|
+
operationType,
|
|
1390
|
+
operationTypeName,
|
|
1391
|
+
operationName: options.name,
|
|
1392
|
+
variables: options.variables ?? {},
|
|
1393
|
+
fieldsFactory: options.fields,
|
|
1394
|
+
adapter: resolvedAdapter,
|
|
1395
|
+
metadata: options.metadata,
|
|
1396
|
+
transformDocument: options.transformDocument,
|
|
1397
|
+
adapterTransformDocument: transformDocument
|
|
1398
|
+
})));
|
|
1232
1399
|
};
|
|
1233
1400
|
};
|
|
1234
1401
|
};
|
|
@@ -1488,9 +1655,20 @@ const createGqlElementComposer = (schema, options) => {
|
|
|
1488
1655
|
const createOperationComposer = createOperationComposerFactory(schema, metadataAdapter, transformDocument);
|
|
1489
1656
|
const transformedContext = applyContextTransformer({
|
|
1490
1657
|
fragment,
|
|
1491
|
-
query: {
|
|
1492
|
-
|
|
1493
|
-
|
|
1658
|
+
query: {
|
|
1659
|
+
operation: createOperationComposer("query"),
|
|
1660
|
+
compat: createCompatComposer(schema, "query")
|
|
1661
|
+
},
|
|
1662
|
+
mutation: {
|
|
1663
|
+
operation: createOperationComposer("mutation"),
|
|
1664
|
+
compat: createCompatComposer(schema, "mutation")
|
|
1665
|
+
},
|
|
1666
|
+
subscription: {
|
|
1667
|
+
operation: createOperationComposer("subscription"),
|
|
1668
|
+
compat: createCompatComposer(schema, "subscription")
|
|
1669
|
+
},
|
|
1670
|
+
define: (factory) => GqlDefine.create(factory),
|
|
1671
|
+
extend: createExtendComposer(schema, metadataAdapter, transformDocument),
|
|
1494
1672
|
$var: createVarBuilder(inputTypeMethods),
|
|
1495
1673
|
$dir: directiveMethods ?? createStandardDirectives(),
|
|
1496
1674
|
$colocate: createColocateHelper(),
|
|
@@ -1759,5 +1937,5 @@ const generateInputTypeFromSpecifiers = (schema, specifiers, options = {}) => {
|
|
|
1759
1937
|
};
|
|
1760
1938
|
|
|
1761
1939
|
//#endregion
|
|
1762
|
-
export { Fragment, GqlElement, Operation, VarRef, appendToPath, applyTypeModifier, buildArgumentValue, buildConstValueNode, buildDocument, buildOperationTypeNode, buildWithTypeModifier, calculateFieldType, calculateFieldsType, createColocateHelper, createDefaultAdapter, createDirectiveBuilder, createDirectiveMethod, createFieldFactories, createGqlElementComposer, createGqlFragmentComposers, createOperationComposerFactory, createStandardDirectives, createTypedDirectiveMethod, createVarAssignments, createVarBuilder, createVarMethod, createVarMethodFactory, createVarRefFromVariable, createVarRefs, defaultMetadataAdapter, defineEnum, defineOperationRoots, defineScalar, generateInputObjectType, generateInputType, generateInputTypeFromSpecifiers, getCurrentFieldPath, getEnumType, getScalarInputType, getScalarOutputType, graphqlTypeToTypeScript, isDirectiveRef, isListType, recordFragmentUsage, withFieldPath, withFragmentUsageCollection };
|
|
1940
|
+
export { Fragment, GqlDefine, GqlElement, Operation, VarRef, appendToPath, applyTypeModifier, buildArgumentValue, buildConstValueNode, buildDocument, buildOperationArtifact, buildOperationTypeNode, buildWithTypeModifier, calculateFieldType, calculateFieldsType, createColocateHelper, createCompatComposer, createDefaultAdapter, createDirectiveBuilder, createDirectiveMethod, createExtendComposer, createFieldFactories, createGqlElementComposer, createGqlFragmentComposers, createOperationComposerFactory, createStandardDirectives, createTypedDirectiveMethod, createVarAssignments, createVarBuilder, createVarMethod, createVarMethodFactory, createVarRefFromVariable, createVarRefs, defaultMetadataAdapter, defineEnum, defineOperationRoots, defineScalar, generateInputObjectType, generateInputType, generateInputTypeFromSpecifiers, getCurrentFieldPath, getEnumType, getScalarInputType, getScalarOutputType, graphqlTypeToTypeScript, isDirectiveRef, isListType, recordFragmentUsage, withFieldPath, withFragmentUsageCollection };
|
|
1763
1941
|
//# sourceMappingURL=index.js.map
|