Skip to content

Commit

Permalink
support RegExp formats with standalone code, #1470
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Mar 31, 2021
1 parent e62d034 commit ec1818b
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 7 deletions.
4 changes: 4 additions & 0 deletions lib/compile/codegen/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,7 @@ export function safeStringify(x: unknown): string {
export function getProperty(key: Code | string | number): Code {
return typeof key == "string" && IDENTIFIER.test(key) ? new _Code(`.${key}`) : _`[${key}]`
}

export function regexpCode(rx: RegExp): Code {
return new _Code(rx.toString())
}
2 changes: 1 addition & 1 deletion lib/compile/codegen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {ScopeValueSets, NameValue, ValueScope, ValueScopeName} from "./scop
import {_, nil, _Code, Code, Name, UsedNames, CodeItem, addCodeArg, _CodeOrName} from "./code"
import {Scope, varKinds} from "./scope"

export {_, str, strConcat, nil, getProperty, stringify, Name, Code} from "./code"
export {_, str, strConcat, nil, getProperty, stringify, regexpCode, Name, Code} from "./code"
export {Scope, ScopeStore, ValueScope, ValueScopeName, ScopeValueSets, varKinds} from "./scope"

// type for expressions that can be safely inserted in code without quotes
Expand Down
14 changes: 8 additions & 6 deletions lib/vocabularies/format/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
ErrorObject,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, nil, or, Code, getProperty} from "../../compile/codegen"
import {_, str, nil, or, Code, getProperty, regexpCode} from "../../compile/codegen"

type FormatValidate =
| FormatValidator<string>
Expand Down Expand Up @@ -92,11 +92,13 @@ const def: CodeKeywordDefinition = {
}

function getFormat(fmtDef: AddedFormat): [string, FormatValidate, Code] {
const fmt = gen.scopeValue("formats", {
key: schema,
ref: fmtDef,
code: opts.code.formats ? _`${opts.code.formats}${getProperty(schema)}` : undefined,
})
const code =
fmtDef instanceof RegExp
? regexpCode(fmtDef)
: opts.code.formats
? _`${opts.code.formats}${getProperty(schema)}`
: undefined
const fmt = gen.scopeValue("formats", {key: schema, ref: fmtDef, code})
if (typeof fmtDef == "object" && !(fmtDef instanceof RegExp)) {
return [fmtDef.type || "string", fmtDef.validate, _`${fmt}.validate`]
}
Expand Down
32 changes: 32 additions & 0 deletions spec/standalone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,36 @@ describe("standalone code generation", () => {
assert.strictEqual(validateUser({email: "foo@bar.com"}), true)
})
})

describe("standalone code with RegExp format", () => {
const schema = {
$schema: "http://json-schema.org/draft-07/schema#",
definitions: {
User: {
type: "object",
properties: {
username: {
type: "string",
format: "username",
},
},
required: ["username"],
additionalProperties: false,
},
},
}

it("should support RegExp format with standalone code", () => {
const ajv = new _Ajv({code: {source: true}})
ajv.addFormat("username", /[a-z][a-z0-9_]*/i)
ajv.addSchema(schema)
const moduleCode = standaloneCode(ajv, {validateUser: "#/definitions/User"})
const {validateUser} = requireFromString(moduleCode)

assert(typeof validateUser == "function")
assert.strictEqual(validateUser({}), false)
assert.strictEqual(validateUser({username: "foo_bar"}), true)
assert.strictEqual(validateUser({email: "foo bar"}), false)
})
})
})

0 comments on commit ec1818b

Please sign in to comment.