[6a3a178] | 1 | "use strict";
|
---|
| 2 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 3 | exports.reportTypeError = exports.checkDataTypes = exports.checkDataType = exports.coerceAndCheckDataType = exports.getJSONTypes = exports.getSchemaTypes = exports.DataType = void 0;
|
---|
| 4 | const rules_1 = require("../rules");
|
---|
| 5 | const applicability_1 = require("./applicability");
|
---|
| 6 | const errors_1 = require("../errors");
|
---|
| 7 | const codegen_1 = require("../codegen");
|
---|
| 8 | const util_1 = require("../util");
|
---|
| 9 | var DataType;
|
---|
| 10 | (function (DataType) {
|
---|
| 11 | DataType[DataType["Correct"] = 0] = "Correct";
|
---|
| 12 | DataType[DataType["Wrong"] = 1] = "Wrong";
|
---|
| 13 | })(DataType = exports.DataType || (exports.DataType = {}));
|
---|
| 14 | function getSchemaTypes(schema) {
|
---|
| 15 | const types = getJSONTypes(schema.type);
|
---|
| 16 | const hasNull = types.includes("null");
|
---|
| 17 | if (hasNull) {
|
---|
| 18 | if (schema.nullable === false)
|
---|
| 19 | throw new Error("type: null contradicts nullable: false");
|
---|
| 20 | }
|
---|
| 21 | else {
|
---|
| 22 | if (!types.length && schema.nullable !== undefined) {
|
---|
| 23 | throw new Error('"nullable" cannot be used without "type"');
|
---|
| 24 | }
|
---|
| 25 | if (schema.nullable === true)
|
---|
| 26 | types.push("null");
|
---|
| 27 | }
|
---|
| 28 | return types;
|
---|
| 29 | }
|
---|
| 30 | exports.getSchemaTypes = getSchemaTypes;
|
---|
| 31 | function getJSONTypes(ts) {
|
---|
| 32 | const types = Array.isArray(ts) ? ts : ts ? [ts] : [];
|
---|
| 33 | if (types.every(rules_1.isJSONType))
|
---|
| 34 | return types;
|
---|
| 35 | throw new Error("type must be JSONType or JSONType[]: " + types.join(","));
|
---|
| 36 | }
|
---|
| 37 | exports.getJSONTypes = getJSONTypes;
|
---|
| 38 | function coerceAndCheckDataType(it, types) {
|
---|
| 39 | const { gen, data, opts } = it;
|
---|
| 40 | const coerceTo = coerceToTypes(types, opts.coerceTypes);
|
---|
| 41 | const checkTypes = types.length > 0 &&
|
---|
| 42 | !(coerceTo.length === 0 && types.length === 1 && applicability_1.schemaHasRulesForType(it, types[0]));
|
---|
| 43 | if (checkTypes) {
|
---|
| 44 | const wrongType = checkDataTypes(types, data, opts.strictNumbers, DataType.Wrong);
|
---|
| 45 | gen.if(wrongType, () => {
|
---|
| 46 | if (coerceTo.length)
|
---|
| 47 | coerceData(it, types, coerceTo);
|
---|
| 48 | else
|
---|
| 49 | reportTypeError(it);
|
---|
| 50 | });
|
---|
| 51 | }
|
---|
| 52 | return checkTypes;
|
---|
| 53 | }
|
---|
| 54 | exports.coerceAndCheckDataType = coerceAndCheckDataType;
|
---|
| 55 | const COERCIBLE = new Set(["string", "number", "integer", "boolean", "null"]);
|
---|
| 56 | function coerceToTypes(types, coerceTypes) {
|
---|
| 57 | return coerceTypes
|
---|
| 58 | ? types.filter((t) => COERCIBLE.has(t) || (coerceTypes === "array" && t === "array"))
|
---|
| 59 | : [];
|
---|
| 60 | }
|
---|
| 61 | function coerceData(it, types, coerceTo) {
|
---|
| 62 | const { gen, data, opts } = it;
|
---|
| 63 | const dataType = gen.let("dataType", codegen_1._ `typeof ${data}`);
|
---|
| 64 | const coerced = gen.let("coerced", codegen_1._ `undefined`);
|
---|
| 65 | if (opts.coerceTypes === "array") {
|
---|
| 66 | gen.if(codegen_1._ `${dataType} == 'object' && Array.isArray(${data}) && ${data}.length == 1`, () => gen
|
---|
| 67 | .assign(data, codegen_1._ `${data}[0]`)
|
---|
| 68 | .assign(dataType, codegen_1._ `typeof ${data}`)
|
---|
| 69 | .if(checkDataTypes(types, data, opts.strictNumbers), () => gen.assign(coerced, data)));
|
---|
| 70 | }
|
---|
| 71 | gen.if(codegen_1._ `${coerced} !== undefined`);
|
---|
| 72 | for (const t of coerceTo) {
|
---|
| 73 | if (COERCIBLE.has(t) || (t === "array" && opts.coerceTypes === "array")) {
|
---|
| 74 | coerceSpecificType(t);
|
---|
| 75 | }
|
---|
| 76 | }
|
---|
| 77 | gen.else();
|
---|
| 78 | reportTypeError(it);
|
---|
| 79 | gen.endIf();
|
---|
| 80 | gen.if(codegen_1._ `${coerced} !== undefined`, () => {
|
---|
| 81 | gen.assign(data, coerced);
|
---|
| 82 | assignParentData(it, coerced);
|
---|
| 83 | });
|
---|
| 84 | function coerceSpecificType(t) {
|
---|
| 85 | switch (t) {
|
---|
| 86 | case "string":
|
---|
| 87 | gen
|
---|
| 88 | .elseIf(codegen_1._ `${dataType} == "number" || ${dataType} == "boolean"`)
|
---|
| 89 | .assign(coerced, codegen_1._ `"" + ${data}`)
|
---|
| 90 | .elseIf(codegen_1._ `${data} === null`)
|
---|
| 91 | .assign(coerced, codegen_1._ `""`);
|
---|
| 92 | return;
|
---|
| 93 | case "number":
|
---|
| 94 | gen
|
---|
| 95 | .elseIf(codegen_1._ `${dataType} == "boolean" || ${data} === null
|
---|
| 96 | || (${dataType} == "string" && ${data} && ${data} == +${data})`)
|
---|
| 97 | .assign(coerced, codegen_1._ `+${data}`);
|
---|
| 98 | return;
|
---|
| 99 | case "integer":
|
---|
| 100 | gen
|
---|
| 101 | .elseIf(codegen_1._ `${dataType} === "boolean" || ${data} === null
|
---|
| 102 | || (${dataType} === "string" && ${data} && ${data} == +${data} && !(${data} % 1))`)
|
---|
| 103 | .assign(coerced, codegen_1._ `+${data}`);
|
---|
| 104 | return;
|
---|
| 105 | case "boolean":
|
---|
| 106 | gen
|
---|
| 107 | .elseIf(codegen_1._ `${data} === "false" || ${data} === 0 || ${data} === null`)
|
---|
| 108 | .assign(coerced, false)
|
---|
| 109 | .elseIf(codegen_1._ `${data} === "true" || ${data} === 1`)
|
---|
| 110 | .assign(coerced, true);
|
---|
| 111 | return;
|
---|
| 112 | case "null":
|
---|
| 113 | gen.elseIf(codegen_1._ `${data} === "" || ${data} === 0 || ${data} === false`);
|
---|
| 114 | gen.assign(coerced, null);
|
---|
| 115 | return;
|
---|
| 116 | case "array":
|
---|
| 117 | gen
|
---|
| 118 | .elseIf(codegen_1._ `${dataType} === "string" || ${dataType} === "number"
|
---|
| 119 | || ${dataType} === "boolean" || ${data} === null`)
|
---|
| 120 | .assign(coerced, codegen_1._ `[${data}]`);
|
---|
| 121 | }
|
---|
| 122 | }
|
---|
| 123 | }
|
---|
| 124 | function assignParentData({ gen, parentData, parentDataProperty }, expr) {
|
---|
| 125 | // TODO use gen.property
|
---|
| 126 | gen.if(codegen_1._ `${parentData} !== undefined`, () => gen.assign(codegen_1._ `${parentData}[${parentDataProperty}]`, expr));
|
---|
| 127 | }
|
---|
| 128 | function checkDataType(dataType, data, strictNums, correct = DataType.Correct) {
|
---|
| 129 | const EQ = correct === DataType.Correct ? codegen_1.operators.EQ : codegen_1.operators.NEQ;
|
---|
| 130 | let cond;
|
---|
| 131 | switch (dataType) {
|
---|
| 132 | case "null":
|
---|
| 133 | return codegen_1._ `${data} ${EQ} null`;
|
---|
| 134 | case "array":
|
---|
| 135 | cond = codegen_1._ `Array.isArray(${data})`;
|
---|
| 136 | break;
|
---|
| 137 | case "object":
|
---|
| 138 | cond = codegen_1._ `${data} && typeof ${data} == "object" && !Array.isArray(${data})`;
|
---|
| 139 | break;
|
---|
| 140 | case "integer":
|
---|
| 141 | cond = numCond(codegen_1._ `!(${data} % 1) && !isNaN(${data})`);
|
---|
| 142 | break;
|
---|
| 143 | case "number":
|
---|
| 144 | cond = numCond();
|
---|
| 145 | break;
|
---|
| 146 | default:
|
---|
| 147 | return codegen_1._ `typeof ${data} ${EQ} ${dataType}`;
|
---|
| 148 | }
|
---|
| 149 | return correct === DataType.Correct ? cond : codegen_1.not(cond);
|
---|
| 150 | function numCond(_cond = codegen_1.nil) {
|
---|
| 151 | return codegen_1.and(codegen_1._ `typeof ${data} == "number"`, _cond, strictNums ? codegen_1._ `isFinite(${data})` : codegen_1.nil);
|
---|
| 152 | }
|
---|
| 153 | }
|
---|
| 154 | exports.checkDataType = checkDataType;
|
---|
| 155 | function checkDataTypes(dataTypes, data, strictNums, correct) {
|
---|
| 156 | if (dataTypes.length === 1) {
|
---|
| 157 | return checkDataType(dataTypes[0], data, strictNums, correct);
|
---|
| 158 | }
|
---|
| 159 | let cond;
|
---|
| 160 | const types = util_1.toHash(dataTypes);
|
---|
| 161 | if (types.array && types.object) {
|
---|
| 162 | const notObj = codegen_1._ `typeof ${data} != "object"`;
|
---|
| 163 | cond = types.null ? notObj : codegen_1._ `!${data} || ${notObj}`;
|
---|
| 164 | delete types.null;
|
---|
| 165 | delete types.array;
|
---|
| 166 | delete types.object;
|
---|
| 167 | }
|
---|
| 168 | else {
|
---|
| 169 | cond = codegen_1.nil;
|
---|
| 170 | }
|
---|
| 171 | if (types.number)
|
---|
| 172 | delete types.integer;
|
---|
| 173 | for (const t in types)
|
---|
| 174 | cond = codegen_1.and(cond, checkDataType(t, data, strictNums, correct));
|
---|
| 175 | return cond;
|
---|
| 176 | }
|
---|
| 177 | exports.checkDataTypes = checkDataTypes;
|
---|
| 178 | const typeError = {
|
---|
| 179 | message: ({ schema }) => `must be ${schema}`,
|
---|
| 180 | params: ({ schema, schemaValue }) => typeof schema == "string" ? codegen_1._ `{type: ${schema}}` : codegen_1._ `{type: ${schemaValue}}`,
|
---|
| 181 | };
|
---|
| 182 | function reportTypeError(it) {
|
---|
| 183 | const cxt = getTypeErrorContext(it);
|
---|
| 184 | errors_1.reportError(cxt, typeError);
|
---|
| 185 | }
|
---|
| 186 | exports.reportTypeError = reportTypeError;
|
---|
| 187 | function getTypeErrorContext(it) {
|
---|
| 188 | const { gen, data, schema } = it;
|
---|
| 189 | const schemaCode = util_1.schemaRefOrVal(it, schema, "type");
|
---|
| 190 | return {
|
---|
| 191 | gen,
|
---|
| 192 | keyword: "type",
|
---|
| 193 | data,
|
---|
| 194 | schema: schema.type,
|
---|
| 195 | schemaCode,
|
---|
| 196 | schemaValue: schemaCode,
|
---|
| 197 | parentSchema: schema,
|
---|
| 198 | params: {},
|
---|
| 199 | it,
|
---|
| 200 | };
|
---|
| 201 | }
|
---|
| 202 | //# sourceMappingURL=dataType.js.map |
---|