@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.9 kB
JavaScript
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;
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') {
// #8437: conflict with `graphql-config` also using TypeScriptLoader(), causing a double `ts-node` register.
const tsLoader = (0, cosmiconfig_typescript_loader_1.TypeScriptLoader)({ transpileOnly: true });
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;
;