@jakobkg/shapes-ts 0.1.0
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/LICENSE +19 -0
- package/README.md +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/shapes.d.ts +96 -0
- package/dist/shapes.d.ts.map +1 -0
- package/dist/shapes.js +318 -0
- package/jakobkg-shapes-ts-0.1.0.tgz +0 -0
- package/package.json +14 -0
- package/shapes-ts-0.1.0.tgz +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2025 Jakob Grønhaug.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
4
|
+
are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
9
|
+
|
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
11
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
12
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
13
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
14
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
15
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
16
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
17
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
18
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
19
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/shapes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
package/dist/shapes.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge to convert a Shape into a TS type.
|
|
3
|
+
*/
|
|
4
|
+
export type Type<T extends Shape> = T["primitive"];
|
|
5
|
+
type ShapePredicate<T> = (x: T) => boolean;
|
|
6
|
+
interface Shape<T = any> {
|
|
7
|
+
readonly typename: string;
|
|
8
|
+
readonly primitive: T;
|
|
9
|
+
readonly optional?: boolean;
|
|
10
|
+
readonly predicates: ShapePredicate<T>[];
|
|
11
|
+
check(x: unknown): x is T;
|
|
12
|
+
/**
|
|
13
|
+
* Adds a custom validation predicate to the shape
|
|
14
|
+
* @param predicate A function that takes a value of the shape's type and returns a boolean
|
|
15
|
+
* @param description Optional description of the constraint for error messages
|
|
16
|
+
* @returns A new shape with the additional validation
|
|
17
|
+
*/
|
|
18
|
+
where(predicate: ShapePredicate<T>, description: string): Shape<T>;
|
|
19
|
+
and<U>(other: Shape<U>): IntersectionShape<T, U>;
|
|
20
|
+
or<U>(other: Shape<U>): UnionShape<T, U>;
|
|
21
|
+
}
|
|
22
|
+
interface ObjectShape<T = Record<string, unknown>> extends Shape<T> {
|
|
23
|
+
readonly properties: Record<string, Shape<T>>;
|
|
24
|
+
readonly allowUnknownProperties?: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface ObjectShapeOptions {
|
|
27
|
+
readonly allowUnknownProperties?: boolean;
|
|
28
|
+
readonly additionalPermittedProperties?: Record<string, Shape<Record<string, unknown>>>;
|
|
29
|
+
}
|
|
30
|
+
interface ArrayShape<T extends Shape> extends Shape<Array<T["primitive"]>> {
|
|
31
|
+
readonly inner: T;
|
|
32
|
+
}
|
|
33
|
+
interface UnionShape<Left, Right> extends Shape<Left | Right> {
|
|
34
|
+
left: Shape<Left>;
|
|
35
|
+
right: Shape<Right>;
|
|
36
|
+
}
|
|
37
|
+
interface IntersectionShape<Left, Right> extends Shape<Left & Right> {
|
|
38
|
+
left: Shape<Left>;
|
|
39
|
+
right: Shape<Right>;
|
|
40
|
+
}
|
|
41
|
+
interface OptionalShape<T extends Shape> extends Shape<T["primitive"] | undefined> {
|
|
42
|
+
readonly inner: T;
|
|
43
|
+
}
|
|
44
|
+
interface NullableShape<T extends Shape> extends Shape<T["primitive"] | null> {
|
|
45
|
+
readonly inner: T;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a shape representing a JS `number`.
|
|
49
|
+
* Does not support BigInt.
|
|
50
|
+
*/
|
|
51
|
+
export declare function number(): Shape<number>;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a shape representing a JS `string`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function string(): Shape<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a shape representing a JS `boolean`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function boolean(): Shape<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates an array shape, representing `Array<T>` (aka `T[]`).
|
|
62
|
+
* Takes the shape representing `T` as a parameter.
|
|
63
|
+
*/
|
|
64
|
+
export declare function array<T extends Shape>(shape: T): ArrayShape<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Creates an object shape.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* const Group = Shapes.object({
|
|
70
|
+
* id: Shapes.number(),
|
|
71
|
+
* name: Shapes.string(),
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* const User = Shapes.object({
|
|
75
|
+
* id: Shapes.number(),
|
|
76
|
+
* name: Shapes.string(),
|
|
77
|
+
* groups: Shapes.nullable(
|
|
78
|
+
* Shapes.array(Group)
|
|
79
|
+
* )
|
|
80
|
+
* });
|
|
81
|
+
*/
|
|
82
|
+
export declare function object<T extends Record<string, Shape>>(properties: T, options?: ObjectShapeOptions): ObjectShape<{
|
|
83
|
+
[K in keyof T]: Type<T[K]>;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Creates a shape representing an optional type.
|
|
87
|
+
* `Shapes.optional(T)` corresponds to `T | undefined`
|
|
88
|
+
*/
|
|
89
|
+
export declare function optional<T extends Shape>(shape: T): OptionalShape<T>;
|
|
90
|
+
/**
|
|
91
|
+
* Creates a shape representing a nullable type.
|
|
92
|
+
* `Shapes.nullable(T)` corresponds to `T | null`
|
|
93
|
+
*/
|
|
94
|
+
export declare function nullable<T extends Shape>(shape: T): NullableShape<T>;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes/shapes.ts"],"names":[],"mappings":"AAkCA;;GAEG;AACH,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;AAGnD,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;AAI3C,UAAU,KAAK,CAAC,CAAC,GAAG,GAAG;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzC,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;IAE1B;;;;;OAKG;IACH,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjD,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAC1C;AAGD,UAAU,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,KAAK,CAAC,CAAC,CAAC;IACjE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAC3C;AAED,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,6BAA6B,CAAC,EAAE,MAAM,CAC7C,MAAM,EACN,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAC/B,CAAC;CACH;AAED,UAAU,UAAU,CAAC,CAAC,SAAS,KAAK,CAAE,SAAQ,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACxE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED,UAAU,UAAU,CAAC,IAAI,EAAE,KAAK,CAAE,SAAQ,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;IAC3D,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;CACrB;AAgCD,UAAU,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAE,SAAQ,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;IAClE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;CACrB;AA+CD,UAAU,aAAa,CAAC,CAAC,SAAS,KAAK,CAAE,SACvC,KAAK,CACH,CAAC,CAAC,WAAW,CAAC,GAAG,SAAS,CAC3B;IACD,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED,UAAU,aAAa,CAAC,CAAC,SAAS,KAAK,CAAE,SAAQ,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;IAC3E,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAqBtC;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAqBtC;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAqBxC;AAID;;;GAGG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAmC9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACpD,UAAU,EAAE,CAAC,EACb,OAAO,CAAC,EAAE,kBAAkB,GAC3B,WAAW,CACZ;KACG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3B,CACF,CA0DA;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAsBpE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAwBpE"}
|
package/dist/shapes.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// TYPE GUARDS
|
|
3
|
+
// These are static functions to avoid allocating guards per Shape instance,
|
|
4
|
+
// Shapes may reference these instead
|
|
5
|
+
var __assign = (this && this.__assign) || function () {
|
|
6
|
+
__assign = Object.assign || function(t) {
|
|
7
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
8
|
+
s = arguments[i];
|
|
9
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
10
|
+
t[p] = s[p];
|
|
11
|
+
}
|
|
12
|
+
return t;
|
|
13
|
+
};
|
|
14
|
+
return __assign.apply(this, arguments);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.number = number;
|
|
18
|
+
exports.string = string;
|
|
19
|
+
exports.boolean = boolean;
|
|
20
|
+
exports.array = array;
|
|
21
|
+
exports.object = object;
|
|
22
|
+
exports.optional = optional;
|
|
23
|
+
exports.nullable = nullable;
|
|
24
|
+
function isString(input) {
|
|
25
|
+
return typeof input === "string";
|
|
26
|
+
}
|
|
27
|
+
function isNumber(input) {
|
|
28
|
+
return Number.isFinite(input);
|
|
29
|
+
}
|
|
30
|
+
function isObject(input) {
|
|
31
|
+
return input !== null && typeof input === "object" && !Array.isArray(input);
|
|
32
|
+
}
|
|
33
|
+
function isArray(input) {
|
|
34
|
+
return Array.isArray(input);
|
|
35
|
+
}
|
|
36
|
+
function isNull(input) {
|
|
37
|
+
return input === null;
|
|
38
|
+
}
|
|
39
|
+
function isBoolean(input) {
|
|
40
|
+
return typeof input === "boolean";
|
|
41
|
+
}
|
|
42
|
+
function isUndefined(input) {
|
|
43
|
+
return input === undefined;
|
|
44
|
+
}
|
|
45
|
+
function makeUnion(left, right) {
|
|
46
|
+
return {
|
|
47
|
+
typename: "".concat(left.typename, " | ").concat(right.typename),
|
|
48
|
+
primitive: undefined,
|
|
49
|
+
left: left,
|
|
50
|
+
right: right,
|
|
51
|
+
predicates: [],
|
|
52
|
+
where: function (p) {
|
|
53
|
+
this.predicates.push(p);
|
|
54
|
+
return this;
|
|
55
|
+
},
|
|
56
|
+
check: function (x) {
|
|
57
|
+
return (left.check(x) || right.check(x)) &&
|
|
58
|
+
this.predicates.every(function (p) { return p(x); });
|
|
59
|
+
}, // TODO: refine for objects?
|
|
60
|
+
and: function (other) {
|
|
61
|
+
return makeIntersection(this, other);
|
|
62
|
+
},
|
|
63
|
+
or: function (other) {
|
|
64
|
+
return makeUnion(this, other);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function makeIntersection(left, right) {
|
|
69
|
+
return {
|
|
70
|
+
typename: "".concat(left.typename, " | ").concat(right.typename),
|
|
71
|
+
primitive: undefined,
|
|
72
|
+
left: __assign(__assign({}, left), {
|
|
73
|
+
// Trickery: combine permitted properties of left and right
|
|
74
|
+
properties: __assign(__assign({}, right.properties), left.properties) }),
|
|
75
|
+
right: __assign(__assign({}, right), {
|
|
76
|
+
// Trickery: combine permitted properties of left and right
|
|
77
|
+
properties: __assign(__assign({}, left.properties), right.properties) }),
|
|
78
|
+
predicates: [],
|
|
79
|
+
where: function (p) {
|
|
80
|
+
this.predicates.push(p);
|
|
81
|
+
return this;
|
|
82
|
+
},
|
|
83
|
+
check: function (x) {
|
|
84
|
+
return this.left.check(x) && this.right.check(x) &&
|
|
85
|
+
this.predicates.every(function (p) { return p(x); });
|
|
86
|
+
},
|
|
87
|
+
and: function (other) {
|
|
88
|
+
return makeIntersection(this, other);
|
|
89
|
+
},
|
|
90
|
+
or: function (other) {
|
|
91
|
+
return makeUnion(this, other);
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/// PRIMITIVE SHAPE FACTORIES
|
|
96
|
+
/**
|
|
97
|
+
* Creates a shape representing a JS `number`.
|
|
98
|
+
* Does not support BigInt.
|
|
99
|
+
*/
|
|
100
|
+
function number() {
|
|
101
|
+
return {
|
|
102
|
+
typename: "number",
|
|
103
|
+
predicates: [],
|
|
104
|
+
primitive: undefined,
|
|
105
|
+
check: function (x) {
|
|
106
|
+
return isNumber(x) && this.predicates.every(function (p) { return p(x); });
|
|
107
|
+
},
|
|
108
|
+
where: function (p) {
|
|
109
|
+
this.predicates.push(p);
|
|
110
|
+
return this;
|
|
111
|
+
},
|
|
112
|
+
and: function (other) {
|
|
113
|
+
return makeIntersection(this, other);
|
|
114
|
+
},
|
|
115
|
+
or: function (other) {
|
|
116
|
+
return makeUnion(this, other);
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates a shape representing a JS `string`.
|
|
122
|
+
*/
|
|
123
|
+
function string() {
|
|
124
|
+
return {
|
|
125
|
+
typename: "string",
|
|
126
|
+
primitive: undefined,
|
|
127
|
+
check: function (x) {
|
|
128
|
+
return isString(x) && this.predicates.every(function (p) { return p(x); });
|
|
129
|
+
},
|
|
130
|
+
predicates: [],
|
|
131
|
+
where: function (predicate) {
|
|
132
|
+
this.predicates.push(predicate);
|
|
133
|
+
return this;
|
|
134
|
+
},
|
|
135
|
+
and: function (other) {
|
|
136
|
+
return makeIntersection(this, other);
|
|
137
|
+
},
|
|
138
|
+
or: function (other) {
|
|
139
|
+
return makeUnion(this, other);
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Creates a shape representing a JS `boolean`.
|
|
145
|
+
*/
|
|
146
|
+
function boolean() {
|
|
147
|
+
return {
|
|
148
|
+
primitive: undefined,
|
|
149
|
+
typename: "boolean",
|
|
150
|
+
check: function (x) {
|
|
151
|
+
return isBoolean(x) && this.predicates.every(function (p) { return p(x); });
|
|
152
|
+
},
|
|
153
|
+
predicates: [],
|
|
154
|
+
where: function (predicate) {
|
|
155
|
+
this.predicates.push(predicate);
|
|
156
|
+
return this;
|
|
157
|
+
},
|
|
158
|
+
and: function (other) {
|
|
159
|
+
return makeIntersection(this, other);
|
|
160
|
+
},
|
|
161
|
+
or: function (other) {
|
|
162
|
+
return makeUnion(this, other);
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/// COMPLEX SHAPE FACTORIES
|
|
167
|
+
/**
|
|
168
|
+
* Creates an array shape, representing `Array<T>` (aka `T[]`).
|
|
169
|
+
* Takes the shape representing `T` as a parameter.
|
|
170
|
+
*/
|
|
171
|
+
function array(shape) {
|
|
172
|
+
var typename = "Array<".concat(shape.typename, ">");
|
|
173
|
+
return {
|
|
174
|
+
typename: typename,
|
|
175
|
+
inner: shape,
|
|
176
|
+
primitive: undefined,
|
|
177
|
+
check: function (input) {
|
|
178
|
+
if (!isArray(input)) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return input.every(function (entry) {
|
|
182
|
+
if (!shape.check(entry)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
}) && this.predicates.every(function (p) { return p(input); });
|
|
187
|
+
},
|
|
188
|
+
predicates: [],
|
|
189
|
+
where: function (predicate) {
|
|
190
|
+
this.predicates.push(predicate);
|
|
191
|
+
return this;
|
|
192
|
+
},
|
|
193
|
+
and: function (other) {
|
|
194
|
+
return makeIntersection(this, other);
|
|
195
|
+
},
|
|
196
|
+
or: function (other) {
|
|
197
|
+
return makeUnion(this, other);
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Creates an object shape.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const Group = Shapes.object({
|
|
206
|
+
* id: Shapes.number(),
|
|
207
|
+
* name: Shapes.string(),
|
|
208
|
+
* });
|
|
209
|
+
*
|
|
210
|
+
* const User = Shapes.object({
|
|
211
|
+
* id: Shapes.number(),
|
|
212
|
+
* name: Shapes.string(),
|
|
213
|
+
* groups: Shapes.nullable(
|
|
214
|
+
* Shapes.array(Group)
|
|
215
|
+
* )
|
|
216
|
+
* });
|
|
217
|
+
*/
|
|
218
|
+
function object(properties, options) {
|
|
219
|
+
var allowUnknownProperties = options === null || options === void 0 ? void 0 : options.allowUnknownProperties;
|
|
220
|
+
return {
|
|
221
|
+
typename: "Object",
|
|
222
|
+
allowUnknownProperties: allowUnknownProperties,
|
|
223
|
+
check: function (input) {
|
|
224
|
+
// Check that input is an object
|
|
225
|
+
if (!isObject(input)) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
// Check for unknown properties
|
|
229
|
+
if (!this.allowUnknownProperties) {
|
|
230
|
+
for (var inputProperty in input) {
|
|
231
|
+
if (!(inputProperty in this.properties)) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Check required properties and their types
|
|
237
|
+
for (var property in properties) {
|
|
238
|
+
var field = input[property];
|
|
239
|
+
var propertyShape = properties[property];
|
|
240
|
+
// Property presence check
|
|
241
|
+
if (!(property in input) && !propertyShape.optional) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
// Property type check
|
|
245
|
+
if (!propertyShape.check(field)) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return this.predicates.every(function (p) { return p(input); });
|
|
250
|
+
},
|
|
251
|
+
properties: __assign(__assign({}, properties), options === null || options === void 0 ? void 0 : options.additionalPermittedProperties),
|
|
252
|
+
primitive: undefined,
|
|
253
|
+
predicates: [],
|
|
254
|
+
where: function (predicate) {
|
|
255
|
+
this.predicates.push(predicate);
|
|
256
|
+
return this;
|
|
257
|
+
},
|
|
258
|
+
and: function (other) {
|
|
259
|
+
return makeIntersection(this, other);
|
|
260
|
+
},
|
|
261
|
+
or: function (other) {
|
|
262
|
+
return makeUnion(this, other);
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/// TYPE MODIFIERS
|
|
267
|
+
/**
|
|
268
|
+
* Creates a shape representing an optional type.
|
|
269
|
+
* `Shapes.optional(T)` corresponds to `T | undefined`
|
|
270
|
+
*/
|
|
271
|
+
function optional(shape) {
|
|
272
|
+
return {
|
|
273
|
+
typename: "".concat(shape.typename, " | undefined"),
|
|
274
|
+
inner: shape,
|
|
275
|
+
optional: true,
|
|
276
|
+
primitive: undefined,
|
|
277
|
+
predicates: [],
|
|
278
|
+
check: function (input) {
|
|
279
|
+
return isUndefined(input) || shape.check(input);
|
|
280
|
+
},
|
|
281
|
+
where: function (predicate) {
|
|
282
|
+
this.inner.predicates.push(predicate);
|
|
283
|
+
return this;
|
|
284
|
+
},
|
|
285
|
+
and: function (other) {
|
|
286
|
+
return makeIntersection(this, other);
|
|
287
|
+
},
|
|
288
|
+
or: function (other) {
|
|
289
|
+
return makeUnion(this, other);
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Creates a shape representing a nullable type.
|
|
295
|
+
* `Shapes.nullable(T)` corresponds to `T | null`
|
|
296
|
+
*/
|
|
297
|
+
function nullable(shape) {
|
|
298
|
+
var nullShape = {
|
|
299
|
+
typename: "".concat(shape.typename, " | null"),
|
|
300
|
+
check: function (input) {
|
|
301
|
+
return isNull(input) || shape.check(input);
|
|
302
|
+
},
|
|
303
|
+
inner: shape,
|
|
304
|
+
primitive: undefined,
|
|
305
|
+
predicates: [],
|
|
306
|
+
where: function (p) {
|
|
307
|
+
this.inner.predicates.push(p);
|
|
308
|
+
return this;
|
|
309
|
+
},
|
|
310
|
+
and: function (other) {
|
|
311
|
+
return makeIntersection(this, other);
|
|
312
|
+
},
|
|
313
|
+
or: function (other) {
|
|
314
|
+
return makeUnion(this, other);
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
return nullShape;
|
|
318
|
+
}
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jakobkg/shapes-ts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "deno test",
|
|
8
|
+
"test:coverage": "deno test --coverage",
|
|
9
|
+
"build": "tsc"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"typescript": "5.9.3"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
Binary file
|