context.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getData = void 0;
  4. const dataType_1 = require("./validate/dataType");
  5. const util_1 = require("./util");
  6. const errors_1 = require("./errors");
  7. const codegen_1 = require("./codegen");
  8. const names_1 = require("./names");
  9. const subschema_1 = require("./subschema");
  10. class KeywordCxt {
  11. constructor(it, def, keyword) {
  12. validateKeywordUsage(it, def, keyword);
  13. this.gen = it.gen;
  14. this.allErrors = it.allErrors;
  15. this.keyword = keyword;
  16. this.data = it.data;
  17. this.schema = it.schema[keyword];
  18. this.$data = def.$data && it.opts.$data && this.schema && this.schema.$data;
  19. this.schemaValue = util_1.schemaRefOrVal(it, this.schema, keyword, this.$data);
  20. this.schemaType = def.schemaType;
  21. this.parentSchema = it.schema;
  22. this.params = {};
  23. this.it = it;
  24. this.def = def;
  25. if (this.$data) {
  26. this.schemaCode = it.gen.const("vSchema", getData(this.$data, it));
  27. }
  28. else {
  29. this.schemaCode = this.schemaValue;
  30. if (!validSchemaType(this.schema, def.schemaType, def.allowUndefined)) {
  31. throw new Error(`${keyword} value must be ${JSON.stringify(def.schemaType)}`);
  32. }
  33. }
  34. if ("code" in def ? def.trackErrors : def.errors !== false) {
  35. this.errsCount = it.gen.const("_errs", names_1.default.errors);
  36. }
  37. }
  38. result(condition, successAction, failAction) {
  39. this.gen.if(codegen_1.not(condition));
  40. if (failAction)
  41. failAction();
  42. else
  43. this.error();
  44. if (successAction) {
  45. this.gen.else();
  46. successAction();
  47. if (this.allErrors)
  48. this.gen.endIf();
  49. }
  50. else {
  51. if (this.allErrors)
  52. this.gen.endIf();
  53. else
  54. this.gen.else();
  55. }
  56. }
  57. pass(condition, failAction) {
  58. this.result(condition, undefined, failAction);
  59. }
  60. fail(condition) {
  61. if (condition === undefined) {
  62. this.error();
  63. if (!this.allErrors)
  64. this.gen.if(false); // this branch will be removed by gen.optimize
  65. return;
  66. }
  67. this.gen.if(condition);
  68. this.error();
  69. if (this.allErrors)
  70. this.gen.endIf();
  71. else
  72. this.gen.else();
  73. }
  74. fail$data(condition) {
  75. if (!this.$data)
  76. return this.fail(condition);
  77. const { schemaCode } = this;
  78. this.fail(codegen_1._ `${schemaCode} !== undefined && (${codegen_1.or(this.invalid$data(), condition)})`);
  79. }
  80. error(append) {
  81. ;
  82. (append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error || errors_1.keywordError);
  83. }
  84. $dataError() {
  85. errors_1.reportError(this, this.def.$dataError || errors_1.keyword$DataError);
  86. }
  87. reset() {
  88. if (this.errsCount === undefined)
  89. throw new Error('add "trackErrors" to keyword definition');
  90. errors_1.resetErrorsCount(this.gen, this.errsCount);
  91. }
  92. ok(cond) {
  93. if (!this.allErrors)
  94. this.gen.if(cond);
  95. }
  96. setParams(obj, assign) {
  97. if (assign)
  98. Object.assign(this.params, obj);
  99. else
  100. this.params = obj;
  101. }
  102. block$data(valid, codeBlock, $dataValid = codegen_1.nil) {
  103. this.gen.block(() => {
  104. this.check$data(valid, $dataValid);
  105. codeBlock();
  106. });
  107. }
  108. check$data(valid = codegen_1.nil, $dataValid = codegen_1.nil) {
  109. if (!this.$data)
  110. return;
  111. const { gen, schemaCode, schemaType, def } = this;
  112. gen.if(codegen_1.or(codegen_1._ `${schemaCode} === undefined`, $dataValid));
  113. if (valid !== codegen_1.nil)
  114. gen.assign(valid, true);
  115. if (schemaType.length || def.validateSchema) {
  116. gen.elseIf(this.invalid$data());
  117. this.$dataError();
  118. if (valid !== codegen_1.nil)
  119. gen.assign(valid, false);
  120. }
  121. gen.else();
  122. }
  123. invalid$data() {
  124. const { gen, schemaCode, schemaType, def, it } = this;
  125. return codegen_1.or(wrong$DataType(), invalid$DataSchema());
  126. function wrong$DataType() {
  127. if (schemaType.length) {
  128. /* istanbul ignore if */
  129. if (!(schemaCode instanceof codegen_1.Name))
  130. throw new Error("ajv implementation error");
  131. const st = Array.isArray(schemaType) ? schemaType : [schemaType];
  132. return codegen_1._ `${dataType_1.checkDataTypes(st, schemaCode, it.opts.strict, dataType_1.DataType.Wrong)}`;
  133. }
  134. return codegen_1.nil;
  135. }
  136. function invalid$DataSchema() {
  137. if (def.validateSchema) {
  138. const validateSchemaRef = gen.scopeValue("validate$data", { ref: def.validateSchema }); // TODO value.code for standalone
  139. return codegen_1._ `!${validateSchemaRef}(${schemaCode})`;
  140. }
  141. return codegen_1.nil;
  142. }
  143. }
  144. subschema(appl, valid) {
  145. return subschema_1.applySubschema(this.it, appl, valid);
  146. }
  147. mergeEvaluated(schemaCxt, toName) {
  148. const { it, gen } = this;
  149. if (!it.opts.unevaluated)
  150. return;
  151. if (it.props !== true && schemaCxt.props !== undefined) {
  152. it.props = util_1.mergeEvaluated.props(gen, schemaCxt.props, it.props, toName);
  153. }
  154. if (it.items !== true && schemaCxt.items !== undefined) {
  155. it.items = util_1.mergeEvaluated.items(gen, schemaCxt.items, it.items, toName);
  156. }
  157. }
  158. mergeValidEvaluated(schemaCxt, valid) {
  159. const { it, gen } = this;
  160. if (it.opts.unevaluated && (it.props !== true || it.items !== true)) {
  161. gen.if(valid, () => this.mergeEvaluated(schemaCxt, codegen_1.Name));
  162. return true;
  163. }
  164. }
  165. }
  166. exports.default = KeywordCxt;
  167. function validSchemaType(schema, schemaType, allowUndefined = false) {
  168. // TODO add tests
  169. return (!schemaType.length ||
  170. schemaType.some((st) => st === "array"
  171. ? Array.isArray(schema)
  172. : st === "object"
  173. ? schema && typeof schema == "object" && !Array.isArray(schema)
  174. : typeof schema == st || (allowUndefined && typeof schema == "undefined")));
  175. }
  176. function validateKeywordUsage({ schema, opts, self }, def, keyword) {
  177. /* istanbul ignore if */
  178. if (Array.isArray(def.keyword) ? !def.keyword.includes(keyword) : def.keyword !== keyword) {
  179. throw new Error("ajv implementation error");
  180. }
  181. const deps = def.dependencies;
  182. if (deps === null || deps === void 0 ? void 0 : deps.some((kwd) => !Object.prototype.hasOwnProperty.call(schema, kwd))) {
  183. throw new Error(`parent schema must have dependencies of ${keyword}: ${deps.join(",")}`);
  184. }
  185. if (def.validateSchema) {
  186. const valid = def.validateSchema(schema[keyword]);
  187. if (!valid) {
  188. const msg = "keyword value is invalid: " + self.errorsText(def.validateSchema.errors);
  189. if (opts.validateSchema === "log")
  190. self.logger.error(msg);
  191. else
  192. throw new Error(msg);
  193. }
  194. }
  195. }
  196. const JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
  197. const RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
  198. function getData($data, { dataLevel, dataNames, dataPathArr }) {
  199. let jsonPointer;
  200. let data;
  201. if ($data === "")
  202. return names_1.default.rootData;
  203. if ($data[0] === "/") {
  204. if (!JSON_POINTER.test($data))
  205. throw new Error(`Invalid JSON-pointer: ${$data}`);
  206. jsonPointer = $data;
  207. data = names_1.default.rootData;
  208. }
  209. else {
  210. const matches = RELATIVE_JSON_POINTER.exec($data);
  211. if (!matches)
  212. throw new Error(`Invalid JSON-pointer: ${$data}`);
  213. const up = +matches[1];
  214. jsonPointer = matches[2];
  215. if (jsonPointer === "#") {
  216. if (up >= dataLevel)
  217. throw new Error(errorMsg("property/index", up));
  218. return dataPathArr[dataLevel - up];
  219. }
  220. if (up > dataLevel)
  221. throw new Error(errorMsg("data", up));
  222. data = dataNames[dataLevel - up];
  223. if (!jsonPointer)
  224. return data;
  225. }
  226. let expr = data;
  227. const segments = jsonPointer.split("/");
  228. for (const segment of segments) {
  229. if (segment) {
  230. data = codegen_1._ `${data}${codegen_1.getProperty(util_1.unescapeJsonPointer(segment))}`;
  231. expr = codegen_1._ `${expr} && ${data}`;
  232. }
  233. }
  234. return expr;
  235. function errorMsg(pointerType, up) {
  236. return `Cannot access ${pointerType} ${up} levels up, current level is ${dataLevel}`;
  237. }
  238. }
  239. exports.getData = getData;
  240. //# sourceMappingURL=context.js.map