UNPKG

@graphql-codegen/cli

Version:

<p align="center"> <img src="https://github.com/dotansimha/graphql-code-generator/blob/master/logo.png?raw=true" /> </p>

361 lines (358 loc) • 13.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shouldEmitLegacyCommonJSImports = exports.ensureContext = exports.CodegenContext = exports.updateContextWithCliFlags = exports.createContext = exports.parseArgv = exports.buildOptions = exports.loadContext = exports.loadCodegenConfig = exports.generateSearchPlaces = void 0; const tslib_1 = require("tslib"); const cosmiconfig_1 = require("cosmiconfig"); const cosmiconfig_typescript_loader_1 = require("cosmiconfig-typescript-loader"); const path_1 = require("path"); const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers"); const string_env_interpolation_1 = require("string-env-interpolation"); const yargs_1 = tslib_1.__importDefault(require("yargs")); const graphql_config_js_1 = require("./graphql-config.js"); const load_js_1 = require("./load.js"); const graphql_1 = require("graphql"); const yaml_1 = tslib_1.__importDefault(require("yaml")); const module_1 = require("module"); const fs_1 = require("fs"); const crypto_1 = require("crypto"); const { lstat } = fs_1.promises; // #8437: conflict with `graphql-config` also using TypeScriptLoader(), causing a double `ts-node` register. const tsLoader = (0, cosmiconfig_typescript_loader_1.TypeScriptLoader)({ transpileOnly: true }); function generateSearchPlaces(moduleName) { const extensions = ['json', 'yaml', 'yml', 'js', 'ts', 'config.js']; // gives codegen.json... const regular = extensions.map(ext => `${moduleName}.${ext}`); // gives .codegenrc.json... but no .codegenrc.config.js const dot = extensions.filter(ext => ext !== 'config.js').map(ext => `.${moduleName}rc.${ext}`); return [...regular.concat(dot), 'package.json']; } exports.generateSearchPlaces = generateSearchPlaces; function customLoader(ext) { function loader(filepath, content) { if (typeof process !== 'undefined' && 'env' in process) { content = (0, string_env_interpolation_1.env)(content); } if (ext === 'json') { return cosmiconfig_1.defaultLoaders['.json'](filepath, content); } if (ext === 'yaml') { try { const result = yaml_1.default.parse(content, { prettyErrors: true, merge: true }); return result; } catch (error) { error.message = `YAML Error in ${filepath}:\n${error.message}`; throw error; } } if (ext === 'js') { return cosmiconfig_1.defaultLoaders['.js'](filepath, content); } if (ext === 'ts') { return tsLoader(filepath, content); } } return loader; } async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) { configFilePath = configFilePath || process.cwd(); moduleName = moduleName || 'codegen'; packageProp = packageProp || moduleName; const cosmi = (0, cosmiconfig_1.cosmiconfig)(moduleName, { searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []), packageProp, loaders: { '.json': customLoader('json'), '.yaml': customLoader('yaml'), '.yml': customLoader('yaml'), '.js': customLoader('js'), '.ts': customLoader('ts'), noExt: customLoader('yaml'), ...customLoaders, }, }); const pathStats = await lstat(configFilePath); return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath); } exports.loadCodegenConfig = loadCodegenConfig; async function loadContext(configFilePath) { const graphqlConfig = await (0, graphql_config_js_1.findAndLoadGraphQLConfig)(configFilePath); if (graphqlConfig) { return new CodegenContext({ graphqlConfig, }); } const result = await loadCodegenConfig({ configFilePath }); if (!result) { if (configFilePath) { throw new Error(` Config ${configFilePath} does not exist. $ graphql-codegen --config ${configFilePath} Please make sure the --config points to a correct file. `); } throw new Error(`Unable to find Codegen config file! \n Please make sure that you have a configuration file under the current directory! `); } if (result.isEmpty) { throw new Error(`Found Codegen config file but it was empty! \n Please make sure that you have a valid configuration file under the current directory! `); } return new CodegenContext({ filepath: result.filepath, config: result.config, }); } exports.loadContext = loadContext; function getCustomConfigPath(cliFlags) { const configFile = cliFlags.config; return configFile ? (0, path_1.resolve)(process.cwd(), configFile) : null; } function buildOptions() { return { c: { alias: 'config', type: 'string', describe: 'Path to GraphQL codegen YAML config file, defaults to "codegen.yml" on the current directory', }, w: { alias: 'watch', describe: 'Watch for changes and execute generation automatically. You can also specify a glob expression for custom watch list.', coerce: (watch) => { if (watch === 'false') { return false; } if (typeof watch === 'string' || Array.isArray(watch)) { return watch; } return !!watch; }, }, r: { alias: 'require', describe: 'Loads specific require.extensions before running the codegen and reading the configuration', type: 'array', default: [], }, o: { alias: 'overwrite', describe: 'Overwrites existing files', type: 'boolean', }, s: { alias: 'silent', describe: 'Suppresses printing errors', type: 'boolean', }, e: { alias: 'errors-only', describe: 'Only print errors', type: 'boolean', }, profile: { describe: 'Use profiler to measure performance', type: 'boolean', }, p: { alias: 'project', describe: 'Name of a project in GraphQL Config', type: 'string', }, v: { alias: 'verbose', describe: 'output more detailed information about performed tasks', type: 'boolean', default: false, }, d: { alias: 'debug', describe: 'Print debug logs to stdout', type: 'boolean', default: false, }, }; } exports.buildOptions = buildOptions; function parseArgv(argv = process.argv) { return (0, yargs_1.default)(argv).options(buildOptions()).parse(argv); } exports.parseArgv = parseArgv; async function createContext(cliFlags = parseArgv(process.argv)) { if (cliFlags.require && cliFlags.require.length > 0) { const relativeRequire = (0, module_1.createRequire)(process.cwd()); await Promise.all(cliFlags.require.map(mod => Promise.resolve().then(() => tslib_1.__importStar(require(relativeRequire.resolve(mod, { paths: [process.cwd()], })))))); } const customConfigPath = getCustomConfigPath(cliFlags); const context = await loadContext(customConfigPath); updateContextWithCliFlags(context, cliFlags); return context; } exports.createContext = createContext; function updateContextWithCliFlags(context, cliFlags) { const config = { configFilePath: context.filepath, }; if (cliFlags.watch !== undefined) { config.watch = cliFlags.watch; } if (cliFlags.overwrite === true) { config.overwrite = cliFlags.overwrite; } if (cliFlags.silent === true) { config.silent = cliFlags.silent; } if (cliFlags.verbose === true || process.env.VERBOSE) { config.verbose = true; } if (cliFlags.debug === true || process.env.DEBUG) { config.debug = true; } if (cliFlags.errorsOnly === true) { config.errorsOnly = cliFlags.errorsOnly; } if (cliFlags['ignore-no-documents'] !== undefined) { // for some reason parsed value is `'false'` string so this ensure it always is a boolean. config.ignoreNoDocuments = cliFlags['ignore-no-documents'] === true; } if (cliFlags['emit-legacy-common-js-imports'] !== undefined) { // for some reason parsed value is `'false'` string so this ensure it always is a boolean. config.emitLegacyCommonJSImports = cliFlags['emit-legacy-common-js-imports'] === true; } if (cliFlags.project) { context.useProject(cliFlags.project); } if (cliFlags.profile === true) { context.useProfiler(); } if (cliFlags.check === true) { context.enableCheckMode(); } context.updateConfig(config); } exports.updateContextWithCliFlags = updateContextWithCliFlags; class CodegenContext { constructor({ config, graphqlConfig, filepath, }) { this._checkMode = false; this._pluginContext = {}; this.checkModeStaleFiles = []; this._config = config; this._graphqlConfig = graphqlConfig; this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath; this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd(); this.profiler = (0, plugin_helpers_1.createNoopProfiler)(); } useProject(name) { this._project = name; } getConfig(extraConfig) { if (!this.config) { if (this._graphqlConfig) { const project = this._graphqlConfig.getProject(this._project); this.config = { ...project.extension('codegen'), schema: project.schema, documents: project.documents, pluginContext: this._pluginContext, }; } else { this.config = { ...this._config, pluginContext: this._pluginContext }; } } return { ...extraConfig, ...this.config, }; } updateConfig(config) { this.config = { ...this.getConfig(), ...config, }; } enableCheckMode() { this._checkMode = true; } get checkMode() { return this._checkMode; } useProfiler() { this.profiler = (0, plugin_helpers_1.createProfiler)(); const now = new Date(); // 2011-10-05T14:48:00.000Z const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00 const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800 this.profilerOutput = `codegen-${datetimeNormalized}.json`; } getPluginContext() { return this._pluginContext; } async loadSchema(pointer) { const config = this.getConfig(load_js_1.defaultSchemaLoadOptions); if (this._graphqlConfig) { // TODO: SchemaWithLoader won't work here return addHashToSchema(this._graphqlConfig.getProject(this._project).loadSchema(pointer, 'GraphQLSchema', config)); } return addHashToSchema((0, load_js_1.loadSchema)(pointer, config)); } async loadDocuments(pointer) { const config = this.getConfig(load_js_1.defaultDocumentsLoadOptions); if (this._graphqlConfig) { // TODO: pointer won't work here return addHashToDocumentFiles(this._graphqlConfig.getProject(this._project).loadDocuments(pointer, config)); } return addHashToDocumentFiles((0, load_js_1.loadDocuments)(pointer, config)); } } exports.CodegenContext = CodegenContext; function ensureContext(input) { return input instanceof CodegenContext ? input : new CodegenContext({ config: input }); } exports.ensureContext = ensureContext; function hashContent(content) { return (0, crypto_1.createHash)('sha256').update(content).digest('hex'); } function hashSchema(schema) { return hashContent((0, graphql_1.print)((0, plugin_helpers_1.getCachedDocumentNodeFromSchema)(schema))); } function addHashToSchema(schemaPromise) { return schemaPromise.then(schema => { // It's consumed later on. The general purpose is to use it for caching. if (!schema.extensions) { schema.extensions = {}; } schema.extensions['hash'] = hashSchema(schema); return schema; }); } function hashDocument(doc) { if (doc.rawSDL) { return hashContent(doc.rawSDL); } if (doc.document) { return hashContent((0, graphql_1.print)(doc.document)); } return null; } function addHashToDocumentFiles(documentFilesPromise) { return documentFilesPromise.then(documentFiles => documentFiles.map(doc => { doc.hash = hashDocument(doc); return doc; })); } function shouldEmitLegacyCommonJSImports(config, outputPath) { const globalValue = config.emitLegacyCommonJSImports === undefined ? true : !!config.emitLegacyCommonJSImports; // const outputConfig = config.generates[outputPath]; // if (!outputConfig) { // debugLog(`Couldn't find a config of ${outputPath}`); // return globalValue; // } // if (isConfiguredOutput(outputConfig) && typeof outputConfig.emitLegacyCommonJSImports === 'boolean') { // return outputConfig.emitLegacyCommonJSImports; // } return globalValue; } exports.shouldEmitLegacyCommonJSImports = shouldEmitLegacyCommonJSImports;