-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
account for ajv.opts.code.esm option in addFormats #73
base: master
Are you sure you want to change the base?
Conversation
One drawback now is that this would output top-level awaits instead of "proper" es6 imports. Additionally, this also happens with non-ajv-format imports if code has been generated with So, in short, all code-generating code would need to handle ES6 imports properly instead of defaulting to commonjs-requires. For anyone needing a workaround to post-process the output of // modify to fit your output of standaloneCode
let moduleCode = standaloneCode(/*...*/);
// regexp to capture the "old" commonjs code
const requireRewriteRegex: RegExp = /const (func\d*) = require\("(.*?)"\)\.default;/m;
// used to find the first possible start position in which to insert the re-written imports
const USE_STRICT_TEXT = "\"use strict\";";
let match: RegExpMatchArray | null = null;
while (match = moduleCode.match(requireRewriteRegex)) {
moduleCode = moduleCode.substring(0, match.index) + moduleCode.substring(match.index + match[0].length);
const useStrictStart = moduleCode.indexOf(USE_STRICT_TEXT);
let insertionIndex = 0;
if (useStrictStart !== -1) {
insertionIndex = useStrictStart + USE_STRICT_TEXT.length;
}
moduleCode = moduleCode.substring(0, insertionIndex) + `import ${match[1]} from "${match[2]}";` + moduleCode.substring(insertionIndex);
}
// write moduleCode to a file or whatever. |
This change seems to make code that uses ajv-format asynchronous, which is a major breaking change to validators. I think converting to |
I hope this code helps someone. const ajv = new Ajv({
formats: { 'iso-date-time': true },
schemas: [schema],
code: {
source: true,
esm: true,
},
});
addFormats(ajv, ['iso-date-time']);
const moduleCode = standaloneCode(ajv, {
validate: schema.$id,
});
const importAjvFormatsDict = new Map();
const splitBySemiColon = moduleCode.split(';');
splitBySemiColon.forEach((item, idx) => {
if (item.includes('require("ajv-formats/dist/formats")')) {
importAjvFormatsDict.set(idx, item);
}
});
importAjvFormatsDict.forEach((value, key) => {
const formatVariable = (value.match(/const formats\d+/) ?? [])[0];
const formatName = value.match(/fullFormats\["(.+?)"\]/)[1];
splitBySemiColon[
key
] = `import { fullFormats } from "ajv-formats/dist/formats";${formatVariable} = fullFormats["${formatName}"]`;
});
fs.writeFileSync(path.join(__dirname, '../src/services/ajv/index.ts'), `// @ts-nocheck\n${splitBySemiColon.join(';')}`); |
@kooku0 thank you, I slightly improved your version to:
let codeRaw = standaloneCode(ajv, validate)
const codeArr = codeRaw.split(`;`)
const mapAjvFormats = new Map<number, string>()
const mapAjvTransform = new Map<number, string>()
codeArr.forEach((item, idx) => {
if (item.includes(`require("ajv-formats/dist/formats")`)) {
return mapAjvFormats.set(idx, item)
}
if (item.includes(`require("ajv-keywords/dist/definitions/transform")`)) {
return mapAjvTransform.set(idx, item)
}
})
mapAjvFormats.forEach((value, key) => {
const varDeclaration = /const formats\d+/.exec(value)![0]
const name = /fullFormats\.(.*)/.exec(value)![1]
codeArr[key] = `${varDeclaration} = fullFormats["${name}"]`
})
mapAjvTransform.forEach((value, key) => {
const varDeclaration = /const func\d+/.exec(value)![0]
const name = /transform\.(.*)/.exec(value)![1]
codeArr[key] = `${varDeclaration} = transformDef.transform["${name}"]`
})
if (mapAjvFormats.size) {
const idx = mapAjvFormats.keys().next().value
codeArr[
idx
] = `import { fullFormats } from "ajv-formats/dist/formats";${codeArr[idx]}`
}
if (mapAjvTransform.size) {
const idx = mapAjvTransform.keys().next().value
codeArr[
idx
] = `import transformDef from "ajv-keywords/dist/definitions/transform";${codeArr[idx]}`
}
codeRaw = codeArr.join(`;`) This is the result in the validator file: import transformDef from "ajv-keywords/dist/definitions/transform"
const func2 = transformDef.transform[`trim`]
const func3 = transformDef.transform[`toLowerCase`]
import { fullFormats } from "ajv-formats/dist/formats"
const formats0 = fullFormats[`int32`] |
Hey @epoberezkin, @ChALkeR, any timeline on when this PR and some of the other open ones can be merged? The module ajv-formats is blowing up in some of my native esm projects currently, because it still has some strange imports like the ones fixed with this PR. It would be great to have a current, completely esm compliant version of ajv-formats available for use in modern projects. |
I arrived here from the error from my use of ajv standalone when updating a project to ES modules. Still very much learning to adapt to ES modules but I did find that appending the following to the top of the standalone output seemed to be a very simple solution:
|
Closes #68
This checks
ajv.opts.code.esm
and uses a dynamicimport
if true, otherwise it uses previous behavior.I'm not sure how best to add a test for this so would be happy to add that based on any suggestions you have.