Skip to content

Commit

Permalink
[Data masking] Add codemod to apply @unmask to all named fragments (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller authored Nov 13, 2024
1 parent 8422a30 commit 6a98e76
Show file tree
Hide file tree
Showing 11 changed files with 1,736 additions and 3 deletions.
15 changes: 15 additions & 0 deletions .changeset/flat-beans-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@apollo/client": patch
---

Provide a codemod that applies `@unmask` to all named fragments for all operations and fragments. To use the codemod, run the following command:

```
npx jscodeshift -t node_modules/@apollo/client/scripts/codemods/data-masking/unmask.ts --extensions tsx --parser tsx path/to/app/
```

To customize the tag used to search for GraphQL operations, use the `--tag` option. By default the codemod looks for `gql` and `graphql` tags.

To apply the directive in migrate mode in order to receive runtime warnings on potentially masked fields, use the `--mode migrate` option.

For more information on the options that can be used with `jscodeshift`, check out the [`jscodeshift` documentation](https://github.com/facebook/jscodeshift).
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
"excludedFiles": ["**/__tests__/**/*.*", "*.d.ts"],
"extends": ["plugin:react-hooks/recommended"],
"parserOptions": {
"project": "./tsconfig.json"
"project": [
"./tsconfig.json",
"./scripts/codemods/data-masking/tsconfig.json"
]
},
"plugins": ["eslint-plugin-react-compiler"],
"rules": {
Expand Down
4 changes: 2 additions & 2 deletions .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 41580,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 34368
"dist/apollo-client.min.cjs": 41576,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 34364
}
26 changes: 26 additions & 0 deletions scripts/codemods/data-masking/examples/queries-codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { graphql } from "./gql";

export const query = graphql(`
query GetCurrentUser {
currentUser {
id
...CurrentUserFields
}
}
`);

export const currentUserFieldsFragment = graphql(`
fragment CurrentUserFields on User {
name
...ProfileFields
}
`);

export const profileFieldsFragment = graphql(`
fragment ProfileFields on User {
profile {
id
avatarUrl
}
}
`);
39 changes: 39 additions & 0 deletions scripts/codemods/data-masking/examples/queries-react.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import { gql, useQuery } from "@apollo/client";

const ProfileFieldsFragment = gql`
fragment ProfileFields on User {
profile {
id
avatarUrl
}
}
`;

const fragment = gql`
fragment CurrentUserFields on User {
name
...ProfileFields
}
${ProfileFieldsFragment}
`;

export function MyComponent() {
const { data, loading } = useQuery(gql`
query GetCurrentUser {
currentUser {
id
...CurrentUserFields
}
}
${fragment}
`);

if (loading) {
return <div>Loading...</div>;
}

return <div>{JSON.stringify(data)}</div>;
}
18 changes: 18 additions & 0 deletions scripts/codemods/data-masking/examples/queries.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
query GetCurrentUser {
currentUser {
id
...CurrentUserFields
}
}

fragment CurrentUserFields on User {
name
...ProfileFields
}

fragment ProfileFields on User {
profile {
id
avatarUrl
}
}
31 changes: 31 additions & 0 deletions scripts/codemods/data-masking/examples/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { gql } from "@apollo/client";
import type { TypedDocumentNode } from "@apollo/client";

export const ProfileFieldsFragment: TypedDocumentNode<{
profile: { id: string; avatarUrl: string };
}> = gql`
fragment ProfileFields on User {
profile {
id
avatarUrl
}
}
`;

const CurrentUserFieldsFragment = gql`
fragment CurrentUserFields on User {
name
...ProfileFields
}
`;

export const GetCurrentUser = gql`
query GetCurrentUser {
currentUser {
id
...CurrentUserFields
}
}
${CurrentUserFieldsFragment}
`;
Loading

0 comments on commit 6a98e76

Please sign in to comment.