diff --git a/declarations/util/memorize.d.ts b/declarations/util/memorize.d.ts new file mode 100644 index 0000000..5c9968f --- /dev/null +++ b/declarations/util/memorize.d.ts @@ -0,0 +1,7 @@ +export default memoize; +/** + * @template T + * @param fn {(function(): any) | undefined} + * @returns {function(): T} + */ +declare function memoize(fn: (() => any) | undefined): () => T; diff --git a/src/ValidationError.js b/src/ValidationError.js index bc026b8..cec8556 100644 --- a/src/ValidationError.js +++ b/src/ValidationError.js @@ -1,4 +1,4 @@ -const { stringHints, numberHints } = require("./util/hints"); +import memoize from "./util/memorize"; /** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */ /** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */ @@ -384,6 +384,11 @@ function formatHints(hints) { return hints.length > 0 ? `(${hints.join(", ")})` : ""; } +const getUtilHints = memoize(() => + // eslint-disable-next-line global-require + require("./util/hints") +); + /** * @param {Schema} schema * @param {boolean} logic @@ -391,9 +396,13 @@ function formatHints(hints) { */ function getHints(schema, logic) { if (likeNumber(schema) || likeInteger(schema)) { - return numberHints(schema, logic); + const util = getUtilHints(); + + return util.numberHints(schema, logic); } else if (likeString(schema)) { - return stringHints(schema, logic); + const util = getUtilHints(); + + return util.stringHints(schema, logic); } return []; diff --git a/src/util/memorize.js b/src/util/memorize.js new file mode 100644 index 0000000..414185e --- /dev/null +++ b/src/util/memorize.js @@ -0,0 +1,26 @@ +/** + * @template T + * @param fn {(function(): any) | undefined} + * @returns {function(): T} + */ +const memoize = (fn) => { + let cache = false; + /** @type {T} */ + let result; + + return () => { + if (cache) { + return result; + } + result = /** @type {function(): any} */ (fn)(); + cache = true; + // Allow to clean up memory for fn + // and all dependent resources + // eslint-disable-next-line no-undefined, no-param-reassign + fn = undefined; + + return result; + }; +}; + +export default memoize; diff --git a/src/validate.js b/src/validate.js index a072407..a361ecc 100644 --- a/src/validate.js +++ b/src/validate.js @@ -1,32 +1,5 @@ -import addAbsolutePathKeyword from "./keywords/absolutePath"; -import addUndefinedAsNullKeyword from "./keywords/undefinedAsNull"; - import ValidationError from "./ValidationError"; - -/** - * @template T - * @param fn {(function(): any) | undefined} - * @returns {function(): T} - */ -const memoize = (fn) => { - let cache = false; - /** @type {T} */ - let result; - - return () => { - if (cache) { - return result; - } - result = /** @type {function(): any} */ (fn)(); - cache = true; - // Allow to clean up memory for fn - // and all dependent resources - // eslint-disable-next-line no-undefined, no-param-reassign - fn = undefined; - - return result; - }; -}; +import memoize from "./util/memorize"; const getAjv = memoize(() => { // Use CommonJS require for ajv libs so TypeScript consumers aren't locked into esModuleInterop (see #110). @@ -51,7 +24,15 @@ const getAjv = memoize(() => { addFormats(ajv, { keywords: true }); // Custom keywords + // eslint-disable-next-line global-require + const addAbsolutePathKeyword = require("./keywords/absolutePath").default; + addAbsolutePathKeyword(ajv); + + const addUndefinedAsNullKeyword = + // eslint-disable-next-line global-require + require("./keywords/undefinedAsNull").default; + addUndefinedAsNullKeyword(ajv); return ajv;