2019-06-15 20:20:04 +00:00
|
|
|
import { createLogger } from 'bunyan';
|
|
|
|
|
2019-08-30 05:24:12 +00:00
|
|
|
import { loadConfig } from './config';
|
|
|
|
import { CONFIG_ARGS_NAME, CONFIG_ARGS_PATH, parseArgs } from './config/args';
|
|
|
|
import { YamlParser } from './parser/YamlParser';
|
|
|
|
import { loadRules, resolveRules, visitRules } from './rule';
|
|
|
|
import { loadSource, writeSource } from './source';
|
|
|
|
import { VERSION_INFO } from './version';
|
|
|
|
import { VisitorContext } from './visitor/context';
|
|
|
|
|
|
|
|
enum MODES {
|
|
|
|
check = 'check',
|
|
|
|
fix = 'fix',
|
|
|
|
list = 'list',
|
|
|
|
}
|
|
|
|
|
|
|
|
const MODES_LIST: Array<string> = [MODES.check, MODES.fix, MODES.list];
|
2019-06-22 16:48:41 +00:00
|
|
|
|
2019-06-15 20:20:04 +00:00
|
|
|
const STATUS_SUCCESS = 0;
|
|
|
|
const STATUS_ERROR = 1;
|
|
|
|
|
|
|
|
export async function main(argv: Array<string>): Promise<number> {
|
2019-07-04 18:58:25 +00:00
|
|
|
const { args, mode } = parseArgs(argv);
|
2019-07-04 15:35:27 +00:00
|
|
|
const config = await loadConfig(args[CONFIG_ARGS_NAME], ...args[CONFIG_ARGS_PATH]);
|
2019-07-04 15:54:22 +00:00
|
|
|
|
2019-06-15 20:20:04 +00:00
|
|
|
const logger = createLogger(config.data.logger);
|
|
|
|
logger.info(VERSION_INFO, 'version info');
|
2019-06-17 13:04:58 +00:00
|
|
|
logger.info({ args }, 'main arguments');
|
2019-06-15 20:20:04 +00:00
|
|
|
|
2019-06-22 16:48:41 +00:00
|
|
|
// check mode
|
2019-08-30 05:24:12 +00:00
|
|
|
if (!MODES_LIST.includes(mode)) {
|
2019-07-04 14:44:54 +00:00
|
|
|
logger.error({ mode }, 'unsupported mode');
|
2019-06-30 17:58:30 +00:00
|
|
|
return STATUS_ERROR;
|
2019-06-22 16:48:41 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 12:11:36 +00:00
|
|
|
const ctx = new VisitorContext({
|
2019-07-04 18:58:25 +00:00
|
|
|
coerce: args.coerce,
|
|
|
|
defaults: args.defaults,
|
2019-06-17 12:11:36 +00:00
|
|
|
logger,
|
2019-07-04 18:58:25 +00:00
|
|
|
mutate: mode === 'fix',
|
2019-06-17 12:11:36 +00:00
|
|
|
});
|
2019-06-16 21:15:01 +00:00
|
|
|
|
2019-06-22 17:26:11 +00:00
|
|
|
const rules = await loadRules(args.rules, ctx.ajv);
|
|
|
|
const activeRules = await resolveRules(rules, args as any);
|
|
|
|
|
2019-07-04 14:44:54 +00:00
|
|
|
if (mode === 'list') {
|
2019-06-25 13:15:04 +00:00
|
|
|
logger.info({ rules: activeRules }, 'listing active rules');
|
2019-06-25 04:47:12 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-07-04 15:35:27 +00:00
|
|
|
const parser = new YamlParser();
|
|
|
|
const source = await loadSource(args.source);
|
|
|
|
let docs = parser.parse(source);
|
|
|
|
|
2019-06-25 03:50:46 +00:00
|
|
|
for (const data of docs) {
|
2019-06-30 17:58:30 +00:00
|
|
|
await visitRules(ctx, activeRules, data);
|
2019-06-15 20:20:04 +00:00
|
|
|
}
|
|
|
|
|
2019-06-16 18:30:04 +00:00
|
|
|
if (ctx.errors.length > 0) {
|
2019-06-22 16:48:41 +00:00
|
|
|
logger.error({ count: ctx.errors.length, errors: ctx.errors }, 'some rules failed');
|
2019-06-17 13:04:58 +00:00
|
|
|
if (args.count) {
|
2019-06-16 18:30:04 +00:00
|
|
|
return Math.min(ctx.errors.length, 255);
|
2019-06-15 23:27:36 +00:00
|
|
|
} else {
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
2019-06-15 23:56:42 +00:00
|
|
|
logger.info('all rules passed');
|
2019-06-25 03:50:46 +00:00
|
|
|
const output = parser.dump(...docs);
|
2019-06-17 13:04:58 +00:00
|
|
|
await writeSource(args.dest, output);
|
2019-06-15 23:27:36 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2019-06-15 20:20:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
main(process.argv).then((status) => process.exit(status)).catch((err) => {
|
|
|
|
/* tslint:disable-next-line:no-console */
|
|
|
|
console.error('uncaught error during main:', err);
|
|
|
|
process.exit(STATUS_ERROR);
|
|
|
|
});
|