@soda-gql/codegen 0.11.16 → 0.11.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +414 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +246 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +246 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +410 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -48,6 +48,7 @@ const emitOperation = (operation, options) => {
|
|
|
48
48
|
const emitFragment = (fragment, options) => {
|
|
49
49
|
const lines = [];
|
|
50
50
|
const schema = options.schemaDocument ? require_generator.createSchemaIndex(options.schemaDocument) : null;
|
|
51
|
+
const hasVariables = fragment.variables.length > 0;
|
|
51
52
|
lines.push(`import { gql } from "${options.graphqlSystemPath}";`);
|
|
52
53
|
if (fragment.fragmentDependencies.length > 0 && options.fragmentImports) {
|
|
53
54
|
for (const fragName of fragment.fragmentDependencies) {
|
|
@@ -59,10 +60,15 @@ const emitFragment = (fragment, options) => {
|
|
|
59
60
|
}
|
|
60
61
|
lines.push("");
|
|
61
62
|
const exportName = `${fragment.name}Fragment`;
|
|
62
|
-
|
|
63
|
+
const destructure = hasVariables ? "fragment, $var" : "fragment";
|
|
64
|
+
lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${destructure} }) =>`);
|
|
63
65
|
lines.push(` fragment.${fragment.onType}({`);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
if (hasVariables) {
|
|
67
|
+
lines.push(` variables: { ${emitVariables(fragment.variables)} },`);
|
|
68
|
+
}
|
|
69
|
+
const fieldsContext = hasVariables ? "{ f, $ }" : "{ f }";
|
|
70
|
+
lines.push(` fields: (${fieldsContext}) => ({`);
|
|
71
|
+
const fieldLinesResult = emitSelections(fragment.selections, 3, fragment.variables, schema);
|
|
66
72
|
if (fieldLinesResult.isErr()) {
|
|
67
73
|
return (0, neverthrow.err)(fieldLinesResult.error);
|
|
68
74
|
}
|
|
@@ -80,7 +86,7 @@ const emitVariables = (variables) => {
|
|
|
80
86
|
};
|
|
81
87
|
/**
|
|
82
88
|
* Emit field selections (public API).
|
|
83
|
-
* Converts
|
|
89
|
+
* Converts variable array to Set<string> and delegates to internal implementation.
|
|
84
90
|
*/
|
|
85
91
|
const emitSelections = (selections, indent, variables, schema) => {
|
|
86
92
|
const variableNames = new Set(variables.map((v) => v.name));
|
|
@@ -556,36 +562,399 @@ const builtinScalarTypes = new Set([
|
|
|
556
562
|
"Boolean"
|
|
557
563
|
]);
|
|
558
564
|
/**
|
|
565
|
+
* Parse a modifier string into its structural components.
|
|
566
|
+
* @param modifier - Modifier string like "!", "?", "![]!", "?[]?[]!"
|
|
567
|
+
* @returns Parsed structure with inner nullability and list modifiers
|
|
568
|
+
*/
|
|
569
|
+
const parseModifierStructure = (modifier) => {
|
|
570
|
+
const inner = modifier[0] === "!" ? "!" : "?";
|
|
571
|
+
const lists = [];
|
|
572
|
+
const listPattern = /\[\]([!?])/g;
|
|
573
|
+
let match;
|
|
574
|
+
while ((match = listPattern.exec(modifier)) !== null) {
|
|
575
|
+
lists.push(`[]${match[1]}`);
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
inner,
|
|
579
|
+
lists
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
/**
|
|
583
|
+
* Rebuild modifier string from structure.
|
|
584
|
+
*/
|
|
585
|
+
const buildModifier = (structure) => {
|
|
586
|
+
return structure.inner + structure.lists.join("");
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Merge two modifiers by taking the stricter constraint at each level.
|
|
590
|
+
* - Non-null (!) is stricter than nullable (?)
|
|
591
|
+
* - List depths must match
|
|
592
|
+
*
|
|
593
|
+
* @param a - First modifier
|
|
594
|
+
* @param b - Second modifier
|
|
595
|
+
* @returns Merged modifier or error if incompatible
|
|
596
|
+
*/
|
|
597
|
+
const mergeModifiers = (a, b) => {
|
|
598
|
+
const structA = parseModifierStructure(a);
|
|
599
|
+
const structB = parseModifierStructure(b);
|
|
600
|
+
if (structA.lists.length !== structB.lists.length) {
|
|
601
|
+
return {
|
|
602
|
+
ok: false,
|
|
603
|
+
reason: `Incompatible list depths: "${a}" has ${structA.lists.length} list level(s), "${b}" has ${structB.lists.length}`
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
const mergedInner = structA.inner === "!" || structB.inner === "!" ? "!" : "?";
|
|
607
|
+
const mergedLists = [];
|
|
608
|
+
for (let i = 0; i < structA.lists.length; i++) {
|
|
609
|
+
const listA = structA.lists[i];
|
|
610
|
+
const listB = structB.lists[i];
|
|
611
|
+
mergedLists.push(listA === "[]!" || listB === "[]!" ? "[]!" : "[]?");
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
ok: true,
|
|
615
|
+
value: buildModifier({
|
|
616
|
+
inner: mergedInner,
|
|
617
|
+
lists: mergedLists
|
|
618
|
+
})
|
|
619
|
+
};
|
|
620
|
+
};
|
|
621
|
+
/**
|
|
622
|
+
* Get the expected type for a field argument from the schema.
|
|
623
|
+
* Returns null if the field or argument is not found.
|
|
624
|
+
*/
|
|
625
|
+
const getArgumentType = (schema, parentTypeName, fieldName, argumentName) => {
|
|
626
|
+
const objectRecord = schema.objects.get(parentTypeName);
|
|
627
|
+
if (!objectRecord) return null;
|
|
628
|
+
const fieldDef = objectRecord.fields.get(fieldName);
|
|
629
|
+
if (!fieldDef) return null;
|
|
630
|
+
const argDef = fieldDef.arguments?.find((arg) => arg.name.value === argumentName);
|
|
631
|
+
if (!argDef) return null;
|
|
632
|
+
return parseTypeNode(argDef.type);
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* Get the expected type for an input object field from the schema.
|
|
636
|
+
*/
|
|
637
|
+
const getInputFieldType = (schema, inputTypeName, fieldName) => {
|
|
638
|
+
const inputRecord = schema.inputs.get(inputTypeName);
|
|
639
|
+
if (!inputRecord) return null;
|
|
640
|
+
const fieldDef = inputRecord.fields.get(fieldName);
|
|
641
|
+
if (!fieldDef) return null;
|
|
642
|
+
return parseTypeNode(fieldDef.type);
|
|
643
|
+
};
|
|
644
|
+
/**
|
|
645
|
+
* Resolve the type kind for a type name.
|
|
646
|
+
*/
|
|
647
|
+
const resolveTypeKindFromName = (schema, typeName) => {
|
|
648
|
+
if (isScalarName(schema, typeName)) return "scalar";
|
|
649
|
+
if (isEnumName(schema, typeName)) return "enum";
|
|
650
|
+
if (schema.inputs.has(typeName)) return "input";
|
|
651
|
+
return null;
|
|
652
|
+
};
|
|
653
|
+
/**
|
|
654
|
+
* Extract variable usages from a parsed value, given the expected type.
|
|
655
|
+
* Handles nested input objects recursively.
|
|
656
|
+
*/
|
|
657
|
+
const collectVariablesFromValue = (value, expectedTypeName, expectedModifier, schema, usages) => {
|
|
658
|
+
if (value.kind === "variable") {
|
|
659
|
+
const typeKind = resolveTypeKindFromName(schema, expectedTypeName);
|
|
660
|
+
if (!typeKind) {
|
|
661
|
+
return {
|
|
662
|
+
code: "GRAPHQL_UNKNOWN_TYPE",
|
|
663
|
+
message: `Unknown type "${expectedTypeName}" for variable "$${value.name}"`,
|
|
664
|
+
typeName: expectedTypeName
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
usages.push({
|
|
668
|
+
name: value.name,
|
|
669
|
+
typeName: expectedTypeName,
|
|
670
|
+
modifier: expectedModifier,
|
|
671
|
+
typeKind
|
|
672
|
+
});
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
if (value.kind === "object") {
|
|
676
|
+
for (const field of value.fields) {
|
|
677
|
+
const fieldType = getInputFieldType(schema, expectedTypeName, field.name);
|
|
678
|
+
if (!fieldType) {
|
|
679
|
+
return {
|
|
680
|
+
code: "GRAPHQL_UNKNOWN_FIELD",
|
|
681
|
+
message: `Unknown field "${field.name}" on input type "${expectedTypeName}"`,
|
|
682
|
+
typeName: expectedTypeName,
|
|
683
|
+
fieldName: field.name
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
const error = collectVariablesFromValue(field.value, fieldType.typeName, fieldType.modifier, schema, usages);
|
|
687
|
+
if (error) return error;
|
|
688
|
+
}
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
if (value.kind === "list") {
|
|
692
|
+
const struct = parseModifierStructure(expectedModifier);
|
|
693
|
+
if (struct.lists.length > 0) {
|
|
694
|
+
const innerModifier = buildModifier({
|
|
695
|
+
inner: struct.inner,
|
|
696
|
+
lists: struct.lists.slice(1)
|
|
697
|
+
});
|
|
698
|
+
for (const item of value.values) {
|
|
699
|
+
const error = collectVariablesFromValue(item, expectedTypeName, innerModifier, schema, usages);
|
|
700
|
+
if (error) return error;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return null;
|
|
705
|
+
};
|
|
706
|
+
/**
|
|
707
|
+
* Collect variable usages from field arguments.
|
|
708
|
+
*/
|
|
709
|
+
const collectVariablesFromArguments = (args, parentTypeName, fieldName, schema, usages) => {
|
|
710
|
+
for (const arg of args) {
|
|
711
|
+
const argType = getArgumentType(schema, parentTypeName, fieldName, arg.name);
|
|
712
|
+
if (!argType) {
|
|
713
|
+
return {
|
|
714
|
+
code: "GRAPHQL_UNKNOWN_ARGUMENT",
|
|
715
|
+
message: `Unknown argument "${arg.name}" on field "${fieldName}"`,
|
|
716
|
+
fieldName,
|
|
717
|
+
argumentName: arg.name
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
const error = collectVariablesFromValue(arg.value, argType.typeName, argType.modifier, schema, usages);
|
|
721
|
+
if (error) return error;
|
|
722
|
+
}
|
|
723
|
+
return null;
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* Recursively collect all variable usages from selections.
|
|
727
|
+
*/
|
|
728
|
+
const collectVariableUsages = (selections, parentTypeName, schema) => {
|
|
729
|
+
const usages = [];
|
|
730
|
+
const collect = (sels, parentType) => {
|
|
731
|
+
for (const sel of sels) {
|
|
732
|
+
switch (sel.kind) {
|
|
733
|
+
case "field": {
|
|
734
|
+
if (sel.arguments && sel.arguments.length > 0) {
|
|
735
|
+
const error$1 = collectVariablesFromArguments(sel.arguments, parentType, sel.name, schema, usages);
|
|
736
|
+
if (error$1) return error$1;
|
|
737
|
+
}
|
|
738
|
+
if (sel.selections && sel.selections.length > 0) {
|
|
739
|
+
const fieldReturnType = getFieldReturnType(schema, parentType, sel.name);
|
|
740
|
+
if (!fieldReturnType) {
|
|
741
|
+
return {
|
|
742
|
+
code: "GRAPHQL_UNKNOWN_FIELD",
|
|
743
|
+
message: `Unknown field "${sel.name}" on type "${parentType}"`,
|
|
744
|
+
typeName: parentType,
|
|
745
|
+
fieldName: sel.name
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const error$1 = collect(sel.selections, fieldReturnType);
|
|
749
|
+
if (error$1) return error$1;
|
|
750
|
+
}
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
case "inlineFragment": {
|
|
754
|
+
const error$1 = collect(sel.selections, sel.onType);
|
|
755
|
+
if (error$1) return error$1;
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
case "fragmentSpread": break;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return null;
|
|
762
|
+
};
|
|
763
|
+
const error = collect(selections, parentTypeName);
|
|
764
|
+
if (error) return (0, neverthrow.err)(error);
|
|
765
|
+
return (0, neverthrow.ok)(usages);
|
|
766
|
+
};
|
|
767
|
+
/**
|
|
768
|
+
* Get the return type of a field (unwrapped from modifiers).
|
|
769
|
+
*/
|
|
770
|
+
const getFieldReturnType = (schema, parentTypeName, fieldName) => {
|
|
771
|
+
const objectRecord = schema.objects.get(parentTypeName);
|
|
772
|
+
if (!objectRecord) return null;
|
|
773
|
+
const fieldDef = objectRecord.fields.get(fieldName);
|
|
774
|
+
if (!fieldDef) return null;
|
|
775
|
+
const { typeName } = parseTypeNode(fieldDef.type);
|
|
776
|
+
return typeName;
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* Merge multiple variable usages into a single InferredVariable.
|
|
780
|
+
* Validates type compatibility and merges modifiers using stricter constraint.
|
|
781
|
+
*/
|
|
782
|
+
const mergeVariableUsages = (variableName, usages) => {
|
|
783
|
+
if (usages.length === 0) {
|
|
784
|
+
return (0, neverthrow.err)({
|
|
785
|
+
code: "GRAPHQL_UNDECLARED_VARIABLE",
|
|
786
|
+
message: `No usages found for variable "${variableName}"`,
|
|
787
|
+
variableName
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
const first = usages[0];
|
|
791
|
+
for (const usage of usages) {
|
|
792
|
+
if (usage.typeName !== first.typeName) {
|
|
793
|
+
return (0, neverthrow.err)({
|
|
794
|
+
code: "GRAPHQL_VARIABLE_TYPE_MISMATCH",
|
|
795
|
+
message: `Variable "$${variableName}" has conflicting types: "${first.typeName}" and "${usage.typeName}"`,
|
|
796
|
+
variableName
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
let mergedModifier = first.modifier;
|
|
801
|
+
for (let i = 1; i < usages.length; i++) {
|
|
802
|
+
const result = mergeModifiers(mergedModifier, usages[i].modifier);
|
|
803
|
+
if (!result.ok) {
|
|
804
|
+
return (0, neverthrow.err)({
|
|
805
|
+
code: "GRAPHQL_VARIABLE_MODIFIER_INCOMPATIBLE",
|
|
806
|
+
message: `Variable "$${variableName}" has incompatible modifiers: ${result.reason}`,
|
|
807
|
+
variableName
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
mergedModifier = result.value;
|
|
811
|
+
}
|
|
812
|
+
return (0, neverthrow.ok)({
|
|
813
|
+
name: variableName,
|
|
814
|
+
typeName: first.typeName,
|
|
815
|
+
modifier: mergedModifier,
|
|
816
|
+
typeKind: first.typeKind
|
|
817
|
+
});
|
|
818
|
+
};
|
|
819
|
+
/**
|
|
820
|
+
* Infer variables from collected usages.
|
|
821
|
+
* Groups by variable name and merges each group.
|
|
822
|
+
*/
|
|
823
|
+
const inferVariablesFromUsages = (usages) => {
|
|
824
|
+
const byName = new Map();
|
|
825
|
+
for (const usage of usages) {
|
|
826
|
+
const existing = byName.get(usage.name);
|
|
827
|
+
if (existing) {
|
|
828
|
+
existing.push(usage);
|
|
829
|
+
} else {
|
|
830
|
+
byName.set(usage.name, [usage]);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const variables = [];
|
|
834
|
+
for (const [name, group] of byName) {
|
|
835
|
+
const result = mergeVariableUsages(name, group);
|
|
836
|
+
if (result.isErr()) return (0, neverthrow.err)(result.error);
|
|
837
|
+
variables.push(result.value);
|
|
838
|
+
}
|
|
839
|
+
variables.sort((a, b) => a.name.localeCompare(b.name));
|
|
840
|
+
return (0, neverthrow.ok)(variables);
|
|
841
|
+
};
|
|
842
|
+
/**
|
|
559
843
|
* Check if a type name is a scalar type.
|
|
560
844
|
*/
|
|
561
845
|
const isScalarName = (schema, name) => builtinScalarTypes.has(name) || schema.scalars.has(name);
|
|
562
846
|
/**
|
|
847
|
+
* Topologically sort fragments so dependencies come before dependents.
|
|
848
|
+
* Detects circular dependencies.
|
|
849
|
+
*
|
|
850
|
+
* Note: Uses the existing collectFragmentDependencies function defined below.
|
|
851
|
+
*/
|
|
852
|
+
const sortFragmentsByDependency = (fragments) => {
|
|
853
|
+
const graph = new Map();
|
|
854
|
+
for (const fragment of fragments) {
|
|
855
|
+
const deps = collectFragmentDependenciesSet(fragment.selections);
|
|
856
|
+
graph.set(fragment.name, deps);
|
|
857
|
+
}
|
|
858
|
+
const fragmentByName = new Map();
|
|
859
|
+
for (const f of fragments) {
|
|
860
|
+
fragmentByName.set(f.name, f);
|
|
861
|
+
}
|
|
862
|
+
const sorted = [];
|
|
863
|
+
const visited = new Set();
|
|
864
|
+
const visiting = new Set();
|
|
865
|
+
const visit = (name, path) => {
|
|
866
|
+
if (visited.has(name)) return null;
|
|
867
|
+
if (visiting.has(name)) {
|
|
868
|
+
const cycleStart = path.indexOf(name);
|
|
869
|
+
const cycle = path.slice(cycleStart).concat(name);
|
|
870
|
+
return {
|
|
871
|
+
code: "GRAPHQL_FRAGMENT_CIRCULAR_DEPENDENCY",
|
|
872
|
+
message: `Circular dependency detected in fragments: ${cycle.join(" -> ")}`,
|
|
873
|
+
fragmentNames: cycle
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
const fragment = fragmentByName.get(name);
|
|
877
|
+
if (!fragment) {
|
|
878
|
+
visited.add(name);
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
visiting.add(name);
|
|
882
|
+
const deps = graph.get(name) ?? new Set();
|
|
883
|
+
for (const dep of deps) {
|
|
884
|
+
const error = visit(dep, [...path, name]);
|
|
885
|
+
if (error) return error;
|
|
886
|
+
}
|
|
887
|
+
visiting.delete(name);
|
|
888
|
+
visited.add(name);
|
|
889
|
+
sorted.push(fragment);
|
|
890
|
+
return null;
|
|
891
|
+
};
|
|
892
|
+
for (const fragment of fragments) {
|
|
893
|
+
const error = visit(fragment.name, []);
|
|
894
|
+
if (error) return (0, neverthrow.err)(error);
|
|
895
|
+
}
|
|
896
|
+
return (0, neverthrow.ok)(sorted);
|
|
897
|
+
};
|
|
898
|
+
/**
|
|
899
|
+
* Recursively collect fragment spread names from selections into a Set.
|
|
900
|
+
* Internal helper for sortFragmentsByDependency.
|
|
901
|
+
*/
|
|
902
|
+
const collectFragmentDependenciesSet = (selections) => {
|
|
903
|
+
const deps = new Set();
|
|
904
|
+
const collect = (sels) => {
|
|
905
|
+
for (const sel of sels) {
|
|
906
|
+
switch (sel.kind) {
|
|
907
|
+
case "fragmentSpread":
|
|
908
|
+
deps.add(sel.name);
|
|
909
|
+
break;
|
|
910
|
+
case "field":
|
|
911
|
+
if (sel.selections) {
|
|
912
|
+
collect(sel.selections);
|
|
913
|
+
}
|
|
914
|
+
break;
|
|
915
|
+
case "inlineFragment":
|
|
916
|
+
collect(sel.selections);
|
|
917
|
+
break;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
collect(selections);
|
|
922
|
+
return deps;
|
|
923
|
+
};
|
|
924
|
+
/**
|
|
563
925
|
* Check if a type name is an enum type.
|
|
564
926
|
*/
|
|
565
927
|
const isEnumName = (schema, name) => schema.enums.has(name);
|
|
566
928
|
/**
|
|
567
929
|
* Transform parsed operations/fragments by enriching them with schema information.
|
|
568
930
|
*
|
|
569
|
-
* This resolves variable type kinds (scalar, enum, input)
|
|
570
|
-
* fragment dependencies.
|
|
931
|
+
* This resolves variable type kinds (scalar, enum, input), collects
|
|
932
|
+
* fragment dependencies, and infers variables for fragments.
|
|
571
933
|
*/
|
|
572
934
|
const transformParsedGraphql = (parsed, options) => {
|
|
573
935
|
const schema = require_generator.createSchemaIndex(options.schemaDocument);
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
936
|
+
const sortResult = sortFragmentsByDependency(parsed.fragments);
|
|
937
|
+
if (sortResult.isErr()) {
|
|
938
|
+
return (0, neverthrow.err)(sortResult.error);
|
|
939
|
+
}
|
|
940
|
+
const sortedFragments = sortResult.value;
|
|
941
|
+
const resolvedFragmentVariables = new Map();
|
|
942
|
+
const fragments = [];
|
|
943
|
+
for (const frag of sortedFragments) {
|
|
944
|
+
const result = transformFragment(frag, schema, resolvedFragmentVariables);
|
|
577
945
|
if (result.isErr()) {
|
|
578
946
|
return (0, neverthrow.err)(result.error);
|
|
579
947
|
}
|
|
580
|
-
|
|
948
|
+
resolvedFragmentVariables.set(frag.name, result.value.variables);
|
|
949
|
+
fragments.push(result.value);
|
|
581
950
|
}
|
|
582
|
-
const
|
|
583
|
-
for (const
|
|
584
|
-
const result =
|
|
951
|
+
const operations = [];
|
|
952
|
+
for (const op of parsed.operations) {
|
|
953
|
+
const result = transformOperation(op, schema);
|
|
585
954
|
if (result.isErr()) {
|
|
586
955
|
return (0, neverthrow.err)(result.error);
|
|
587
956
|
}
|
|
588
|
-
|
|
957
|
+
operations.push(result.value);
|
|
589
958
|
}
|
|
590
959
|
return (0, neverthrow.ok)({
|
|
591
960
|
operations,
|
|
@@ -620,12 +989,36 @@ const transformOperation = (op, schema) => {
|
|
|
620
989
|
};
|
|
621
990
|
/**
|
|
622
991
|
* Transform a single fragment.
|
|
992
|
+
* Infers variables from field arguments and propagates variables from spread fragments.
|
|
623
993
|
*/
|
|
624
|
-
const transformFragment = (frag,
|
|
994
|
+
const transformFragment = (frag, schema, resolvedFragmentVariables) => {
|
|
625
995
|
const fragmentDependencies = collectFragmentDependencies(frag.selections);
|
|
996
|
+
const directUsagesResult = collectVariableUsages(frag.selections, frag.onType, schema);
|
|
997
|
+
if (directUsagesResult.isErr()) {
|
|
998
|
+
return (0, neverthrow.err)(directUsagesResult.error);
|
|
999
|
+
}
|
|
1000
|
+
const directUsages = directUsagesResult.value;
|
|
1001
|
+
const spreadVariables = [];
|
|
1002
|
+
for (const depName of fragmentDependencies) {
|
|
1003
|
+
const depVariables = resolvedFragmentVariables.get(depName);
|
|
1004
|
+
if (depVariables) {
|
|
1005
|
+
spreadVariables.push(...depVariables);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
const allUsages = [...directUsages, ...spreadVariables.map((v) => ({
|
|
1009
|
+
name: v.name,
|
|
1010
|
+
typeName: v.typeName,
|
|
1011
|
+
modifier: v.modifier,
|
|
1012
|
+
typeKind: v.typeKind
|
|
1013
|
+
}))];
|
|
1014
|
+
const variablesResult = inferVariablesFromUsages(allUsages);
|
|
1015
|
+
if (variablesResult.isErr()) {
|
|
1016
|
+
return (0, neverthrow.err)(variablesResult.error);
|
|
1017
|
+
}
|
|
626
1018
|
return (0, neverthrow.ok)({
|
|
627
1019
|
...frag,
|
|
628
|
-
fragmentDependencies
|
|
1020
|
+
fragmentDependencies,
|
|
1021
|
+
variables: variablesResult.value
|
|
629
1022
|
});
|
|
630
1023
|
};
|
|
631
1024
|
/**
|
|
@@ -1149,14 +1542,19 @@ export * from "./_internal";
|
|
|
1149
1542
|
};
|
|
1150
1543
|
|
|
1151
1544
|
//#endregion
|
|
1545
|
+
exports.collectVariableUsages = collectVariableUsages;
|
|
1152
1546
|
exports.emitFragment = emitFragment;
|
|
1153
1547
|
exports.emitOperation = emitOperation;
|
|
1154
1548
|
exports.hashSchema = hashSchema;
|
|
1549
|
+
exports.inferVariablesFromUsages = inferVariablesFromUsages;
|
|
1155
1550
|
exports.loadSchema = loadSchema;
|
|
1551
|
+
exports.mergeModifiers = mergeModifiers;
|
|
1552
|
+
exports.mergeVariableUsages = mergeVariableUsages;
|
|
1156
1553
|
exports.parseGraphqlFile = parseGraphqlFile;
|
|
1157
1554
|
exports.parseGraphqlSource = parseGraphqlSource;
|
|
1158
1555
|
exports.parseTypeNode = parseTypeNode;
|
|
1159
1556
|
exports.runCodegen = runCodegen;
|
|
1557
|
+
exports.sortFragmentsByDependency = sortFragmentsByDependency;
|
|
1160
1558
|
exports.transformParsedGraphql = transformParsedGraphql;
|
|
1161
1559
|
exports.writeInjectTemplate = writeInjectTemplate;
|
|
1162
1560
|
//# sourceMappingURL=index.cjs.map
|