@graphcommerce/graphql-codegen-relay-optimizer-plugin 2.101.2 → 2.102.2

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.
@@ -0,0 +1,4 @@
1
+ import { PluginFunction } from '@graphql-codegen/plugin-helpers';
2
+ export interface RelayOptimizerPluginConfig {
3
+ }
4
+ export declare const plugin: PluginFunction<RelayOptimizerPluginConfig>;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.plugin = void 0;
16
+ var graphql_1 = require("graphql");
17
+ var relay_compiler_1 = require("relay-compiler");
18
+ var CompilerContext_1 = __importDefault(require("relay-compiler/lib/core/CompilerContext"));
19
+ var IRPrinter_1 = require("relay-compiler/lib/core/IRPrinter");
20
+ var Schema_1 = require("relay-compiler/lib/core/Schema");
21
+ var ApplyFragmentArgumentTransform_1 = require("relay-compiler/lib/transforms/ApplyFragmentArgumentTransform");
22
+ var FlattenTransform_1 = require("relay-compiler/lib/transforms/FlattenTransform");
23
+ var InlineFragmentsTransform_1 = require("relay-compiler/lib/transforms/InlineFragmentsTransform");
24
+ var SkipRedundantNodesTransform_1 = require("relay-compiler/lib/transforms/SkipRedundantNodesTransform");
25
+ function isFragment(documentFile) {
26
+ var name = false;
27
+ (0, graphql_1.visit)(documentFile.document, {
28
+ enter: {
29
+ FragmentDefinition: function () {
30
+ name = true;
31
+ },
32
+ },
33
+ });
34
+ return name;
35
+ }
36
+ var plugin = function (schema, documents, _config) {
37
+ var isFrag = documents.every(function (d) { return isFragment(d); });
38
+ if (isFrag)
39
+ return { content: '' };
40
+ // @TODO way for users to define directives they use, otherwise relay will throw an unknown directive error
41
+ // Maybe we can scan the queries and add them dynamically without users having to do some extra stuff
42
+ // transformASTSchema creates a new schema instance instead of mutating the old one
43
+ var adjustedSchema = (0, Schema_1.create)((0, graphql_1.printSchema)(schema)).extend([
44
+ /* GraphQL */ "\n directive @connection(key: String!, filter: [String!]) on FIELD\n directive @client on FIELD\n ",
45
+ ]);
46
+ var documentAsts = documents.reduce(function (prev, v) { var _a, _b; return __spreadArray(__spreadArray([], prev, true), ((_b = (_a = v.document) === null || _a === void 0 ? void 0 : _a.definitions) !== null && _b !== void 0 ? _b : []), true); }, []);
47
+ var relayDocuments = relay_compiler_1.Parser.transform(adjustedSchema, documentAsts);
48
+ var fragmentCompilerContext = new CompilerContext_1.default(adjustedSchema).addAll(relayDocuments);
49
+ var fragmentDocuments = fragmentCompilerContext
50
+ .applyTransforms([
51
+ ApplyFragmentArgumentTransform_1.transform,
52
+ (0, FlattenTransform_1.transformWithOptions)({ flattenAbstractTypes: false }),
53
+ SkipRedundantNodesTransform_1.transform,
54
+ ])
55
+ .documents()
56
+ .filter(function (doc) { return doc.kind === 'Fragment'; });
57
+ var queryCompilerContext = new CompilerContext_1.default(adjustedSchema)
58
+ .addAll(relayDocuments)
59
+ .applyTransforms([
60
+ ApplyFragmentArgumentTransform_1.transform,
61
+ InlineFragmentsTransform_1.transform,
62
+ (0, FlattenTransform_1.transformWithOptions)({ flattenAbstractTypes: false }),
63
+ SkipRedundantNodesTransform_1.transform,
64
+ ]);
65
+ var newQueryDocuments = queryCompilerContext.documents().map(function (doc) { return ({
66
+ location: 'optimized by relay',
67
+ document: (0, graphql_1.parse)((0, IRPrinter_1.print)(adjustedSchema, doc)),
68
+ }); });
69
+ var newDocuments = [];
70
+ if (newQueryDocuments.length === 0) {
71
+ return { content: '' };
72
+ }
73
+ if (newQueryDocuments.length === 1) {
74
+ newDocuments = newQueryDocuments;
75
+ }
76
+ else {
77
+ newDocuments = __spreadArray(__spreadArray([], fragmentDocuments.map(function (doc) { return ({
78
+ location: 'optimized by relay',
79
+ document: (0, graphql_1.parse)((0, IRPrinter_1.print)(adjustedSchema, doc)),
80
+ }); }), true), newQueryDocuments, true);
81
+ }
82
+ documents.splice(0, documents.length);
83
+ documents.push.apply(documents, newDocuments);
84
+ return {
85
+ content: '',
86
+ };
87
+ };
88
+ exports.plugin = plugin;
@@ -0,0 +1,4 @@
1
+ import { PluginFunction } from '@graphql-codegen/plugin-helpers';
2
+ export interface RelayOptimizerPluginConfig {
3
+ }
4
+ export declare const plugin: PluginFunction<RelayOptimizerPluginConfig>;
@@ -0,0 +1,78 @@
1
+ import { parse, printSchema, visit } from 'graphql';
2
+ import { Parser as RelayParser } from 'relay-compiler';
3
+ import CompilerContext from 'relay-compiler/lib/core/CompilerContext';
4
+ import { print as relayPrint } from 'relay-compiler/lib/core/IRPrinter';
5
+ import { create as relayCreate } from 'relay-compiler/lib/core/Schema';
6
+ import { transform as applyFragmentArgumentTransform } from 'relay-compiler/lib/transforms/ApplyFragmentArgumentTransform';
7
+ import { transformWithOptions as flattenTransformWithOptions } from 'relay-compiler/lib/transforms/FlattenTransform';
8
+ import { transform as inlineFragmentsTransform } from 'relay-compiler/lib/transforms/InlineFragmentsTransform';
9
+ import { transform as skipRedundantNodesTransform } from 'relay-compiler/lib/transforms/SkipRedundantNodesTransform';
10
+ function isFragment(documentFile) {
11
+ let name = false;
12
+ visit(documentFile.document, {
13
+ enter: {
14
+ FragmentDefinition: () => {
15
+ name = true;
16
+ },
17
+ },
18
+ });
19
+ return name;
20
+ }
21
+ export const plugin = (schema, documents, _config) => {
22
+ const isFrag = documents.every((d) => isFragment(d));
23
+ if (isFrag)
24
+ return { content: '' };
25
+ // @TODO way for users to define directives they use, otherwise relay will throw an unknown directive error
26
+ // Maybe we can scan the queries and add them dynamically without users having to do some extra stuff
27
+ // transformASTSchema creates a new schema instance instead of mutating the old one
28
+ const adjustedSchema = relayCreate(printSchema(schema)).extend([
29
+ /* GraphQL */ `
30
+ directive @connection(key: String!, filter: [String!]) on FIELD
31
+ directive @client on FIELD
32
+ `,
33
+ ]);
34
+ const documentAsts = documents.reduce((prev, v) => { var _a, _b; return [...prev, ...((_b = (_a = v.document) === null || _a === void 0 ? void 0 : _a.definitions) !== null && _b !== void 0 ? _b : [])]; }, []);
35
+ const relayDocuments = RelayParser.transform(adjustedSchema, documentAsts);
36
+ const fragmentCompilerContext = new CompilerContext(adjustedSchema).addAll(relayDocuments);
37
+ const fragmentDocuments = fragmentCompilerContext
38
+ .applyTransforms([
39
+ applyFragmentArgumentTransform,
40
+ flattenTransformWithOptions({ flattenAbstractTypes: false }),
41
+ skipRedundantNodesTransform,
42
+ ])
43
+ .documents()
44
+ .filter((doc) => doc.kind === 'Fragment');
45
+ const queryCompilerContext = new CompilerContext(adjustedSchema)
46
+ .addAll(relayDocuments)
47
+ .applyTransforms([
48
+ applyFragmentArgumentTransform,
49
+ inlineFragmentsTransform,
50
+ flattenTransformWithOptions({ flattenAbstractTypes: false }),
51
+ skipRedundantNodesTransform,
52
+ ]);
53
+ const newQueryDocuments = queryCompilerContext.documents().map((doc) => ({
54
+ location: 'optimized by relay',
55
+ document: parse(relayPrint(adjustedSchema, doc)),
56
+ }));
57
+ let newDocuments = [];
58
+ if (newQueryDocuments.length === 0) {
59
+ return { content: '' };
60
+ }
61
+ if (newQueryDocuments.length === 1) {
62
+ newDocuments = newQueryDocuments;
63
+ }
64
+ else {
65
+ newDocuments = [
66
+ ...fragmentDocuments.map((doc) => ({
67
+ location: 'optimized by relay',
68
+ document: parse(relayPrint(adjustedSchema, doc)),
69
+ })),
70
+ ...newQueryDocuments,
71
+ ];
72
+ }
73
+ documents.splice(0, documents.length);
74
+ documents.push(...newDocuments);
75
+ return {
76
+ content: '',
77
+ };
78
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphcommerce/graphql-codegen-relay-optimizer-plugin",
3
- "version": "2.101.2",
3
+ "version": "2.102.2",
4
4
  "description": "GraphQL Code Generator plugin for optimizing your GraphQL queries relay style.",
5
5
  "license": "MIT",
6
6
  "main": "dist/main/index.js",
@@ -20,13 +20,13 @@
20
20
  "relay-compiler": "12.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@graphcommerce/eslint-config-pwa": "^3.0.2",
23
+ "@graphcommerce/eslint-config-pwa": "^3.0.4",
24
24
  "@graphcommerce/prettier-config-pwa": "^3.0.2",
25
25
  "@graphql-codegen/testing": "1.17.7",
26
- "@types/jest": "27.0.1",
26
+ "@types/jest": "27.0.2",
27
27
  "@types/relay-compiler": "8.0.1",
28
28
  "graphql": "^15.6.0",
29
- "jest": "27.2.2",
29
+ "jest": "27.2.4",
30
30
  "ts-jest": "27.0.5",
31
31
  "typescript": "^4.4.3"
32
32
  },
