validateDirectives()

in composition/src/v1/normalization/normalization-factory.ts [795:869]


  validateDirectives(data: NodeData | SchemaData, directiveCoords: string) {
    const undefinedDirectiveNames = new Set<string>();
    for (const [directiveName, directiveNodes] of data.directivesByDirectiveName) {
      const definitionData = this.directiveDefinitionDataByDirectiveName.get(directiveName);
      if (!definitionData) {
        if (!undefinedDirectiveNames.has(directiveName)) {
          this.errors.push(undefinedDirectiveError(directiveName, directiveCoords));
          undefinedDirectiveNames.add(directiveName);
        }
        continue;
      }
      const definitionErrorMessages: Array<string> = [];
      const directiveLocation = nodeKindToDirectiveLocation(data.kind);
      if (!definitionData.locations.has(directiveLocation)) {
        definitionErrorMessages.push(invalidDirectiveLocationErrorMessage(directiveName, directiveLocation));
      }
      if (directiveNodes.length > 1 && !definitionData.isRepeatable) {
        const handledDirectiveNames = getValueOrDefault(
          this.invalidRepeatedDirectiveNameByCoords,
          directiveCoords,
          () => new Set<string>(),
        );
        if (!handledDirectiveNames.has(directiveName)) {
          handledDirectiveNames.add(directiveName);
          definitionErrorMessages.push(invalidRepeatedDirectiveErrorMessage(directiveName));
        }
      }
      const requiredArgumentNames = [...definitionData.requiredArgumentNames];
      for (let i = 0; i < directiveNodes.length; i++) {
        const errorMessages = this.validateDirective({
          data,
          directiveNode: directiveNodes[i],
          definitionData,
          directiveCoords,
          errorMessages: i < 1 ? definitionErrorMessages : [],
          requiredArgumentNames,
        });
        if (errorMessages.length > 0) {
          this.errors.push(
            invalidDirectiveError(directiveName, directiveCoords, numberToOrdinal(i + 1), errorMessages),
          );
        }
      }
    }
    switch (data.kind) {
      case Kind.ENUM_TYPE_DEFINITION: {
        for (const [enumValueName, enumValueData] of data.enumValueDataByValueName) {
          this.validateDirectives(enumValueData, `${data.name}.${enumValueName}`);
        }
        return;
      }
      case Kind.FIELD_DEFINITION: {
        for (const [argumentName, argumentData] of data.argumentDataByArgumentName) {
          this.validateDirectives(argumentData, `${data.originalParentTypeName}.${data.name}(${argumentName}: ...)`);
        }
        return;
      }
      case Kind.INPUT_OBJECT_TYPE_DEFINITION: {
        for (const [inputValueName, inputValueData] of data.inputValueDataByValueName) {
          this.validateDirectives(inputValueData, `${data.name}.${inputValueName}`);
        }
        return;
      }
      case Kind.INTERFACE_TYPE_DEFINITION:
      // intentional fallthrough
      case Kind.OBJECT_TYPE_DEFINITION: {
        for (const [fieldName, fieldData] of data.fieldDataByFieldName) {
          this.validateDirectives(fieldData, `${data.name}.${fieldName}`);
        }
        return;
      }
      default:
        return;
    }
  }