1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.shouldEmitLegacyCommonJSImports = exports.ensureContext = exports.CodegenContext = exports.updateContextWithCliFlags = exports.createContext = exports.parseArgv = exports.buildOptions = exports.loadContext = exports.loadCodegenConfig = exports.generateSearchPlaces = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const cosmiconfig_1 = require("cosmiconfig");
|
6 | const cosmiconfig_typescript_loader_1 = require("cosmiconfig-typescript-loader");
|
7 | const path_1 = require("path");
|
8 | const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
|
9 | const string_env_interpolation_1 = require("string-env-interpolation");
|
10 | const yargs_1 = tslib_1.__importDefault(require("yargs"));
|
11 | const graphql_config_js_1 = require("./graphql-config.js");
|
12 | const load_js_1 = require("./load.js");
|
13 | const graphql_1 = require("graphql");
|
14 | const yaml_1 = tslib_1.__importDefault(require("yaml"));
|
15 | const module_1 = require("module");
|
16 | const fs_1 = require("fs");
|
17 | const crypto_1 = require("crypto");
|
18 | const { lstat } = fs_1.promises;
|
19 | function generateSearchPlaces(moduleName) {
|
20 | const extensions = ['json', 'yaml', 'yml', 'js', 'ts', 'config.js'];
|
21 |
|
22 | const regular = extensions.map(ext => `${moduleName}.${ext}`);
|
23 |
|
24 | const dot = extensions.filter(ext => ext !== 'config.js').map(ext => `.${moduleName}rc.${ext}`);
|
25 | return [...regular.concat(dot), 'package.json'];
|
26 | }
|
27 | exports.generateSearchPlaces = generateSearchPlaces;
|
28 | function customLoader(ext) {
|
29 | function loader(filepath, content) {
|
30 | if (typeof process !== 'undefined' && 'env' in process) {
|
31 | content = (0, string_env_interpolation_1.env)(content);
|
32 | }
|
33 | if (ext === 'json') {
|
34 | return cosmiconfig_1.defaultLoaders['.json'](filepath, content);
|
35 | }
|
36 | if (ext === 'yaml') {
|
37 | try {
|
38 | const result = yaml_1.default.parse(content, { prettyErrors: true, merge: true });
|
39 | return result;
|
40 | }
|
41 | catch (error) {
|
42 | error.message = `YAML Error in ${filepath}:\n${error.message}`;
|
43 | throw error;
|
44 | }
|
45 | }
|
46 | if (ext === 'js') {
|
47 | return cosmiconfig_1.defaultLoaders['.js'](filepath, content);
|
48 | }
|
49 | if (ext === 'ts') {
|
50 | return (0, cosmiconfig_typescript_loader_1.TypeScriptLoader)()(filepath, content);
|
51 | }
|
52 | }
|
53 | return loader;
|
54 | }
|
55 | async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
|
56 | configFilePath = configFilePath || process.cwd();
|
57 | moduleName = moduleName || 'codegen';
|
58 | packageProp = packageProp || moduleName;
|
59 | const cosmi = (0, cosmiconfig_1.cosmiconfig)(moduleName, {
|
60 | searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
|
61 | packageProp,
|
62 | loaders: {
|
63 | '.json': customLoader('json'),
|
64 | '.yaml': customLoader('yaml'),
|
65 | '.yml': customLoader('yaml'),
|
66 | '.js': customLoader('js'),
|
67 | '.ts': customLoader('ts'),
|
68 | noExt: customLoader('yaml'),
|
69 | ...customLoaders,
|
70 | },
|
71 | });
|
72 | const pathStats = await lstat(configFilePath);
|
73 | return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
|
74 | }
|
75 | exports.loadCodegenConfig = loadCodegenConfig;
|
76 | async function loadContext(configFilePath) {
|
77 | const graphqlConfig = await (0, graphql_config_js_1.findAndLoadGraphQLConfig)(configFilePath);
|
78 | if (graphqlConfig) {
|
79 | return new CodegenContext({
|
80 | graphqlConfig,
|
81 | });
|
82 | }
|
83 | const result = await loadCodegenConfig({ configFilePath });
|
84 | if (!result) {
|
85 | if (configFilePath) {
|
86 | throw new plugin_helpers_1.DetailedError(`Config ${configFilePath} does not exist`, `
|
87 | Config ${configFilePath} does not exist.
|
88 |
|
89 | $ graphql-codegen --config ${configFilePath}
|
90 |
|
91 | Please make sure the --config points to a correct file.
|
92 | `);
|
93 | }
|
94 | throw new plugin_helpers_1.DetailedError(`Unable to find Codegen config file!`, `
|
95 | Please make sure that you have a configuration file under the current directory!
|
96 | `);
|
97 | }
|
98 | if (result.isEmpty) {
|
99 | throw new plugin_helpers_1.DetailedError(`Found Codegen config file but it was empty!`, `
|
100 | Please make sure that you have a valid configuration file under the current directory!
|
101 | `);
|
102 | }
|
103 | return new CodegenContext({
|
104 | filepath: result.filepath,
|
105 | config: result.config,
|
106 | });
|
107 | }
|
108 | exports.loadContext = loadContext;
|
109 | function getCustomConfigPath(cliFlags) {
|
110 | const configFile = cliFlags.config;
|
111 | return configFile ? (0, path_1.resolve)(process.cwd(), configFile) : null;
|
112 | }
|
113 | function buildOptions() {
|
114 | return {
|
115 | c: {
|
116 | alias: 'config',
|
117 | type: 'string',
|
118 | describe: 'Path to GraphQL codegen YAML config file, defaults to "codegen.yml" on the current directory',
|
119 | },
|
120 | w: {
|
121 | alias: 'watch',
|
122 | describe: 'Watch for changes and execute generation automatically. You can also specify a glob expression for custom watch list.',
|
123 | coerce: (watch) => {
|
124 | if (watch === 'false') {
|
125 | return false;
|
126 | }
|
127 | if (typeof watch === 'string' || Array.isArray(watch)) {
|
128 | return watch;
|
129 | }
|
130 | return !!watch;
|
131 | },
|
132 | },
|
133 | r: {
|
134 | alias: 'require',
|
135 | describe: 'Loads specific require.extensions before running the codegen and reading the configuration',
|
136 | type: 'array',
|
137 | default: [],
|
138 | },
|
139 | o: {
|
140 | alias: 'overwrite',
|
141 | describe: 'Overwrites existing files',
|
142 | type: 'boolean',
|
143 | },
|
144 | s: {
|
145 | alias: 'silent',
|
146 | describe: 'Suppresses printing errors',
|
147 | type: 'boolean',
|
148 | },
|
149 | e: {
|
150 | alias: 'errors-only',
|
151 | describe: 'Only print errors',
|
152 | type: 'boolean',
|
153 | },
|
154 | profile: {
|
155 | describe: 'Use profiler to measure performance',
|
156 | type: 'boolean',
|
157 | },
|
158 | p: {
|
159 | alias: 'project',
|
160 | describe: 'Name of a project in GraphQL Config',
|
161 | type: 'string',
|
162 | },
|
163 | v: {
|
164 | alias: 'verbose',
|
165 | describe: 'output more detailed information about performed tasks',
|
166 | type: 'boolean',
|
167 | default: false,
|
168 | },
|
169 | d: {
|
170 | alias: 'debug',
|
171 | describe: 'Print debug logs to stdout',
|
172 | type: 'boolean',
|
173 | default: false,
|
174 | },
|
175 | };
|
176 | }
|
177 | exports.buildOptions = buildOptions;
|
178 | function parseArgv(argv = process.argv) {
|
179 | return (0, yargs_1.default)(argv).options(buildOptions()).parse(argv);
|
180 | }
|
181 | exports.parseArgv = parseArgv;
|
182 | async function createContext(cliFlags = parseArgv(process.argv)) {
|
183 | if (cliFlags.require && cliFlags.require.length > 0) {
|
184 | const relativeRequire = (0, module_1.createRequire)(process.cwd());
|
185 | await Promise.all(cliFlags.require.map(mod => Promise.resolve().then(() => tslib_1.__importStar(require(relativeRequire.resolve(mod, {
|
186 | paths: [process.cwd()],
|
187 | }))))));
|
188 | }
|
189 | const customConfigPath = getCustomConfigPath(cliFlags);
|
190 | const context = await loadContext(customConfigPath);
|
191 | updateContextWithCliFlags(context, cliFlags);
|
192 | return context;
|
193 | }
|
194 | exports.createContext = createContext;
|
195 | function updateContextWithCliFlags(context, cliFlags) {
|
196 | const config = {
|
197 | configFilePath: context.filepath,
|
198 | };
|
199 | if (cliFlags.watch !== undefined) {
|
200 | config.watch = cliFlags.watch;
|
201 | }
|
202 | if (cliFlags.overwrite === true) {
|
203 | config.overwrite = cliFlags.overwrite;
|
204 | }
|
205 | if (cliFlags.silent === true) {
|
206 | config.silent = cliFlags.silent;
|
207 | }
|
208 | if (cliFlags.verbose === true || process.env.VERBOSE) {
|
209 | config.verbose = true;
|
210 | }
|
211 | if (cliFlags.debug === true || process.env.DEBUG) {
|
212 | config.debug = true;
|
213 | }
|
214 | if (cliFlags.errorsOnly === true) {
|
215 | config.errorsOnly = cliFlags.errorsOnly;
|
216 | }
|
217 | if (cliFlags['ignore-no-documents'] !== undefined) {
|
218 |
|
219 | config.ignoreNoDocuments = cliFlags['ignore-no-documents'] === true;
|
220 | }
|
221 | if (cliFlags['emit-legacy-common-js-imports'] !== undefined) {
|
222 |
|
223 | config.emitLegacyCommonJSImports = cliFlags['emit-legacy-common-js-imports'] === true;
|
224 | }
|
225 | if (cliFlags.project) {
|
226 | context.useProject(cliFlags.project);
|
227 | }
|
228 | if (cliFlags.profile === true) {
|
229 | context.useProfiler();
|
230 | }
|
231 | if (cliFlags.check === true) {
|
232 | context.enableCheckMode();
|
233 | }
|
234 | context.updateConfig(config);
|
235 | }
|
236 | exports.updateContextWithCliFlags = updateContextWithCliFlags;
|
237 | class CodegenContext {
|
238 | constructor({ config, graphqlConfig, filepath, }) {
|
239 | this._checkMode = false;
|
240 | this._pluginContext = {};
|
241 | this.checkModeStaleFiles = [];
|
242 | this._config = config;
|
243 | this._graphqlConfig = graphqlConfig;
|
244 | this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
|
245 | this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
|
246 | this.profiler = (0, plugin_helpers_1.createNoopProfiler)();
|
247 | }
|
248 | useProject(name) {
|
249 | this._project = name;
|
250 | }
|
251 | getConfig(extraConfig) {
|
252 | if (!this.config) {
|
253 | if (this._graphqlConfig) {
|
254 | const project = this._graphqlConfig.getProject(this._project);
|
255 | this.config = {
|
256 | ...project.extension('codegen'),
|
257 | schema: project.schema,
|
258 | documents: project.documents,
|
259 | pluginContext: this._pluginContext,
|
260 | };
|
261 | }
|
262 | else {
|
263 | this.config = { ...this._config, pluginContext: this._pluginContext };
|
264 | }
|
265 | }
|
266 | return {
|
267 | ...extraConfig,
|
268 | ...this.config,
|
269 | };
|
270 | }
|
271 | updateConfig(config) {
|
272 | this.config = {
|
273 | ...this.getConfig(),
|
274 | ...config,
|
275 | };
|
276 | }
|
277 | enableCheckMode() {
|
278 | this._checkMode = true;
|
279 | }
|
280 | get checkMode() {
|
281 | return this._checkMode;
|
282 | }
|
283 | useProfiler() {
|
284 | this.profiler = (0, plugin_helpers_1.createProfiler)();
|
285 | const now = new Date();
|
286 | const datetime = now.toISOString().split('.')[0];
|
287 | const datetimeNormalized = datetime.replace(/-|:/g, '');
|
288 | this.profilerOutput = `codegen-${datetimeNormalized}.json`;
|
289 | }
|
290 | getPluginContext() {
|
291 | return this._pluginContext;
|
292 | }
|
293 | async loadSchema(pointer) {
|
294 | const config = this.getConfig(load_js_1.defaultSchemaLoadOptions);
|
295 | if (this._graphqlConfig) {
|
296 |
|
297 | return addHashToSchema(this._graphqlConfig.getProject(this._project).loadSchema(pointer, 'GraphQLSchema', config));
|
298 | }
|
299 | return addHashToSchema((0, load_js_1.loadSchema)(pointer, config));
|
300 | }
|
301 | async loadDocuments(pointer) {
|
302 | const config = this.getConfig(load_js_1.defaultDocumentsLoadOptions);
|
303 | if (this._graphqlConfig) {
|
304 |
|
305 | return addHashToDocumentFiles(this._graphqlConfig.getProject(this._project).loadDocuments(pointer, config));
|
306 | }
|
307 | return addHashToDocumentFiles((0, load_js_1.loadDocuments)(pointer, config));
|
308 | }
|
309 | }
|
310 | exports.CodegenContext = CodegenContext;
|
311 | function ensureContext(input) {
|
312 | return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
|
313 | }
|
314 | exports.ensureContext = ensureContext;
|
315 | function hashContent(content) {
|
316 | return (0, crypto_1.createHash)('sha256').update(content).digest('hex');
|
317 | }
|
318 | function hashSchema(schema) {
|
319 | return hashContent((0, graphql_1.print)((0, plugin_helpers_1.getCachedDocumentNodeFromSchema)(schema)));
|
320 | }
|
321 | function addHashToSchema(schemaPromise) {
|
322 | return schemaPromise.then(schema => {
|
323 |
|
324 | if (!schema.extensions) {
|
325 | schema.extensions = {};
|
326 | }
|
327 | schema.extensions['hash'] = hashSchema(schema);
|
328 | return schema;
|
329 | });
|
330 | }
|
331 | function hashDocument(doc) {
|
332 | if (doc.rawSDL) {
|
333 | return hashContent(doc.rawSDL);
|
334 | }
|
335 | if (doc.document) {
|
336 | return hashContent((0, graphql_1.print)(doc.document));
|
337 | }
|
338 | return null;
|
339 | }
|
340 | function addHashToDocumentFiles(documentFilesPromise) {
|
341 | return documentFilesPromise.then(documentFiles => documentFiles.map(doc => {
|
342 | doc.hash = hashDocument(doc);
|
343 | return doc;
|
344 | }));
|
345 | }
|
346 | function shouldEmitLegacyCommonJSImports(config, outputPath) {
|
347 | const globalValue = config.emitLegacyCommonJSImports === undefined ? true : !!config.emitLegacyCommonJSImports;
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 | return globalValue;
|
357 | }
|
358 | exports.shouldEmitLegacyCommonJSImports = shouldEmitLegacyCommonJSImports;
|