graphqldoc
Version:
Generate GraphQL docs from schema.
189 lines (188 loc) • 10.4 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const fs = require("fs");
const glob = require("glob");
const deepmerge = require("deepmerge");
const mustache_1 = require("mustache");
const utility_1 = require("./utility");
const fs_1 = require("./utility/fs");
const schema_loader_1 = require("./schema-loader");
const command_1 = require("@2fd/command");
const graphqldocPackageJson = require(path.resolve(__dirname, '../package.json'));
class GraphQLDocumentor extends command_1.Command {
constructor() {
super(...arguments);
this.description = graphqldocPackageJson.description + ' v' + graphqldocPackageJson.version;
this.params = new command_1.NoParams();
this.flags = [
new command_1.ValueFlag('configFile', ['-c', '--config'], 'Configuration file [./package.json].', String, './package.json'),
new command_1.ValueFlag('endpoint', ['-e', '--endpoint'], 'Graphql http endpoint ["https://domain.com/graphql"].'),
new command_1.ListValueFlag('headers', ['-x', '--header'], 'HTTP header for request (use with --endpoint). ["Authorization: Token cb8795e7"].'),
new command_1.ListValueFlag('queries', ['-q', '--query'], 'HTTP querystring for request (use with --endpoint) ["token=cb8795e7"].'),
new command_1.ValueFlag('schemaFile', ['-s', '--schema', '--schema-file'], 'Graphql Schema file ["./schema.json"].'),
new command_1.ListValueFlag('plugins', ['-p', '--plugin'], 'Use plugins [default=graphqldoc/plugins/default].'),
new command_1.ValueFlag('template', ['-t', '--template'], 'Use template [default=graphqldoc/template/slds].'),
new command_1.ValueFlag('output', ['-o', '--output'], 'Output directory.'),
new command_1.ValueFlag('data', ['-d', '--data'], 'Inject custom data.', JSON.parse, {}),
new command_1.ValueFlag('baseUrl', ['-b', '--base-url'], 'Base url for templates.'),
new command_1.BooleanFlag('force', ['-f', '--force'], 'Delete outputDirectory if exists.'),
new command_1.BooleanFlag('verbose', ['-v', '--verbose'], 'Output more information.'),
new command_1.BooleanFlag('version', ['-V', '--version'], 'Show graphqldoc version.'),
];
}
action(input, out) {
return __awaiter(this, void 0, void 0, function* () {
const output = new utility_1.Output(out, input.flags);
try {
if (input.flags.version)
return output.out.log('graphqldoc v%s', graphqldocPackageJson.version);
// Load project info
const projectPackageJSON = yield this.getProjectPackage(input);
// Load Schema
const schema = yield this.getSchema(projectPackageJSON);
// Load plugins
const plugins = this.getPluginInstances(projectPackageJSON.graphqldoc.plugins, schema, projectPackageJSON, graphqldocPackageJson);
projectPackageJSON.graphqldoc.plugins
.forEach(plugin => output.info('use plugin', plugin));
// Collect assets
const assets = yield utility_1.Plugin.collectAssets(plugins);
assets
.forEach(asset => output.info('use asset', path.relative(process.cwd(), asset)));
// Ensure Output directory
output.info('output directory', path.relative(process.cwd(), projectPackageJSON.graphqldoc.output));
yield this.ensureOutputDirectory(projectPackageJSON.graphqldoc.output, projectPackageJSON.graphqldoc.force);
// Create Output directory
yield fs_1.createBuildDirectory(projectPackageJSON.graphqldoc.output, projectPackageJSON.graphqldoc.template, assets);
// Collect partials
const partials = yield this.getTemplatePartials(projectPackageJSON.graphqldoc.template);
// Render index.html
output.info('render', 'index');
yield this.renderFile(projectPackageJSON, partials, plugins);
// Render types
const renderTypes = []
.concat(schema.types || [])
.concat(schema.directives || [])
.map((type) => {
output.info('render', type.name);
return this.renderFile(projectPackageJSON, partials, plugins, type);
});
const files = yield Promise.all(renderTypes);
output.ok('complete', String(files.length + 1 /* index.html */) + ' files generated.');
}
catch (err) {
output.error(err);
}
});
}
ensureOutputDirectory(dir, force) {
return __awaiter(this, void 0, void 0, function* () {
try {
const stats = fs.statSync(dir);
if (!stats.isDirectory())
return Promise.reject(new Error('Unexpected output: ' + dir + ' is not a directory.'));
if (!force)
return Promise.reject(new Error(dir + ' already exists (delete it or use the --force flag)'));
return fs_1.removeBuildDirectory(dir);
}
catch (err) {
return err.code === 'ENOENT' ?
Promise.resolve() :
Promise.reject(err);
}
});
}
getProjectPackage(input) {
let packageJSON;
try {
packageJSON = require(path.resolve(input.flags.configFile));
}
catch (err) {
packageJSON = {};
}
packageJSON.graphqldoc = deepmerge(input.flags, packageJSON.graphqldoc || {});
if (packageJSON.graphqldoc.data) {
const data = packageJSON.graphqldoc.data;
packageJSON.graphqldoc = deepmerge(data, packageJSON.graphqldoc);
}
if (packageJSON.graphqldoc.plugins.length === 0)
packageJSON.graphqldoc.plugins = ['graphqldoc/plugins/default'];
packageJSON.graphqldoc.baseUrl = packageJSON.graphqldoc.baseUrl || './';
packageJSON.graphqldoc.template = fs_1.resolve(packageJSON.graphqldoc.template || 'graphqldoc/template/slds');
packageJSON.graphqldoc.output = path.resolve(packageJSON.graphqldoc.output);
packageJSON.graphqldoc.version = graphqldocPackageJson.version;
if (!packageJSON.graphqldoc.output)
return Promise.reject(new Error('Flag output (-o, --output) is required'));
return Promise.resolve(packageJSON);
}
getPluginInstances(paths, schema, projectPackageJSON, graphqldocPackageJson) {
return paths
.map(path => {
const absolutePaths = fs_1.resolve(path);
const Plugin = require(absolutePaths).default;
return typeof Plugin === 'function' ?
// plugins as contructor
new Plugin(schema, projectPackageJSON, graphqldocPackageJson) :
// plugins plain object
Plugin;
});
}
getTemplatePartials(templateDir) {
return __awaiter(this, void 0, void 0, function* () {
const files = yield new Promise((resolve, reject) => glob('**/*.mustache', { cwd: templateDir }, (err, files) => err ? reject(err) : resolve(files)));
const partials = {};
yield Promise.all(files.map(file => {
const name = path.basename(file, '.mustache');
return fs_1.readFile(path.resolve(templateDir, file), 'utf8')
.then(content => partials[name] = content);
}));
if (!partials.index)
throw new Error('The index partial is missing (file ' +
path.resolve(templateDir, 'index.mustache') + ' not found).');
return partials;
});
}
getSchema(projectPackage) {
return __awaiter(this, void 0, void 0, function* () {
if (projectPackage.graphqldoc.schemaFile) {
const schemaFileExt = path.extname(projectPackage.graphqldoc.schemaFile);
switch (schemaFileExt) {
case '.json':
return schema_loader_1.jsonSchemaLoader(projectPackage.graphqldoc);
case '.gql':
case '.gqls':
case '.graphqls':
case '.graphql':
return schema_loader_1.idlSchemaLoader(projectPackage.graphqldoc);
case '.js':
return schema_loader_1.jsSchemaLoader(projectPackage.graphqldoc);
default:
return Promise.reject(new Error('Unexpected schema extension name: ' + schemaFileExt));
}
}
else if (projectPackage.graphqldoc.endpoint) {
return schema_loader_1.httpSchemaLoader(projectPackage.graphqldoc);
}
else {
return Promise.reject(new Error('Endpoint (--endpoint, -e) or Schema File (--schema, -s) are require.'));
}
});
}
renderFile(projectPackageJSON, partials, plugins, type) {
return __awaiter(this, void 0, void 0, function* () {
const templateData = yield utility_1.createData(projectPackageJSON, graphqldocPackageJson, plugins, type);
const file = type ? utility_1.getFilenameOf(type) : 'index.html';
const filepath = path.resolve(projectPackageJSON.graphqldoc.output, file);
return yield fs_1.writeFile(filepath, mustache_1.render(partials.index, templateData, partials));
});
}
}
exports.GraphQLDocumentor = GraphQLDocumentor;