graphql#FragmentDefinitionNode TypeScript Examples

The following examples show how to use graphql#FragmentDefinitionNode. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From apollo-cache-policies with Apache License 2.0 7 votes vote down vote up
function _generateQueryFromFragment({
  fieldName,
  fragmentDefinition,
}: {
  fieldName: string;
  fragmentDefinition: FragmentDefinitionNode;
}): DocumentNode {
  return {
    kind: 'Document',
    definitions: [
      {
        directives: [],
        variableDefinitions: [],
        kind: 'OperationDefinition',
        operation: 'query',
        selectionSet: {
          kind: 'SelectionSet',
          selections: [
            {
              arguments: [],
              kind: "Field",
              name: { kind: "Name", value: fieldName },
              directives: [
                {
                  arguments: [],
                  kind: 'Directive',
                  name: { kind: "Name", value: "client" },
                },
              ],
              selectionSet: fragmentDefinition.selectionSet,
            },
          ]
        },
      }
    ],
  };
}
Example #2
Source File: utils.ts    From apollo-cache-policies with Apache License 2.0 7 votes vote down vote up
// Returns a query that can be used to watch a normalized cache entity by converting the fragment to a query
// and dynamically adding a type policy that returns the entity.
export function buildWatchFragmentQuery(
  options: WatchFragmentOptions & {
    fieldName: string;
    policies: Policies,
  }
): DocumentNode {
  const { fragment, id, policies, fieldName } = options;
  const fragmentDefinition = fragment.definitions[0] as FragmentDefinitionNode;

  const query = _generateQueryFromFragment({
    fragmentDefinition: fragmentDefinition,
    fieldName,
  });

  // @ts-ignore The getFieldPolicy is private but we need it here to determine
  // if the dynamic type policy we generate for the corresponding fragment has
  // already been added
  if (!policies.getFieldPolicy('Query', fieldName)) {
    policies.addTypePolicies({
      Query: {
        fields: {
          [fieldName]: {
            read(_existing) {
              return makeReference(id);
            }
          }
        }
      }
    });
  }

  return query;
}
Example #3
Source File: utils.ts    From apollo-cache-policies with Apache License 2.0 7 votes vote down vote up
// Returns a query that can be used to watch a filtered list of normalized cache entities by converting the fragment to a query
// and dynamically adding a type policy that returns the list of matching entities.
export function buildWatchFragmentWhereQuery<FragmentType>(options: WatchFragmentWhereOptions<FragmentType> & {
  cache: InvalidationPolicyCache;
  policies: Policies;
  fieldName: string;
}): DocumentNode {
  const { fragment, filter, policies, cache, fieldName, } = options;
  const fragmentDefinition = fragment.definitions[0] as FragmentDefinitionNode;
  const __typename = fragmentDefinition.typeCondition.name.value;

  const query = _generateQueryFromFragment({
    fragmentDefinition,
    fieldName,
  });

  // @ts-ignore The getFieldPolicy is private but we need it here to determine
  // if the dynamic type policy we generate for the corresponding fragment has
  // already been added
  if (!policies.getFieldPolicy('Query', fieldName)) {
    policies.addTypePolicies({
      Query: {
        fields: {
          [fieldName]: {
            read(_existing) {
              return cache.readReferenceWhere({
                __typename,
                filter,
              });
            }
          }
        }
      }
    });
  }

  return query;
}
Example #4
Source File: graphql-js-validation.ts    From graphql-eslint with MIT License 6 votes vote down vote up
handleMissingFragments: GetDocumentNode = ({ ruleId, context, node }) => {
  const missingFragments = getMissingFragments(node);
  if (missingFragments.length > 0) {
    const siblings = requireSiblingsOperations(ruleId, context);
    const fragmentsToAdd: FragmentDefinitionNode[] = [];

    for (const fragmentName of missingFragments) {
      const [foundFragment] = siblings.getFragment(fragmentName).map(source => source.document);
      if (foundFragment) {
        fragmentsToAdd.push(foundFragment);
      }
    }

    if (fragmentsToAdd.length > 0) {
      // recall fn to make sure to add fragments inside fragments
      return handleMissingFragments({
        ruleId,
        context,
        node: {
          kind: Kind.DOCUMENT,
          definitions: [...node.definitions, ...fragmentsToAdd],
        },
      });
    }
  }
  return node;
}
Example #5
Source File: InvalidationPolicyCache.ts    From apollo-cache-policies with Apache License 2.0 6 votes vote down vote up
// Supports reading a collection of entities by type from the cache and filtering them by the given fields. Returns
  // a list of the dereferenced matching entities from the cache based on the given fragment.
  readFragmentWhere<FragmentType, TVariables = any>(options: Cache.ReadFragmentOptions<FragmentType, TVariables> & {
    filter?: FragmentWhereFilter<FragmentType>;
  }): FragmentType[] {
    const { fragment, filter, ...restOptions } = options;
    const fragmentDefinition = fragment.definitions[0] as FragmentDefinitionNode;
    const __typename = fragmentDefinition.typeCondition.name.value;

    const matchingRefs = this.readReferenceWhere(
      {
        __typename,
        filter
      }
    );

    const matchingFragments = matchingRefs.map(ref => this.readFragment({
      ...restOptions,
      fragment,
      id: ref.__ref,
    }));

    return compact(matchingFragments);
  }
