keyword.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.validateKeywordUsage = exports.validSchemaType = exports.funcKeywordCode = exports.macroKeywordCode = void 0;
  4. const codegen_1 = require("../codegen");
  5. const names_1 = require("../names");
  6. const code_1 = require("../../vocabularies/code");
  7. const errors_1 = require("../errors");
  8. function macroKeywordCode(cxt, def) {
  9. const { gen, keyword, schema, parentSchema, it } = cxt;
  10. const macroSchema = def.macro.call(it.self, schema, parentSchema, it);
  11. const schemaRef = useKeyword(gen, keyword, macroSchema);
  12. if (it.opts.validateSchema !== false)
  13. it.self.validateSchema(macroSchema, true);
  14. const valid = gen.name("valid");
  15. cxt.subschema({
  16. schema: macroSchema,
  17. schemaPath: codegen_1.nil,
  18. errSchemaPath: `${it.errSchemaPath}/${keyword}`,
  19. topSchemaRef: schemaRef,
  20. compositeRule: true,
  21. }, valid);
  22. cxt.pass(valid, () => cxt.error(true));
  23. }
  24. exports.macroKeywordCode = macroKeywordCode;
  25. function funcKeywordCode(cxt, def) {
  26. var _a;
  27. const { gen, keyword, schema, parentSchema, $data, it } = cxt;
  28. checkAsyncKeyword(it, def);
  29. const validate = !$data && def.compile ? def.compile.call(it.self, schema, parentSchema, it) : def.validate;
  30. const validateRef = useKeyword(gen, keyword, validate);
  31. const valid = gen.let("valid");
  32. cxt.block$data(valid, validateKeyword);
  33. cxt.ok((_a = def.valid) !== null && _a !== void 0 ? _a : valid);
  34. function validateKeyword() {
  35. if (def.errors === false) {
  36. assignValid();
  37. if (def.modifying)
  38. modifyData(cxt);
  39. reportErrs(() => cxt.error());
  40. }
  41. else {
  42. const ruleErrs = def.async ? validateAsync() : validateSync();
  43. if (def.modifying)
  44. modifyData(cxt);
  45. reportErrs(() => addErrs(cxt, ruleErrs));
  46. }
  47. }
  48. function validateAsync() {
  49. const ruleErrs = gen.let("ruleErrs", null);
  50. gen.try(() => assignValid((0, codegen_1._) `await `), (e) => gen.assign(valid, false).if((0, codegen_1._) `${e} instanceof ${it.ValidationError}`, () => gen.assign(ruleErrs, (0, codegen_1._) `${e}.errors`), () => gen.throw(e)));
  51. return ruleErrs;
  52. }
  53. function validateSync() {
  54. const validateErrs = (0, codegen_1._) `${validateRef}.errors`;
  55. gen.assign(validateErrs, null);
  56. assignValid(codegen_1.nil);
  57. return validateErrs;
  58. }
  59. function assignValid(_await = def.async ? (0, codegen_1._) `await ` : codegen_1.nil) {
  60. const passCxt = it.opts.passContext ? names_1.default.this : names_1.default.self;
  61. const passSchema = !(("compile" in def && !$data) || def.schema === false);
  62. gen.assign(valid, (0, codegen_1._) `${_await}${(0, code_1.callValidateCode)(cxt, validateRef, passCxt, passSchema)}`, def.modifying);
  63. }
  64. function reportErrs(errors) {
  65. var _a;
  66. gen.if((0, codegen_1.not)((_a = def.valid) !== null && _a !== void 0 ? _a : valid), errors);
  67. }
  68. }
  69. exports.funcKeywordCode = funcKeywordCode;
  70. function modifyData(cxt) {
  71. const { gen, data, it } = cxt;
  72. gen.if(it.parentData, () => gen.assign(data, (0, codegen_1._) `${it.parentData}[${it.parentDataProperty}]`));
  73. }
  74. function addErrs(cxt, errs) {
  75. const { gen } = cxt;
  76. gen.if((0, codegen_1._) `Array.isArray(${errs})`, () => {
  77. gen
  78. .assign(names_1.default.vErrors, (0, codegen_1._) `${names_1.default.vErrors} === null ? ${errs} : ${names_1.default.vErrors}.concat(${errs})`)
  79. .assign(names_1.default.errors, (0, codegen_1._) `${names_1.default.vErrors}.length`);
  80. (0, errors_1.extendErrors)(cxt);
  81. }, () => cxt.error());
  82. }
  83. function checkAsyncKeyword({ schemaEnv }, def) {
  84. if (def.async && !schemaEnv.$async)
  85. throw new Error("async keyword in sync schema");
  86. }
  87. function useKeyword(gen, keyword, result) {
  88. if (result === undefined)
  89. throw new Error(`keyword "${keyword}" failed to compile`);
  90. return gen.scopeValue("keyword", typeof result == "function" ? { ref: result } : { ref: result, code: (0, codegen_1.stringify)(result) });
  91. }
  92. function validSchemaType(schema, schemaType, allowUndefined = false) {
  93. // TODO add tests
  94. return (!schemaType.length ||
  95. schemaType.some((st) => st === "array"
  96. ? Array.isArray(schema)
  97. : st === "object"
  98. ? schema && typeof schema == "object" && !Array.isArray(schema)
  99. : typeof schema == st || (allowUndefined && typeof schema == "undefined")));
  100. }
  101. exports.validSchemaType = validSchemaType;
  102. function validateKeywordUsage({ schema, opts, self, errSchemaPath }, def, keyword) {
  103. /* istanbul ignore if */
  104. if (Array.isArray(def.keyword) ? !def.keyword.includes(keyword) : def.keyword !== keyword) {
  105. throw new Error("ajv implementation error");
  106. }
  107. const deps = def.dependencies;
  108. if (deps === null || deps === void 0 ? void 0 : deps.some((kwd) => !Object.prototype.hasOwnProperty.call(schema, kwd))) {
  109. throw new Error(`parent schema must have dependencies of ${keyword}: ${deps.join(",")}`);
  110. }
  111. if (def.validateSchema) {
  112. const valid = def.validateSchema(schema[keyword]);
  113. if (!valid) {
  114. const msg = `keyword "${keyword}" value is invalid at path "${errSchemaPath}": ` +
  115. self.errorsText(def.validateSchema.errors);
  116. if (opts.validateSchema === "log")
  117. self.logger.error(msg);
  118. else
  119. throw new Error(msg);
  120. }
  121. }
  122. }
  123. exports.validateKeywordUsage = validateKeywordUsage;
  124. //# sourceMappingURL=keyword.js.map