-
-
Notifications
You must be signed in to change notification settings - Fork 818
/
index.ts
111 lines (90 loc) · 3.25 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import os from 'os';
import { isExecutableDefinitionNode, Kind, DocumentNode } from 'graphql';
import { uniqueCode } from '@graphql-tools/webpack-loader-runtime';
import { parseDocument } from './parser';
import { optimizeDocumentNode, removeDescriptions, removeEmptyNodes } from '@graphql-tools/optimize';
import type { LoaderContext } from 'webpack';
function isSDL(doc: DocumentNode) {
return !doc.definitions.some(def => isExecutableDefinitionNode(def));
}
interface Options {
noDescription?: boolean;
noEmptyNodes?: boolean;
noLoc?: boolean;
replaceKinds?: boolean;
esModule?: boolean;
importHelpers?: boolean;
}
function expandImports(source: string, options: Options) {
const lines = source.split(/\r\n|\r|\n/);
let outputCode = options.importHelpers
? `
var useUnique = require('@graphql-tools/webpack-loader-runtime').useUnique;
var unique = useUnique();
`
: `
${uniqueCode}
`;
lines.some(line => {
if (line[0] === '#' && line.slice(1).split(' ')[0] === 'import') {
const importFile = line.slice(1).split(' ')[1];
const parseDocument = `require(${importFile})`;
const appendDef = `doc.definitions = doc.definitions.concat(unique(${parseDocument}.definitions));`;
outputCode += appendDef + os.EOL;
}
return line.length !== 0 && line[0] !== '#';
});
return outputCode;
}
export default function graphqlLoader(this: LoaderContext<Options>, source: string) {
this.cacheable();
// TODO: This should probably use this.getOptions()
const options = (this.query as Options) || {};
let doc = parseDocument(source);
const optimizers = [];
if (options.noDescription) {
optimizers.push(removeDescriptions);
}
if (options.noEmptyNodes) {
optimizers.push(removeEmptyNodes);
}
if (optimizers.length > 0 && isSDL(doc)) {
doc = optimizeDocumentNode(doc, optimizers);
}
let stringifiedDoc = JSON.stringify(doc);
if (options.replaceKinds) {
for (const identifier in Kind) {
const value = Kind[identifier as keyof typeof Kind];
stringifiedDoc = stringifiedDoc.replace(new RegExp(`"kind":"${value}"`, 'g'), `"kind": Kind.${identifier}`);
}
}
const headerCode = `
${options.replaceKinds ? "var Kind = require('graphql/language/kinds');" : ''}
var doc = ${stringifiedDoc};
`;
let outputCode = '';
// Allow multiple query/mutation definitions in a file. This parses out dependencies
// at compile time, and then uses those at load time to create minimal query documents
// We cannot do the latter at compile time due to how the #import code works.
const operationCount = doc.definitions.reduce<number>((accum, op) => {
if (op.kind === Kind.OPERATION_DEFINITION) {
return accum + 1;
}
return accum;
}, 0);
function exportDefaultStatement(identifier: string) {
if (options.esModule) {
return `export default ${identifier}`;
}
return `module.exports = ${identifier}`;
}
if (operationCount > 1) {
throw new Error('GraphQL Webpack Loader allows only for one GraphQL Operation per file');
}
outputCode += `
${exportDefaultStatement('doc')}
`;
const importOutputCode = expandImports(source, options);
const allCode = [headerCode, importOutputCode, outputCode, ''].join(os.EOL);
return allCode;
}