@wundergraph/composition 0.56.0 → 0.58.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.
@@ -305,7 +305,10 @@ class NormalizationFactory {
305
305
  if (isAuthenticated) {
306
306
  this.handleAuthenticatedDirective(data, parentTypeName);
307
307
  }
308
- if (isSemanticNonNull && isField) {
308
+ if (!isField) {
309
+ return errorMessages;
310
+ }
311
+ if (isSemanticNonNull) {
309
312
  // The default argument for levels is [0], so a non-null wrapper is invalid.
310
313
  if ((0, utils_4.isTypeRequired)(data.type)) {
311
314
  errorMessages.push((0, errors_1.semanticNonNullLevelsNonNullErrorMessage)({
@@ -317,9 +320,12 @@ class NormalizationFactory {
317
320
  data.nullLevelsBySubgraphName.set(this.subgraphName, new Set([0]));
318
321
  }
319
322
  }
320
- if (isListSize && isField && !(0, utils_4.isTypeNodeListType)(data.type)) {
323
+ if (isListSize && !(0, utils_4.isTypeNodeListType)(data.type)) {
321
324
  errorMessages.push((0, errors_1.listSizeFieldMustReturnListOrUseSizedFieldsErrorMessage)(directiveCoords, (0, merge_1.printTypeNode)(data.type)));
322
325
  }
326
+ if (!isCost && !isListSize) {
327
+ this.recordDirectiveWeightOnField({ data: data, definitionData, directiveName, directiveNode });
328
+ }
323
329
  return errorMessages;
324
330
  }
325
331
  const definedArgumentNames = new Set();
@@ -376,8 +382,13 @@ class NormalizationFactory {
376
382
  if (isCost) {
377
383
  this.handleCostDirective({ data, directiveCoords, directiveNode, errorMessages });
378
384
  }
379
- else if (isListSize && isField) {
380
- this.handleListSizeDirective({ data, directiveCoords, directiveNode, errorMessages });
385
+ else if (isField) {
386
+ if (isListSize) {
387
+ this.handleListSizeDirective({ data, directiveCoords, directiveNode, errorMessages });
388
+ }
389
+ else {
390
+ this.recordDirectiveWeightOnField({ data: data, definitionData, directiveName, directiveNode });
391
+ }
381
392
  }
382
393
  if (duplicateArgumentNames.size > 0) {
383
394
  errorMessages.push((0, errors_1.duplicateDirectiveArgumentDefinitionsErrorMessage)([...duplicateArgumentNames]));
@@ -1733,6 +1744,15 @@ class NormalizationFactory {
1733
1744
  }
1734
1745
  data.nullLevelsBySubgraphName.set(this.subgraphName, levels);
1735
1746
  }
1747
+ getOrCreateFieldWeight(typeName, fieldName) {
1748
+ const fieldCoords = `${typeName}.${fieldName}`;
1749
+ return (0, utils_5.getValueOrDefault)(this.costs.fieldWeights, fieldCoords, () => ({
1750
+ typeName,
1751
+ fieldName,
1752
+ argumentWeights: new Map(),
1753
+ directiveArgumentWeights: new Map(),
1754
+ }));
1755
+ }
1736
1756
  handleCostDirective({ data, directiveCoords, directiveNode, errorMessages }) {
1737
1757
  const weightArg = directiveNode.arguments?.find((arg) => arg.name.value === string_constants_1.WEIGHT);
1738
1758
  if (!weightArg || weightArg.value.kind !== graphql_1.Kind.INT) {
@@ -1756,12 +1776,7 @@ class NormalizationFactory {
1756
1776
  errorMessages.push((0, errors_1.costOnInterfaceFieldErrorMessage)(directiveCoords));
1757
1777
  break;
1758
1778
  }
1759
- const fieldCoords = `${typeName}.${data.name}`;
1760
- const fieldWeight = (0, utils_5.getValueOrDefault)(this.costs.fieldWeights, fieldCoords, () => ({
1761
- typeName,
1762
- fieldName: data.name,
1763
- argumentWeights: new Map(),
1764
- }));
1779
+ const fieldWeight = this.getOrCreateFieldWeight(typeName, data.name);
1765
1780
  fieldWeight.weight = weightValue;
1766
1781
  break;
1767
1782
  }
@@ -1779,28 +1794,61 @@ class NormalizationFactory {
1779
1794
  errorMessages.push((0, errors_1.costOnInterfaceFieldErrorMessage)(directiveCoords));
1780
1795
  break;
1781
1796
  }
1782
- const parentFieldCoords = `${typeName}.${ivData.fieldName}`;
1783
- const fieldWeight = (0, utils_5.getValueOrDefault)(this.costs.fieldWeights, parentFieldCoords, () => ({
1784
- typeName,
1785
- fieldName: ivData.fieldName,
1786
- argumentWeights: new Map(),
1787
- }));
1797
+ const fieldWeight = this.getOrCreateFieldWeight(typeName, ivData.fieldName);
1788
1798
  fieldWeight.argumentWeights.set(ivData.name, weightValue);
1789
1799
  }
1790
1800
  else {
1791
1801
  const typeName = ivData.renamedParentTypeName || ivData.originalParentTypeName;
1792
- const fieldCoords = `${typeName}.${ivData.name}`;
1793
- const fieldWeight = (0, utils_5.getValueOrDefault)(this.costs.fieldWeights, fieldCoords, () => ({
1794
- typeName,
1795
- fieldName: ivData.name,
1796
- argumentWeights: new Map(),
1797
- }));
1802
+ const fieldWeight = this.getOrCreateFieldWeight(typeName, ivData.name);
1798
1803
  fieldWeight.weight = weightValue;
1799
1804
  }
1800
1805
  break;
1801
1806
  }
1802
1807
  }
1803
1808
  }
1809
+ recordDirectiveWeightOnField({ data, definitionData, directiveName, directiveNode, }) {
1810
+ // This method walks every argument defined on the directive and records a directive weight
1811
+ // on the field only when all these conditions hold:
1812
+ // 1. The argument of the directive has a cost weight assigned
1813
+ // 2. The argument is non-null
1814
+ // 3. The parent type is not an interface type.
1815
+ const typeName = data.renamedParentTypeName || data.originalParentTypeName;
1816
+ const parentTypeData = this.parentDefinitionDataByTypeName.get(typeName);
1817
+ // Directive argument weights should only be recorded for concrete type fields.
1818
+ if (!parentTypeData || parentTypeData.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
1819
+ return;
1820
+ }
1821
+ // Determine which arguments are non-null on this directive usage.
1822
+ // Record the DirectiveArgument coords if its argument has an explicit non-null value or
1823
+ // if it has a default value and was not explicitly set to null.
1824
+ const suppliedArgNodeByName = new Map();
1825
+ for (const arg of directiveNode.arguments ?? []) {
1826
+ suppliedArgNodeByName.set(arg.name.value, arg.value);
1827
+ }
1828
+ for (const [argName, argData] of definitionData.argumentTypeNodeByName) {
1829
+ const coords = `${directiveName}.${argName}`;
1830
+ const argWeight = this.costs.directiveArgumentWeights.get(coords);
1831
+ // Bail if the argName argument does not have cost attached to it.
1832
+ if (argWeight === undefined) {
1833
+ continue;
1834
+ }
1835
+ // Check if this argument is non-null at the usage site:
1836
+ const argNode = suppliedArgNodeByName.get(argName);
1837
+ if (argNode) {
1838
+ if (argNode.kind === graphql_1.Kind.NULL) {
1839
+ continue;
1840
+ }
1841
+ }
1842
+ else if (!argData.defaultValue || argData.defaultValue.kind === graphql_1.Kind.NULL) {
1843
+ continue;
1844
+ }
1845
+ const fieldWeight = this.getOrCreateFieldWeight(typeName, data.name);
1846
+ // Accumulate across directive usages so that repeatable directives on the same
1847
+ // field are charged once per usage.
1848
+ const existingWeight = fieldWeight.directiveArgumentWeights.get(coords) ?? 0;
1849
+ fieldWeight.directiveArgumentWeights.set(coords, existingWeight + argWeight);
1850
+ }
1851
+ }
1804
1852
  handleListSizeDirective({ data, directiveCoords, directiveNode, errorMessages }) {
1805
1853
  const args = directiveNode.arguments;
1806
1854
  if (!args) {