@graphql-inspector/audit-command
Version:
Audit Documents in GraphQL Inspector
114 lines (113 loc) • 5.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = handler;
const tslib_1 = require("tslib");
const cli_table3_1 = tslib_1.__importDefault(require("cli-table3"));
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");
exports.default = (0, commands_1.createCommand)(api => {
return {
command: 'audit <documents>',
describe: 'Audit Fragments and Operations for a better understanding of the depth, alias count, and directive count.',
builder(yargs) {
return yargs
.positional('documents', {
describe: 'Point to some documents',
type: 'string',
demandOption: true,
})
.options({
detail: {
alias: 'd',
describe: 'Print an overview of all operations and their audit breakdown.',
type: 'boolean',
default: false,
},
complexityScalarCost: {
describe: 'The cost per scalar for calculating the complexity score.',
type: 'number',
default: 1,
},
complexityObjectCost: {
describe: 'The cost per object for calculating the complexity score.',
type: 'number',
default: 2,
},
complexityDepthCostFactor: {
describe: 'The cost factor per introduced depth level for calculating the complexity score.',
type: 'number',
default: 1.5,
},
});
},
async handler(args) {
const { loaders } = api;
const ignore = args.ignore || [];
const documents = await loaders.loadDocuments(args.documents, {
ignore,
});
const complexityConfig = {
scalarCost: args.complexityScalarCost,
objectCost: args.complexityObjectCost,
depthCostFactor: args.complexityDepthCostFactor,
};
return handler({ documents, detail: args.detail, complexityConfig });
},
};
});
function handler(args) {
const fragments = new Map();
const fragmentStrings = new Map();
const operations = new Map();
const getFragmentReference = (fragmentName) => fragments.get(fragmentName);
const getFragmentSource = (fragmentName) => fragmentStrings.get(fragmentName);
for (const record of args.documents) {
if (record.document) {
for (const definition of record.document.definitions) {
if (definition.kind === 'FragmentDefinition') {
fragments.set(definition.name.value, definition);
fragmentStrings.set(definition.name.value, (0, graphql_1.print)(definition));
}
else if (definition.kind === 'OperationDefinition' && definition.name) {
operations.set(definition.name.value, definition);
}
}
}
}
let maxDepth = 0;
let maxAliases = 0;
let maxDirectives = 0;
let maxTokenCount = 0;
let maxComplexity = 0;
const results = [];
for (const [name, operation] of operations.entries()) {
const depth = (0, core_1.countDepth)(operation, 0, getFragmentReference);
const aliases = (0, core_1.countAliases)(operation, getFragmentReference);
const directives = (0, core_1.countDirectives)(operation, getFragmentReference);
const tokenCount = (0, core_1.calculateTokenCount)({
source: (0, graphql_1.print)(operation),
getReferencedFragmentSource: getFragmentSource,
});
const complexity = (0, core_1.calculateOperationComplexity)(operation, args.complexityConfig, getFragmentReference);
results.push([name, depth, aliases, directives, tokenCount, complexity.toFixed(2)]);
maxDepth = Math.max(maxDepth, depth);
maxAliases = Math.max(maxAliases, aliases);
maxDirectives = Math.max(maxDirectives, directives);
maxTokenCount = Math.max(maxTokenCount, tokenCount);
maxComplexity = Math.max(maxComplexity, complexity);
}
if (args.detail) {
const table = new cli_table3_1.default({
head: ['Operation Name', 'Depth', 'Aliases', 'Directives', 'Token Count', 'Complexity Score'],
});
table.push(...results);
logger_1.Logger.log(table.toString());
}
logger_1.Logger.log(`Maximum depth is ${logger_1.chalk.bold(maxDepth)}`);
logger_1.Logger.log(`Maximum alias amount is ${logger_1.chalk.bold(maxAliases)}`);
logger_1.Logger.log(`Maximum directive amount is ${logger_1.chalk.bold(maxDirectives)}`);
logger_1.Logger.log(`Maximum token count is ${logger_1.chalk.bold(maxTokenCount)}`);
logger_1.Logger.log(`Maximum complexity score is ${logger_1.chalk.bold(maxComplexity.toFixed(2))}`);
}
;