1
0
Fork 0

feat: fix mode and type coercion

This commit is contained in:
ssube 2019-06-17 07:11:36 -05:00
parent 97d5c7aac6
commit 719954e2a8
5 changed files with 35 additions and 15 deletions

View File

@ -180,7 +180,7 @@ The application mode.
Options: Options:
- `check` runs each rule and exits with an indicative status - `check` runs each rule and exits with an indicative status
- `clean` runs each rule and updates the source data with any defaults or other changes before running the next rule - `fix` runs each rule and updates the source data with any defaults before running the next rule
#### Rules #### Rules

View File

@ -31,12 +31,14 @@ const MAIN_ARGS: Options = {
'rules', 'rules',
], ],
boolean: [ boolean: [
'coerce',
'count', 'count',
], ],
count: ['v'], count: ['v'],
default: { default: {
[CONFIG_ARGS_NAME]: `.${VERSION_INFO.app.name}.yml`, [CONFIG_ARGS_NAME]: `.${VERSION_INFO.app.name}.yml`,
[CONFIG_ARGS_PATH]: [], [CONFIG_ARGS_PATH]: [],
'coerce': false,
'count': false, 'count': false,
'dest': '-', 'dest': '-',
'excludeLevel': [], 'excludeLevel': [],
@ -81,10 +83,15 @@ export async function main(argv: Array<string>): Promise<number> {
const data = parser.parse(source); const data = parser.parse(source);
const activeRules = await resolveRules(rules, args.argv as any); const activeRules = await resolveRules(rules, args.argv as any);
const ctx = new VisitorContext(logger); const ctx = new VisitorContext({
coerce: args.argv.coerce,
defaults: args.argv.mode === 'fix',
logger,
});
switch (args.argv.mode) { switch (args.argv.mode) {
case 'check': case 'check':
case 'fix':
for (const rule of activeRules) { for (const rule of activeRules) {
if (rule.visit(ctx, data)) { if (rule.visit(ctx, data)) {
logger.info({ rule }, 'passed rule'); logger.info({ rule }, 'passed rule');
@ -94,8 +101,7 @@ export async function main(argv: Array<string>): Promise<number> {
} }
break; break;
default: default:
ctx.logger.error({ mode: args.argv.mode }, 'unsupported mode'); ctx.error({ mode: args.argv.mode }, 'unsupported mode');
ctx.errors.push('unsupported mode');
} }
if (ctx.errors.length > 0) { if (ctx.errors.length > 0) {

View File

@ -1,4 +1,3 @@
import * as Ajv from 'ajv';
import { JSONPath } from 'jsonpath-plus'; import { JSONPath } from 'jsonpath-plus';
import { cloneDeep, intersection, isNil } from 'lodash'; import { cloneDeep, intersection, isNil } from 'lodash';
import { LogLevel } from 'noicejs'; import { LogLevel } from 'noicejs';
@ -103,9 +102,8 @@ export class Rule implements RuleData, Visitor {
} }
public async visit(ctx: VisitorContext, node: any): Promise<VisitorContext> { public async visit(ctx: VisitorContext, node: any): Promise<VisitorContext> {
const ajv = new ((Ajv as any).default)() const check = ctx.ajv.compile(this.check);
const check = ajv.compile(this.check); const filter = this.compileFilter(ctx);
const filter = this.compileFilter(ajv);
const scopes = JSONPath({ const scopes = JSONPath({
json: node, json: node,
path: this.select, path: this.select,
@ -122,8 +120,7 @@ export class Rule implements RuleData, Visitor {
ctx.logger.debug({ item }, 'checking item') ctx.logger.debug({ item }, 'checking item')
if (!check(item)) { if (!check(item)) {
ctx.logger.warn({ ctx.logger.warn({
desc: this.desc, name: this.name,
errors: check.errors,
item, item,
}, 'rule failed on item'); }, 'rule failed on item');
ctx.errors.push(...check.errors); ctx.errors.push(...check.errors);
@ -137,11 +134,11 @@ export class Rule implements RuleData, Visitor {
return ctx; return ctx;
} }
protected compileFilter(ajv: any): any { protected compileFilter(ctx: VisitorContext): any {
if (isNil(this.filter)) { if (isNil(this.filter)) {
return () => true; return () => true;
} else { } else {
return ajv.compile(this.filter); return ctx.ajv.compile(this.filter);
} }
} }
} }

View File

@ -1,13 +1,30 @@
import * as Ajv from 'ajv';
import { Logger } from 'noicejs'; import { Logger } from 'noicejs';
export interface VisitorContextOptions {
coerce: boolean;
defaults: boolean;
logger: Logger;
}
export class VisitorContext { export class VisitorContext {
public readonly ajv: any;
public readonly changes: Array<any>; public readonly changes: Array<any>;
public readonly errors: Array<any>; public readonly errors: Array<any>;
public readonly logger: Logger; public readonly logger: Logger;
constructor(logger: Logger) { constructor(options: VisitorContextOptions) {
this.ajv = new ((Ajv as any).default)({
coerceTypes: options.coerce,
useDefaults: options.defaults,
});
this.changes = []; this.changes = [];
this.errors = []; this.errors = [];
this.logger = logger; this.logger = options.logger;
}
public error(options: any, msg: string) {
this.logger.error(options, msg);
this.errors.push(options || msg);
} }
} }