Skip to content

Commit

Permalink
refactor(validate): keywords validation to typescript (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Aug 15, 2020
1 parent 822336c commit 6c48299
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 9 deletions.
2 changes: 2 additions & 0 deletions lib/compile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import {getSchemaTypes, coerceAndCheckDataType} from "./validate/dataType"
import {booleanOrEmptySchema} from "./validate/boolSchema"
import {assignDefaults} from "./validate/defaults"
import schemaKeywords from "./validate/keywords"

const equal = require("fast-deep-equal")
const ucs2length = require("./ucs2length")
Expand Down Expand Up @@ -128,6 +129,7 @@ function compile(schema, root, localRefs, baseId) {
booleanOrEmptySchema, // TODO remove when validate is replaced
commentKeyword, // TODO remove when validate is replaced
assignDefaults, // TODO remove when validate is replaced
schemaKeywords, // TODO remove when validate is replaced
util: util,
resolve: resolve,
resolveRef: resolveRef,
Expand Down
2 changes: 1 addition & 1 deletion lib/compile/validate/applicability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function shouldUseGroup(schema, group): boolean {
return group.rules.some((rule) => shouldUseRule(schema, rule))
}

function shouldUseRule(schema, rule): boolean {
export function shouldUseRule(schema, rule): boolean {
return schema[rule.keyword] !== undefined || ruleImplementsSomeKeyword(schema, rule)
}

Expand Down
14 changes: 8 additions & 6 deletions lib/compile/validate/dataType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,25 @@ export function getSchemaTypes({schema, opts}: CompilationContext): string[] {
}
}

export function coerceAndCheckDataType(it: CompilationContext, types: string[]): void {
export function coerceAndCheckDataType(it: CompilationContext, types: string[]): boolean {
const {
gen,
dataLevel,
opts: {coerceTypes, strictNumbers},
} = it
let coerceTo = coerceToTypes(types, coerceTypes)
if (
types.length &&
(coerceTo.length || types.length > 1 || !schemaHasRulesForType(it, types[0]))
) {
const checkTypes =
types.length > 0 &&
(coerceTo.length > 0 || types.length > 1 || !schemaHasRulesForType(it, types[0]))
if (checkTypes) {
// TODO refactor `data${dataLevel || ""}`
const wrongType = checkDataTypes(types, `data${dataLevel || ""}`, strictNumbers, true)
gen.code(`if (${wrongType}) {`)
if (coerceTo.length) coerceData(it, coerceTo)
else reportTypeError(it)
gen.code("}")
}
return checkTypes
}

const COERCIBLE = toHash(["string", "number", "integer", "boolean", "null"])
Expand Down Expand Up @@ -136,7 +138,7 @@ const typeError: KeywordErrorDefinition = {

// TODO maybe combine with boolSchemaError
// TODO refactor type keyword context creation
function reportTypeError(it: CompilationContext) {
export function reportTypeError(it: CompilationContext) {
const {gen, schema, schemaPath, dataLevel} = it
const schemaCode = schemaRefOrVal(schema, schemaPath, "type")
const cxt: KeywordContext = {
Expand Down
129 changes: 129 additions & 0 deletions lib/compile/validate/keywords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import {CompilationContext} from "../../types"
import {shouldUseGroup, shouldUseRule} from "./applicability"
import {checkDataType, schemaHasRulesExcept} from "../util"
import {assignDefaults} from "./defaults"
import {reportTypeError} from "./dataType"

export default function schemaKeywords(
it: CompilationContext,
types: string[],
typeErrors: boolean,
top: boolean
) {
const {
gen,
schema,
level,
dataLevel,
RULES,
opts: {allErrors, strictNumbers, useDefaults},
} = it
let closingBraces2 = ""
if (schema.$ref && !schemaHasRulesExcept(schema, RULES.all, "$ref")) {
gen.code(RULES.all.$ref.code(it, "$ref"))
if (!allErrors) {
// TODO refactor with below
const errCount = top ? "0" : `errs_${level}`
gen.code(`if (errors === ${errCount}) {`)
closingBraces2 += "}"
}
} else {
for (const group of RULES) {
if (shouldUseGroup(schema, group)) {
if (group.type) {
// TODO refactor `data${dataLevel || ""}`
const checkType = checkDataType(group.type, `data${dataLevel || ""}`, strictNumbers)
gen.code(`if (${checkType}) {`)
}
if (useDefaults) assignDefaults(it, group)
let closingBraces1 = ""
for (const rule of group.rules) {
if (shouldUseRule(schema, rule)) {
const code = rule.code(it, rule.keyword, group.type)
if (code) {
gen.code(code)
if (!allErrors) closingBraces1 += "}"
}
}
}
if (!allErrors) gen.code(closingBraces1)
if (group.type) {
gen.code("}")
if (types.length === 1 && types[0] === group.type && typeErrors) {
gen.code(`else {`)
reportTypeError(it)
gen.code(`}`)
}
}
if (!allErrors) {
const errCount = top ? "0" : `errs_${level}`
gen.code(`if (errors === ${errCount}) {`)
closingBraces2 += "}"
}
}
}
}
if (!allErrors) gen.code(closingBraces2)
}

// {{? it.schema.$ref && !$refKeywords }}
// {{= it.RULES.all.$ref.code(it, '$ref') }}
// {{? $breakOnError }}
// }
// if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) {
// {{ $closingBraces2 += '}'; }}
// {{?}}
// {{??}}
// {{~ it.RULES:$rulesGroup }}
// {{? $shouldUseGroup($rulesGroup) }}
// {{? $rulesGroup.type }}
// if ({{= it.util.checkDataType($rulesGroup.type, $data, it.opts.strictNumbers) }}) {
// {{?}}
// {{? it.opts.useDefaults }}
// {{
// it.gen._out = "";
// it.assignDefaults(it, $rulesGroup);
// }}
// {{=it.gen._out}}
// {{?}}
//

// {{~ $rulesGroup.rules:$rule }}
// {{? $shouldUseRule($rule) }}
// {{ var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); }}
// {{? $code }}
// {{= $code }}
// {{? $breakOnError }}
// {{ $closingBraces1 += '}'; }}
// {{?}}
// {{?}}
// {{?}}
// {{~}}

// {{? $breakOnError }}
// {{= $closingBraces1 }}
// {{ $closingBraces1 = ''; }}
// {{?}}

// {{? $rulesGroup.type }}
// }
// {{? $typeSchema && $typeSchema === $rulesGroup.type && !(it.opts.coerceTypes && it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema)) }}
// else {
// {{
// var $schemaPath = it.schemaPath + '.type'
// , $errSchemaPath = it.errSchemaPath + '/type';
// }}
// {{# def.error:'type' }}
// }
// {{?}}
// {{?}}

// {{? $breakOnError }}
// if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) {
// {{ $closingBraces2 += '}'; }}
// {{?}}
// {{?}}
// {{~}}
// {{?}}

// {{? $breakOnError }} {{= $closingBraces2 }} {{?}}
4 changes: 2 additions & 2 deletions lib/dot/validate.jst
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
const types = it.getSchemaTypes(it);
/* TODO do not clear _out */
it.gen._out = "";
it.coerceAndCheckDataType(it, types);
const checkedTypes = it.coerceAndCheckDataType(it, types);
}}
{{= it.gen._out }}

Expand Down Expand Up @@ -159,7 +159,7 @@
{{?}}
{{? $rulesGroup.type }}
}
{{? $typeSchema && $typeSchema === $rulesGroup.type && !(it.opts.coerceTypes && it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema)) }}
{{? $typeSchema && $typeSchema === $rulesGroup.type && !checkedTypes }}
else {
{{
var $schemaPath = it.schemaPath + '.type'
Expand Down

0 comments on commit 6c48299

Please sign in to comment.