1 | import { parseValue, valueFromASTUntyped } from 'graphql';
|
2 | import { extractVariables } from './extractVariables.js';
|
3 | import { EXPANSION_PREFIX, KEY_DELIMITER, preparseMergeArgsExpr } from './preparseMergeArgsExpr.js';
|
4 | import { propertyTreeFromPaths } from './properties.js';
|
5 | import { getSourcePaths } from './getSourcePaths.js';
|
6 | export function parseMergeArgsExpr(mergeArgsExpr, selectionSet) {
|
7 | const { mergeArgsExpr: newMergeArgsExpr, expansionExpressions } = preparseMergeArgsExpr(mergeArgsExpr);
|
8 | const inputValue = parseValue(`{ ${newMergeArgsExpr} }`, { noLocation: true });
|
9 | const { inputValue: newInputValue, variablePaths } = extractVariables(inputValue);
|
10 | if (!Object.keys(expansionExpressions).length) {
|
11 | if (!Object.keys(variablePaths).length) {
|
12 | throw new Error('Merge arguments must declare a key.');
|
13 | }
|
14 | const mappingInstructions = getMappingInstructions(variablePaths);
|
15 | const usedProperties = propertyTreeFromPaths(getSourcePaths(mappingInstructions, selectionSet));
|
16 | return { args: valueFromASTUntyped(newInputValue), usedProperties, mappingInstructions };
|
17 | }
|
18 | const expansionRegEx = new RegExp(`^${EXPANSION_PREFIX}[0-9]+$`);
|
19 | for (const variableName in variablePaths) {
|
20 | if (!variableName.match(expansionRegEx)) {
|
21 | throw new Error('Expansions cannot be mixed with single key declarations.');
|
22 | }
|
23 | }
|
24 | const expansions = [];
|
25 | const sourcePaths = [];
|
26 | for (const variableName in expansionExpressions) {
|
27 | const str = expansionExpressions[variableName];
|
28 | const valuePath = variablePaths[variableName];
|
29 | const { inputValue: expansionInputValue, variablePaths: expansionVariablePaths } = extractVariables(parseValue(`${str}`, { noLocation: true }));
|
30 | if (!Object.keys(expansionVariablePaths).length) {
|
31 | throw new Error('Merge arguments must declare a key.');
|
32 | }
|
33 | const mappingInstructions = getMappingInstructions(expansionVariablePaths);
|
34 | const value = valueFromASTUntyped(expansionInputValue);
|
35 | sourcePaths.push(...getSourcePaths(mappingInstructions, selectionSet));
|
36 | assertNotWithinList(valuePath);
|
37 | expansions.push({
|
38 | valuePath,
|
39 | value,
|
40 | mappingInstructions,
|
41 | });
|
42 | }
|
43 | const usedProperties = propertyTreeFromPaths(sourcePaths);
|
44 | return { args: valueFromASTUntyped(newInputValue), usedProperties, expansions };
|
45 | }
|
46 | function getMappingInstructions(variablePaths) {
|
47 | const mappingInstructions = [];
|
48 | for (const keyPath in variablePaths) {
|
49 | const valuePath = variablePaths[keyPath];
|
50 | const splitKeyPath = keyPath.split(KEY_DELIMITER).slice(1);
|
51 | assertNotWithinList(valuePath);
|
52 | mappingInstructions.push({
|
53 | destinationPath: valuePath,
|
54 | sourcePath: splitKeyPath,
|
55 | });
|
56 | }
|
57 | return mappingInstructions;
|
58 | }
|
59 | function assertNotWithinList(path) {
|
60 | for (const pathSegment of path) {
|
61 | if (typeof pathSegment === 'number') {
|
62 | throw new Error('Insertions cannot be made into a list.');
|
63 | }
|
64 | }
|
65 | }
|