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:
- `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

View File

@ -11,4 +11,4 @@ spec:
memory: 5Mi
requests:
cpu: 1m
memory: 2Mi
memory: 2Mi

View File

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

View File

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