diff --git a/src/index.ts b/src/index.ts index c6f2c2e..fed5312 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,9 @@ import { createLogger } from 'bunyan'; -import { applyDiff, diff } from 'deep-diff'; -import { cloneDeep } from 'lodash'; import { Options, usage } from 'yargs'; import { loadConfig } from 'src/config'; import { YamlParser } from 'src/parser/YamlParser'; -import { loadRules, resolveRules } from 'src/rule'; +import { loadRules, resolveRules, visitRules } from 'src/rule'; import { loadSource, writeSource } from 'src/source'; import { VERSION_INFO } from 'src/version'; import { VisitorContext } from 'src/visitor/context'; @@ -21,7 +19,7 @@ const RULE_OPTION: Options = { type: 'array', }; -const MAIN_ARGS = usage(`Usage: salty-dog [options]`) +const MAIN_ARGS = usage(`Usage: salty-dog [-m mode] [options]`) .option(CONFIG_ARGS_NAME, { default: `.${VERSION_INFO.app.name}.yml`, group: 'Config:', @@ -95,6 +93,7 @@ export async function main(argv: Array): Promise { // check mode if (!MODES.includes(args.mode)) { logger.error({ mode: args.mode }, 'unsupported mode'); + return STATUS_ERROR; } // const schema = new Schema(); @@ -123,32 +122,7 @@ export async function main(argv: Array): Promise { } for (const data of docs) { - for (const rule of activeRules) { - const items = await rule.pick(ctx, data); - for (const item of items) { - const itemCopy = cloneDeep(item); - const itemResult = await rule.visit(ctx, itemCopy); - - if (itemResult.errors.length > 0) { - logger.warn({ count: itemResult.errors.length, rule }, 'rule failed'); - - ctx.mergeResult(itemResult); - } else { - const itemDiff = diff(item, itemCopy); - if (Array.isArray(itemDiff) && itemDiff.length > 0) { - logger.info({ - diff: itemDiff, - item, - rule: rule.name, - }, 'rule passed with modifications'); - - applyDiff(item, itemCopy); - } else { - logger.info({ rule: rule.name }, 'rule passed'); - } - } - } - } + await visitRules(ctx, activeRules, data); } if (ctx.errors.length > 0) { diff --git a/src/rule.ts b/src/rule.ts index 836707d..7d312c5 100644 --- a/src/rule.ts +++ b/src/rule.ts @@ -1,3 +1,4 @@ +import { applyDiff, diff } from 'deep-diff'; import { JSONPath } from 'jsonpath-plus'; import { cloneDeep, intersection, isNil } from 'lodash'; import { LogLevel } from 'noicejs'; @@ -114,9 +115,39 @@ export async function resolveRules(rules: Array, selector: RuleSelector): return Array.from(activeRules); } +export async function visitRules(ctx: VisitorContext, rules: Array, data: any): Promise { + for (const rule of rules) { + const items = await rule.pick(ctx, data); + for (const item of items) { + const itemCopy = cloneDeep(item); + const itemResult = await rule.visit(ctx, itemCopy); + + if (itemResult.errors.length > 0) { + ctx.logger.warn({ count: itemResult.errors.length, rule }, 'rule failed'); + ctx.mergeResult(itemResult); + } else { + const itemDiff = diff(item, itemCopy); + if (Array.isArray(itemDiff) && itemDiff.length > 0) { + ctx.logger.info({ + diff: itemDiff, + item, + rule: rule.name, + }, 'rule passed with modifications'); + + applyDiff(item, itemCopy); + } else { + ctx.logger.info({ rule: rule.name }, 'rule passed'); + } + } + } + } + + return ctx; +} + export interface RuleResult extends VisitorResult { rule: Rule; -} +} export class Rule implements RuleData, Visitor { public readonly check: any; @@ -156,7 +187,7 @@ export class Rule implements RuleData, Visitor { } public async visit(ctx: VisitorContext, node: any): Promise { - ctx.logger.debug({ item: node, rule: this}, 'visiting node'); + ctx.logger.debug({ item: node, rule: this }, 'visiting node'); const check = ctx.ajv.compile(this.check); const filter = this.compileFilter(ctx);