@@ -35,7 +35,8 @@
35
35
  "dev": "tsc --preserveWatchOutput --watch --sourceMap --outDir dist/main",
36
36
  "build:module": "tsc --target es2017 --outDir dist/module",
37
37
  "build:main": "tsc --target es5 --outDir dist/main",
38
- "build": "yarn build:module && yarn build:main"
38
+ "build": "yarn build:module && yarn build:main",
39
+ "prepack": "yarn build"
39
40
  },
40
41
  "prettier": "@graphcommerce/prettier-config-pwa",
41
42
  "browserslist": [
@@ -52,8 +53,9 @@
52
53
  },
53
54
  "files": [
54
55
  "dist/**/*",
56
+ "src",
55
57
  "LICENSE",
56
58
  "README.md"
57
59
  ],
58
- "gitHead": "c1aca21f6830cb9e4ec906e0f3f905623d977918"
60
+ "gitHead": "cf2b61fa96aca043ff841b018334ca8c28e5e6cf"
59
61
  }
@@ -0,0 +1,149 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-ignore */
2
+ import '@graphql-codegen/testing'
3
+
4
+ import { Types } from '@graphql-codegen/plugin-helpers'
5
+ import { buildSchema, parse, print, ASTNode } from 'graphql'
6
+ import { plugin } from '..'
7
+
8
+ const testSchema = buildSchema(/* GraphQL */ `
9
+ type Avatar {
10
+ id: ID!
11
+ url: String!
12
+ }
13
+
14
+ type User {
15
+ id: ID!
16
+ login: String!
17
+ avatar(height: Int!, width: Int!): Avatar
18
+ }
19
+
20
+ type Query {
21
+ user: User!
22
+ users: [User!]!
23
+ }
24
+ `)
25
+
26
+ // eslint-disable-next-line jest/expect-expect
27
+ it('can be called', async () => {
28
+ const testDocument = parse(/* GraphQL */ `
29
+ query user {
30
+ user {
31
+ id
32
+ }
33
+ }
34
+ `)
35
+ await plugin(testSchema, [{ document: testDocument }], {})
36
+ })
37
+
38
+ // eslint-disable-next-line jest/expect-expect
39
+ it('can be called with queries that include connection fragments', async () => {
40
+ const testDocument = parse(/* GraphQL */ `
41
+ query user {
42
+ users @connection(key: "foo") {
43
+ id
44
+ }
45
+ }
46
+ `)
47
+ await plugin(testSchema, [{ document: testDocument }], {})
48
+ })
49
+
50
+ it('can inline @argumentDefinitions/@arguments annotated fragments', async () => {
51
+ const fragmentDocument = parse(/* GraphQL */ `
52
+ fragment UserLogin on User
53
+ @argumentDefinitions(
54
+ height: { type: "Int", defaultValue: 10 }
55
+ width: { type: "Int", defaultValue: 10 }
56
+ ) {
57
+ id
58
+ login
59
+ avatar(width: $width, height: $height) {
60
+ id
61
+ url
62
+ }
63
+ }
64
+ `)
65
+ const queryDocument = parse(/* GraphQL */ `
66
+ query user {
67
+ users {
68
+ ...UserLogin @arguments(height: 30, width: 30)
69
+ }
70
+ }
71
+ `)
72
+ const input: Types.DocumentFile[] = [{ document: fragmentDocument }, { document: queryDocument }]
73
+ await plugin(testSchema, input, {})
74
+ const queryDoc = input.find((doc) => doc.document?.definitions[0].kind === 'OperationDefinition')
75
+
76
+ expect(queryDoc).toBeDefined()
77
+ expect(print(queryDoc?.document as ASTNode)).toBeSimilarStringTo(/* GraphQL */ `
78
+ query user {
79
+ users {
80
+ id
81
+ login
82
+ avatar(width: 30, height: 30) {
83
+ id
84
+ url
85
+ }
86
+ }
87
+ }
88
+ `)
89
+ })
90
+
91
+ it('handles unions with interfaces the correct way', async () => {
92
+ const schema = buildSchema(/* GraphQL */ `
93
+ type User {
94
+ id: ID!
95
+ login: String!
96
+ }
97
+
98
+ interface Error {
99
+ message: String!
100
+ }
101
+
102
+ type UserNotFoundError implements Error {
103
+ message: String!
104
+ }
105
+
106
+ type UserBlockedError implements Error {
107
+ message: String!
108
+ }
109
+
110
+ union UserResult = User | UserNotFoundError | UserBlockedError
111
+
112
+ type Query {
113
+ user: UserResult!
114
+ }
115
+ `)
116
+
117
+ const queryDocument = parse(/* GraphQL */ `
118
+ query user {
119
+ user {
120
+ ... on User {
121
+ id
122
+ login
123
+ }
124
+ ... on Error {
125
+ message
126
+ }
127
+ }
128
+ }
129
+ `)
130
+
131
+ const input: Types.DocumentFile[] = [{ document: queryDocument }]
132
+ await plugin(schema, input, {})
133
+ const queryDoc = input.find((doc) => doc.document?.definitions[0].kind === 'OperationDefinition')
134
+
135
+ expect(queryDoc).toBeDefined()
136
+ expect(print(queryDoc?.document as ASTNode)).toBeSimilarStringTo(/* GraphQL */ `
137
+ query user {
138
+ user {
139
+ ... on User {
140
+ id
141
+ login
142
+ }
143
+ ... on Error {
144
+ message
145
+ }
146
+ }
147
+ }
148
+ `)
149
+ })
package/src/index.ts ADDED
@@ -0,0 +1,104 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+ import { Types, PluginFunction } from '@graphql-codegen/plugin-helpers'
3
+ import { GraphQLSchema, parse, printSchema, DefinitionNode, visit } from 'graphql'
4
+
5
+ import { Parser as RelayParser } from 'relay-compiler'
6
+ import CompilerContext from 'relay-compiler/lib/core/CompilerContext'
7
+ import { print as relayPrint } from 'relay-compiler/lib/core/IRPrinter'
8
+ import { create as relayCreate } from 'relay-compiler/lib/core/Schema'
9
+
10
+ import { transform as applyFragmentArgumentTransform } from 'relay-compiler/lib/transforms/ApplyFragmentArgumentTransform'
11
+ import { transformWithOptions as flattenTransformWithOptions } from 'relay-compiler/lib/transforms/FlattenTransform'
12
+ import { transform as inlineFragmentsTransform } from 'relay-compiler/lib/transforms/InlineFragmentsTransform'
13
+ import { transform as skipRedundantNodesTransform } from 'relay-compiler/lib/transforms/SkipRedundantNodesTransform'
14
+
15
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
16
+ export interface RelayOptimizerPluginConfig {}
17
+
18
+ function isFragment(documentFile: Types.DocumentFile) {
19
+ let name = false
20
+
21
+ visit(documentFile.document!, {
22
+ enter: {
23
+ FragmentDefinition: () => {
24
+ name = true
25
+ },
26
+ },
27
+ })
28
+ return name
29
+ }
30
+
31
+ export const plugin: PluginFunction<RelayOptimizerPluginConfig> = (
32
+ schema: GraphQLSchema,
33
+ documents: Types.DocumentFile[],
34
+ _config: RelayOptimizerPluginConfig,
35
+ ) => {
36
+ const isFrag = documents.every((d) => isFragment(d))
37
+
38
+ if (isFrag) return { content: '' }
39
+
40
+ // @TODO way for users to define directives they use, otherwise relay will throw an unknown directive error
41
+ // Maybe we can scan the queries and add them dynamically without users having to do some extra stuff
42
+ // transformASTSchema creates a new schema instance instead of mutating the old one
43
+ const adjustedSchema = relayCreate(printSchema(schema)).extend([
44
+ /* GraphQL */ `
45
+ directive @connection(key: String!, filter: [String!]) on FIELD
46
+ directive @client on FIELD
47
+ `,
48
+ ])
49
+
50
+ const documentAsts = documents.reduce(
51
+ (prev, v) => [...prev, ...(v.document?.definitions ?? [])],
52
+ [] as DefinitionNode[],
53
+ )
54
+
55
+ const relayDocuments = RelayParser.transform(adjustedSchema, documentAsts)
56
+
57
+ const fragmentCompilerContext = new CompilerContext(adjustedSchema).addAll(relayDocuments)
58
+
59
+ const fragmentDocuments = fragmentCompilerContext
60
+ .applyTransforms([
61
+ applyFragmentArgumentTransform,
62
+ flattenTransformWithOptions({ flattenAbstractTypes: false }),
63
+ skipRedundantNodesTransform,
64
+ ])
65
+ .documents()
66
+ .filter((doc) => doc.kind === 'Fragment')
67
+
68
+ const queryCompilerContext = new CompilerContext(adjustedSchema)
69
+ .addAll(relayDocuments)
70
+ .applyTransforms([
71
+ applyFragmentArgumentTransform,
72
+ inlineFragmentsTransform,
73
+ flattenTransformWithOptions({ flattenAbstractTypes: false }),
74
+ skipRedundantNodesTransform,
75
+ ])
76
+
77
+ const newQueryDocuments: Types.DocumentFile[] = queryCompilerContext.documents().map((doc) => ({
78
+ location: 'optimized by relay',
79
+ document: parse(relayPrint(adjustedSchema, doc)),
80
+ }))
81
+
82
+ let newDocuments: Types.DocumentFile[] = []
83
+ if (newQueryDocuments.length === 0) {
84
+ return { content: '' }
85
+ }
86
+ if (newQueryDocuments.length === 1) {
87
+ newDocuments = newQueryDocuments
88
+ } else {
89
+ newDocuments = [
90
+ ...fragmentDocuments.map((doc) => ({
91
+ location: 'optimized by relay',
92
+ document: parse(relayPrint(adjustedSchema, doc)),
93
+ })),
94
+ ...newQueryDocuments,
95
+ ]
96
+ }
97
+
98
+ documents.splice(0, documents.length)
99
+ documents.push(...newDocuments)
100
+
101
+ return {
102
+ content: '',
103
+ }
104
+ }
package/src/tyes.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ declare module 'relay-compiler/lib/core/Schema' {
2
+ export function create(schema: string): import('relay-compiler').Schema
3
+ }
4
+
5
+ declare module 'relay-compiler/lib/core/IRPrinter' {
6
+ export function print(schema: import('relay-compiler').Schema, document: any): string
7
+ }
8
+
9
+ declare module 'relay-compiler/lib/core/CompilerContext' {
10
+ let CompilerContext: typeof import('relay-compiler').CompilerContext
11
+ export = CompilerContext
12
+ }