Skip to content

Commit f13a09a

Browse files
committed
feat: support keywords written in typescript
1 parent be01c4c commit f13a09a

File tree

6 files changed

+64
-2
lines changed

6 files changed

+64
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Multiple meta-schemas can be passed, as in `-r` parameter.
8888
##### `-c` - custom keywords/formats definitions
8989

9090
You can pass module(s) that define custom keywords/formats. The modules should export a function that accepts Ajv instance as a parameter. The file name should start with ".", it will be resolved relative to the current folder. The package name can also be passed - it will be used in require as is.
91+
These modules can be written in TypeScript if you have `ts-node` installed.
9192

9293
For example, you can use `-c ajv-keywords` to add all keywords from [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package or `-c ajv-keywords/keywords/typeof` to add only typeof keyword.
9394

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@
6666
"ts-node": "^9.1.0",
6767
"typescript": "^4.1.2"
6868
},
69+
"peerDependencies": {
70+
"ts-node": ">=9.0.0"
71+
},
72+
"peerDependenciesMeta": {
73+
"ts-node": {
74+
"optional": true
75+
}
76+
},
6977
"prettier": "@ajv-validator/config/prettierrc.json",
7078
"husky": {
7179
"hooks": {

src/commands/ajv.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
import type AjvCore from "ajv/dist/core"
22
import type {ParsedArgs} from "minimist"
3-
import Ajv7 from "ajv"
3+
import Ajv7, {Plugin} from "ajv"
44
import Ajv2019 from "ajv/dist/2019"
5+
import {Service} from "ts-node"
56
import {getOptions} from "./options"
67
import util = require("./util")
78
import path = require("path")
89
import draft6metaSchema = require("ajv/lib/refs/json-schema-draft-06.json")
910

1011
type AjvMethod = "addSchema" | "addMetaSchema"
1112

13+
// copied from https://github.com/babel/babel/blob/d8da63c929f2d28c401571e2a43166678c555bc4/packages/babel-helpers/src/helpers.js#L602-L606
14+
/* istanbul ignore next */
15+
const interopRequireDefault = (obj: any): {default: any} =>
16+
obj && obj.__esModule ? obj : {default: obj}
17+
18+
const importDefault = <T = unknown>(moduleName: string): T =>
19+
interopRequireDefault(require(moduleName)).default
20+
1221
export default function (argv: ParsedArgs): AjvCore {
1322
const opts = getOptions(argv)
1423
if (argv.o) opts.code.source = true
@@ -43,12 +52,39 @@ export default function (argv: ParsedArgs): AjvCore {
4352
files.forEach((file) => {
4453
if (file[0] === ".") file = path.resolve(process.cwd(), file)
4554
try {
46-
require(file)(ajv)
55+
if (file.endsWith(".ts")) {
56+
requireTypeScriptKeyword(file)
57+
} else {
58+
require(file)(ajv)
59+
}
4760
} catch (err) {
4861
console.error(`module ${file} is invalid; it should export function`)
4962
console.error(`error: ${(err as Error).message}`)
5063
invalid = true
5164
}
5265
})
5366
}
67+
68+
function requireTypeScriptKeyword(file: string): void {
69+
let registerer: Service
70+
71+
try {
72+
registerer = require("ts-node").register()
73+
} catch (err) {
74+
/* istanbul ignore next */
75+
if (err.code === "MODULE_NOT_FOUND") {
76+
throw new Error(
77+
`'ts-node' is required for the TypeScript configuration files. Make sure it is installed\nError: ${err.message}`
78+
)
79+
}
80+
81+
throw err
82+
}
83+
84+
registerer.enabled(true)
85+
86+
importDefault<Plugin<undefined>>(file)(ajv)
87+
88+
registerer.enabled(false)
89+
}
5490
}

test/compile.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ describe("compile", function () {
9898
)
9999
})
100100

101+
it("should compile schema with custom keyword written in typescript", (done) => {
102+
cli(
103+
"compile -s test/custom/schema -c ./test/custom/typeof_ts.ts -o test/custom/validate_schema.js",
104+
(error, stdout, stderr) => {
105+
assertCompiledCustom(error, stdout, stderr)
106+
done()
107+
}
108+
)
109+
})
110+
101111
it("should fail to compile invalid schema with a custom meta-schema", (done) => {
102112
cli("compile -s test/meta/invalid_schema -m test/meta/meta_schema", (error, stdout, stderr) => {
103113
assert(error instanceof Error)

test/custom/invalid_custom_ts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export = [];

test/custom/typeof_ts.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import ajvKeywords from "ajv-keywords"
2+
import {Plugin} from "ajv"
3+
4+
const typeofPlugin: Plugin<undefined> = (ajv) => ajvKeywords(ajv, "typeof")
5+
6+
export default typeofPlugin

0 commit comments

Comments
 (0)