Example #6
Source File: index.ts    From amplify-codegen with Apache License 2.0 6 votes vote down vote up
compileFragment(fragmentDefinition: FragmentDefinitionNode): Fragment {
    const fragmentName = fragmentDefinition.name.value;

    const filePath = filePathForNode(fragmentDefinition);
    const source = print(fragmentDefinition);

    const type = typeFromAST(this.schema, fragmentDefinition.typeCondition) as GraphQLCompositeType;

    return {
      fragmentName,
      filePath,
      source,
      type,
      selectionSet: this.compileSelectionSet(fragmentDefinition.selectionSet, type),
    };
  }
Example #7
Source File: match-document-filename.ts    From graphql-eslint with MIT License 4 votes vote down vote up
rule: GraphQLESLintRule<[MatchDocumentFilenameRuleConfig]> = {
  meta: {
    type: 'suggestion',
    docs: {
      category: 'Operations',
      description: 'This rule allows you to enforce that the file name should match the operation name.',
      url: 'https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/match-document-filename.md',
      examples: [
        {
          title: 'Correct',
          usage: [{ fileExtension: '.gql' }],
          code: /* GraphQL */ `
            # user.gql
            type User {
              id: ID!
            }
          `,
        },
        {
          title: 'Correct',
          usage: [{ query: 'snake_case' }],
          code: /* GraphQL */ `
            # user_by_id.gql
            query UserById {
              userById(id: 5) {
                id
                name
                fullName
              }
            }
          `,
        },
        {
          title: 'Correct',
          usage: [{ fragment: { style: 'kebab-case', suffix: '.fragment' } }],
          code: /* GraphQL */ `
            # user-fields.fragment.gql
            fragment user_fields on User {
              id
              email
            }
          `,
        },
        {
          title: 'Correct',
          usage: [{ mutation: { style: 'PascalCase', suffix: 'Mutation' } }],
          code: /* GraphQL */ `
            # DeleteUserMutation.gql
            mutation DELETE_USER {
              deleteUser(id: 5)
            }
          `,
        },
        {
          title: 'Incorrect',
          usage: [{ fileExtension: '.graphql' }],
          code: /* GraphQL */ `
            # post.gql
            type Post {
              id: ID!
            }
          `,
        },
        {
          title: 'Incorrect',
          usage: [{ query: 'PascalCase' }],
          code: /* GraphQL */ `
            # user-by-id.gql
            query UserById {
              userById(id: 5) {
                id
                name
                fullName
              }
            }
          `,
        },
      ],
      configOptions: [
        {
          query: 'kebab-case',
          mutation: 'kebab-case',
          subscription: 'kebab-case',
          fragment: 'kebab-case',
        },
      ],
    },
    messages: {
      [MATCH_EXTENSION]: 'File extension "{{ fileExtension }}" don\'t match extension "{{ expectedFileExtension }}"',
      [MATCH_STYLE]: 'Unexpected filename "{{ filename }}". Rename it to "{{ expectedFilename }}"',
    },
    schema: {
      definitions: {
        asString: {
          enum: CASE_STYLES,
          description: `One of: ${CASE_STYLES.map(t => `\`${t}\``).join(', ')}`,
        },
        asObject: {
          type: 'object',
          additionalProperties: false,
          minProperties: 1,
          properties: {
            style: { enum: CASE_STYLES },
            suffix: { type: 'string' },
          },
        },
      },
      type: 'array',
      minItems: 1,
      maxItems: 1,
      items: {
        type: 'object',
        additionalProperties: false,
        minProperties: 1,
        properties: {
          fileExtension: { enum: ACCEPTED_EXTENSIONS },
          query: schemaOption,
          mutation: schemaOption,
          subscription: schemaOption,
          fragment: schemaOption,
        },
      },
    },
  },
  create(context) {
    const options: MatchDocumentFilenameRuleConfig = context.options[0] || {
      fileExtension: null,
    };
    const filePath = context.getFilename();
    const isVirtualFile = !existsSync(filePath);

    if (process.env.NODE_ENV !== 'test' && isVirtualFile) {
      // Skip validation for code files
      return {};
    }

    const fileExtension = extname(filePath);
    const filename = basename(filePath, fileExtension);

    return {
      Document(documentNode) {
        if (options.fileExtension && options.fileExtension !== fileExtension) {
          context.report({
            loc: REPORT_ON_FIRST_CHARACTER,
            messageId: MATCH_EXTENSION,
            data: {
              fileExtension,
              expectedFileExtension: options.fileExtension,
            },
          });
        }

        const firstOperation = documentNode.definitions.find(
          n => n.kind === Kind.OPERATION_DEFINITION
        ) as GraphQLESTreeNode<OperationDefinitionNode>;
        const firstFragment = documentNode.definitions.find(
          n => n.kind === Kind.FRAGMENT_DEFINITION
        ) as GraphQLESTreeNode<FragmentDefinitionNode>;

        const node = firstOperation || firstFragment;

        if (!node) {
          return;
        }
        const docName = node.name?.value;

        if (!docName) {
          return;
        }
        const docType = 'operation' in node ? node.operation : 'fragment';

        let option = options[docType];
        if (!option) {
          // Config not provided
          return;
        }

        if (typeof option === 'string') {
          option = { style: option } as PropertySchema;
        }
        const expectedExtension = options.fileExtension || fileExtension;
        let expectedFilename: string;
        if (option.style) {
          expectedFilename = option.style === 'matchDocumentStyle' ? docName : convertCase(option.style, docName);
        } else {
          expectedFilename = filename;
        }
        expectedFilename += (option.suffix || '') + expectedExtension;
        const filenameWithExtension = filename + expectedExtension;

        if (expectedFilename !== filenameWithExtension) {
          context.report({
            loc: REPORT_ON_FIRST_CHARACTER,
            messageId: MATCH_STYLE,
            data: {
              expectedFilename,
              filename: filenameWithExtension,
            },
          });
        }
      },
    };
  },
}
Example #8
Source File: sibling-operations.ts    From graphql-eslint with MIT License 4 votes vote down vote up
export function getSiblingOperations(projectForFile: GraphQLProjectConfig): SiblingOperations {
  const siblings = getSiblings(projectForFile);

  if (siblings.length === 0) {
    let printed = false;

    const noopWarn = () => {
      if (!printed) {
        logger.warn(
          'getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!'
        );
        printed = true;
      }
      return [];
    };

    return {
      available: false,
      getFragment: noopWarn,
      getFragments: noopWarn,
      getFragmentByType: noopWarn,
      getFragmentsInUse: noopWarn,
      getOperation: noopWarn,
      getOperations: noopWarn,
      getOperationByType: noopWarn,
    };
  }

  // Since the siblings array is cached, we can use it as cache key.
  // We should get the same array reference each time we get
  // to this point for the same graphql project
  if (siblingOperationsCache.has(siblings)) {
    return siblingOperationsCache.get(siblings);
  }

  let fragmentsCache: FragmentSource[] | null = null;

  const getFragments = (): FragmentSource[] => {
    if (fragmentsCache === null) {
      const result: FragmentSource[] = [];

      for (const source of siblings) {
        for (const definition of source.document.definitions) {
          if (definition.kind === Kind.FRAGMENT_DEFINITION) {
            result.push({
              filePath: source.location,
              document: definition,
            });
          }
        }
      }
      fragmentsCache = result;
    }
    return fragmentsCache;
  };

  let cachedOperations: OperationSource[] | null = null;

  const getOperations = (): OperationSource[] => {
    if (cachedOperations === null) {
      const result: OperationSource[] = [];

      for (const source of siblings) {
        for (const definition of source.document.definitions) {
          if (definition.kind === Kind.OPERATION_DEFINITION) {
            result.push({
              filePath: source.location,
              document: definition,
            });
          }
        }
      }
      cachedOperations = result;
    }
    return cachedOperations;
  };

  const getFragment = (name: string) => getFragments().filter(f => f.document.name?.value === name);

  const collectFragments = (
    selectable: SelectionSetNode | OperationDefinitionNode | FragmentDefinitionNode,
    recursive,
    collected = new Map<string, FragmentDefinitionNode>()
  ) => {
    visit(selectable, {
      FragmentSpread(spread) {
        const fragmentName = spread.name.value;
        const [fragment] = getFragment(fragmentName);

        if (!fragment) {
          logger.warn(
            `Unable to locate fragment named "${fragmentName}", please make sure it's loaded using "parserOptions.operations"`
          );
          return;
        }
        if (!collected.has(fragmentName)) {
          collected.set(fragmentName, fragment.document);
          if (recursive) {
            collectFragments(fragment.document, recursive, collected);
          }
        }
      },
    });
    return collected;
  };

  const siblingOperations: SiblingOperations = {
    available: true,
    getFragment,
    getFragments,
    getFragmentByType: typeName => getFragments().filter(f => f.document.typeCondition?.name?.value === typeName),
    getFragmentsInUse: (selectable, recursive = true) => Array.from(collectFragments(selectable, recursive).values()),
    getOperation: name => getOperations().filter(o => o.document.name?.value === name),
    getOperations,
    getOperationByType: type => getOperations().filter(o => o.document.operation === type),
  };

  siblingOperationsCache.set(siblings, siblingOperations);
  return siblingOperations;
}