1 | import { extname } from 'path';
|
2 | import { removeFederation } from '@graphql-codegen/plugin-helpers';
|
3 | import { execute, parse } from 'graphql';
|
4 | const extensions = {
|
5 | ts: ['.ts', '.tsx'],
|
6 | js: ['.js', '.jsx'],
|
7 | json: ['.json'],
|
8 | };
|
9 | export const plugin = async (schema, _documents, pluginConfig, info) => {
|
10 | const config = {
|
11 | module: 'es2015',
|
12 | federation: false,
|
13 | apolloClientVersion: 3,
|
14 | useExplicitTyping: false,
|
15 | ...pluginConfig,
|
16 | };
|
17 | const apolloClientVersion = parseInt(config.apolloClientVersion);
|
18 | const cleanSchema = config.federation ? removeFederation(schema) : schema;
|
19 | const { useExplicitTyping } = config;
|
20 | const introspection = (await execute({
|
21 | schema: cleanSchema,
|
22 | document: parse(`
|
23 | {
|
24 | __schema {
|
25 | types {
|
26 | kind
|
27 | name
|
28 | possibleTypes {
|
29 | name
|
30 | }
|
31 | }
|
32 | }
|
33 | }
|
34 | `),
|
35 | }));
|
36 | const ext = extname(info.outputFile).toLowerCase();
|
37 | if (!introspection.data) {
|
38 | throw new Error(`Plugin "fragment-matcher" couldn't introspect the schema`);
|
39 | }
|
40 | const filterUnionAndInterfaceTypes = type => type.kind === 'UNION' || type.kind === 'INTERFACE';
|
41 | const createPossibleTypesCollection = (acc, type) => {
|
42 | return { ...acc, ...{ [type.name]: type.possibleTypes.map(possibleType => possibleType.name) } };
|
43 | };
|
44 | const filteredData = apolloClientVersion === 2
|
45 | ? {
|
46 | __schema: {
|
47 | ...introspection.data.__schema,
|
48 | types: introspection.data.__schema.types.filter(type => type.kind === 'UNION' || type.kind === 'INTERFACE'),
|
49 | },
|
50 | }
|
51 | : {
|
52 | possibleTypes: introspection.data.__schema.types
|
53 | .filter(filterUnionAndInterfaceTypes)
|
54 | .reduce(createPossibleTypesCollection, {}),
|
55 | };
|
56 | const content = JSON.stringify(filteredData, null, 2);
|
57 | if (extensions.json.includes(ext)) {
|
58 | return content;
|
59 | }
|
60 | if (extensions.js.includes(ext)) {
|
61 | const defaultExportStatement = config.module === 'es2015' ? `export default` : 'module.exports =';
|
62 | return `
|
63 | ${defaultExportStatement} ${content}
|
64 | `;
|
65 | }
|
66 | if (extensions.ts.includes(ext)) {
|
67 | let typename;
|
68 | if (apolloClientVersion === 2) {
|
69 | typename = `IntrospectionResultData`;
|
70 | }
|
71 | else if (apolloClientVersion === 3) {
|
72 | typename = `PossibleTypesResultData`;
|
73 | }
|
74 | let type;
|
75 | if (useExplicitTyping) {
|
76 | type = `export type ${typename} = ${content};`;
|
77 | }
|
78 | else if (apolloClientVersion === 2) {
|
79 | type = `export interface ${typename} {
|
80 | __schema: {
|
81 | types: {
|
82 | kind: string;
|
83 | name: string;
|
84 | possibleTypes: {
|
85 | name: string;
|
86 | }[];
|
87 | }[];
|
88 | };
|
89 | }`;
|
90 | }
|
91 | else if (apolloClientVersion === 3) {
|
92 | type = `export interface ${typename} {
|
93 | possibleTypes: {
|
94 | [key: string]: string[]
|
95 | }
|
96 | }`;
|
97 | }
|
98 | return `
|
99 | ${type}
|
100 | const result: ${typename} = ${content};
|
101 | export default result;
|
102 | `;
|
103 | }
|
104 | throw new Error(`Extension ${ext} is not supported`);
|
105 | };
|
106 | export const validate = async (_schema, _documents, config, outputFile) => {
|
107 | const ext = extname(outputFile).toLowerCase();
|
108 | const all = Object.values(extensions).reduce((acc, exts) => [...acc, ...exts], []);
|
109 | if (!all.includes(ext)) {
|
110 | throw new Error(`Plugin "fragment-matcher" requires extension to be one of ${all.map(val => val.replace('.', '')).join(', ')}!`);
|
111 | }
|
112 | if (config.module === 'commonjs' && extensions.ts.includes(ext)) {
|
113 | throw new Error(`Plugin "fragment-matcher" doesn't support commonjs modules combined with TypeScript!`);
|
114 | }
|
115 | };
|