arstotzka 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var A=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var P=(t,n)=>{for(var o in n)A(t,o,{get:n[o],enumerable:!0})},D=(t,n,o,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of _(n))!N.call(t,r)&&r!==o&&A(t,r,{get:()=>n[r],enumerable:!(a=k(n,r))||a.enumerable});return t};var Y=t=>D(A({},"__esModule",{value:!0}),t);var B={};P(B,{ANY_OF:()=>K,ARRAY_OF:()=>L,DYNAMIC:()=>U,ERRORS:()=>F,OPTIONAL:()=>R,isTruthy:()=>q,validate:()=>V});module.exports=Y(B);var F={noProperty:"Required property not present",typeMismatch:"Provided type is not allowed by schema",customFail:"Custom validation function failed",extraProperty:"Provided object contains properties not present in schema",exceptionOnCustom:"Exception thrown during constraint validation",notArray:"Tried using ARRAY_OF constraint on non-array value",targetIsNull:"Passed object or array item is null",functionExpected:"Expected function as dynamic constraint",objectExpected:"Expected object",anyFailed:"None of ANY_OF constraints are met",parsingError:"Schema parsing error",deadError:"This error never occurs (i guess)"},j=t=>n=>typeof n==t,M=t=>Array.isArray(t),S=Symbol(),x=Symbol(),E=Symbol(),O=Symbol(),T=Symbol(),$={allErrors:!0,allowExtraProperties:!0};function V(t,n={},o={}){o=Object.assign($,o);let a=[],[r,p]=m(n,a);p.length>0&&console.error("Flags can't be used at schema's root");let s=b("",t,r,o);return s.push(...a),s.forEach(y=>{y.propertyName?.startsWith(".")&&(y.propertyName=y.propertyName.slice(1))}),s}function m(t,n){function o(e){if(!e)return null;if(typeof e=="object"&&"type"in e&&e.type===S)return e;if(Array.isArray(e))return e.map(o).filter(c=>c);switch(typeof e){case"string":return e=="array"?f(M,"typeMismatch",e):f(j(e),"typeMismatch",e);case"function":return f(e,"customFail",e);case"object":return f(T,"deadError",e);case"symbol":return e}return n.push(u("<schema>","parsingError",void 0,e)),null}let a=o(t)||[];function r(e){return Array.isArray(e)?e:[e]}let p=r(a),s=p.filter(e=>typeof e!="symbol"&&e.type==S),y=p.filter(e=>typeof e=="symbol");return[s,y]}function b(t,n,o,a){let r=[];function p(s){return typeof s=="function"}for(let s of o){let y=s.validation;if(p(y)){let[e,c]=v(()=>y(n));e?c||r.push(u(t,s.failMessageId,"[function]",n)):r.push(u(t,"exceptionOnCustom",void 0,c?.toString()));continue}switch(s.validation){case T:{if(typeof n!="object"||!n){r.push(u(t,"objectExpected","object",n));break}let e=Object.keys(n),c=Object.keys(s.expected);for(let i of c){let[l,h]=m(s.expected[i],r);if(!e.includes(i)){h.includes(R)||r.push(u(`${d(t)}.${i}`,"noProperty"));continue}let g=b(`${d(t)}.${i}`,n[i],l,a);r.push(...g)}if(!a.allowExtraProperties){let i=e.filter(l=>!c.includes(l));i.length>0&&r.push(...i.map(l=>u(`${d(t)}.${l}`,"extraProperty")))}break}case x:{if(!Array.isArray(n)){r.push(u(t,"notArray","array",typeof n));break}let[e,c]=m(s.expected,r),i=0;for(let l of n){let h=b(`${d(t)}[${i}]`,l,e,a);r.push(...h),++i}break}case E:{let e=s.expected,c=[],i=!1,l=0;for(let h of e){let g=[],[I,G]=m(h,g),C=b(`${d(t)}.<any#${l}>`,n,I,a);if(C.push(...g),++l,c.push(C),C.length==0){i=!0;break}}i||r.push(u(t,"anyFailed",void 0,c));break}case O:{let e=s.expected;if(typeof e!="function"){r.push(u(t,"functionExpected","function",typeof e));break}let[c,i]=m(e(n),r),l=b(t,n,c,a);r.push(...l);break}}if(!a.allErrors&&r.length>0)break}return r}function v(t){try{return[!0,t()]}catch(n){return[!1,n]}}function d(t){return typeof t=="symbol"?"[symbol]":String(t)}function u(t,n,o,a){return{propertyName:d(t),id:n,message:F[n],expected:o,got:a}}function f(t,n,o){return{type:S,validation:t,failMessageId:n,expected:o}}var R=Symbol();function L(t){return arguments.length>1&&console.error("Got more than one argument to ARRAY_OF. Did you mean to pass an array of constraints?"),f(x,"deadError",t)}function K(t){return arguments.length>1?f(E,"deadError",Array.from(arguments)):Array.isArray(t)?f(E,"deadError",t):f(E,"deadError",[t])}function U(t){return f(O,"deadError",t)}function q(t){return!!t}0&&(module.exports={ANY_OF,ARRAY_OF,DYNAMIC,ERRORS,OPTIONAL,isTruthy,validate});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const ERRORS = {\n\tnoProperty: \"Required property not present\",\n\ttypeMismatch: \"Provided type is not allowed by schema\",\n\tcustomFail: \"Custom validation function failed\",\n\textraProperty: \"Provided object contains properties not present in schema\",\n\texceptionOnCustom: \"Exception thrown during constraint validation\",\n\tnotArray: \"Tried using ARRAY_OF constraint on non-array value\",\n\ttargetIsNull: \"Passed object or array item is null\",\n\tfunctionExpected: \"Expected function as dynamic constraint\",\n\tobjectExpected: \"Expected object\",\n\tanyFailed: \"None of ANY_OF constraints are met\",\n\tparsingError: \"Schema parsing error\",\n\tdeadError: \"This error never occurs (i guess)\"\n};\n\nconst TYPE = (t: string) => (x: any) => typeof x == t;\nconst IS_ARRAY = (x: any) => Array.isArray(x);\n\nconst CONSTRAINT = Symbol();\nconst FC_ARRAY = Symbol(); // https://www.youtube.com/watch?v=qSqXGeJJBaI\nconst FC_ANY = Symbol();\nconst FC_DYNAMIC = Symbol();\nconst FC_NESTED = Symbol();\n\nconst VALIDATION_DEFAULTS = {\n\tallErrors: true,\n\tallowExtraProperties: true\n};\n\n/**\n* @param options Validation options:\n*\n* - allErrors (true) : return all errors instead of interrupting after first fail\n* - allowExtraProperties (true) : If false, adds specific error to a list for every property of target object not present in schema\n* @return Array of errors\n */\nexport function validate(target: any, schema: Schema = {}, options: ValidationOptions = {}) {\n\toptions = Object.assign(VALIDATION_DEFAULTS, options)\n\n\tconst parseErrors: Error[] = [];\n\tconst [constraints, flags] = parseSchema(schema, parseErrors);\n\n\tif (flags.length > 0) {\n\t\tconsole.error(\"Flags can't be used at schema's root\")\n\t}\n\n\tconst errors = checkValue(\"\", target, constraints, options);\n\terrors.push(...parseErrors)\n\terrors.forEach(e => {\n\t\tif (e.propertyName?.startsWith(\".\"))\n\t\t\te.propertyName = e.propertyName.slice(1);\n\t});\n\n\treturn errors;\n}\n\nfunction parseSchema(schemaProperty: Schema, errors: Error[]): [Constraint[], OptionalFlag[]] {\n\tfunction translate(raw: Schema): Constraint | Constraint[] | OptionalFlag | null {\n\t\tif (!raw) return null;\n\n\t\tif (\n\t\t\ttypeof raw === \"object\" &&\n\t\t\t\"type\" in raw &&\n\t\t\traw.type === CONSTRAINT\n\t\t)\n\t\t\treturn raw as Constraint;\n\n\t\tif (Array.isArray(raw)) {\n\t\t\treturn raw.map(translate).filter(raw => raw) as Constraint | Constraint[] | OptionalFlag;\n\t\t} else {\n\t\t\tswitch (typeof raw) {\n\t\t\t\tcase (\"string\"): {\n\t\t\t\t\tif (raw == \"array\")\n\t\t\t\t\t\treturn constraint(IS_ARRAY, \"typeMismatch\", raw);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn constraint(TYPE(raw as TypeofValueSchema), \"typeMismatch\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"function\"): {\n\t\t\t\t\treturn constraint(raw as FunctionSchema, \"customFail\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"object\"): {\n\t\t\t\t\treturn constraint(FC_NESTED, \"deadError\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"symbol\"): {\n\t\t\t\t\treturn raw as OptionalFlag;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\terrors.push(error(\"<schema>\", \"parsingError\", undefined, raw));\n\t\treturn null;\n\t}\n\n\tconst intermediate = translate(schemaProperty) || [];\n\n\tfunction wrap(\n\t\ttranslated: OptionalFlag | Constraint | Constraint[]\n\t): (OptionalFlag | Constraint)[] {\n\t\tif (!Array.isArray(translated))\n\t\t\treturn [translated];\n\t\treturn translated;\n\t}\n\n\tconst wrapped = wrap(intermediate);\n\tconst constraints = wrapped.filter(i => typeof i !== \"symbol\" && i.type == CONSTRAINT);\n\tconst flags = wrapped.filter(i => typeof i === \"symbol\");\n\n\treturn [\n\t\tconstraints as Constraint[],\n\t\tflags as OptionalFlag[]\n\t];\n}\n\nfunction checkValue(\n\tpropertyName: keyof any,\n\tvalue: any,\n\tconstraints: Constraint[],\n\toptions: ValidationOptions\n): Error[] {\n\tconst errors = [];\n\n\tfunction constraintFunctional(v: Constraint[\"validation\"]): v is (value: any) => any {\n\t\treturn typeof v == \"function\";\n\t}\n\n\tfor (let constraint of constraints) {\n\t\tconst validationCall = constraint.validation;\n\t\tif (constraintFunctional(validationCall)) {\n\t\t\tconst [success, validationResult] = nothrow(() => validationCall(value));\n\t\t\tif (!success) {\n\t\t\t\terrors.push(error(propertyName, \"exceptionOnCustom\", undefined, validationResult?.toString()));\n\t\t\t} else if (!validationResult) {\n\t\t\t\terrors.push(error(propertyName, constraint.failMessageId, \"[function]\", value));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch(constraint.validation) {\n\t\t\tcase FC_NESTED: {\n\t\t\t\tif (typeof value != \"object\" || !value) {\n\t\t\t\t\terrors.push(error(propertyName, \"objectExpected\", \"object\", value));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst targetKeys = Object.keys(value);\n\t\t\t\tconst schemaKeys = Object.keys(constraint.expected!);\n\n\t\t\t\tfor (let key of schemaKeys) {\n\t\t\t\t\t// @ts-ignore // FC_NESTED guarantees expected scheme to be an object\n\t\t\t\t\tconst [subConstraints, flags] = parseSchema(constraint.expected[key], errors);\n\n\t\t\t\t\tif (!targetKeys.includes(key)) {\n\t\t\t\t\t\tif (!flags.includes(OPTIONAL)) {\n\t\t\t\t\t\t\terrors.push(error(`${stringifyKey(propertyName)}.${key}`, \"noProperty\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst subErrors = checkValue(`${stringifyKey(propertyName)}.${key}`, value[key], subConstraints, options);\n\t\t\t\t\terrors.push(...subErrors);\n\t\t\t\t}\n\n\t\t\t\tif (!options.allowExtraProperties) {\n\t\t\t\t\tconst extraProperties = targetKeys.filter(k => !schemaKeys.includes(k));\n\t\t\t\t\tif (extraProperties.length > 0) {\n\t\t\t\t\t\terrors.push(...extraProperties.map(k => error(`${stringifyKey(propertyName)}.${k}`, \"extraProperty\")))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_ARRAY: {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\terrors.push(error(propertyName, \"notArray\", \"array\", typeof value))\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst [subConstraints, flags] = parseSchema(constraint.expected, errors);\n\n\t\t\t\tlet indexCounter = 0;\n\t\t\t\tfor (let item of value) {\n\t\t\t\t\tconst subErrors = checkValue(`${stringifyKey(propertyName)}[${indexCounter}]`, item, subConstraints, options);\n\t\t\t\t\terrors.push(...subErrors);\n\t\t\t\t\t++indexCounter;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_ANY: {\n\t\t\t\tconst subSchemas = constraint.expected as Schema[];\n\n\t\t\t\tconst subErrors = [];\n\t\t\t\tlet passed = false;\n\t\t\t\tlet counter = 0;\n\n\t\t\t\tfor (let subSchema of subSchemas) {\n\t\t\t\t\tconst subParseErrors: Error[] = [];\n\t\t\t\t\tconst [subConstraints, flags] = parseSchema(subSchema, subParseErrors);\n\t\t\t\t\tconst caseErrors = checkValue(`${stringifyKey(propertyName)}.<any#${counter}>`, value, subConstraints, options);\n\t\t\t\t\tcaseErrors.push(...subParseErrors);\n\t\t\t\t\t++counter;\n\t\t\t\t\tsubErrors.push(caseErrors);\n\t\t\t\t\tif (caseErrors.length == 0) {\n\t\t\t\t\t\tpassed = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!passed) errors.push(error(propertyName, \"anyFailed\", undefined, subErrors));\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_DYNAMIC: {\n\t\t\t\tconst constraintCallback = constraint.expected;\n\n\t\t\t\tif (typeof constraintCallback != \"function\") {\n\t\t\t\t\terrors.push(error(propertyName, \"functionExpected\", \"function\", typeof constraintCallback))\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst [subConstraints, flags] = parseSchema(constraintCallback(value), errors)\n\t\t\t\tconst subErrors = checkValue(propertyName, value, subConstraints, options);\n\t\t\t\terrors.push(...subErrors);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!options.allErrors && errors.length > 0) break;\n\t}\n\treturn errors;\n}\n\nfunction nothrow<T>(cb: () => T): [true, T] | [false, unknown] {\n\ttry {\n\t\treturn [true, cb()];\n\t} catch (e) {\n\t\treturn [false, e];\n\t}\n}\n\nfunction stringifyKey(k: keyof any): string {\n\treturn typeof k === \"symbol\" ? \"[symbol]\" : String(k);\n}\n\nfunction error(\n\tpropertyName: keyof any,\n\tid: ErrorID,\n\texpected?: string,\n\tgot?: any\n) {\n\treturn {\n\t\tpropertyName: stringifyKey(propertyName),\n\t\tid,\n\t\tmessage: ERRORS[id],\n\t\texpected,\n\t\tgot\n\t};\n}\n\nfunction constraint(\n\tf: Constraint[\"validation\"],\n\tfailMessageId: Constraint[\"failMessageId\"],\n\texpected: Constraint[\"expected\"]\n): Constraint {\n\treturn {\n\t\ttype: CONSTRAINT,\n\t\tvalidation: f,\n\t\tfailMessageId: failMessageId,\n\t\texpected: expected\n\t};\n}\n\nexport const OPTIONAL = Symbol();\nexport function ARRAY_OF(constraints: Schema) {\n\tif (arguments.length > 1) {\n\t\tconsole.error(\"Got more than one argument to ARRAY_OF. Did you mean to pass an array of constraints?\");\n\t}\n\treturn constraint(FC_ARRAY, \"deadError\", constraints);\n}\nexport function ANY_OF(constraints: Schema[]) {\n\tif (arguments.length > 1) {\n\t\treturn constraint(FC_ANY, \"deadError\", Array.from(arguments));\n\t} else {\n\t\tif (Array.isArray(constraints)) {\n\t\t\treturn constraint(FC_ANY, \"deadError\", constraints);\n\t\t} else {\n\t\t\treturn constraint(FC_ANY, \"deadError\", [constraints]);\n\t\t}\n\t}\n}\nexport function DYNAMIC(constraints: Schema) {\n\treturn constraint(FC_DYNAMIC, \"deadError\", constraints);\n}\n\nexport function isTruthy<T>(value: T): value is NonNullable<T> {\n\treturn Boolean(value);\n}\n\nexport type ErrorID = keyof typeof ERRORS;\n\ntype TypeofValueSchema = \n\t| \"bigint\"\n\t| \"boolean\"\n\t| \"function\"\n\t| \"number\"\n\t| \"object\"\n\t| \"string\"\n\t| \"symbol\"\n\t| \"undefined\"\n\t| \"array\"; // array is special case\ntype FunctionSchema = (value: any) => boolean | any;\ntype OptionalFlag = typeof OPTIONAL;\n\ntype ForbiddenConstraintFlag =\n\t| typeof FC_ARRAY\n\t| typeof FC_ANY\n\t| typeof FC_DYNAMIC\n\t| typeof FC_NESTED\ntype Constraint = {\n\ttype: typeof CONSTRAINT,\n\tvalidation:\n\t\t| ((value: any) => any)\n\t\t| ForbiddenConstraintFlag,\n\tfailMessageId: ErrorID,\n\texpected: Schema\n}\n\nexport type Schema = \n\t| TypeofValueSchema\n\t| FunctionSchema\n\t| OptionalFlag\n\t| { [property: keyof any]: Schema }\n\t| Schema[]\n\t| Constraint;\n\ntype ValidationOptions = Partial<typeof VALIDATION_DEFAULTS>;\n\ntype Error = {\n\tpropertyName: string,\n\tid: ErrorID,\n\tmessage: string,\n\texpected: any,\n\tgot: any\n};"],"mappings":"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","names":["index_exports","__export","ANY_OF","ARRAY_OF","DYNAMIC","ERRORS","OPTIONAL","isTruthy","validate","__toCommonJS","TYPE","x","IS_ARRAY","CONSTRAINT","FC_ARRAY","FC_ANY","FC_DYNAMIC","FC_NESTED","VALIDATION_DEFAULTS","target","schema","options","parseErrors","constraints","flags","parseSchema","errors","checkValue","e","schemaProperty","translate","raw","constraint","error","intermediate","wrap","translated","wrapped","i","propertyName","value","constraintFunctional","v","validationCall","success","validationResult","nothrow","targetKeys","schemaKeys","key","subConstraints","stringifyKey","subErrors","extraProperties","k","indexCounter","item","subSchemas","passed","counter","subSchema","subParseErrors","caseErrors","constraintCallback","cb","id","expected","got","f","failMessageId"]}
@@ -0,0 +1,60 @@
1
+ declare const ERRORS: {
2
+ noProperty: string;
3
+ typeMismatch: string;
4
+ customFail: string;
5
+ extraProperty: string;
6
+ exceptionOnCustom: string;
7
+ notArray: string;
8
+ targetIsNull: string;
9
+ functionExpected: string;
10
+ objectExpected: string;
11
+ anyFailed: string;
12
+ parsingError: string;
13
+ deadError: string;
14
+ };
15
+ declare const CONSTRAINT: unique symbol;
16
+ declare const FC_ARRAY: unique symbol;
17
+ declare const FC_ANY: unique symbol;
18
+ declare const FC_DYNAMIC: unique symbol;
19
+ declare const FC_NESTED: unique symbol;
20
+ declare const VALIDATION_DEFAULTS: {
21
+ allErrors: boolean;
22
+ allowExtraProperties: boolean;
23
+ };
24
+ /**
25
+ * @param options Validation options:
26
+ *
27
+ * - allErrors (true) : return all errors instead of interrupting after first fail
28
+ * - allowExtraProperties (true) : If false, adds specific error to a list for every property of target object not present in schema
29
+ * @return Array of errors
30
+ */
31
+ declare function validate(target: any, schema?: Schema, options?: ValidationOptions): Error[];
32
+ declare const OPTIONAL: unique symbol;
33
+ declare function ARRAY_OF(constraints: Schema): Constraint;
34
+ declare function ANY_OF(constraints: Schema[]): Constraint;
35
+ declare function DYNAMIC(constraints: Schema): Constraint;
36
+ declare function isTruthy<T>(value: T): value is NonNullable<T>;
37
+ type ErrorID = keyof typeof ERRORS;
38
+ type TypeofValueSchema = "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" | "array";
39
+ type FunctionSchema = (value: any) => boolean | any;
40
+ type OptionalFlag = typeof OPTIONAL;
41
+ type ForbiddenConstraintFlag = typeof FC_ARRAY | typeof FC_ANY | typeof FC_DYNAMIC | typeof FC_NESTED;
42
+ type Constraint = {
43
+ type: typeof CONSTRAINT;
44
+ validation: ((value: any) => any) | ForbiddenConstraintFlag;
45
+ failMessageId: ErrorID;
46
+ expected: Schema;
47
+ };
48
+ type Schema = TypeofValueSchema | FunctionSchema | OptionalFlag | {
49
+ [property: keyof any]: Schema;
50
+ } | Schema[] | Constraint;
51
+ type ValidationOptions = Partial<typeof VALIDATION_DEFAULTS>;
52
+ type Error = {
53
+ propertyName: string;
54
+ id: ErrorID;
55
+ message: string;
56
+ expected: any;
57
+ got: any;
58
+ };
59
+
60
+ export { ANY_OF, ARRAY_OF, DYNAMIC, ERRORS, type ErrorID, OPTIONAL, type Schema, isTruthy, validate };
@@ -0,0 +1,60 @@
1
+ declare const ERRORS: {
2
+ noProperty: string;
3
+ typeMismatch: string;
4
+ customFail: string;
5
+ extraProperty: string;
6
+ exceptionOnCustom: string;
7
+ notArray: string;
8
+ targetIsNull: string;
9
+ functionExpected: string;
10
+ objectExpected: string;
11
+ anyFailed: string;
12
+ parsingError: string;
13
+ deadError: string;
14
+ };
15
+ declare const CONSTRAINT: unique symbol;
16
+ declare const FC_ARRAY: unique symbol;
17
+ declare const FC_ANY: unique symbol;
18
+ declare const FC_DYNAMIC: unique symbol;
19
+ declare const FC_NESTED: unique symbol;
20
+ declare const VALIDATION_DEFAULTS: {
21
+ allErrors: boolean;
22
+ allowExtraProperties: boolean;
23
+ };
24
+ /**
25
+ * @param options Validation options:
26
+ *
27
+ * - allErrors (true) : return all errors instead of interrupting after first fail
28
+ * - allowExtraProperties (true) : If false, adds specific error to a list for every property of target object not present in schema
29
+ * @return Array of errors
30
+ */
31
+ declare function validate(target: any, schema?: Schema, options?: ValidationOptions): Error[];
32
+ declare const OPTIONAL: unique symbol;
33
+ declare function ARRAY_OF(constraints: Schema): Constraint;
34
+ declare function ANY_OF(constraints: Schema[]): Constraint;
35
+ declare function DYNAMIC(constraints: Schema): Constraint;
36
+ declare function isTruthy<T>(value: T): value is NonNullable<T>;
37
+ type ErrorID = keyof typeof ERRORS;
38
+ type TypeofValueSchema = "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" | "array";
39
+ type FunctionSchema = (value: any) => boolean | any;
40
+ type OptionalFlag = typeof OPTIONAL;
41
+ type ForbiddenConstraintFlag = typeof FC_ARRAY | typeof FC_ANY | typeof FC_DYNAMIC | typeof FC_NESTED;
42
+ type Constraint = {
43
+ type: typeof CONSTRAINT;
44
+ validation: ((value: any) => any) | ForbiddenConstraintFlag;
45
+ failMessageId: ErrorID;
46
+ expected: Schema;
47
+ };
48
+ type Schema = TypeofValueSchema | FunctionSchema | OptionalFlag | {
49
+ [property: keyof any]: Schema;
50
+ } | Schema[] | Constraint;
51
+ type ValidationOptions = Partial<typeof VALIDATION_DEFAULTS>;
52
+ type Error = {
53
+ propertyName: string;
54
+ id: ErrorID;
55
+ message: string;
56
+ expected: any;
57
+ got: any;
58
+ };
59
+
60
+ export { ANY_OF, ARRAY_OF, DYNAMIC, ERRORS, type ErrorID, OPTIONAL, type Schema, isTruthy, validate };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var T={noProperty:"Required property not present",typeMismatch:"Provided type is not allowed by schema",customFail:"Custom validation function failed",extraProperty:"Provided object contains properties not present in schema",exceptionOnCustom:"Exception thrown during constraint validation",notArray:"Tried using ARRAY_OF constraint on non-array value",targetIsNull:"Passed object or array item is null",functionExpected:"Expected function as dynamic constraint",objectExpected:"Expected object",anyFailed:"None of ANY_OF constraints are met",parsingError:"Schema parsing error",deadError:"This error never occurs (i guess)"},R=t=>n=>typeof n==t,I=t=>Array.isArray(t),A=Symbol(),S=Symbol(),E=Symbol(),F=Symbol(),x=Symbol(),k={allErrors:!0,allowExtraProperties:!0};function D(t,n={},c={}){c=Object.assign(k,c);let s=[],[r,p]=m(n,s);p.length>0&&console.error("Flags can't be used at schema's root");let o=b("",t,r,c);return o.push(...s),o.forEach(y=>{y.propertyName?.startsWith(".")&&(y.propertyName=y.propertyName.slice(1))}),o}function m(t,n){function c(e){if(!e)return null;if(typeof e=="object"&&"type"in e&&e.type===A)return e;if(Array.isArray(e))return e.map(c).filter(i=>i);switch(typeof e){case"string":return e=="array"?f(I,"typeMismatch",e):f(R(e),"typeMismatch",e);case"function":return f(e,"customFail",e);case"object":return f(x,"deadError",e);case"symbol":return e}return n.push(u("<schema>","parsingError",void 0,e)),null}let s=c(t)||[];function r(e){return Array.isArray(e)?e:[e]}let p=r(s),o=p.filter(e=>typeof e!="symbol"&&e.type==A),y=p.filter(e=>typeof e=="symbol");return[o,y]}function b(t,n,c,s){let r=[];function p(o){return typeof o=="function"}for(let o of c){let y=o.validation;if(p(y)){let[e,i]=_(()=>y(n));e?i||r.push(u(t,o.failMessageId,"[function]",n)):r.push(u(t,"exceptionOnCustom",void 0,i?.toString()));continue}switch(o.validation){case x:{if(typeof n!="object"||!n){r.push(u(t,"objectExpected","object",n));break}let e=Object.keys(n),i=Object.keys(o.expected);for(let a of i){let[l,h]=m(o.expected[a],r);if(!e.includes(a)){h.includes(N)||r.push(u(`${d(t)}.${a}`,"noProperty"));continue}let g=b(`${d(t)}.${a}`,n[a],l,s);r.push(...g)}if(!s.allowExtraProperties){let a=e.filter(l=>!i.includes(l));a.length>0&&r.push(...a.map(l=>u(`${d(t)}.${l}`,"extraProperty")))}break}case S:{if(!Array.isArray(n)){r.push(u(t,"notArray","array",typeof n));break}let[e,i]=m(o.expected,r),a=0;for(let l of n){let h=b(`${d(t)}[${a}]`,l,e,s);r.push(...h),++a}break}case E:{let e=o.expected,i=[],a=!1,l=0;for(let h of e){let g=[],[O,P]=m(h,g),C=b(`${d(t)}.<any#${l}>`,n,O,s);if(C.push(...g),++l,i.push(C),C.length==0){a=!0;break}}a||r.push(u(t,"anyFailed",void 0,i));break}case F:{let e=o.expected;if(typeof e!="function"){r.push(u(t,"functionExpected","function",typeof e));break}let[i,a]=m(e(n),r),l=b(t,n,i,s);r.push(...l);break}}if(!s.allErrors&&r.length>0)break}return r}function _(t){try{return[!0,t()]}catch(n){return[!1,n]}}function d(t){return typeof t=="symbol"?"[symbol]":String(t)}function u(t,n,c,s){return{propertyName:d(t),id:n,message:T[n],expected:c,got:s}}function f(t,n,c){return{type:A,validation:t,failMessageId:n,expected:c}}var N=Symbol();function Y(t){return arguments.length>1&&console.error("Got more than one argument to ARRAY_OF. Did you mean to pass an array of constraints?"),f(S,"deadError",t)}function j(t){return arguments.length>1?f(E,"deadError",Array.from(arguments)):Array.isArray(t)?f(E,"deadError",t):f(E,"deadError",[t])}function M(t){return f(F,"deadError",t)}function $(t){return!!t}export{j as ANY_OF,Y as ARRAY_OF,M as DYNAMIC,T as ERRORS,N as OPTIONAL,$ as isTruthy,D as validate};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const ERRORS = {\n\tnoProperty: \"Required property not present\",\n\ttypeMismatch: \"Provided type is not allowed by schema\",\n\tcustomFail: \"Custom validation function failed\",\n\textraProperty: \"Provided object contains properties not present in schema\",\n\texceptionOnCustom: \"Exception thrown during constraint validation\",\n\tnotArray: \"Tried using ARRAY_OF constraint on non-array value\",\n\ttargetIsNull: \"Passed object or array item is null\",\n\tfunctionExpected: \"Expected function as dynamic constraint\",\n\tobjectExpected: \"Expected object\",\n\tanyFailed: \"None of ANY_OF constraints are met\",\n\tparsingError: \"Schema parsing error\",\n\tdeadError: \"This error never occurs (i guess)\"\n};\n\nconst TYPE = (t: string) => (x: any) => typeof x == t;\nconst IS_ARRAY = (x: any) => Array.isArray(x);\n\nconst CONSTRAINT = Symbol();\nconst FC_ARRAY = Symbol(); // https://www.youtube.com/watch?v=qSqXGeJJBaI\nconst FC_ANY = Symbol();\nconst FC_DYNAMIC = Symbol();\nconst FC_NESTED = Symbol();\n\nconst VALIDATION_DEFAULTS = {\n\tallErrors: true,\n\tallowExtraProperties: true\n};\n\n/**\n* @param options Validation options:\n*\n* - allErrors (true) : return all errors instead of interrupting after first fail\n* - allowExtraProperties (true) : If false, adds specific error to a list for every property of target object not present in schema\n* @return Array of errors\n */\nexport function validate(target: any, schema: Schema = {}, options: ValidationOptions = {}) {\n\toptions = Object.assign(VALIDATION_DEFAULTS, options)\n\n\tconst parseErrors: Error[] = [];\n\tconst [constraints, flags] = parseSchema(schema, parseErrors);\n\n\tif (flags.length > 0) {\n\t\tconsole.error(\"Flags can't be used at schema's root\")\n\t}\n\n\tconst errors = checkValue(\"\", target, constraints, options);\n\terrors.push(...parseErrors)\n\terrors.forEach(e => {\n\t\tif (e.propertyName?.startsWith(\".\"))\n\t\t\te.propertyName = e.propertyName.slice(1);\n\t});\n\n\treturn errors;\n}\n\nfunction parseSchema(schemaProperty: Schema, errors: Error[]): [Constraint[], OptionalFlag[]] {\n\tfunction translate(raw: Schema): Constraint | Constraint[] | OptionalFlag | null {\n\t\tif (!raw) return null;\n\n\t\tif (\n\t\t\ttypeof raw === \"object\" &&\n\t\t\t\"type\" in raw &&\n\t\t\traw.type === CONSTRAINT\n\t\t)\n\t\t\treturn raw as Constraint;\n\n\t\tif (Array.isArray(raw)) {\n\t\t\treturn raw.map(translate).filter(raw => raw) as Constraint | Constraint[] | OptionalFlag;\n\t\t} else {\n\t\t\tswitch (typeof raw) {\n\t\t\t\tcase (\"string\"): {\n\t\t\t\t\tif (raw == \"array\")\n\t\t\t\t\t\treturn constraint(IS_ARRAY, \"typeMismatch\", raw);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn constraint(TYPE(raw as TypeofValueSchema), \"typeMismatch\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"function\"): {\n\t\t\t\t\treturn constraint(raw as FunctionSchema, \"customFail\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"object\"): {\n\t\t\t\t\treturn constraint(FC_NESTED, \"deadError\", raw);\n\t\t\t\t}\n\t\t\t\tcase (\"symbol\"): {\n\t\t\t\t\treturn raw as OptionalFlag;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\terrors.push(error(\"<schema>\", \"parsingError\", undefined, raw));\n\t\treturn null;\n\t}\n\n\tconst intermediate = translate(schemaProperty) || [];\n\n\tfunction wrap(\n\t\ttranslated: OptionalFlag | Constraint | Constraint[]\n\t): (OptionalFlag | Constraint)[] {\n\t\tif (!Array.isArray(translated))\n\t\t\treturn [translated];\n\t\treturn translated;\n\t}\n\n\tconst wrapped = wrap(intermediate);\n\tconst constraints = wrapped.filter(i => typeof i !== \"symbol\" && i.type == CONSTRAINT);\n\tconst flags = wrapped.filter(i => typeof i === \"symbol\");\n\n\treturn [\n\t\tconstraints as Constraint[],\n\t\tflags as OptionalFlag[]\n\t];\n}\n\nfunction checkValue(\n\tpropertyName: keyof any,\n\tvalue: any,\n\tconstraints: Constraint[],\n\toptions: ValidationOptions\n): Error[] {\n\tconst errors = [];\n\n\tfunction constraintFunctional(v: Constraint[\"validation\"]): v is (value: any) => any {\n\t\treturn typeof v == \"function\";\n\t}\n\n\tfor (let constraint of constraints) {\n\t\tconst validationCall = constraint.validation;\n\t\tif (constraintFunctional(validationCall)) {\n\t\t\tconst [success, validationResult] = nothrow(() => validationCall(value));\n\t\t\tif (!success) {\n\t\t\t\terrors.push(error(propertyName, \"exceptionOnCustom\", undefined, validationResult?.toString()));\n\t\t\t} else if (!validationResult) {\n\t\t\t\terrors.push(error(propertyName, constraint.failMessageId, \"[function]\", value));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch(constraint.validation) {\n\t\t\tcase FC_NESTED: {\n\t\t\t\tif (typeof value != \"object\" || !value) {\n\t\t\t\t\terrors.push(error(propertyName, \"objectExpected\", \"object\", value));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst targetKeys = Object.keys(value);\n\t\t\t\tconst schemaKeys = Object.keys(constraint.expected!);\n\n\t\t\t\tfor (let key of schemaKeys) {\n\t\t\t\t\t// @ts-ignore // FC_NESTED guarantees expected scheme to be an object\n\t\t\t\t\tconst [subConstraints, flags] = parseSchema(constraint.expected[key], errors);\n\n\t\t\t\t\tif (!targetKeys.includes(key)) {\n\t\t\t\t\t\tif (!flags.includes(OPTIONAL)) {\n\t\t\t\t\t\t\terrors.push(error(`${stringifyKey(propertyName)}.${key}`, \"noProperty\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst subErrors = checkValue(`${stringifyKey(propertyName)}.${key}`, value[key], subConstraints, options);\n\t\t\t\t\terrors.push(...subErrors);\n\t\t\t\t}\n\n\t\t\t\tif (!options.allowExtraProperties) {\n\t\t\t\t\tconst extraProperties = targetKeys.filter(k => !schemaKeys.includes(k));\n\t\t\t\t\tif (extraProperties.length > 0) {\n\t\t\t\t\t\terrors.push(...extraProperties.map(k => error(`${stringifyKey(propertyName)}.${k}`, \"extraProperty\")))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_ARRAY: {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\terrors.push(error(propertyName, \"notArray\", \"array\", typeof value))\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst [subConstraints, flags] = parseSchema(constraint.expected, errors);\n\n\t\t\t\tlet indexCounter = 0;\n\t\t\t\tfor (let item of value) {\n\t\t\t\t\tconst subErrors = checkValue(`${stringifyKey(propertyName)}[${indexCounter}]`, item, subConstraints, options);\n\t\t\t\t\terrors.push(...subErrors);\n\t\t\t\t\t++indexCounter;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_ANY: {\n\t\t\t\tconst subSchemas = constraint.expected as Schema[];\n\n\t\t\t\tconst subErrors = [];\n\t\t\t\tlet passed = false;\n\t\t\t\tlet counter = 0;\n\n\t\t\t\tfor (let subSchema of subSchemas) {\n\t\t\t\t\tconst subParseErrors: Error[] = [];\n\t\t\t\t\tconst [subConstraints, flags] = parseSchema(subSchema, subParseErrors);\n\t\t\t\t\tconst caseErrors = checkValue(`${stringifyKey(propertyName)}.<any#${counter}>`, value, subConstraints, options);\n\t\t\t\t\tcaseErrors.push(...subParseErrors);\n\t\t\t\t\t++counter;\n\t\t\t\t\tsubErrors.push(caseErrors);\n\t\t\t\t\tif (caseErrors.length == 0) {\n\t\t\t\t\t\tpassed = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!passed) errors.push(error(propertyName, \"anyFailed\", undefined, subErrors));\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FC_DYNAMIC: {\n\t\t\t\tconst constraintCallback = constraint.expected;\n\n\t\t\t\tif (typeof constraintCallback != \"function\") {\n\t\t\t\t\terrors.push(error(propertyName, \"functionExpected\", \"function\", typeof constraintCallback))\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst [subConstraints, flags] = parseSchema(constraintCallback(value), errors)\n\t\t\t\tconst subErrors = checkValue(propertyName, value, subConstraints, options);\n\t\t\t\terrors.push(...subErrors);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!options.allErrors && errors.length > 0) break;\n\t}\n\treturn errors;\n}\n\nfunction nothrow<T>(cb: () => T): [true, T] | [false, unknown] {\n\ttry {\n\t\treturn [true, cb()];\n\t} catch (e) {\n\t\treturn [false, e];\n\t}\n}\n\nfunction stringifyKey(k: keyof any): string {\n\treturn typeof k === \"symbol\" ? \"[symbol]\" : String(k);\n}\n\nfunction error(\n\tpropertyName: keyof any,\n\tid: ErrorID,\n\texpected?: string,\n\tgot?: any\n) {\n\treturn {\n\t\tpropertyName: stringifyKey(propertyName),\n\t\tid,\n\t\tmessage: ERRORS[id],\n\t\texpected,\n\t\tgot\n\t};\n}\n\nfunction constraint(\n\tf: Constraint[\"validation\"],\n\tfailMessageId: Constraint[\"failMessageId\"],\n\texpected: Constraint[\"expected\"]\n): Constraint {\n\treturn {\n\t\ttype: CONSTRAINT,\n\t\tvalidation: f,\n\t\tfailMessageId: failMessageId,\n\t\texpected: expected\n\t};\n}\n\nexport const OPTIONAL = Symbol();\nexport function ARRAY_OF(constraints: Schema) {\n\tif (arguments.length > 1) {\n\t\tconsole.error(\"Got more than one argument to ARRAY_OF. Did you mean to pass an array of constraints?\");\n\t}\n\treturn constraint(FC_ARRAY, \"deadError\", constraints);\n}\nexport function ANY_OF(constraints: Schema[]) {\n\tif (arguments.length > 1) {\n\t\treturn constraint(FC_ANY, \"deadError\", Array.from(arguments));\n\t} else {\n\t\tif (Array.isArray(constraints)) {\n\t\t\treturn constraint(FC_ANY, \"deadError\", constraints);\n\t\t} else {\n\t\t\treturn constraint(FC_ANY, \"deadError\", [constraints]);\n\t\t}\n\t}\n}\nexport function DYNAMIC(constraints: Schema) {\n\treturn constraint(FC_DYNAMIC, \"deadError\", constraints);\n}\n\nexport function isTruthy<T>(value: T): value is NonNullable<T> {\n\treturn Boolean(value);\n}\n\nexport type ErrorID = keyof typeof ERRORS;\n\ntype TypeofValueSchema = \n\t| \"bigint\"\n\t| \"boolean\"\n\t| \"function\"\n\t| \"number\"\n\t| \"object\"\n\t| \"string\"\n\t| \"symbol\"\n\t| \"undefined\"\n\t| \"array\"; // array is special case\ntype FunctionSchema = (value: any) => boolean | any;\ntype OptionalFlag = typeof OPTIONAL;\n\ntype ForbiddenConstraintFlag =\n\t| typeof FC_ARRAY\n\t| typeof FC_ANY\n\t| typeof FC_DYNAMIC\n\t| typeof FC_NESTED\ntype Constraint = {\n\ttype: typeof CONSTRAINT,\n\tvalidation:\n\t\t| ((value: any) => any)\n\t\t| ForbiddenConstraintFlag,\n\tfailMessageId: ErrorID,\n\texpected: Schema\n}\n\nexport type Schema = \n\t| TypeofValueSchema\n\t| FunctionSchema\n\t| OptionalFlag\n\t| { [property: keyof any]: Schema }\n\t| Schema[]\n\t| Constraint;\n\ntype ValidationOptions = Partial<typeof VALIDATION_DEFAULTS>;\n\ntype Error = {\n\tpropertyName: string,\n\tid: ErrorID,\n\tmessage: string,\n\texpected: any,\n\tgot: any\n};"],"mappings":"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","names":["ERRORS","TYPE","x","IS_ARRAY","CONSTRAINT","FC_ARRAY","FC_ANY","FC_DYNAMIC","FC_NESTED","VALIDATION_DEFAULTS","validate","target","schema","options","parseErrors","constraints","flags","parseSchema","errors","checkValue","e","schemaProperty","translate","raw","constraint","error","intermediate","wrap","translated","wrapped","i","propertyName","value","constraintFunctional","v","validationCall","success","validationResult","nothrow","targetKeys","schemaKeys","key","subConstraints","OPTIONAL","stringifyKey","subErrors","extraProperties","k","indexCounter","item","subSchemas","passed","counter","subSchema","subParseErrors","caseErrors","constraintCallback","cb","id","expected","got","f","failMessageId","ARRAY_OF","ANY_OF","DYNAMIC","isTruthy"]}
package/package.json CHANGED
@@ -1,11 +1,22 @@
1
1
  {
2
2
  "name": "arstotzka",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "description": "JS validation utility",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "main": "./dist/index.cjs",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
7
17
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
18
+ "build": "tsup src/index.ts",
19
+ "test": "node src/tests.js"
9
20
  },
