nexus
Version:
Scalable, strongly typed GraphQL schema development
160 lines • 7.29 kB
JavaScript
import { __awaiter } from "tslib";
import { lexicographicSortSchema, printSchema } from 'graphql';
import * as path from 'path';
import { SDL_HEADER, TYPEGEN_HEADER } from './lang';
import { typegenAutoConfig } from './typegenAutoConfig';
import { typegenFormatPrettier } from './typegenFormatPrettier';
import { TypegenPrinter } from './typegenPrinter';
/**
* Passed into the SchemaBuilder, this keeps track of any necessary field / type metadata we need to be aware
* of when building the generated types and/or SDL artifact, including but not limited to:
*/
export class TypegenMetadata {
constructor(config) {
this.config = config;
}
/** Generates the artifacts of the build based on what we know about the schema and how it was defined. */
generateArtifacts(schema) {
return __awaiter(this, void 0, void 0, function* () {
const sortedSchema = this.sortSchema(schema);
const { typegen } = this.config.outputs;
if (this.config.outputs.schema || typegen) {
const { schemaTypes, tsTypes, globalTypes } = yield this.generateArtifactContents(sortedSchema, typegen);
if (this.config.outputs.schema) {
yield this.writeFile('schema', schemaTypes, this.config.outputs.schema);
}
if (typegen) {
if (typeof typegen === 'string') {
yield this.writeFile('types', tsTypes, typegen);
}
else {
yield this.writeFile('types', tsTypes, typegen.outputPath);
if (typeof typegen.globalsPath === 'string') {
yield this.writeFile('types', globalTypes !== null && globalTypes !== void 0 ? globalTypes : '', typegen.globalsPath);
}
}
}
}
});
}
generateArtifactContents(schema, typegen) {
return __awaiter(this, void 0, void 0, function* () {
const result = {
schemaTypes: this.generateSchemaFile(schema),
tsTypes: '',
globalTypes: null,
};
if (!typegen) {
return result;
}
if (typeof typegen === 'string') {
result.tsTypes = yield this.generateTypesFile(schema, typegen);
}
else {
const generateResult = yield this.generateConfiguredTypes(schema, typegen);
result.tsTypes = generateResult.tsTypes;
result.globalTypes = generateResult.globalTypes;
}
return result;
});
}
sortSchema(schema) {
let sortedSchema = schema;
if (typeof lexicographicSortSchema !== 'undefined') {
sortedSchema = lexicographicSortSchema(schema);
}
return sortedSchema;
}
writeFile(type, output, filePath) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof filePath !== 'string' || !path.isAbsolute(filePath)) {
return Promise.reject(new Error(`Expected an absolute path to output the Nexus ${type}, saw ${filePath}`));
}
const fs = require('fs');
const util = require('util');
const [readFile, writeFile, removeFile, mkdir] = [
util.promisify(fs.readFile),
util.promisify(fs.writeFile),
util.promisify(fs.unlink),
util.promisify(fs.mkdir),
];
let formatTypegen = null;
if (typeof this.config.formatTypegen === 'function') {
formatTypegen = this.config.formatTypegen;
}
else if (this.config.prettierConfig) {
formatTypegen = typegenFormatPrettier(this.config.prettierConfig);
}
const content = typeof formatTypegen === 'function' ? yield formatTypegen(output, type) : output;
const [toSave, existing] = yield Promise.all([content, readFile(filePath, 'utf8').catch(() => '')]);
if (toSave !== existing) {
const dirPath = path.dirname(filePath);
try {
yield mkdir(dirPath, { recursive: true });
}
catch (e) {
if (e.code !== 'EEXIST') {
throw e;
}
}
// VSCode reacts to file changes better if a file is first deleted,
// apparently. See issue motivating this logic here:
// https://github.com/graphql-nexus/schema/issues/247.
try {
yield removeFile(filePath);
}
catch (e) {
/* istanbul ignore next */
if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') {
throw e;
}
}
return writeFile(filePath, toSave);
}
});
}
/** Generates the schema, adding any directives as necessary */
generateSchemaFile(schema) {
let printedSchema = this.config.customPrintSchemaFn
? this.config.customPrintSchemaFn(schema)
: printSchema(schema);
return [SDL_HEADER, printedSchema].join('\n\n');
}
/** Generates the type definitions */
generateTypesFile(schema, typegenPath) {
return __awaiter(this, void 0, void 0, function* () {
const typegenInfo = yield this.getTypegenInfo(schema, typegenPath);
return new TypegenPrinter(schema, Object.assign(Object.assign({ declareInputs: false }, typegenInfo), { typegenPath })).print();
});
}
/** Generates the type definitions */
generateConfiguredTypes(schema, typegen) {
return __awaiter(this, void 0, void 0, function* () {
const { outputPath: typegenPath, globalsPath, globalsHeaders, declareInputs = false } = typegen;
const typegenInfo = yield this.getTypegenInfo(schema, typegenPath);
return new TypegenPrinter(schema, Object.assign(Object.assign({}, typegenInfo), { typegenPath,
globalsPath,
globalsHeaders,
declareInputs })).printConfigured();
});
}
getTypegenInfo(schema, typegenPath) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if ('typegenConfig' in this.config) {
throw new Error('Error: typegenConfig was removed from the API. Please open an issue if you were using it.');
}
if (this.config.sourceTypes) {
return typegenAutoConfig(this.config.sourceTypes, this.config.contextType)(schema, typegenPath || ((_a = this.config.outputs.typegen) === null || _a === void 0 ? void 0 : _a.outputPath) || '');
}
return {
nexusSchemaImportId: this.config.nexusSchemaImportId,
headers: [TYPEGEN_HEADER],
imports: [],
contextTypeImport: this.config.contextType,
sourceTypeMap: {},
};
});
}
}
//# sourceMappingURL=typegenMetadata.js.map