1
0
Fork 0
salty-dog/src/index.ts

124 lines
3.2 KiB
TypeScript
Raw Normal View History

2019-06-15 20:20:04 +00:00
import { createLogger } from 'bunyan';
2019-06-16 01:21:11 +00:00
import { safeDump, safeLoad } from 'js-yaml';
2019-06-15 20:20:04 +00:00
import { detailed, Options } from 'yargs-parser';
2019-06-16 01:21:11 +00:00
import { CONFIG_SCHEMA, loadConfig } from 'src/config';
import { loadRules, resolveRules } from 'src/rule';
2019-06-16 01:21:11 +00:00
import { loadSource, writeSource } from 'src/source';
2019-06-15 20:20:04 +00:00
import { VERSION_INFO } from 'src/version';
import { VisitorContext } from 'src/visitor/context';
2019-06-15 20:20:04 +00:00
const CONFIG_ARGS_NAME = 'config-name';
const CONFIG_ARGS_PATH = 'config-path';
const MAIN_ARGS: Options = {
alias: {
'count': ['c'],
2019-06-16 01:21:11 +00:00
'dest': ['d'],
'format': ['f'],
'includeTag': ['t', 'tag'],
'mode': ['m'],
2019-06-16 01:21:11 +00:00
'source': ['s'],
},
array: [
CONFIG_ARGS_PATH,
'excludeLevel',
'excludeName',
'excludeTag',
'includeLevel',
'includeName',
'includeTag',
'rules',
],
boolean: [
'count',
],
2019-06-15 20:20:04 +00:00
count: ['v'],
default: {
[CONFIG_ARGS_NAME]: `.${VERSION_INFO.app.name}.yml`,
[CONFIG_ARGS_PATH]: [],
'count': false,
2019-06-16 01:21:11 +00:00
'dest': '-',
'excludeLevel': [],
'excludeName': [],
'excludeTag': [],
2019-06-16 01:21:11 +00:00
'format': 'yaml',
'includeLevel': [],
'includeName': [],
'includeTag': [],
'mode': 'check',
'rules': [],
'source': '-',
2019-06-15 20:20:04 +00:00
},
envPrefix: VERSION_INFO.app.name,
2019-06-16 01:21:11 +00:00
string: [
'mode',
],
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> {
const args = detailed(argv, MAIN_ARGS);
const config = await loadConfig(args.argv[CONFIG_ARGS_NAME], ...args.argv[CONFIG_ARGS_PATH]);
const logger = createLogger(config.data.logger);
logger.info(VERSION_INFO, 'version info');
2019-06-16 02:59:28 +00:00
logger.info({ args: args.argv }, 'main arguments');
2019-06-15 20:20:04 +00:00
// const schema = new Schema();
const result = { errors: [], valid: true }; // schema.match(config);
if (!result.valid) {
logger.error({ errors: result.errors }, 'config failed to validate');
return STATUS_ERROR;
}
const rules = await loadRules(args.argv.rules);
const source = await loadSource(args.argv.source);
const data = safeLoad(source, {
schema: CONFIG_SCHEMA,
});
const activeRules = await resolveRules(rules, args.argv as any);
// run rules
const ctx = new VisitorContext(logger);
2019-06-15 23:07:46 +00:00
switch (args.argv.mode) {
case 'check':
for (const rule of activeRules) {
if (rule.visit(ctx, data)) {
2019-06-15 23:07:46 +00:00
logger.info({ rule }, 'passed rule');
} else {
logger.warn({ rule }, 'failed rule');
}
}
break;
default:
ctx.logger.error({ mode: args.argv.mode }, 'unsupported mode');
ctx.errors.push('unsupported mode');
2019-06-15 20:20:04 +00:00
}
if (ctx.errors.length > 0) {
logger.error({ errors: ctx.errors }, 'some rules failed');
if (args.argv.count) {
return Math.min(ctx.errors.length, 255);
} else {
return STATUS_ERROR;
}
} else {
logger.info('all rules passed');
2019-06-16 01:21:11 +00:00
const output = safeDump(data, {
schema: CONFIG_SCHEMA,
});
await writeSource(args.argv.dest, output);
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);
});