@graphql-inspector/coverage-command
Version:
Schema Coverage in GraphQL Inspector
159 lines (158 loc) • 6.35 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = handler;
const fs_1 = require("fs");
const path_1 = require("path");
const graphql_1 = require("graphql");
const commands_1 = require("@graphql-inspector/commands");
const core_1 = require("@graphql-inspector/core");
const logger_1 = require("@graphql-inspector/logger");
function handler({ schema, documents, silent, writePath, }) {
const shouldWrite = typeof writePath !== 'undefined';
const coverage = (0, core_1.coverage)(schema, documents.map(doc => new graphql_1.Source((0, graphql_1.print)(doc.document), doc.location)));
if (silent !== true) {
renderCoverage(coverage);
}
if (shouldWrite) {
if (typeof writePath !== 'string') {
throw new Error(`--write is not valid file path: ${writePath}`);
}
const absPath = (0, commands_1.ensureAbsolute)(writePath);
const ext = (0, path_1.extname)(absPath).replace('.', '').toLocaleLowerCase();
let output = undefined;
if (ext === 'json') {
output = outputJSON(coverage);
}
if (output) {
(0, fs_1.writeFileSync)(absPath, output, 'utf8');
logger_1.Logger.success(`Available at ${absPath}\n`);
}
else {
throw new Error(`Extension ${ext} is not supported`);
}
}
}
exports.default = (0, commands_1.createCommand)(api => {
const { loaders } = api;
return {
command: 'coverage <documents> <schema>',
describe: 'Schema coverage based on documents',
builder(yargs) {
return yargs
.positional('schema', {
describe: 'Point to a schema',
type: 'string',
demandOption: true,
})
.positional('documents', {
describe: 'Point to documents',
type: 'string',
demandOption: true,
})
.options({
w: {
alias: 'write',
describe: 'Write a file with coverage stats',
type: 'string',
},
s: {
alias: 'silent',
describe: 'Do not render any stats in the terminal',
type: 'boolean',
},
});
},
async handler(args) {
const writePath = args.write;
const silent = args.silent;
const { headers, token } = (0, commands_1.parseGlobalArgs)(args);
const apolloFederation = args.federation || false;
const aws = args.aws || false;
const method = args.method?.toUpperCase() || 'POST';
const schema = await loaders.loadSchema(args.schema, {
token,
headers,
method,
}, apolloFederation, aws);
const documents = await loaders.loadDocuments(args.documents);
return handler({ schema, documents, silent, writePath });
},
};
});
function outputJSON(coverage) {
return JSON.stringify(coverage, null, 2);
}
function renderCoverage(coverage) {
logger_1.Logger.info('Schema coverage based on documents:\n');
for (const typeName in coverage.types) {
if (Object.prototype.hasOwnProperty.call(coverage.types, typeName)) {
const typeCoverage = coverage.types[typeName];
logger_1.Logger.log([
logger_1.chalk.grey((0, core_1.getTypePrefix)(typeCoverage.type)),
logger_1.chalk.bold(String(typeName)),
logger_1.chalk.grey('{'),
].join(' '));
for (const childName in typeCoverage.children) {
if (Object.prototype.hasOwnProperty.call(typeCoverage.children, childName)) {
const childCoverage = typeCoverage.children[childName];
if (childCoverage.hits) {
logger_1.Logger.log([indent(childName, 2), logger_1.chalk.italic.grey(`x ${childCoverage.hits}`)].join(' '));
}
else {
logger_1.Logger.log([logger_1.chalk.redBright(indent(childName, 2)), logger_1.chalk.italic.grey('x 0')].join(' '));
}
}
}
logger_1.Logger.log(logger_1.chalk.grey('}\n'));
}
}
const logStatsResult = [
{
method: 'Types covered',
result: `${coverage.stats.numTypes > 0
? ((coverage.stats.numTypesCovered / coverage.stats.numTypes) * 100).toFixed(1)
: 'N/A'}%`,
},
{
method: 'Types covered fully',
result: `${coverage.stats.numTypes > 0
? ((coverage.stats.numTypesCoveredFully / coverage.stats.numTypes) * 100).toFixed(1)
: 'N/A'}%`,
},
{
method: 'Fields covered',
result: `${coverage.stats.numFields > 0
? ((coverage.stats.numFiledsCovered / coverage.stats.numFields) * 100).toFixed(1)
: 'N/A'}%`,
},
{
method: 'Total Queries',
result: String(coverage.stats.numQueries > 0 ? coverage.stats.numQueries : '0'),
},
{
method: 'Covered Queries',
result: String(coverage.stats.numCoveredQueries > 0 ? coverage.stats.numCoveredQueries : '0'),
},
{
method: 'Total Mutations',
result: String(coverage.stats.numMutations > 0 ? coverage.stats.numMutations : '0'),
},
{
method: 'Covered Mutations',
result: String(coverage.stats.numCoveredMutations > 0 ? coverage.stats.numCoveredMutations : '0'),
},
{
method: 'Total Subscriptions',
result: String(coverage.stats.numSubscriptions > 0 ? coverage.stats.numSubscriptions : '0'),
},
{
method: 'Covered Subscriptions',
result: String(coverage.stats.numCoveredSubscriptions > 0 ? coverage.stats.numCoveredSubscriptions : '0'),
},
];
logger_1.Logger.table(logStatsResult);
logger_1.Logger.log(``);
}
function indent(line, space) {
return line.padStart(line.length + space, ' ');
}
;