spectaql
Version:
A powerful library for autogenerating static GraphQL API documentation
577 lines (396 loc) • 14.8 kB
JavaScript
"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.buildSchemas = exports.augmentData = void 0;Object.defineProperty(exports, "generateDirectiveSdl", { enumerable: true, get: function () {return _directive.generateDirectiveSdl;} });Object.defineProperty(exports, "generateOptionsSdl", { enumerable: true, get: function () {return _directive.generateOptionsSdl;} });Object.defineProperty(exports, "generateSpectaqlSdl", { enumerable: true, get: function () {return _directive.generateSpectaqlSdl;} });exports.introspectionOptionsToMicrofiberOptions = introspectionOptionsToMicrofiberOptions;exports.loadData = void 0;Object.defineProperty(exports, "parseCliOptions", { enumerable: true, get: function () {return _cli.default;} });exports.resolveOptions = resolveOptions;exports.run = void 0;var _path = _interopRequireDefault(require("path"));
var _lodash = _interopRequireDefault(require("lodash"));
var _grunt = _interopRequireDefault(require("grunt"));
var _package = _interopRequireDefault(require("../package.json"));
var _loadYaml = _interopRequireDefault(require("./lib/loadYaml"));
var _utils = require("./spectaql/utils");
var _directive = require("./spectaql/directive");
var _cli = _interopRequireDefault(require("./cli"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}
const defaultAppDir = (0, _utils.normalizePathFromRoot)('dist');
let spectaql = require(_path.default.resolve(defaultAppDir, 'spectaql/index'));
let gruntConfigFn;
const DEFAULT_THEM_NAME = 'default';
const defaultThemeDir = (0, _utils.normalizePathFromRoot)('dist/themes/default');
const BASIC_THEME_NAME = 'basic';
const basicThemeDir = (0, _utils.normalizePathFromRoot)('dist/themes/basic');
const SPECTAQL_THEME_NAME = 'spectaql';
const spectaqlThemeDir = (0, _utils.normalizePathFromRoot)('dist/themes/spectaql');
const defaults = Object.freeze({
quiet: false,
port: 4400,
portLive: 4401,
targetDir: _path.default.resolve(process.cwd(), 'public'),
targetFile: 'index.html',
appDir: defaultAppDir,
gruntConfigFile: (0, _utils.normalizePathFromRoot)('dist/lib/gruntConfig.js'),
themeDir: defaultThemeDir,
defaultThemeDir,
cacheDir: (0, _utils.tmpFolder)(),
specData: {}
});
const spectaqlOptionDefaults = Object.freeze({
oneFile: false,
embeddable: false,
errorOnInterpolationReferenceNotFound: true,
displayAllServers: false,
resolveWithOutput: true,
embedLogo: false,
embedFavicon: false
});
const spectaqlDirectiveDefault = Object.freeze({
enable: true,
directiveName: 'spectaql',
optionsTypeName: 'SpectaQLOption',
onlyAddIfMissing: true
});
const introspectionOptionDefaults = Object.freeze({
dynamicExamplesProcessingModule: false,
spectaqlDirective: Object.assign({}, spectaqlDirectiveDefault),
removeTrailingPeriodFromDescriptions: false,
inputValueDeprecation: false,
fieldExpansionDepth: 1,
metadatasReadPath: 'documentation',
metadatasWritePath: 'documentation',
metadatasPath: 'documentation',
metadatas: true,
queriesDocumentedDefault: true,
queryDocumentedDefault: true,
queryArgDocumentedDefault: true,
hideQueriesWithUndocumentedReturnType: true,
mutationsDocumentedDefault: true,
mutationDocumentedDefault: true,
mutationArgDocumentedDefault: true,
hideMutationsWithUndocumentedReturnType: true,
subscriptionsDocumentedDefault: true,
subscriptionDocumentedDefault: true,
subscriptionArgDocumentedDefault: true,
hideSubscriptionsWithUndocumentedReturnType: true,
hideUnusedTypes: true,
objectsDocumentedDefault: true,
objectDocumentedDefault: true,
inputsDocumentedDefault: true,
inputDocumentedDefault: true,
enumsDocumentedDefault: true,
enumDocumentedDefault: true,
unionsDocumentedDefault: true,
unionDocumentedDefault: true,
hideUnionTypesOfUndocumentedType: true,
fieldDocumentedDefault: true,
hideFieldsOfUndocumentedType: true,
inputFieldDocumentedDefault: true,
hideInputFieldsOfUndocumentedType: true,
argDocumentedDefault: true,
hideArgsOfUndocumentedType: true
});
const extensionsOptionDefaults = Object.freeze({
graphqlScalarExamples: true
});
const introspectionOptionsMap = Object.freeze({
schemaFile: 'schemaFile',
introspectionUrl: 'url',
introspectionFile: 'introspectionFile',
introspectionMetadataFile: 'metadataFile',
dynamicExamplesProcessingModule: 'dynamicExamplesProcessingModule',
headers: 'headers'
});
const introspectionOptionsToNormalize = Object.values(
introspectionOptionsMap
).filter((key) => !['url', 'headers'].includes(key));
function resolvePaths(
options,
keys = [
'targetDir',
'appDir',
'logoFile',
'faviconFile',
'specFile',
'gruntConfigFile'])
{
keys.forEach((key) => {
const pth = options[key];
if (typeof pth === 'string') {
options[key] = (0, _utils.normalizePathFromCwd)(pth);
}
});
}
function introspectionOptionsToMicrofiberOptions(introspectionOptions) {
const {
hideUnusedTypes: removeUnusedTypes,
hideFieldsOfUndocumentedType: removeFieldsWithMissingTypes,
hideArgsOfUndocumentedType: removeArgsWithMissingTypes,
hideInputFieldsOfUndocumentedType: removeInputFieldsWithMissingTypes,
hideUnionTypesOfUndocumentedType: removePossibleTypesOfMissingTypes,
hideQueriesWithUndocumentedReturnType: removeQueriesWithMissingTypes,
hideMutationsWithUndocumentedReturnType: removeMutationsWithMissingTypes,
hideSubscriptionsWithUndocumentedReturnType:
removeSubscriptionsWithMissingTypes
} = Object.assign({}, introspectionOptionDefaults, introspectionOptions);
return {
removeUnusedTypes,
removeFieldsWithMissingTypes,
removeArgsWithMissingTypes,
removeInputFieldsWithMissingTypes,
removePossibleTypesOfMissingTypes,
removeQueriesWithMissingTypes,
removeMutationsWithMissingTypes,
removeSubscriptionsWithMissingTypes
};
}
function resolveOptions(cliOptions) {
let opts = _lodash.default.extend({}, cliOptions);
resolvePaths(opts);
const introspectionCliOptions = Object.entries(
introspectionOptionsMap
).reduce((acc, [fromKey, toKey]) => {
if (typeof opts[fromKey] !== 'undefined') {
acc[toKey] = opts[fromKey];
}
return acc;
}, {});
if (opts.specFile) {
const spec = opts.specData = (0, _loadYaml.default)(opts.specFile);
const {
spectaql: spectaqlYaml
} = spec;
if (spectaqlYaml) {
opts = _lodash.default.defaults({}, opts, spectaqlYaml);
}
}
if (!opts.themeDir || opts.themeDir === DEFAULT_THEM_NAME) {
opts.themeDir = defaultThemeDir;
} else if (opts.themeDir === BASIC_THEME_NAME) {
opts.themeDir = basicThemeDir;
} else if (opts.themeDir === SPECTAQL_THEME_NAME) {
opts.themeDir = spectaqlThemeDir;
} else {
opts.themeDir = (0, _utils.normalizePathFromCwd)(opts.themeDir);
}
opts = _lodash.default.defaults({}, opts, defaults);
resolvePaths(opts);
opts.specData.introspection = _lodash.default.defaults(
{},
introspectionCliOptions,
opts.specData.introspection,
introspectionOptionDefaults
);
opts.specData.introspection.microfiberOptions =
introspectionOptionsToMicrofiberOptions(opts.specData.introspection);
opts.specData.introspection.spectaqlDirective = _lodash.default.defaults(
opts.specData.introspection.spectaqlDirective,
spectaqlDirectiveDefault
);
opts.specData.extensions = _lodash.default.defaults(
{},
opts.specData.extensions,
extensionsOptionDefaults
);
resolvePaths(opts.specData.introspection, introspectionOptionsToNormalize);
opts = _lodash.default.defaults({}, opts, spectaqlOptionDefaults);
if (!opts.targetDir || opts.targetDir.endsWith('/null')) {
opts.targetDir = (0, _utils.tmpFolder)();
}
if (opts.logoFile) {
if (opts.embedLogo) {
opts.logoData = (0, _utils.readFileAsBase64)(opts.logoFile);
} else {
opts.logoFileTargetName = opts.preserveLogoName ?
_path.default.basename(opts.logoFile) :
`logo${_path.default.extname(opts.logoFile)}`;
opts.logoImageName = _path.default.basename(opts.logoFileTargetName);
}
} else if (opts.logoUrl) {
}
if (opts.faviconFile) {
if (opts.embedFavicon) {
opts.faviconData = (0, _utils.readFileAsBase64)(opts.faviconFile);
} else {
opts.faviconFileTargetName = opts.preserveFaviconName ?
_path.default.basename(opts.faviconFile) :
`favicon${_path.default.extname(opts.faviconFile)}`;
opts.faviconImageName = _path.default.basename(opts.faviconFileTargetName);
}
} else if (opts.faviconUrl) {
}
const pathToSpectaql = _path.default.resolve(opts.appDir, 'spectaql/index');
if (pathToSpectaql !== defaultAppDir) {
spectaql = require(pathToSpectaql);
}
gruntConfigFn = require(opts.gruntConfigFile);
return opts;
}
const run = async function (cliOptions = {}) {
const opts = resolveOptions(cliOptions);
const gruntConfig = gruntConfigFn(_grunt.default, opts, await loadData(opts));
_grunt.default.initConfig(_lodash.default.merge({ pkg: _package.default }, gruntConfig));
if (opts.quiet) {
_grunt.default.log.writeln = function () {};
_grunt.default.log.write = function () {};
_grunt.default.log.header = function () {};
_grunt.default.log.ok = function () {};
}
const cwd = process.cwd();
const exists = _grunt.default.file.exists(
_path.default.join(
_path.default.resolve('node_modules'),
'grunt-contrib-concat',
'package.json'
)
);
if (!exists) process.chdir(_utils.pathToRoot);
_grunt.default.loadNpmTasks('grunt-contrib-concat');
_grunt.default.loadNpmTasks('grunt-contrib-uglify');
_grunt.default.loadNpmTasks('grunt-contrib-cssmin');
_grunt.default.loadNpmTasks('grunt-contrib-watch');
_grunt.default.loadNpmTasks('grunt-contrib-clean');
_grunt.default.loadNpmTasks('grunt-contrib-copy');
_grunt.default.loadNpmTasks('grunt-contrib-connect');
_grunt.default.loadNpmTasks('grunt-sass');
_grunt.default.loadTasks(
(0, _utils.normalizePathFromRoot)('vendor/grunt-compile-handlebars/tasks')
);
_grunt.default.loadTasks((0, _utils.normalizePathFromRoot)('vendor/grunt-prettify/tasks'));
_grunt.default.loadTasks((0, _utils.normalizePathFromRoot)('vendor/grunt-embed/tasks'));
process.chdir(cwd);
const pathToHtmlFile = opts.cacheDir + '/' + opts.targetFile;
_grunt.default.registerTask(
'predentation',
'Remove indentation from generated <pre> tags.',
function () {
let html = (0, _utils.readTextFile)(pathToHtmlFile);
html = html.replace(
/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gim,
function (x, _y) {
const lines = x.split('\n');
let level = null;
if (lines) {
lines.forEach(function (line) {
if (line[0] === '<') return;
var wsp = line.search(/\S/);
level =
level === null || wsp < line.length && wsp < level ?
wsp :
level;
});
const regex = new RegExp('^\\s{' + level + '}');
lines.forEach(function (line, index, lines) {
lines[index] = line.replace(regex, '');
});
}
return lines.join('\n');
}
);
(0, _utils.writeTextFile)(pathToHtmlFile, html);
}
);
const themeCopyTasks = ['copy:default-theme-to-cache'];
if (opts.themeDir !== defaultThemeDir) {
themeCopyTasks.push('copy:overlay-custom-theme-to-cache');
}
_grunt.default.registerTask('copy-theme-stuff', themeCopyTasks);
_grunt.default.registerTask('clean-things', [
'clean:css',
'clean:js',
'clean:html',
'clean:views',
'clean:helpers']
);
const stylesheetsTasks = [];
if (!opts.disableCss) {
stylesheetsTasks.push('sass:main', 'concat:css', 'cssmin:css');
}
_grunt.default.registerTask('stylesheets', stylesheetsTasks);
_grunt.default.registerTask('javascripts', ['concat:js', 'uglify']);
_grunt.default.registerTask('templates', [
'compile-handlebars',
'predentation',
'prettify']
);
const defaultTasks = [];
_grunt.default.registerTask('server', ['connect']);
_grunt.default.registerTask('develop', ['server', 'watch']);
_grunt.default.event.on('watch', async function () {
try {
_grunt.default.config.set(
'compile-handlebars.compile.templateData',
await loadData(opts)
);
} catch (e) {
console.error(e);
_grunt.default.fatal(e);
}
});
const donePromise = new Promise(function (resolve, reject) {
_grunt.default.task.options({
error: function (e) {
if (!opts.quiet) {
console.warn('Task error:', e);
}
reject(e);
},
done: function () {
if (!opts.quiet) {
console.log('All tasks complete');
}
let result;
if (opts.resolveWithOutput) {
result = {
html: (0, _utils.readTextFile)(pathToHtmlFile)
};
}
resolve(result);
}
});
});
const copiesToTarget = ['html-to-target'];
let doDevelop = false;
if (opts.startServer) {
defaultTasks.push('server');
} else {
defaultTasks.push('clean-things');
defaultTasks.push('copy-theme-stuff');
defaultTasks.push('stylesheets');
if (!opts.oneFile) {
copiesToTarget.unshift('css-to-target');
}
if (!opts.disableJs) {
defaultTasks.push('javascripts');
if (!opts.oneFile) {
copiesToTarget.unshift('js-to-target');
}
}
if (opts.logoFile && !opts.embedLogo) {
copiesToTarget.unshift('logo-to-target');
}
if (opts.faviconFile && !opts.embedFavicon) {
copiesToTarget.unshift('favicon-to-target');
}
defaultTasks.push('templates');
if (opts.oneFile) {
defaultTasks.push('embed');
}
copiesToTarget.forEach((flavor) => {
defaultTasks.push(`copy:${flavor}`);
});
if (opts.developmentMode || opts.developmentModeLive) {
doDevelop = true;
}
}
_grunt.default.registerTask('default', defaultTasks);
_grunt.default.task.run('default');
if (doDevelop) {
_grunt.default.task.run('develop');
}
_grunt.default.task.start();
return donePromise;
};exports.run = run;
const loadData = function (options) {
return spectaql(options);
};exports.loadData = loadData;
const buildSchemas = function (options) {
const { buildSchemas } = spectaql;
return buildSchemas(options);
};exports.buildSchemas = buildSchemas;
const augmentData = function (options) {
const { augmentData } = spectaql;
return augmentData(options);
};exports.augmentData = augmentData;