10
21
  "keywords": [
11
22
  "JSON",
@@ -25,5 +36,9 @@
25
36
  "bugs": {
26
37
  "url": "https://github.com/MilesVII/arstotzka/issues"
27
38
  },
28
- "homepage": "https://github.com/MilesVII/arstotzka#readme"
39
+ "homepage": "https://github.com/MilesVII/arstotzka#readme",
40
+ "devDependencies": {
41
+ "tsup": "^8.5.0",
42
+ "typescript": "^5.9.3"
43
+ }
29
44
  }
package/readme.md CHANGED
@@ -77,7 +77,7 @@ Applying a schema to a property that is an object can be done by combining **obj
77
77
  ### Error format
78
78
  ```
79
79
  { // Example error item:
80
- propertyName: 'age', // Name of a property that failed validation
80
+ propertyName: 'age', // Name of a property that failed the validation
81
81
  id: 'typeMismatch', // String describing type of an error. Can be used to localize error message
82
82
  message: 'Provided type is not allowed by schema', // Error message that coressponds to error id
83
83
  expected: 'number', // Arbitrary-purpose fields
package/index.js DELETED
@@ -1,244 +0,0 @@
1
- export const ERRORS = {
2
- noProperty: "Required property not present",
3
- typeMismatch: "Provided type is not allowed by schema",
4
- customFail: "Custom validation function failed",
5
- extraProperty: "Provided object contains properties not present in schema",
6
- exceptionOnCustom: "Exception thrown during constraint validation",
7
- notArray: "Tried using ARRAY_OF constraint on non-array value",
8
- targetIsNull: "Passed object or array item is null",
9
- functionExpected: "Expected function as dynamic constraint",
10
- objectExpected: "Expected object",
11
- anyFailed: "None of ANY_OF constraints are met"
12
- };
13
-
14
- export const OPTIONAL = Symbol();
15
- export function ARRAY_OF(constraints){
16
- if (arguments.length > 1){
17
- console.error("Got more than one argument to ARRAY_OF. Did you mean to pass an array of constraints?");
18
- }
19
- return constraint(FC_ARRAY, null, constraints);
20
- }
21
- export function ANY_OF(constraints){
22
- if (arguments.length > 1){
23
- return constraint(FC_ANY, null, Array.from(arguments));
24
- } else {
25
- if (Array.isArray(constraints)){
26
- return constraint(FC_ANY, null, constraints);
27
- } else {
28
- return constraint(FC_ANY, null, [constraints]);
29
- }
30
- }
31
-
32
- }
33
- export function DYNAMIC(constraints){
34
- return constraint(FC_DYNAMIC, null, constraints);
35
- }
36
-
37
- const TYPE = t => x => typeof x == t;
38
- const IS_ARRAY = x => Array.isArray(x);
39
-
40
- const CONSTRAINT = Symbol();
41
- const FC_ARRAY = Symbol(); // https://www.youtube.com/watch?v=qSqXGeJJBaI
42
- const FC_ANY = Symbol();
43
- const FC_DYNAMIC = Symbol();
44
- const FC_NESTED = Symbol();
45
-
46
- const VALIDATION_DEFAULTS = {
47
- allErrors: true,
48
- allowExtraProperties: true
49
- };
50
-
51
- function safe(cb){
52
- try {
53
- return [true, cb()];
54
- } catch (e) {
55
- return [false, e];
56
- }
57
- }
58
-
59
- function error(propertyName, id, expected, got){
60
- return {
61
- propertyName,
62
- id,
63
- message: ERRORS[id],
64
- expected,
65
- got
66
- };
67
- }
68
-
69
- function constraint(f, failMessageId, expected){
70
- return {
71
- type: CONSTRAINT,
72
- validation: f,
73
- failMessageId: failMessageId,
74
- expected: expected
75
- };
76
- }
77
-
78
- function parseSchema(schemaProperty){
79
- function unify(raw){
80
- if (raw.type == CONSTRAINT) return raw;
81
-
82
- if (Array.isArray(raw)){
83
- return raw.map(c => unify(c));
84
- } else {
85
- switch (typeof raw){
86
- case ("string"): {
87
- if (raw == "array")
88
- return constraint(IS_ARRAY, "typeMismatch", raw);
89
- else
90
- return constraint(TYPE(raw), "typeMismatch", raw);
91
- }
92
- case ("function"): {
93
- return constraint(raw, "customFail", undefined);
94
- }
95
- case ("object"): {
96
- return constraint(FC_NESTED, null, raw);
97
- }
98
- case ("symbol"): {
99
- return raw;
100
- }
101
- }
102
- }
103
- }
104
-
105
- let intermediate = unify(schemaProperty);
106
- if (!Array.isArray(intermediate))
107
- intermediate = [intermediate];
108
- return [
109
- intermediate.filter(i => i.type == CONSTRAINT),
110
- intermediate.filter(i => i.type != CONSTRAINT && typeof i == "symbol")
111
- ];
112
- }
113
-
114
- function checkValue(propertyName, value, constraints, options){
115
- const errors = [];
116
- for (let constraint of constraints){
117
- if (typeof constraint.validation == "function"){
118
- const [success, validationResult] = safe(() => constraint.validation(value));
119
- if (!success){
120
- errors.push(error(propertyName, "exceptionOnCustom", undefined, validationResult.toString()));
121
- } else if (!validationResult){
122
- errors.push(error(propertyName, constraint.failMessageId, constraint.expected, value));
123
- }
124
- continue;
125
- }
126
-
127
- switch(constraint.validation){
128
- case FC_NESTED: {
129
- if (typeof value != "object" || value === null || value == undefined){
130
- errors.push(error(propertyName, "objectExpected", "object", value));
131
- break;
132
- }
133
-
134
- const targetKeys = Object.keys(value);
135
- const schemaKeys = Object.keys(constraint.expected);
136
-
137
- for (let key of schemaKeys){
138
- const [subConstraints, flags] = parseSchema(constraint.expected[key]);
139
-
140
- if (!targetKeys.includes(key)){
141
- if (!flags.includes(OPTIONAL)){
142
- errors.push(error(`${propertyName}.${key}`, "noProperty"));
143
- }
144
- continue;
145
- }
146
-
147
- const subErrors = checkValue(`${propertyName}.${key}`, value[key], subConstraints, options);
148
- errors.push(...subErrors);
149
- }
150
-
151
- if (!options.allowExtraProperties){
152
- const extraProperties = targetKeys.filter(k => !schemaKeys.includes(k));
153
- if (extraProperties.length > 0){
154
- errors.push(...extraProperties.map(k => error(`${propertyName}.${k}`, "extraProperty")))
155
- }
156
- }
157
-
158
- break;
159
- }
160
- case FC_ARRAY: {
161
- if (!Array.isArray(value)){
162
- errors.push(error(propertyName, "notArray", "array", typeof value))
163
- break;
164
- }
165
-
166
- const [subConstraints, flags] = parseSchema(constraint.expected);
167
-
168
- let indexCounter = 0;
169
- for (let item of value){
170
- const subErrors = checkValue(`${propertyName}[${indexCounter}]`, item, subConstraints, options);
171
- errors.push(...subErrors);
172
- ++indexCounter;
173
- }
174
-
175
- break;
176
- }
177
- case FC_ANY: {
178
- const subSchemas = constraint.expected;
179
-
180
- const subErrors = [];
181
- let passed = false;
182
- let counter = 0;
183
-
184
- for (let subSchema of subSchemas){
185
- const [subConstraints, flags] = parseSchema(subSchema);
186
- const caseErrors = checkValue(`${propertyName}.<any#${counter}>`, value, subConstraints, options);
187
- ++counter;
188
- subErrors.push(caseErrors);
189
- if (caseErrors.length == 0) {
190
- passed = true;
191
- break;
192
- }
193
- }
194
-
195
- if (!passed) errors.push(error(propertyName, "anyFailed", undefined, subErrors));
196
-
197
- break;
198
- }
199
- case FC_DYNAMIC: {
200
- const constraintCallback = constraint.expected;
201
-
202
- if (typeof constraintCallback != "function"){
203
- errors.push(error(propertyName, "functionExpected", "function", typeof constraintCallback))
204
- break;
205
- }
206
-
207
- const [subConstraints, flags] = parseSchema(constraintCallback(value))
208
- const subErrors = checkValue(propertyName, value, subConstraints, options);
209
- errors.push(...subErrors);
210
-
211
- break;
212
- }
213
- }
214
-
215
- if (!options.allErrors && errors.length > 0) break;
216
- }
217
- return errors;
218
- }
219
-
220
- /**
221
- * @param options Validation options:
222
- *
223
- * - allErrors (true) : return all errors instead of interrupting after first fail
224
- * - allowExtraProperties (true) : If false, adds specific error to a list for every property of target object not present in schema
225
- * @return Array of errors
226
- */
227
- export function validate(target, schema = {}, options = {}){
228
- options = Object.assign(VALIDATION_DEFAULTS, options)
229
-
230
- const [constraints, flags] = parseSchema(schema);
231
-
232
- if (flags.length > 0) {
233
- console.error("Flags can't be used at schema's root")
234
- }
235
-
236
- const errors = checkValue("", target, constraints, options);
237
-
238
- errors.forEach(e => {
239
- if (e.propertyName?.startsWith("."))
240
- e.propertyName = e.propertyName.slice(1);
241
- });
242
-
243
- return errors;
244
- }
package/usage.js DELETED
@@ -1,110 +0,0 @@
1
- import * as Arstotzka from "./index.js";
2
-
3
- const schema = {
4
- title: "string",
5
- array: [Arstotzka.ARRAY_OF("number"), x => x.length > 1],
6
- arrayOfObjs: Arstotzka.ARRAY_OF({
7
- id: "number",
8
- name: "string"
9
- }),
10
- notArray: Arstotzka.ARRAY_OF("string"),
11
- arrayOof: Arstotzka.ARRAY_OF(Arstotzka.ARRAY_OF("number")),
12
- positiveArray: Arstotzka.ARRAY_OF(x => x > 0),
13
- nested: {
14
- parseableNumber: [x => !isNaN(parseInt(x, 10))],
15
- anotherNest: [{
16
- phrase: "string",
17
- wordCount: "number"
18
- }, x => x.phrase.split(" ").length == x.wordCount],
19
- missing: []
20
- },
21
- invalidValidator: [x => null.invalid],
22
- optional: ["number", Arstotzka.OPTIONAL]
23
- };
24
-
25
- const testSubject0 = {
26
- title: "1337",
27
- array: [1, 2, 3],
28
- arrayOfObjs: [
29
- {id: 0, name: "_"},
30
- {id: 1, name: "second"},
31
- {id: 2, name: "3"},
32
- ],
33
- notArray: [],
34
- arrayOof: [
35
- [1, 2, 3],
36
- [4, 5, 6],
37
- [1, 2]
38
- ],
39
- positiveArray: [Infinity, 1, 4, 5],
40
- nested: {
41
- parseableNumber: "777",
42
- anotherNest: {
43
- phrase:"henlo",
44
- wordCount: 1
45
- },
46
- missing: 0
47
- },
48
- invalidValidator: "uhm"
49
- };
50
-
51
- const testSubject1 = {
52
- title: 1337,
53
- array: [1, null, 3],
54
- arrayOfObjs: [
55
- {id: 0, name: "_"},
56
- {id: 0,},
57
- {id: "0", name: "_"}
58
- ],
59
- notArray: "[1, 2, 3]",
60
- arrayOof: [
61
- [1, 2, 3],
62
- [4, "5", 6],
63
- null,
64
- [1, 2]
65
- ],
66
- positiveArray: [0, 1, 4, -5],
67
- nested: {
68
- parseableNumber: "seven",
69
- extraProperty: "hey",
70
- anotherNest: {
71
- phrase:"henlo",
72
- wordCount: 2
73
- }
74
- },
75
- invalidValidator: "uhm"
76
- };
77
-
78
- const schema1 = Arstotzka.DYNAMIC(x => dynSchema[x.type]);
79
- const dynSchema = [
80
- {
81
- type: "number",
82
- zero: "string"
83
- },
84
- {
85
- type: "number",
86
- one: ["number", x => x === 1]
87
- }
88
- ];
89
- const testSubject2 = {
90
- type: 0,
91
- zero: "0"
92
- };
93
-
94
- const parseableIntSchema = Arstotzka.ANY_OF(
95
- "number",
96
- ["string", x => !isNaN(parseInt(x))]
97
- );
98
-
99
- const tests = [
100
- [null, "array"],
101
- [testSubject0, schema], // Only an error caused by invalid validator
102
- [testSubject1, schema], // Full of errors
103
- ["miles", "string"], // Any value can be validated, not only objects
104
- [7, "string"],
105
- [testSubject2, schema1],
106
- ["7", parseableIntSchema]
107
- ];
108
-
109
- const TEST_SELECTOR = 0;
110
- console.log(Arstotzka.validate(tests[TEST_SELECTOR][0], tests[TEST_SELECTOR][1], {allowExtraProperties: false}));