Skip to content

Commit

Permalink
refactor: remove function quotedString
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Aug 28, 2020
1 parent f244b06 commit 3ab1066
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 71 deletions.
13 changes: 6 additions & 7 deletions lib/compile/errors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import {KeywordErrorContext, KeywordErrorDefinition} from "../types"
import {quotedString} from "../vocabularies/util"
import CodeGen, {_, Name, Expression} from "./codegen"
import CodeGen, {_, str, Name, Expression} from "./codegen"
import N from "./names"

export const keywordError: KeywordErrorDefinition = {
message: ({keyword}) => `'should pass "${keyword}" keyword validation'`,
params: ({keyword}) => `{keyword: "${keyword}"}`, // TODO possibly remove it as keyword is reported in the object
message: ({keyword}) => str`should pass ${keyword} keyword validation`,
params: ({keyword}) => _`{keyword: ${keyword}}`, // TODO possibly remove it as keyword is reported in the object
}

export function reportError(
Expand Down Expand Up @@ -93,11 +92,11 @@ function errorObjectCode(cxt: KeywordErrorContext, error: KeywordErrorDefinition
let out = `{
keyword: "${keyword}",
dataPath: (${N.dataPath} || "") + ${errorPath},
schemaPath: ${quotedString(errSchemaPath + "/" + keyword)},
params: ${params ? params(cxt) : "{}"},`
schemaPath: ${str`${errSchemaPath}/${keyword}`},
params: ${params ? params(cxt) : _`{}`},`
if (propertyName) out += `propertyName: ${propertyName},`
if (opts.messages !== false) {
out += `message: ${typeof message == "string" ? quotedString(message) : message(cxt)},`
out += `message: ${typeof message == "string" ? _`${message}` : message(cxt)},`
}
if (opts.verbose) {
// TODO trim whitespace
Expand Down
42 changes: 20 additions & 22 deletions lib/compile/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import CodeGen, {_, nil, Expression} from "./codegen"
import {toQuotedString} from "./util"
import {quotedString} from "../vocabularies/util"
import CodeGen, {_, nil, Code, Expression} from "./codegen"
import {validateFunctionCode} from "./validate"
import {ErrorObject, KeywordCompilationResult} from "../types"
import N from "./names"
Expand Down Expand Up @@ -139,12 +137,11 @@ function compile(schema, root, localRefs, baseId) {
self,
})

let sourceCode =
vars(refVal, refValCode) +
vars(patterns, patternCode) +
vars(defaults, defaultCode) +
vars(customRules, customRuleCode) +
gen.toString()
let sourceCode = `${vars(refVal, refValCode)}
${vars(patterns, patternCode)}
${vars(defaults, defaultCode)}
${vars(customRules, customRuleCode)}
${gen.toString()}`

if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema)
// console.log("\n\n\n *** \n", sourceCode)
Expand Down Expand Up @@ -268,13 +265,12 @@ function compile(schema, root, localRefs, baseId) {
return "pattern" + index
}

function useDefault(value: any): string {
function useDefault(value: any): Expression {
switch (typeof value) {
case "boolean":
case "number":
return "" + value
case "string":
return toQuotedString(value)
return _`${value}`
case "object":
if (value === null) return "null"
var valueStr = stableStringify(value)
Expand Down Expand Up @@ -341,22 +337,24 @@ function compIndex(schema, root, baseId) {
return -1
}

function patternCode(i: number, patterns: string[]): string {
return `const pattern${i} = new RegExp(${quotedString(patterns[i])});`
function patternCode(i: number, patterns): Code {
return _`const pattern${i} = new RegExp(${patterns[i]});`
}

function defaultCode(i: number): string {
return `const default${i} = defaults[${i}];`
function defaultCode(i: number): Code {
return _`const default${i} = defaults[${i}];`
}

function refValCode(i: number, refVal): string {
return refVal[i] === undefined ? "" : `const refVal${i} = refVal[${i}];`
function refValCode(i: number, refVal): Code {
return refVal[i] === undefined ? nil : _`const refVal${i} = refVal[${i}];`
}

function customRuleCode(i: number): string {
return `const customRule${i} = customRules[${i}];`
function customRuleCode(i: number): Code {
return _`const customRule${i} = customRules[${i}];`
}

function vars(arr: unknown[], statement: (i: number, arr: any[]) => string) {
return arr.reduce((code: string, _, i: number) => code + statement(i, arr), "")
function vars(arr: unknown[], statement: (i: number, arr?: unknown[]) => Code): Code {
return arr
.map((_el, i, arr) => statement(i, arr))
.reduce((res: Code, c: Code) => _`${res}${c}`, nil)
}
8 changes: 3 additions & 5 deletions lib/compile/subschema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {CompilationContext} from "../types"
import {subschemaCode} from "./validate"
import {getProperty, escapeFragment, getPath, getPathExpr} from "./util"
import {quotedString, accessProperty} from "../vocabularies/util"
import {Code, Name, Expression} from "./codegen"
import {accessProperty} from "../vocabularies/util"
import {_, Code, Name, Expression} from "./codegen"

export interface SubschemaContext {
// TODO use Optional?
Expand Down Expand Up @@ -118,9 +118,7 @@ function extendSubschemaData(
? getPathExpr(errorPath, dataProp, opts.jsonPointers, expr === Expr.Num)
: getPath(errorPath, dataProp, opts.jsonPointers)

subschema.parentDataProperty =
expr === Expr.Const && typeof dataProp == "string" ? quotedString(dataProp) : dataProp

subschema.parentDataProperty = _`${dataProp}`
subschema.dataPathArr = [...dataPathArr, subschema.parentDataProperty]
}

Expand Down
6 changes: 3 additions & 3 deletions lib/compile/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function toHash(arr: string[]): {[key: string]: true} {
const IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i
const SINGLE_QUOTE = /'|\\/g
export function getProperty(key: Expression | number): string {
// return key instanceof Name || (typeof key == "string" && IDENTIFIER.test(key))
// return typeof key == "string" && IDENTIFIER.test(key)
// ? _`.${key}`
// : _`[${key}]`

Expand Down Expand Up @@ -106,7 +106,7 @@ export function schemaUnknownRules(schema: object, rules: object): string | unde
for (const key in schema) if (!rules[key]) return key
}

export function toQuotedString(str: string): string {
function toQuotedString(str: string): string {
return `'${escapeQuotes(str)}'`
}

Expand Down Expand Up @@ -184,7 +184,7 @@ export function getData(
}
}

export function joinPaths(a: string, b: string): string {
function joinPaths(a: string, b: string): string {
if (a === '""' || a === "''") return b
if (b === '""' || b === "''") return a
return `${a} + ${b}`.replace(/([^\\])' \+ '/g, "$1")
Expand Down
1 change: 1 addition & 0 deletions lib/compile/validate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function initializeTop(gen: CodeGen): void {
gen.let(N.vErrors, "null")
gen.let(N.errors, 0)
gen.if(_`${N.rootData} === undefined`, () => gen.assign(N.rootData, N.data))
// gen.if(_`${N.dataPath} === undefined`, () => gen.assign(N.dataPath, _`""`)) // TODO maybe add it
}

function updateContext(it: CompilationContext): void {
Expand Down
8 changes: 4 additions & 4 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Cache from "./cache"
import CodeGen, {Name, Expression} from "./compile/codegen"
import CodeGen, {Code, Name, Expression} from "./compile/codegen"
import {ValidationRules} from "./compile/rules"
import {ResolvedRef} from "./compile"
import KeywordContext from "./compile/context"
Expand Down Expand Up @@ -130,7 +130,7 @@ export interface CompilationContext {
// }
compositeRule?: boolean
usePattern: (str: string) => string
useDefault: (value: any) => string
useDefault: (value: any) => Expression
customRules: KeywordCompilationResult[]
self: any // TODO
RULES: ValidationRules
Expand Down Expand Up @@ -209,8 +209,8 @@ export type KeywordDefinition =
| CodeKeywordDefinition

export interface KeywordErrorDefinition {
message: string | ((cxt: KeywordErrorContext) => Expression)
params?: (cxt: KeywordErrorContext) => Expression
message: string | ((cxt: KeywordErrorContext) => Code)
params?: (cxt: KeywordErrorContext) => Code
}

export type Vocabulary = KeywordDefinition[]
Expand Down
9 changes: 4 additions & 5 deletions lib/vocabularies/applicator/additionalProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import KeywordContext from "../../compile/context"
import {
allSchemaProperties,
schemaRefOrVal,
quotedString,
alwaysValidSchema,
loopPropertiesCode,
orExpr,
} from "../util"
import {applySubschema, SubschemaApplication, Expr} from "../../compile/subschema"
import {Name} from "../../compile/codegen"
import {_, Name, Expression} from "../../compile/codegen"
import N from "../../compile/names"

const def: CodeKeywordDefinition = {
Expand Down Expand Up @@ -38,13 +37,13 @@ const def: CodeKeywordDefinition = {
}

function isAdditional(key: Name): string {
let definedProp = ""
let definedProp: Expression = ""
if (props.length > 8) {
// TODO maybe an option instead of hard-coded 8?
const propsSchema = schemaRefOrVal(it, parentSchema.properties, "properties")
definedProp = `${propsSchema}.hasOwnProperty(${key})`
} else if (props.length) {
definedProp = orExpr(props, (p) => `${key} === ${quotedString(p)}`)
definedProp = orExpr(props, (p) => _`${key} === ${p}`)
}
if (patProps.length) {
definedProp +=
Expand Down Expand Up @@ -103,7 +102,7 @@ const def: CodeKeywordDefinition = {
},
error: {
message: "should NOT have additional properties",
params: ({params}) => `{additionalProperty: ${params.additionalProperty}}`,
params: ({params}) => _`{additionalProperty: ${params.additionalProperty}}`,
},
}

Expand Down
8 changes: 4 additions & 4 deletions lib/vocabularies/missing.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import KeywordContext from "../compile/context"
import {noPropertyInData, quotedString, orExpr} from "./util"
import {Name, _} from "../compile/codegen"
import {noPropertyInData, orExpr} from "./util"
import {_, Name, Expression} from "../compile/codegen"

export function checkReportMissingProp(cxt: KeywordContext, prop: string): void {
const {gen, data, it} = cxt
Expand All @@ -14,10 +14,10 @@ export function checkMissingProp(
{data, it: {opts}}: KeywordContext,
properties: string[],
missing: Name
): string {
): Expression {
return orExpr(properties, (prop) => {
const hasNoProp = noPropertyInData(data, prop, opts.ownProperties)
return `(${hasNoProp} && (${missing} = ${quotedString(prop)}))`
return `(${hasNoProp} && (${missing} = ${_`${prop}`}))`
})
}

Expand Down
20 changes: 8 additions & 12 deletions lib/vocabularies/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ import KeywordContext from "../compile/context"
import {_, Code, Name, Expression} from "../compile/codegen"
import N from "../compile/names"

export function quotedString(str: string): string {
return JSON.stringify(str)
.replace(/\u2028/g, "\\u2028")
.replace(/\u2029/g, "\\u2029")
}

export function dataNotType(
schemaCode: Expression | number | boolean,
schemaType: string,
Expand Down Expand Up @@ -53,9 +47,8 @@ export function schemaProperties(it: CompilationContext, schema: object): string
return allSchemaProperties(schema).filter((p) => !alwaysValidSchema(it, schema[p]))
}

export function isOwnProperty(data: Name, property: Expression): Expression {
const prop = property instanceof Code ? property : quotedString(property)
return `Object.prototype.hasOwnProperty.call(${data}, ${prop})`
export function isOwnProperty(data: Name, property: Expression): Code {
return _`Object.prototype.hasOwnProperty.call(${data}, ${property})`
}

export function propertyInData(data: Name, property: Expression, ownProperties?: boolean): string {
Expand All @@ -74,8 +67,8 @@ export function noPropertyInData(
return cond
}

export function accessProperty(property: Expression | number): string {
return property instanceof Code ? `[${property}]` : getProperty(property)
export function accessProperty(property: Expression | number): Expression {
return property instanceof Code ? _`[${property}]` : getProperty(property)
}

export function loopPropertiesCode(
Expand All @@ -88,7 +81,10 @@ export function loopPropertiesCode(
gen.for(`const ${key} ${iteration}`, () => loopBody(key))
}

export function orExpr(items: string[], mapCondition: (s: string, i: number) => string): string {
export function orExpr(
items: string[],
mapCondition: (s: string, i: number) => Expression
): Expression {
return items.map(mapCondition).reduce((expr, cond) => `${expr} || ${cond}`)
}

Expand Down
3 changes: 2 additions & 1 deletion lib/vocabularies/validation/const.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {CodeKeywordDefinition} from "../../types"
import KeywordContext from "../../compile/context"
import {_} from "../../compile/codegen"

const def: CodeKeywordDefinition = {
keyword: "const",
$data: true,
code: (cxt: KeywordContext) => cxt.fail(`!equal(${cxt.data}, ${cxt.schemaCode})`),
error: {
message: "should be equal to constant",
params: ({schemaCode}) => `{allowedValue: ${schemaCode}}`,
params: ({schemaCode}) => _`{allowedValue: ${schemaCode}}`,
},
}

Expand Down
15 changes: 7 additions & 8 deletions lib/vocabularies/validation/enum.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {CodeKeywordDefinition} from "../../types"
import KeywordContext from "../../compile/context"
import {quotedString, orExpr} from "../util"
import {_, Name} from "../../compile/codegen"
import {orExpr} from "../util"
import {_, Name, Code, Expression} from "../../compile/codegen"

const def: CodeKeywordDefinition = {
keyword: "enum",
Expand All @@ -26,7 +26,7 @@ const def: CodeKeywordDefinition = {
cxt.pass(valid)
} else {
const vSchema = gen.const("schema", schemaCode)
const cond: string = orExpr(schema, (_x, i) => equalCode(vSchema, i))
const cond: Expression = orExpr(schema, (_x, i) => equalCode(vSchema, i))
cxt.pass(cond)
}
}
Expand All @@ -38,13 +38,12 @@ const def: CodeKeywordDefinition = {
)
}

function equalCode(vSchema: Name, i: number): string {
let sch: string = schema[i]
function equalCode(vSchema: Name, i: number): Code {
const sch: string = schema[i]
if (sch && typeof sch === "object") {
return `equal(${data}, ${vSchema}[${i}])`
return _`equal(${data}, ${vSchema}[${i}])`
}
if (typeof sch === "string") sch = quotedString(sch)
return `${data} === ${sch}`
return _`${data} === ${sch}`
}
},
error: {
Expand Down

0 comments on commit 3ab1066

Please sign in to comment.