Skip to content

Commit

Permalink
feat: add option to generate ESM exports instead of CJS (ajv-validato…
Browse files Browse the repository at this point in the history
…r#1523)

- Renamed exportEsm to esm
- Extracted common code
- Changed invalid export names to rather throw an error
  • Loading branch information
Rehan committed Dec 20, 2021
1 parent 2244421 commit 61ec10e
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 31 deletions.
2 changes: 1 addition & 1 deletion docs/guide/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ The default configuration of AJV is to generate code in ES6 with Common JS (CJS)
the ES Modules(ESM) flag.

```javascript
const ajv = new Ajv({code: {exportEsm: true}})
const ajv = new Ajv({code: {esm: true}})
```

## Other JavaScript environments
Expand Down
4 changes: 2 additions & 2 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const defaultOptions = {
code: {
// NEW
es5: false,
exportEsm: false,
esm: false,
lines: false,
source: false,
process: undefined, // (code: string) => string
Expand Down Expand Up @@ -348,7 +348,7 @@ Code generation options:
```typescript
type CodeOptions = {
es5?: boolean // to generate es5 code - by default code is es6, with "for-of" loops, "let" and "const"
exportEsm?: boolean // how functions should be exported - by default CJS is used, so the validate function(s)
esm?: boolean // how functions should be exported - by default CJS is used, so the validate function(s)
// file can be `required`. Set this value to true to export the validate function(s) as ES Modules, enabling
// bunlers to do their job.
lines?: boolean // add line-breaks to code - to simplify debugging of generated functions
Expand Down
7 changes: 1 addition & 6 deletions lib/compile/codegen/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,7 @@ export function getEsmExportName(key: Code | string | number): Code {
if (typeof key == "string" && IDENTIFIER.test(key)) {
return new _Code(`${key}`)
}
const name = key.toString()
let newName = name.replace(/[^\w$_]|[\s]/gi, "_")
if (/^[0-9]/.test(name)) {
newName = "_" + newName
}
return new _Code(`${newName}`)
throw new Error(`CodeGen: invalid export name: ${key}, use explicit $id name mapping`)
}

export function regexpCode(rx: RegExp): Code {
Expand Down
2 changes: 1 addition & 1 deletion lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export interface CurrentOptions {

export interface CodeOptions {
es5?: boolean
exportEsm?: boolean
esm?: boolean
lines?: boolean
optimize?: boolean | number
formats?: Code // code to require (or construct) map of available formats - for standalone code
Expand Down
15 changes: 5 additions & 10 deletions lib/standalone/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function standaloneCode(
const usedValues: UsedScopeValues = {}
const n = source?.validateName
const vCode = validateCode(usedValues, source)
if (ajv.opts.code.exportEsm) {
if (ajv.opts.code.esm) {
// Always do named export as `validate` rather than the variable `n` which is `validateXX` for known export value
return `"use strict";${_n}export const validate = ${n};${_n}export default ${n};${_n}${vCode}`
}
Expand All @@ -47,15 +47,10 @@ function standaloneCode(
const v = getValidateFunc(schemas[name] as T)
if (v) {
const vCode = validateCode(usedValues, v.source)
if (ajv.opts.code.exportEsm) {
code = _`${code}${_n}export const ${getEsmExportName(name)} = ${
v.source?.validateName
};${_n}${vCode}`
} else {
code = _`${code}${_n}exports${getProperty(name)} = ${
v.source?.validateName
};${_n}${vCode}`
}
const exportSyntax = ajv.opts.code.esm
? _`export const ${getEsmExportName(name)}`
: _`exports${getProperty(name)}`
code = _`${code}${_n}${exportSyntax} = ${v.source?.validateName};${_n}${vCode}`
}
}
return `${code}`
Expand Down
29 changes: 18 additions & 11 deletions spec/standalone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe("standalone code generation", () => {
})

it("should generate module code with named export - ESM", () => {
ajv = new _Ajv({code: {source: true, exportEsm: true}})
ajv = new _Ajv({code: {source: true, esm: true}})
ajv.addSchema(numSchema)
ajv.addSchema(strSchema)
const moduleCode = standaloneCode(ajv, {
Expand Down Expand Up @@ -85,17 +85,24 @@ describe("standalone code generation", () => {
})

it("should generate module code with all exports - ESM", () => {
ajv = new _Ajv({code: {source: true, exportEsm: true}})
ajv = new _Ajv({code: {source: true, esm: true}})
ajv.addSchema(numSchema)
ajv.addSchema(strSchema)
const moduleCode = standaloneCode(ajv)
testExportTypeEsm(moduleCode, false)
const m = importFromStringSync(moduleCode)
assert.strictEqual(Object.keys(m).length, 2)
testExports({
validateNumber: m.https___example_com_number_json,
validateString: m.https___example_com_string_json,
})

try {
standaloneCode(ajv)
} catch (err) {
if (err instanceof Error) {
const isMappingErr =
`CodeGen: invalid export name: ${numSchema.$id}, use explicit $id name mapping` ===
err.message ||
`CodeGen: invalid export name: ${strSchema.$id}, use explicit $id name mapping` ===
err.message
assert.strictEqual(isMappingErr, true)
} else {
throw err
}
}
})
})

Expand Down Expand Up @@ -295,7 +302,7 @@ describe("standalone code generation", () => {
})

it("should generate module code with a single export - ESM", () => {
const ajv = new _Ajv({code: {source: true, exportEsm: true}})
const ajv = new _Ajv({code: {source: true, esm: true}})
const v = ajv.compile({
type: "number",
minimum: 0,
Expand Down

0 comments on commit 61ec10e

Please sign in to comment.