@decaf-ts/decorator-validation 1.5.5 → 1.5.7
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/decorator-validation.js +1 -1
- package/dist/esm/decorator-validation.js +1 -1
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -3
- package/lib/esm/model/Model.js +0 -2
- package/lib/esm/model/ModelErrorDefinition.js +0 -2
- package/lib/esm/model/Registry.js +0 -2
- package/lib/esm/model/constants.js +0 -2
- package/lib/esm/model/construction.js +0 -2
- package/lib/esm/model/decorators.js +0 -2
- package/lib/esm/model/index.js +0 -2
- package/lib/esm/model/types.js +0 -2
- package/lib/esm/model/utils.js +0 -2
- package/lib/esm/model/validation.js +0 -2
- package/lib/esm/utils/constants.js +0 -2
- package/lib/esm/utils/dates.js +0 -2
- package/lib/esm/utils/decorators.js +0 -2
- package/lib/esm/utils/hashing.js +0 -2
- package/lib/esm/utils/index.js +0 -2
- package/lib/esm/utils/registry.js +0 -2
- package/lib/esm/utils/serialization.js +0 -2
- package/lib/esm/utils/strings.js +0 -2
- package/lib/esm/validation/Validation.js +0 -2
- package/lib/esm/validation/Validators/DateValidator.js +0 -2
- package/lib/esm/validation/Validators/EmailValidator.js +0 -2
- package/lib/esm/validation/Validators/ListValidator.js +0 -2
- package/lib/esm/validation/Validators/MaxLengthValidator.js +0 -2
- package/lib/esm/validation/Validators/MaxValidator.js +0 -2
- package/lib/esm/validation/Validators/MinLengthValidator.js +0 -2
- package/lib/esm/validation/Validators/MinValidator.js +0 -2
- package/lib/esm/validation/Validators/PasswordValidator.js +0 -2
- package/lib/esm/validation/Validators/PatternValidator.js +0 -2
- package/lib/esm/validation/Validators/RequiredValidator.js +0 -2
- package/lib/esm/validation/Validators/StepValidator.js +0 -2
- package/lib/esm/validation/Validators/TypeValidator.js +0 -2
- package/lib/esm/validation/Validators/URLValidator.js +0 -2
- package/lib/esm/validation/Validators/Validator.js +0 -2
- package/lib/esm/validation/Validators/ValidatorRegistry.js +0 -2
- package/lib/esm/validation/Validators/constants.js +0 -2
- package/lib/esm/validation/Validators/decorators.js +0 -2
- package/lib/esm/validation/Validators/index.js +0 -2
- package/lib/esm/validation/Validators/types.js +0 -2
- package/lib/esm/validation/decorators.js +0 -2
- package/lib/esm/validation/index.js +0 -2
- package/lib/esm/validation/types.js +0 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +59 -0
- package/lib/model/Model.js +300 -0
- package/lib/model/ModelErrorDefinition.js +56 -0
- package/lib/model/Registry.js +78 -0
- package/lib/model/constants.js +72 -0
- package/lib/model/construction.js +68 -0
- package/lib/model/decorators.js +67 -0
- package/lib/{validation/index.cjs → model/index.js} +9 -6
- package/lib/model/types.js +2 -0
- package/lib/model/utils.js +29 -0
- package/lib/model/validation.js +138 -0
- package/lib/utils/constants.js +30 -0
- package/lib/utils/dates.js +251 -0
- package/lib/utils/decorators.js +22 -0
- package/lib/utils/hashing.js +106 -0
- package/lib/utils/index.js +23 -0
- package/lib/utils/registry.js +2 -0
- package/lib/utils/serialization.js +93 -0
- package/lib/utils/strings.js +35 -0
- package/lib/validation/Validation.js +75 -0
- package/lib/validation/Validators/DateValidator.js +57 -0
- package/lib/validation/Validators/EmailValidator.js +53 -0
- package/lib/validation/Validators/ListValidator.js +70 -0
- package/lib/validation/Validators/MaxLengthValidator.js +55 -0
- package/lib/validation/Validators/MaxValidator.js +60 -0
- package/lib/validation/Validators/MinLengthValidator.js +55 -0
- package/lib/validation/Validators/MinValidator.js +60 -0
- package/lib/validation/Validators/PasswordValidator.js +53 -0
- package/lib/validation/Validators/PatternValidator.js +73 -0
- package/lib/validation/Validators/RequiredValidator.js +60 -0
- package/lib/validation/Validators/StepValidator.js +55 -0
- package/lib/validation/Validators/TypeValidator.js +63 -0
- package/lib/validation/Validators/URLValidator.js +52 -0
- package/lib/validation/Validators/Validator.js +51 -0
- package/lib/validation/Validators/ValidatorRegistry.js +85 -0
- package/lib/validation/Validators/constants.js +137 -0
- package/lib/validation/Validators/decorators.js +28 -0
- package/lib/validation/Validators/index.js +69 -0
- package/lib/validation/Validators/types.js +2 -0
- package/lib/validation/decorators.js +304 -0
- package/lib/validation/index.js +20 -0
- package/lib/validation/types.js +2 -0
- package/package.json +1 -1
- package/lib/index.cjs +0 -61
- package/lib/model/Model.cjs +0 -302
- package/lib/model/ModelErrorDefinition.cjs +0 -58
- package/lib/model/Registry.cjs +0 -80
- package/lib/model/constants.cjs +0 -74
- package/lib/model/construction.cjs +0 -70
- package/lib/model/decorators.cjs +0 -69
- package/lib/model/index.cjs +0 -27
- package/lib/model/types.cjs +0 -4
- package/lib/model/utils.cjs +0 -31
- package/lib/model/validation.cjs +0 -140
- package/lib/utils/constants.cjs +0 -32
- package/lib/utils/dates.cjs +0 -253
- package/lib/utils/decorators.cjs +0 -24
- package/lib/utils/hashing.cjs +0 -108
- package/lib/utils/index.cjs +0 -25
- package/lib/utils/registry.cjs +0 -4
- package/lib/utils/serialization.cjs +0 -95
- package/lib/utils/strings.cjs +0 -37
- package/lib/validation/Validation.cjs +0 -77
- package/lib/validation/Validators/DateValidator.cjs +0 -59
- package/lib/validation/Validators/EmailValidator.cjs +0 -55
- package/lib/validation/Validators/ListValidator.cjs +0 -72
- package/lib/validation/Validators/MaxLengthValidator.cjs +0 -57
- package/lib/validation/Validators/MaxValidator.cjs +0 -62
- package/lib/validation/Validators/MinLengthValidator.cjs +0 -57
- package/lib/validation/Validators/MinValidator.cjs +0 -62
- package/lib/validation/Validators/PasswordValidator.cjs +0 -55
- package/lib/validation/Validators/PatternValidator.cjs +0 -75
- package/lib/validation/Validators/RequiredValidator.cjs +0 -62
- package/lib/validation/Validators/StepValidator.cjs +0 -57
- package/lib/validation/Validators/TypeValidator.cjs +0 -65
- package/lib/validation/Validators/URLValidator.cjs +0 -54
- package/lib/validation/Validators/Validator.cjs +0 -53
- package/lib/validation/Validators/ValidatorRegistry.cjs +0 -87
- package/lib/validation/Validators/constants.cjs +0 -139
- package/lib/validation/Validators/decorators.cjs +0 -30
- package/lib/validation/Validators/index.cjs +0 -71
- package/lib/validation/Validators/types.d.ts +0 -88
- package/lib/validation/decorators.cjs +0 -306
- package/lib/validation/types.cjs +0 -4
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.model = model;
|
|
4
|
+
exports.hashedBy = hashedBy;
|
|
5
|
+
exports.serializedBy = serializedBy;
|
|
6
|
+
const construction_1 = require("./construction");
|
|
7
|
+
const constants_1 = require("../utils/constants");
|
|
8
|
+
const Model_1 = require("./Model");
|
|
9
|
+
const reflection_1 = require("@decaf-ts/reflection");
|
|
10
|
+
/**
|
|
11
|
+
* @summary Defines a class as a Model class
|
|
12
|
+
* @description
|
|
13
|
+
*
|
|
14
|
+
* - Registers the class under the model registry so it can be easily rebuilt;
|
|
15
|
+
* - Overrides the class constructor;
|
|
16
|
+
* - Runs the global {@link ModelBuilderFunction} if defined;
|
|
17
|
+
* - Runs the optional {@link InstanceCallback} if provided;
|
|
18
|
+
*
|
|
19
|
+
* @param {InstanceCallback} [instanceCallback] optional callback that will be called with the instance upon instantiation. defaults to undefined
|
|
20
|
+
*
|
|
21
|
+
* @function model
|
|
22
|
+
*
|
|
23
|
+
* @memberOf module:decorator-validation.Model
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
function model(instanceCallback) {
|
|
27
|
+
return ((original) => {
|
|
28
|
+
// the new constructor behaviour
|
|
29
|
+
const newConstructor = function (...args) {
|
|
30
|
+
const instance = (0, construction_1.construct)(original, ...args);
|
|
31
|
+
(0, construction_1.bindModelPrototype)(instance);
|
|
32
|
+
// run a builder function if defined with the first argument (The ModelArg)
|
|
33
|
+
const builder = Model_1.Model.getBuilder();
|
|
34
|
+
if (builder)
|
|
35
|
+
builder(instance, args.length ? args[0] : undefined);
|
|
36
|
+
(0, reflection_1.metadata)(Model_1.Model.key(constants_1.ModelKeys.MODEL), original.name)(instance.constructor);
|
|
37
|
+
if (instanceCallback)
|
|
38
|
+
instanceCallback(instance, ...args);
|
|
39
|
+
return instance;
|
|
40
|
+
};
|
|
41
|
+
// copy prototype so instanceof operator still works
|
|
42
|
+
newConstructor.prototype = original.prototype;
|
|
43
|
+
// Sets the proper constructor name for type verification
|
|
44
|
+
Object.defineProperty(newConstructor, "name", {
|
|
45
|
+
writable: false,
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: false,
|
|
48
|
+
value: original.prototype.constructor.name,
|
|
49
|
+
});
|
|
50
|
+
(0, reflection_1.metadata)(Model_1.Model.key(constants_1.ModelKeys.MODEL), original.name)(original);
|
|
51
|
+
Model_1.Model.register(newConstructor, original.name);
|
|
52
|
+
// return new constructor (will override original)
|
|
53
|
+
return newConstructor;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function hashedBy(algorithm, ...args) {
|
|
57
|
+
return (0, reflection_1.metadata)(Model_1.Model.key(constants_1.ModelKeys.HASHING), {
|
|
58
|
+
algorithm: algorithm,
|
|
59
|
+
args: args,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function serializedBy(serializer, ...args) {
|
|
63
|
+
return (0, reflection_1.metadata)(Model_1.Model.key(constants_1.ModelKeys.SERIALIZATION), {
|
|
64
|
+
serializer: serializer,
|
|
65
|
+
args: args,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -14,9 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
18
|
-
__exportStar(require("./
|
|
19
|
-
__exportStar(require("./
|
|
20
|
-
__exportStar(require("./
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
__exportStar(require("./constants"), exports);
|
|
18
|
+
__exportStar(require("./construction"), exports);
|
|
19
|
+
__exportStar(require("./decorators"), exports);
|
|
20
|
+
__exportStar(require("./Model"), exports);
|
|
21
|
+
__exportStar(require("./ModelErrorDefinition"), exports);
|
|
22
|
+
__exportStar(require("./Registry"), exports);
|
|
23
|
+
__exportStar(require("./types"), exports);
|
|
24
|
+
__exportStar(require("./utils"), exports);
|
|
25
|
+
__exportStar(require("./validation"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isPropertyModel = isPropertyModel;
|
|
4
|
+
exports.isModel = isModel;
|
|
5
|
+
const constants_1 = require("../utils/constants");
|
|
6
|
+
const Model_1 = require("./Model");
|
|
7
|
+
function isPropertyModel(target, attribute) {
|
|
8
|
+
if (isModel(target[attribute]))
|
|
9
|
+
return true;
|
|
10
|
+
const metadata = Reflect.getMetadata(constants_1.ModelKeys.TYPE, target, attribute);
|
|
11
|
+
return Model_1.Model.get(metadata.name) ? metadata.name : undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @summary For Serialization/deserialization purposes.
|
|
15
|
+
* @description Reads the {@link ModelKeys.ANCHOR} property of a {@link Model} to discover the class to instantiate
|
|
16
|
+
*
|
|
17
|
+
* @function isModel
|
|
18
|
+
* @memberOf module:decorator-validation.Validation
|
|
19
|
+
* @category Validation
|
|
20
|
+
*/
|
|
21
|
+
function isModel(target) {
|
|
22
|
+
try {
|
|
23
|
+
return target instanceof Model_1.Model || !!Model_1.Model.getMetadata(target);
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validate = validate;
|
|
4
|
+
const ModelErrorDefinition_1 = require("./ModelErrorDefinition");
|
|
5
|
+
const reflection_1 = require("@decaf-ts/reflection");
|
|
6
|
+
const constants_1 = require("../utils/constants");
|
|
7
|
+
const strings_1 = require("../utils/strings");
|
|
8
|
+
const constants_2 = require("./constants");
|
|
9
|
+
const Validation_1 = require("../validation/Validation");
|
|
10
|
+
const constants_3 = require("../validation/Validators/constants");
|
|
11
|
+
const utils_1 = require("./utils");
|
|
12
|
+
/**
|
|
13
|
+
* @summary Analyses the decorations of the properties and validates the obj according to them
|
|
14
|
+
*
|
|
15
|
+
* @typedef T extends Model
|
|
16
|
+
* @prop {T} obj Model object to validate
|
|
17
|
+
* @prop {string[]} [propsToIgnore] object properties to ignore in the validation
|
|
18
|
+
*
|
|
19
|
+
* @function validate
|
|
20
|
+
* @memberOf module:decorator-validation.Validation
|
|
21
|
+
* @category Validation
|
|
22
|
+
*/
|
|
23
|
+
function validate(obj, ...propsToIgnore) {
|
|
24
|
+
const decoratedProperties = [];
|
|
25
|
+
for (const prop in obj)
|
|
26
|
+
if (Object.prototype.hasOwnProperty.call(obj, prop) &&
|
|
27
|
+
propsToIgnore.indexOf(prop) === -1)
|
|
28
|
+
decoratedProperties.push(reflection_1.Reflection.getPropertyDecorators(constants_3.ValidationKeys.REFLECT, obj, prop));
|
|
29
|
+
let result = undefined;
|
|
30
|
+
for (const decoratedProperty of decoratedProperties) {
|
|
31
|
+
const { prop, decorators } = decoratedProperty;
|
|
32
|
+
if (!decorators || !decorators.length)
|
|
33
|
+
continue;
|
|
34
|
+
const defaultTypeDecorator = decorators[0];
|
|
35
|
+
// tries to find any type decorators or other decorators that already enforce type (the ones with the allowed types property defined). if so, skip the default type verification
|
|
36
|
+
if (decorators.find((d) => {
|
|
37
|
+
if (d.key === constants_3.ValidationKeys.TYPE)
|
|
38
|
+
return true;
|
|
39
|
+
return !!d.props.types?.find((t) => t === defaultTypeDecorator.props.name);
|
|
40
|
+
})) {
|
|
41
|
+
decorators.shift(); // remove the design:type decorator, since the type will already be checked
|
|
42
|
+
}
|
|
43
|
+
let errs = undefined;
|
|
44
|
+
for (const decorator of decorators) {
|
|
45
|
+
const validator = Validation_1.Validation.get(decorator.key);
|
|
46
|
+
if (!validator) {
|
|
47
|
+
throw new Error(`Missing validator for ${decorator.key}`);
|
|
48
|
+
}
|
|
49
|
+
const decoratorProps = decorator.key === constants_1.ModelKeys.TYPE
|
|
50
|
+
? [decorator.props]
|
|
51
|
+
: (decorator.props || {});
|
|
52
|
+
const err = validator.hasErrors(obj[prop.toString()], decoratorProps);
|
|
53
|
+
if (err) {
|
|
54
|
+
errs = errs || {};
|
|
55
|
+
errs[decorator.key] = err;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (errs) {
|
|
59
|
+
result = result || {};
|
|
60
|
+
result[decoratedProperty.prop.toString()] = errs;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// tests nested classes
|
|
64
|
+
for (const prop of Object.keys(obj).filter((k) => !result || !result[k])) {
|
|
65
|
+
let err;
|
|
66
|
+
// if a nested Model
|
|
67
|
+
const allDecorators = reflection_1.Reflection.getPropertyDecorators(constants_3.ValidationKeys.REFLECT, obj, prop).decorators;
|
|
68
|
+
const decorators = reflection_1.Reflection.getPropertyDecorators(constants_3.ValidationKeys.REFLECT, obj, prop).decorators.filter((d) => [constants_1.ModelKeys.TYPE, constants_3.ValidationKeys.TYPE].indexOf(d.key) !== -1);
|
|
69
|
+
if (!decorators || !decorators.length)
|
|
70
|
+
continue;
|
|
71
|
+
const dec = decorators.pop();
|
|
72
|
+
const clazz = dec.props.name
|
|
73
|
+
? [dec.props.name]
|
|
74
|
+
: Array.isArray(dec.props.customTypes)
|
|
75
|
+
? dec.props.customTypes
|
|
76
|
+
: [dec.props.customTypes];
|
|
77
|
+
const reserved = Object.values(constants_2.ReservedModels).map((v) => v.toLowerCase());
|
|
78
|
+
for (const c of clazz) {
|
|
79
|
+
if (reserved.indexOf(c.toLowerCase()) === -1) {
|
|
80
|
+
const typeDecoratorKey = Array.isArray(obj[prop])
|
|
81
|
+
? constants_3.ValidationKeys.LIST
|
|
82
|
+
: constants_3.ValidationKeys.TYPE;
|
|
83
|
+
const types = allDecorators.find((d) => d.key === typeDecoratorKey) || {};
|
|
84
|
+
let allowedTypes = [];
|
|
85
|
+
if (types && types.props) {
|
|
86
|
+
const customTypes = Array.isArray(obj[prop])
|
|
87
|
+
? types.props.class
|
|
88
|
+
: types.props.customTypes;
|
|
89
|
+
if (customTypes)
|
|
90
|
+
allowedTypes = Array.isArray(customTypes)
|
|
91
|
+
? customTypes.map((t) => `${t}`.toLowerCase())
|
|
92
|
+
: [customTypes.toLowerCase()];
|
|
93
|
+
}
|
|
94
|
+
const validate = (prop, value) => {
|
|
95
|
+
if (typeof value === "object" || typeof value === "function")
|
|
96
|
+
return (0, utils_1.isModel)(value)
|
|
97
|
+
? value.hasErrors()
|
|
98
|
+
: allowedTypes.includes(typeof value)
|
|
99
|
+
? undefined
|
|
100
|
+
: "Value has no validatable type";
|
|
101
|
+
};
|
|
102
|
+
switch (c) {
|
|
103
|
+
case Array.name:
|
|
104
|
+
case Set.name:
|
|
105
|
+
if (allDecorators.length) {
|
|
106
|
+
const listDec = allDecorators.find((d) => d.key === constants_3.ValidationKeys.LIST);
|
|
107
|
+
if (listDec) {
|
|
108
|
+
err = (c === Array.name
|
|
109
|
+
? obj[prop]
|
|
110
|
+
: // If it's a Set
|
|
111
|
+
obj[prop].values())
|
|
112
|
+
.map((v) => validate(prop, v))
|
|
113
|
+
.filter((e) => !!e);
|
|
114
|
+
if (!err?.length) {
|
|
115
|
+
// if the result is an empty list...
|
|
116
|
+
err = undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
default:
|
|
122
|
+
try {
|
|
123
|
+
if (obj[prop])
|
|
124
|
+
err = validate(prop, obj[prop]);
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
console.warn((0, strings_1.sf)("Model should be validatable but its not: " + e));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (err) {
|
|
132
|
+
result = result || {};
|
|
133
|
+
result[prop] = err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result ? new ModelErrorDefinition_1.ModelErrorDefinition(result) : undefined;
|
|
138
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModelKeys = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @summary Defines the various Model keys used for reflection
|
|
6
|
+
*
|
|
7
|
+
* @property {string} REFLECT prefix to all other keys
|
|
8
|
+
* @property {string} TYPE type key
|
|
9
|
+
* @property {string} PARAMS method params key
|
|
10
|
+
* @property {string} RETURN method return key
|
|
11
|
+
* @property {string} MODEL model key
|
|
12
|
+
* @property {string} ANCHOR anchor key. will serve as a ghost property in the model
|
|
13
|
+
*
|
|
14
|
+
* @constant ModelKeys
|
|
15
|
+
* @memberOf module:decorator-validation.Model
|
|
16
|
+
* @category Model
|
|
17
|
+
*/
|
|
18
|
+
var ModelKeys;
|
|
19
|
+
(function (ModelKeys) {
|
|
20
|
+
ModelKeys["REFLECT"] = "decaf.model.";
|
|
21
|
+
ModelKeys["TYPE"] = "design:type";
|
|
22
|
+
ModelKeys["PARAMS"] = "design:paramtypes";
|
|
23
|
+
ModelKeys["RETURN"] = "design:returntype";
|
|
24
|
+
ModelKeys["MODEL"] = "model";
|
|
25
|
+
ModelKeys["ANCHOR"] = "__model";
|
|
26
|
+
ModelKeys["CONSTRUCTION"] = "constructed-by";
|
|
27
|
+
ModelKeys["ATTRIBUTE"] = "__attributes";
|
|
28
|
+
ModelKeys["HASHING"] = "hashing";
|
|
29
|
+
ModelKeys["SERIALIZATION"] = "serialization";
|
|
30
|
+
})(ModelKeys || (exports.ModelKeys = ModelKeys = {}));
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dateFromFormat = dateFromFormat;
|
|
4
|
+
exports.bindDateToString = bindDateToString;
|
|
5
|
+
exports.isValidDate = isValidDate;
|
|
6
|
+
exports.twoDigitPad = twoDigitPad;
|
|
7
|
+
exports.formatDate = formatDate;
|
|
8
|
+
exports.parseDate = parseDate;
|
|
9
|
+
require("reflect-metadata");
|
|
10
|
+
const constants_1 = require("../validation/Validators/constants");
|
|
11
|
+
const strings_1 = require("./strings");
|
|
12
|
+
/**
|
|
13
|
+
* @summary Reverses the process from {@link formatDate}
|
|
14
|
+
*
|
|
15
|
+
* @param {string} date the date string to be converted back into date
|
|
16
|
+
* @param {string} format the date format
|
|
17
|
+
* @return {Date} the date from the format or the standard new Date({@prop date}) if the string couldn't be parsed (are you sure the format matches the string?)
|
|
18
|
+
*
|
|
19
|
+
* @function dateFromFormat
|
|
20
|
+
* @memberOf module:decorator-validation.Utils.Dates
|
|
21
|
+
* @category Format
|
|
22
|
+
*/
|
|
23
|
+
function dateFromFormat(date, format) {
|
|
24
|
+
let formatRegexp = format;
|
|
25
|
+
// Hour
|
|
26
|
+
if (formatRegexp.match(/hh/))
|
|
27
|
+
formatRegexp = formatRegexp.replace("hh", "(?<hour>\\d{2})");
|
|
28
|
+
else if (formatRegexp.match(/h/))
|
|
29
|
+
formatRegexp = formatRegexp.replace("h", "(?<hour>\\d{1,2})");
|
|
30
|
+
else if (formatRegexp.match(/HH/))
|
|
31
|
+
formatRegexp = formatRegexp.replace("HH", "(?<hour>\\d{2})");
|
|
32
|
+
else if (formatRegexp.match(/H/))
|
|
33
|
+
formatRegexp = formatRegexp.replace("H", "(?<hour>\\d{1,2})");
|
|
34
|
+
// Minutes
|
|
35
|
+
if (formatRegexp.match(/mm/))
|
|
36
|
+
formatRegexp = formatRegexp.replace("mm", "(?<minutes>\\d{2})");
|
|
37
|
+
else if (formatRegexp.match(/m/))
|
|
38
|
+
formatRegexp = formatRegexp.replace("m", "(?<minutes>\\d{1,2})");
|
|
39
|
+
// Seconds
|
|
40
|
+
if (formatRegexp.match(/ss/))
|
|
41
|
+
formatRegexp = formatRegexp.replace("ss", "(?<seconds>\\d{2})");
|
|
42
|
+
else if (formatRegexp.match(/s/))
|
|
43
|
+
formatRegexp = formatRegexp.replace("s", "(?<seconds>\\d{1,2})");
|
|
44
|
+
// Day
|
|
45
|
+
if (formatRegexp.match(/dd/))
|
|
46
|
+
formatRegexp = formatRegexp.replace("dd", "(?<day>\\d{2})");
|
|
47
|
+
else if (formatRegexp.match(/d/))
|
|
48
|
+
formatRegexp = formatRegexp.replace("d", "(?<day>\\d{1,2})");
|
|
49
|
+
// Day Of Week
|
|
50
|
+
if (formatRegexp.match(/EEEE/))
|
|
51
|
+
formatRegexp = formatRegexp.replace("EEEE", "(?<dayofweek>\\w+)");
|
|
52
|
+
// eslint-disable-next-line no-dupe-else-if
|
|
53
|
+
else if (formatRegexp.match(/EEEE/))
|
|
54
|
+
formatRegexp = formatRegexp.replace("EEE", "(?<dayofweek>\\w+)");
|
|
55
|
+
// Year
|
|
56
|
+
if (formatRegexp.match(/yyyy/))
|
|
57
|
+
formatRegexp = formatRegexp.replace("yyyy", "(?<year>\\d{4})");
|
|
58
|
+
else if (formatRegexp.match(/yy/))
|
|
59
|
+
formatRegexp = formatRegexp.replace("yy", "(?<year>\\d{2})");
|
|
60
|
+
// Month
|
|
61
|
+
if (formatRegexp.match(/MMMM/))
|
|
62
|
+
formatRegexp = formatRegexp.replace("MMMM", "(?<monthname>\\w+)");
|
|
63
|
+
else if (formatRegexp.match(/MMM/))
|
|
64
|
+
formatRegexp = formatRegexp.replace("MMM", "(?<monthnamesmall>\\w+)");
|
|
65
|
+
if (formatRegexp.match(/MM/))
|
|
66
|
+
formatRegexp = formatRegexp.replace("MM", "(?<month>\\d{2})");
|
|
67
|
+
else if (formatRegexp.match(/M/))
|
|
68
|
+
formatRegexp = formatRegexp.replace("M", "(?<month>\\d{1,2})");
|
|
69
|
+
// Milis and Am Pm
|
|
70
|
+
formatRegexp = formatRegexp
|
|
71
|
+
.replace("S", "(?<milis>\\d{1,3})")
|
|
72
|
+
.replace("aaa", "(?<ampm>\\w{2})");
|
|
73
|
+
const regexp = new RegExp(formatRegexp, "g");
|
|
74
|
+
const match = regexp.exec(date);
|
|
75
|
+
if (!match || !match.groups)
|
|
76
|
+
return new Date(date);
|
|
77
|
+
const safeParseInt = function (n) {
|
|
78
|
+
if (!n)
|
|
79
|
+
return 0;
|
|
80
|
+
const result = parseInt(n);
|
|
81
|
+
return isNaN(result) ? 0 : result;
|
|
82
|
+
};
|
|
83
|
+
const year = safeParseInt(match.groups.year);
|
|
84
|
+
const day = safeParseInt(match.groups.day);
|
|
85
|
+
const amPm = match.groups.ampm;
|
|
86
|
+
let hour = safeParseInt(match.groups.hour);
|
|
87
|
+
if (amPm)
|
|
88
|
+
hour = amPm === "PM" ? hour + 12 : hour;
|
|
89
|
+
const minutes = safeParseInt(match.groups.minutes);
|
|
90
|
+
const seconds = safeParseInt(match.groups.seconds);
|
|
91
|
+
const ms = safeParseInt(match.groups.milis);
|
|
92
|
+
const monthName = match.groups.monthname;
|
|
93
|
+
const monthNameSmall = match.groups.monthnamesmall;
|
|
94
|
+
let month = match.groups.month;
|
|
95
|
+
if (monthName)
|
|
96
|
+
month = constants_1.MONTH_NAMES.indexOf(monthName);
|
|
97
|
+
else if (monthNameSmall) {
|
|
98
|
+
const m = constants_1.MONTH_NAMES.find((m) => m.toLowerCase().startsWith(monthNameSmall.toLowerCase()));
|
|
99
|
+
if (!m)
|
|
100
|
+
return new Date(date);
|
|
101
|
+
month = constants_1.MONTH_NAMES.indexOf(m);
|
|
102
|
+
}
|
|
103
|
+
else
|
|
104
|
+
month = safeParseInt(`${month}`);
|
|
105
|
+
return new Date(year, month - 1, day, hour, minutes, seconds, ms);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* @summary Binds a date format to a string
|
|
109
|
+
* @param {Date} [date]
|
|
110
|
+
* @param {string} [format]
|
|
111
|
+
* @memberOf module:decorator-validation.Utils.Format
|
|
112
|
+
* @category Utilities
|
|
113
|
+
*/
|
|
114
|
+
function bindDateToString(date, format) {
|
|
115
|
+
if (!date)
|
|
116
|
+
return;
|
|
117
|
+
const func = () => formatDate(date, format);
|
|
118
|
+
Object.defineProperty(date, "toISOString", {
|
|
119
|
+
enumerable: false,
|
|
120
|
+
configurable: false,
|
|
121
|
+
value: func,
|
|
122
|
+
});
|
|
123
|
+
Object.defineProperty(date, "toString", {
|
|
124
|
+
enumerable: false,
|
|
125
|
+
configurable: false,
|
|
126
|
+
value: func,
|
|
127
|
+
});
|
|
128
|
+
// Object.setPrototypeOf(date, Date.prototype);
|
|
129
|
+
return date;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @summary Helper function to be used instead of instanceOf Date
|
|
133
|
+
* @param date
|
|
134
|
+
* @memberOf module:decorator-validation.Utils.Dates
|
|
135
|
+
* @category Validation
|
|
136
|
+
*/
|
|
137
|
+
function isValidDate(date) {
|
|
138
|
+
return (date &&
|
|
139
|
+
Object.prototype.toString.call(date) === "[object Date]" &&
|
|
140
|
+
!Number.isNaN(date));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* @summary Util function to pad numbers
|
|
144
|
+
* @param {number} num
|
|
145
|
+
*
|
|
146
|
+
* @return {string}
|
|
147
|
+
*
|
|
148
|
+
* @function twoDigitPad
|
|
149
|
+
* @memberOf module:decorator-validation.Utils.Format
|
|
150
|
+
* @category Format
|
|
151
|
+
*/
|
|
152
|
+
function twoDigitPad(num) {
|
|
153
|
+
return num < 10 ? "0" + num : num.toString();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @summary Date Format Handling
|
|
157
|
+
* @description Code from {@link https://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date}
|
|
158
|
+
*
|
|
159
|
+
* <pre>
|
|
160
|
+
* Using similar formatting as Moment.js, Class DateTimeFormatter (Java), and Class SimpleDateFormat (Java),
|
|
161
|
+
* I implemented a comprehensive solution formatDate(date, patternStr) where the code is easy to read and modify.
|
|
162
|
+
* You can display date, time, AM/PM, etc.
|
|
163
|
+
*
|
|
164
|
+
* Date and Time Patterns
|
|
165
|
+
* yy = 2-digit year; yyyy = full year
|
|
166
|
+
* M = digit month; MM = 2-digit month; MMM = short month name; MMMM = full month name
|
|
167
|
+
* EEEE = full weekday name; EEE = short weekday name
|
|
168
|
+
* d = digit day; dd = 2-digit day
|
|
169
|
+
* h = hours am/pm; hh = 2-digit hours am/pm; H = hours; HH = 2-digit hours
|
|
170
|
+
* m = minutes; mm = 2-digit minutes; aaa = AM/PM
|
|
171
|
+
* s = seconds; ss = 2-digit seconds
|
|
172
|
+
* S = miliseconds
|
|
173
|
+
* </pre>
|
|
174
|
+
*
|
|
175
|
+
* @param {Date} date
|
|
176
|
+
* @param {string} [patternStr] defaults to 'yyyy/MM/dd'
|
|
177
|
+
* @return {string} the formatted date
|
|
178
|
+
*
|
|
179
|
+
* @function formatDate
|
|
180
|
+
* @memberOf module:decorator-validation.Utils.Dates
|
|
181
|
+
* @category Format
|
|
182
|
+
*/
|
|
183
|
+
function formatDate(date, patternStr = "yyyy/MM/dd") {
|
|
184
|
+
const day = date.getDate(), month = date.getMonth(), year = date.getFullYear(), hour = date.getHours(), minute = date.getMinutes(), second = date.getSeconds(), miliseconds = date.getMilliseconds(), h = hour % 12, hh = twoDigitPad(h), HH = twoDigitPad(hour), mm = twoDigitPad(minute), ss = twoDigitPad(second), aaa = hour < 12 ? "AM" : "PM", EEEE = constants_1.DAYS_OF_WEEK_NAMES[date.getDay()], EEE = EEEE.substr(0, 3), dd = twoDigitPad(day), M = month + 1, MM = twoDigitPad(M), MMMM = constants_1.MONTH_NAMES[month], MMM = MMMM.substr(0, 3), yyyy = year + "", yy = yyyy.substr(2, 2);
|
|
185
|
+
// checks to see if month name will be used
|
|
186
|
+
patternStr = patternStr
|
|
187
|
+
.replace("hh", hh)
|
|
188
|
+
.replace("h", h.toString())
|
|
189
|
+
.replace("HH", HH)
|
|
190
|
+
.replace("H", hour.toString())
|
|
191
|
+
.replace("mm", mm)
|
|
192
|
+
.replace("m", minute.toString())
|
|
193
|
+
.replace("ss", ss)
|
|
194
|
+
.replace("s", second.toString())
|
|
195
|
+
.replace("S", miliseconds.toString())
|
|
196
|
+
.replace("dd", dd)
|
|
197
|
+
.replace("d", day.toString())
|
|
198
|
+
.replace("EEEE", EEEE)
|
|
199
|
+
.replace("EEE", EEE)
|
|
200
|
+
.replace("yyyy", yyyy)
|
|
201
|
+
.replace("yy", yy)
|
|
202
|
+
.replace("aaa", aaa);
|
|
203
|
+
if (patternStr.indexOf("MMM") > -1) {
|
|
204
|
+
patternStr = patternStr.replace("MMMM", MMMM).replace("MMM", MMM);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
patternStr = patternStr.replace("MM", MM).replace("M", M.toString());
|
|
208
|
+
}
|
|
209
|
+
return patternStr;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* @summary Parses a date from a specified format
|
|
213
|
+
* @param {string} format
|
|
214
|
+
* @param {string | Date | number} [v]
|
|
215
|
+
* @memberOf module:decorator-validation.Utils.Dates
|
|
216
|
+
* @category Format
|
|
217
|
+
*/
|
|
218
|
+
function parseDate(format, v) {
|
|
219
|
+
let value = undefined;
|
|
220
|
+
if (!v)
|
|
221
|
+
return undefined;
|
|
222
|
+
if (v instanceof Date)
|
|
223
|
+
try {
|
|
224
|
+
value = dateFromFormat(formatDate(v, format), format);
|
|
225
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
throw new Error((0, strings_1.sf)("Could not convert date {0} to format: {1}", v.toString(), format));
|
|
229
|
+
}
|
|
230
|
+
else if (typeof v === "string") {
|
|
231
|
+
value = dateFromFormat(v, format);
|
|
232
|
+
}
|
|
233
|
+
else if (typeof v === "number") {
|
|
234
|
+
const d = new Date(v);
|
|
235
|
+
value = dateFromFormat(formatDate(d, format), format);
|
|
236
|
+
}
|
|
237
|
+
else if (isValidDate(v)) {
|
|
238
|
+
try {
|
|
239
|
+
const d = new Date(v);
|
|
240
|
+
value = dateFromFormat(formatDate(d, format), format);
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
throw new Error((0, strings_1.sf)("Could not convert date {0} to format: {1}", v, format));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
throw new Error(`Invalid value provided ${v}`);
|
|
249
|
+
}
|
|
250
|
+
return bindDateToString(value, format);
|
|
251
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prop = prop;
|
|
4
|
+
exports.propMetadata = propMetadata;
|
|
5
|
+
const reflection_1 = require("@decaf-ts/reflection");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
function prop(key = constants_1.ModelKeys.ATTRIBUTE) {
|
|
8
|
+
return (model, propertyKey) => {
|
|
9
|
+
let props;
|
|
10
|
+
if (Object.prototype.hasOwnProperty.call(model, key)) {
|
|
11
|
+
props = model[key];
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
props = model[key] = [];
|
|
15
|
+
}
|
|
16
|
+
if (!props.includes(propertyKey))
|
|
17
|
+
props.push(propertyKey);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function propMetadata(key, value) {
|
|
21
|
+
return (0, reflection_1.apply)(prop(), (0, reflection_1.metadata)(key, value));
|
|
22
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Hashing = exports.DefaultHashingMethod = void 0;
|
|
4
|
+
exports.hashCode = hashCode;
|
|
5
|
+
exports.hashSerialization = hashSerialization;
|
|
6
|
+
exports.hashObj = hashObj;
|
|
7
|
+
const serialization_1 = require("./serialization");
|
|
8
|
+
/**
|
|
9
|
+
* @summary Mimics Java's String's Hash implementation
|
|
10
|
+
*
|
|
11
|
+
* @param {string | number | symbol | Date} obj
|
|
12
|
+
* @return {number} hash value of obj
|
|
13
|
+
*
|
|
14
|
+
* @function hashCode
|
|
15
|
+
* @memberOf module:decorator-validation.Utils.Hashing
|
|
16
|
+
* @category Hashing
|
|
17
|
+
*/
|
|
18
|
+
function hashCode(obj) {
|
|
19
|
+
obj = String(obj);
|
|
20
|
+
let hash = 0;
|
|
21
|
+
for (let i = 0; i < obj.length; i++) {
|
|
22
|
+
const character = obj.charCodeAt(i);
|
|
23
|
+
hash = (hash << 5) - hash + character;
|
|
24
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
25
|
+
}
|
|
26
|
+
return hash.toString();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @summary Hashes an object serializing it and then hashing the string
|
|
30
|
+
* @description The Serialization algorithm used by default (JSON.stringify)
|
|
31
|
+
* is not deterministic and should not be used for hashing
|
|
32
|
+
*
|
|
33
|
+
* @param {Record<string, any>} obj
|
|
34
|
+
* @return {string} the resulting hash
|
|
35
|
+
*
|
|
36
|
+
* @function hashSerialization
|
|
37
|
+
* @memberOf module:decorator-validation.Utils.Hashing
|
|
38
|
+
*
|
|
39
|
+
* @category Hashing
|
|
40
|
+
*/
|
|
41
|
+
function hashSerialization(obj) {
|
|
42
|
+
return hashCode(serialization_1.Serialization.serialize(obj));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @summary Hashes an object by combining the hash of all its properties
|
|
46
|
+
*
|
|
47
|
+
* @param {Record<string, any>} obj
|
|
48
|
+
* @return {string} the resulting hash
|
|
49
|
+
*
|
|
50
|
+
* @function hashObj
|
|
51
|
+
* @memberOf module:decorator-validation.Utils.Hashing
|
|
52
|
+
* @category Hashing
|
|
53
|
+
*/
|
|
54
|
+
function hashObj(obj) {
|
|
55
|
+
const hashReducer = function (h, el) {
|
|
56
|
+
const elHash = hashFunction(el);
|
|
57
|
+
if (typeof elHash === "string")
|
|
58
|
+
return hashFunction((h || "") + hashFunction(el));
|
|
59
|
+
h = h || 0;
|
|
60
|
+
h = (h << 5) - h + elHash;
|
|
61
|
+
return h & h;
|
|
62
|
+
};
|
|
63
|
+
const func = hashCode;
|
|
64
|
+
const hashFunction = function (value) {
|
|
65
|
+
if (typeof value === "undefined")
|
|
66
|
+
return "";
|
|
67
|
+
if (["string", "number", "symbol"].indexOf(typeof value) !== -1)
|
|
68
|
+
return func(value.toString());
|
|
69
|
+
if (value instanceof Date)
|
|
70
|
+
return func(value.getTime());
|
|
71
|
+
if (Array.isArray(value))
|
|
72
|
+
return value.reduce(hashReducer, undefined);
|
|
73
|
+
return Object.values(value).reduce(hashReducer, undefined);
|
|
74
|
+
};
|
|
75
|
+
const result = Object.values(obj).reduce(hashReducer, 0);
|
|
76
|
+
return (typeof result === "number" ? Math.abs(result) : result).toString();
|
|
77
|
+
}
|
|
78
|
+
exports.DefaultHashingMethod = "default";
|
|
79
|
+
class Hashing {
|
|
80
|
+
static { this.current = exports.DefaultHashingMethod; }
|
|
81
|
+
static { this.cache = {
|
|
82
|
+
default: hashObj,
|
|
83
|
+
}; }
|
|
84
|
+
constructor() { }
|
|
85
|
+
static get(key) {
|
|
86
|
+
if (key in this.cache)
|
|
87
|
+
return this.cache[key];
|
|
88
|
+
throw new Error(`No hashing method registered under ${key}`);
|
|
89
|
+
}
|
|
90
|
+
static register(key, func, setDefault = false) {
|
|
91
|
+
if (key in this.cache)
|
|
92
|
+
throw new Error(`Hashing method ${key} already registered`);
|
|
93
|
+
this.cache[key] = func;
|
|
94
|
+
if (setDefault)
|
|
95
|
+
this.current = key;
|
|
96
|
+
}
|
|
97
|
+
static hash(obj, method, ...args) {
|
|
98
|
+
if (!method)
|
|
99
|
+
return this.get(this.current)(obj, ...args);
|
|
100
|
+
return this.get(method)(obj, ...args);
|
|
101
|
+
}
|
|
102
|
+
static setDefault(method) {
|
|
103
|
+
this.current = this.get(method);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.Hashing = Hashing;
|