@jakobkg/shapes-ts 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,3 +1,94 @@
1
1
  # shapes-ts
2
2
 
3
- Toy library to create runtime safe types in TS, see `main.ts` for example usage
3
+ Toy library to create runtime safe types in TS.
4
+
5
+ When describing the shape of your data in shapes-ts, you get the corresponding TS type and a validation utility for free!
6
+
7
+ ```typescript
8
+ const Role = Shapes.object({
9
+ role: Shapes.string(),
10
+ actor: Shapes.string(),
11
+ });
12
+
13
+ const Movie = Shapes.object({
14
+ title: Shapes.string(),
15
+ rating: Shapes.number().where(
16
+ (n) => n >= 0 && n <= 5,
17
+ "rating must be in range 0.0-5.0",
18
+ ),
19
+ cast: Shapes.array(Role),
20
+ });
21
+
22
+ // This infers as
23
+ // {
24
+ // title: string,
25
+ // rating: number,
26
+ // cast: { role: string, actor: string }[]
27
+ // }
28
+ type Movie = Shapes.Type<typeof Movie>;
29
+
30
+ const movieData: unknown = getFromIMDB("tt23289160");
31
+
32
+ if (!Movie.check(movieData)) {
33
+ throw new Error("Unexpected data from API");
34
+ }
35
+
36
+ // Past this point, movieData is typed as Movie
37
+
38
+ for (const member of movieData.cast) {
39
+ console.log(`${member.actor} as ${member.role}`);
40
+ }
41
+ ```
42
+
43
+ ## Supported types
44
+
45
+ ### Primitives
46
+
47
+ - string
48
+ - number
49
+ - boolean
50
+ - object
51
+ - array
52
+
53
+ ### Modified types
54
+
55
+ - Nullable types (`T | null`)
56
+ - Optional types (`T | undefined`)
57
+ - Unions (`A & B`)
58
+ - Intersections (`A | B`)
59
+
60
+ ## Predicates
61
+
62
+ Shapes can have additional validation checks added to them. These do not affect the inferred type, but are still ran as part of a shape's `.check()` method to help enforce constraints that are not easily modeled using the type system.
63
+
64
+ ```typescript
65
+ const Username = Shapes.string().where(
66
+ (str) => str.length < 10,
67
+ "must be less than 10 characters long",
68
+ );
69
+
70
+ Username.check("jakob :)"); // true
71
+ Username.check("CptAmericaFan207"); // false
72
+ ```
73
+
74
+ Predicates can be used with all types of shapes, and they may be combined both by stacking them on a single shape and by combining shapes that already have predicates on them.
75
+
76
+ ```typescript
77
+ const Fizz = Shapes.number().where(
78
+ (n) => n % 3 === 0,
79
+ "must be divisible by 3",
80
+ );
81
+
82
+ const Buzz = Shapes.number().where(
83
+ (n) => n % 5 === 0,
84
+ "must be divisible by 5",
85
+ );
86
+
87
+ const FizzBuzz = Fizz.and(Buzz);
88
+
89
+ Fizz.check(3); // true
90
+ FizzBuzz.check(3); // false
91
+ Fizz.check(5); // false
92
+ Buzz.check(5); // true
93
+ FizzBuzz.check(15); //true
94
+ ```
package/dist/shapes.d.ts CHANGED
@@ -1,13 +1,16 @@
1
+ declare const Predicates: unique symbol;
2
+ declare const Optional: unique symbol;
3
+ declare const Properties: unique symbol;
4
+ declare const AllowUnknownProperties: unique symbol;
1
5
  /**
2
6
  * Bridge to convert a Shape into a TS type.
3
7
  */
4
- export type Type<T extends Shape> = T["primitive"];
8
+ export type Type<T> = T extends Shape<infer U> ? U : never;
5
9
  type ShapePredicate<T> = (x: T) => boolean;
6
- interface Shape<T = any> {
10
+ interface Shape<T> {
7
11
  readonly typename: string;
8
- readonly primitive: T;
9
- readonly optional?: boolean;
10
- readonly predicates: ShapePredicate<T>[];
12
+ readonly [Optional]?: boolean;
13
+ readonly [Predicates]: ShapePredicate<T>[];
11
14
  check(x: unknown): x is T;
12
15
  /**
13
16
  * Adds a custom validation predicate to the shape
@@ -20,15 +23,15 @@ interface Shape<T = any> {
20
23
  or<U>(other: Shape<U>): UnionShape<T, U>;
21
24
  }
22
25
  interface ObjectShape<T = Record<string, unknown>> extends Shape<T> {
23
- readonly properties: Record<string, Shape<T>>;
24
- readonly allowUnknownProperties?: boolean;
26
+ readonly [Properties]: Record<string, Shape<T>>;
27
+ readonly [AllowUnknownProperties]?: boolean;
25
28
  }
26
29
  interface ObjectShapeOptions {
27
30
  readonly allowUnknownProperties?: boolean;
28
31
  readonly additionalPermittedProperties?: Record<string, Shape<Record<string, unknown>>>;
29
32
  }
30
- interface ArrayShape<T extends Shape> extends Shape<Array<T["primitive"]>> {
31
- readonly inner: T;
33
+ interface ArrayShape<T> extends Shape<Array<T>> {
34
+ readonly inner: Shape<T>;
32
35
  }
33
36
  interface UnionShape<Left, Right> extends Shape<Left | Right> {
34
37
  left: Shape<Left>;
@@ -38,11 +41,11 @@ interface IntersectionShape<Left, Right> extends Shape<Left & Right> {
38
41
  left: Shape<Left>;
39
42
  right: Shape<Right>;
40
43
  }
41
- interface OptionalShape<T extends Shape> extends Shape<T["primitive"] | undefined> {
42
- readonly inner: T;
44
+ interface OptionalShape<T> extends Shape<T | undefined> {
45
+ readonly inner: Shape<T>;
43
46
  }
44
- interface NullableShape<T extends Shape> extends Shape<T["primitive"] | null> {
45
- readonly inner: T;
47
+ interface NullableShape<T> extends Shape<T | null> {
48
+ readonly inner: Shape<T>;
46
49
  }
47
50
  /**
48
51
  * Creates a shape representing a JS `number`.
@@ -57,15 +60,18 @@ export declare function string(): Shape<string>;
57
60
  * Creates a shape representing a JS `boolean`.
58
61
  */
59
62
  export declare function boolean(): Shape<boolean>;
63
+ type Primitive = number | string | boolean | object | null | undefined;
64
+ export declare function literal<X extends Primitive, T extends Primitive extends X ? never : X>(x: X): Shape<T>;
60
65
  /**
61
66
  * Creates an array shape, representing `Array<T>` (aka `T[]`).
62
67
  * Takes the shape representing `T` as a parameter.
63
68
  */
64
- export declare function array<T extends Shape>(shape: T): ArrayShape<T>;
69
+ export declare function array<T>(shape: Shape<T>): ArrayShape<T>;
65
70
  /**
66
71
  * Creates an object shape.
67
72
  *
68
73
  * @example
74
+ * ```typescript
69
75
  * const Group = Shapes.object({
70
76
  * id: Shapes.number(),
71
77
  * name: Shapes.string(),
@@ -78,19 +84,20 @@ export declare function array<T extends Shape>(shape: T): ArrayShape<T>;
78
84
  * Shapes.array(Group)
79
85
  * )
80
86
  * });
87
+ * ```
81
88
  */
82
- export declare function object<T extends Record<string, Shape>>(properties: T, options?: ObjectShapeOptions): ObjectShape<{
89
+ export declare function object<T extends Record<string, Shape<any>>>(properties: T, options?: ObjectShapeOptions): ObjectShape<{
83
90
  [K in keyof T]: Type<T[K]>;
84
91
  }>;
85
92
  /**
86
93
  * Creates a shape representing an optional type.
87
94
  * `Shapes.optional(T)` corresponds to `T | undefined`
88
95
  */
89
- export declare function optional<T extends Shape>(shape: T): OptionalShape<T>;
96
+ export declare function optional<T>(shape: Shape<T>): OptionalShape<T>;
90
97
  /**
91
98
  * Creates a shape representing a nullable type.
92
99
  * `Shapes.nullable(T)` corresponds to `T | null`
93
100
  */
94
- export declare function nullable<T extends Shape>(shape: T): NullableShape<T>;
101
+ export declare function nullable<T>(shape: Shape<T>): NullableShape<T>;
95
102
  export {};
96
103
  //# sourceMappingURL=shapes.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes/shapes.ts"],"names":[],"mappings":"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"}
package/dist/shapes.js CHANGED
@@ -1,7 +1,4 @@
1
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
2
  var __assign = (this && this.__assign) || function () {
6
3
  __assign = Object.assign || function(t) {
7
4
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -13,14 +10,33 @@ var __assign = (this && this.__assign) || function () {
13
10
  };
14
11
  return __assign.apply(this, arguments);
15
12
  };
13
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
+ if (ar || !(i in from)) {
16
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
+ ar[i] = from[i];
18
+ }
19
+ }
20
+ return to.concat(ar || Array.prototype.slice.call(from));
21
+ };
16
22
  Object.defineProperty(exports, "__esModule", { value: true });
17
23
  exports.number = number;
18
24
  exports.string = string;
19
25
  exports.boolean = boolean;
26
+ exports.literal = literal;
20
27
  exports.array = array;
21
28
  exports.object = object;
22
29
  exports.optional = optional;
23
30
  exports.nullable = nullable;
31
+ /// SYMBOLS
32
+ // These are here to hide some API bits from consumers
33
+ var Predicates = Symbol();
34
+ var Optional = Symbol();
35
+ var Properties = Symbol();
36
+ var AllowUnknownProperties = Symbol();
37
+ /// TYPE GUARDS
38
+ // These are static functions to avoid allocating guards per Shape instance,
39
+ // Shapes may reference these instead
24
40
  function isString(input) {
25
41
  return typeof input === "string";
26
42
  }
@@ -43,54 +59,51 @@ function isUndefined(input) {
43
59
  return input === undefined;
44
60
  }
45
61
  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) {
62
+ var _a;
63
+ return _a = {
64
+ typename: "".concat(left.typename, " | ").concat(right.typename),
65
+ left: left,
66
+ right: right
67
+ },
68
+ _a[Predicates] = [],
69
+ _a.where = function (predicate) {
70
+ return __assign(__assign({}, this), { predicates: __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false) });
71
+ },
72
+ _a.check = function (x) {
57
73
  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) {
74
+ this[Predicates].every(function (p) { return p(x); });
75
+ },
76
+ _a.and = function (other) {
61
77
  return makeIntersection(this, other);
62
78
  },
63
- or: function (other) {
79
+ _a.or = function (other) {
64
80
  return makeUnion(this, other);
65
81
  },
66
- };
82
+ _a;
67
83
  }
68
84
  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) {
85
+ var _a, _b, _c;
86
+ return _a = {
87
+ typename: "".concat(left.typename, " | ").concat(right.typename),
88
+ left: __assign(__assign({}, left), (_b = {}, _b[Properties] = __assign(__assign({}, right[Properties]), left[Properties]), _b)),
89
+ right: __assign(__assign({}, right), (_c = {}, _c[Properties] = __assign(__assign({}, left[Properties]), right[Properties]), _c))
90
+ },
91
+ _a[Predicates] = [],
92
+ _a.where = function (predicate) {
93
+ var _a;
94
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
95
+ },
96
+ _a.check = function (x) {
84
97
  return this.left.check(x) && this.right.check(x) &&
85
- this.predicates.every(function (p) { return p(x); });
98
+ this[Predicates].every(function (p) { return p(x); });
86
99
  },
87
- and: function (other) {
100
+ _a.and = function (other) {
88
101
  return makeIntersection(this, other);
89
102
  },
90
- or: function (other) {
103
+ _a.or = function (other) {
91
104
  return makeUnion(this, other);
92
105
  },
93
- };
106
+ _a;
94
107
  }
95
108
  /// PRIMITIVE SHAPE FACTORIES
96
109
  /**
@@ -98,70 +111,94 @@ function makeIntersection(left, right) {
98
111
  * Does not support BigInt.
99
112
  */
100
113
  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) {
114
+ var _a;
115
+ return _a = {
116
+ typename: "number"
117
+ },
118
+ _a[Predicates] = [],
119
+ _a.check = function (x) {
120
+ return isNumber(x) && this[Predicates].every(function (p) { return p(x); });
121
+ },
122
+ _a.where = function (predicate) {
123
+ var _a;
124
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
125
+ },
126
+ _a.and = function (other) {
113
127
  return makeIntersection(this, other);
114
128
  },
115
- or: function (other) {
129
+ _a.or = function (other) {
116
130
  return makeUnion(this, other);
117
131
  },
118
- };
132
+ _a;
119
133
  }
120
134
  /**
121
135
  * Creates a shape representing a JS `string`.
122
136
  */
123
137
  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) {
138
+ var _a;
139
+ return _a = {
140
+ typename: "string",
141
+ check: function (x) {
142
+ return isString(x) && this[Predicates].every(function (p) { return p(x); });
143
+ }
144
+ },
145
+ _a[Predicates] = [],
146
+ _a.where = function (predicate) {
147
+ var _a;
148
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
149
+ },
150
+ _a.and = function (other) {
136
151
  return makeIntersection(this, other);
137
152
  },
138
- or: function (other) {
153
+ _a.or = function (other) {
139
154
  return makeUnion(this, other);
140
155
  },
141
- };
156
+ _a;
142
157
  }
143
158
  /**
144
159
  * Creates a shape representing a JS `boolean`.
145
160
  */
146
161
  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) {
162
+ var _a;
163
+ return _a = {
164
+ typename: "boolean",
165
+ check: function (x) {
166
+ return isBoolean(x) && this[Predicates].every(function (p) { return p(x); });
167
+ }
168
+ },
169
+ _a[Predicates] = [],
170
+ _a.where = function (predicate) {
171
+ var _a;
172
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
173
+ },
174
+ _a.and = function (other) {
159
175
  return makeIntersection(this, other);
160
176
  },
161
- or: function (other) {
177
+ _a.or = function (other) {
162
178
  return makeUnion(this, other);
163
179
  },
164
- };
180
+ _a;
181
+ }
182
+ function literal(x) {
183
+ var _a;
184
+ return _a = {
185
+ typename: JSON.stringify(x)
186
+ },
187
+ _a[Predicates] = [],
188
+ _a.check = function (input) {
189
+ return input === x && this[Predicates].every(function (p) { return p(input); });
190
+ },
191
+ _a.where = function (predicate) {
192
+ var _a;
193
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
194
+ },
195
+ _a.and = function (other) {
196
+ return makeIntersection(this, other);
197
+ },
198
+ _a.or = function (other) {
199
+ return makeUnion(this, other);
200
+ },
201
+ _a;
165
202
  }
166
203
  /// COMPLEX SHAPE FACTORIES
167
204
  /**
@@ -169,39 +206,41 @@ function boolean() {
169
206
  * Takes the shape representing `T` as a parameter.
170
207
  */
171
208
  function array(shape) {
209
+ var _a;
172
210
  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)) {
211
+ return _a = {
212
+ typename: typename,
213
+ inner: shape,
214
+ check: function (input) {
215
+ if (!isArray(input)) {
183
216
  return false;
184
217
  }
185
- return true;
186
- }) && this.predicates.every(function (p) { return p(input); });
218
+ return input.every(function (entry) {
219
+ if (!shape.check(entry)) {
220
+ return false;
221
+ }
222
+ return true;
223
+ }) && this[Predicates].every(function (p) { return p(input); });
224
+ }
187
225
  },
188
- predicates: [],
189
- where: function (predicate) {
190
- this.predicates.push(predicate);
191
- return this;
226
+ _a[Predicates] = [],
227
+ _a.where = function (predicate) {
228
+ var _a;
229
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
192
230
  },
193
- and: function (other) {
231
+ _a.and = function (other) {
194
232
  return makeIntersection(this, other);
195
233
  },
196
- or: function (other) {
234
+ _a.or = function (other) {
197
235
  return makeUnion(this, other);
198
236
  },
199
- };
237
+ _a;
200
238
  }
201
239
  /**
202
240
  * Creates an object shape.
203
241
  *
204
242
  * @example
243
+ * ```typescript
205
244
  * const Group = Shapes.object({
206
245
  * id: Shapes.number(),
207
246
  * name: Shapes.string(),
@@ -214,31 +253,35 @@ function array(shape) {
214
253
  * Shapes.array(Group)
215
254
  * )
216
255
  * });
256
+ * ```
217
257
  */
258
+ // deno-lint-ignore no-explicit-any
218
259
  function object(properties, options) {
260
+ var _a;
219
261
  var allowUnknownProperties = options === null || options === void 0 ? void 0 : options.allowUnknownProperties;
220
- return {
221
- typename: "Object",
222
- allowUnknownProperties: allowUnknownProperties,
223
- check: function (input) {
262
+ return _a = {
263
+ typename: "Object"
264
+ },
265
+ _a[AllowUnknownProperties] = allowUnknownProperties,
266
+ _a.check = function (input) {
224
267
  // Check that input is an object
225
268
  if (!isObject(input)) {
226
269
  return false;
227
270
  }
228
271
  // Check for unknown properties
229
- if (!this.allowUnknownProperties) {
272
+ if (!this[AllowUnknownProperties]) {
230
273
  for (var inputProperty in input) {
231
- if (!(inputProperty in this.properties)) {
274
+ if (!(inputProperty in this[Properties])) {
232
275
  return false;
233
276
  }
234
277
  }
235
278
  }
236
279
  // Check required properties and their types
237
- for (var property in properties) {
280
+ for (var property in this[Properties]) {
238
281
  var field = input[property];
239
- var propertyShape = properties[property];
282
+ var propertyShape = this[Properties][property];
240
283
  // Property presence check
241
- if (!(property in input) && !propertyShape.optional) {
284
+ if (!(property in input) && !propertyShape[Optional]) {
242
285
  return false;
243
286
  }
244
287
  // Property type check
@@ -246,22 +289,21 @@ function object(properties, options) {
246
289
  return false;
247
290
  }
248
291
  }
249
- return this.predicates.every(function (p) { return p(input); });
292
+ return this[Predicates].every(function (p) { return p(input); });
250
293
  },
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;
294
+ _a[Properties] = __assign(__assign({}, properties), options === null || options === void 0 ? void 0 : options.additionalPermittedProperties),
295
+ _a[Predicates] = [],
296
+ _a.where = function (predicate) {
297
+ var _a;
298
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
257
299
  },
258
- and: function (other) {
300
+ _a.and = function (other) {
259
301
  return makeIntersection(this, other);
260
302
  },
261
- or: function (other) {
303
+ _a.or = function (other) {
262
304
  return makeUnion(this, other);
263
305
  },
264
- };
306
+ _a;
265
307
  }
266
308
  /// TYPE MODIFIERS
267
309
  /**
@@ -269,50 +311,54 @@ function object(properties, options) {
269
311
  * `Shapes.optional(T)` corresponds to `T | undefined`
270
312
  */
271
313
  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) {
314
+ var _a;
315
+ return _a = {
316
+ typename: "".concat(shape.typename, " | undefined"),
317
+ inner: shape
318
+ },
319
+ _a[Optional] = true,
320
+ _a[Predicates] = [],
321
+ _a.check = function (input) {
322
+ return (isUndefined(input) || shape.check(input)) &&
323
+ this[Predicates].every(function (p) { return p(input); });
324
+ },
325
+ _a.where = function (predicate) {
326
+ var _a;
327
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
328
+ },
329
+ _a.and = function (other) {
286
330
  return makeIntersection(this, other);
287
331
  },
288
- or: function (other) {
332
+ _a.or = function (other) {
289
333
  return makeUnion(this, other);
290
334
  },
291
- };
335
+ _a;
292
336
  }
293
337
  /**
294
338
  * Creates a shape representing a nullable type.
295
339
  * `Shapes.nullable(T)` corresponds to `T | null`
296
340
  */
297
341
  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) {
342
+ var _a;
343
+ var nullShape = (_a = {
344
+ typename: "".concat(shape.typename, " | null"),
345
+ check: function (input) {
346
+ return (isNull(input) || shape.check(input)) &&
347
+ this[Predicates].every(function (p) { return p(input); });
348
+ },
349
+ inner: shape
350
+ },
351
+ _a[Predicates] = [],
352
+ _a.where = function (predicate) {
353
+ var _a;
354
+ return __assign(__assign({}, this), (_a = {}, _a[Predicates] = __spreadArray(__spreadArray([], this[Predicates], true), [predicate], false), _a));
355
+ },
356
+ _a.and = function (other) {
311
357
  return makeIntersection(this, other);
312
358
  },
313
- or: function (other) {
359
+ _a.or = function (other) {
314
360
  return makeUnion(this, other);
315
361
  },
316
- };
362
+ _a);
317
363
  return nullShape;
318
364
  }
package/package.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "name": "@jakobkg/shapes-ts",
3
- "version": "0.1.1",
3
+ "repository": {
4
+ "type": "git",
5
+ "url": "https://codeberg.org/jakobkg/shapes-ts"
6
+ },
7
+ "homepage": "https://codeberg.org/jakobkg/shapes-ts#readme",
8
+ "license": "BSD-3-Clause",
9
+ "version": "0.2.0",
4
10
  "private": false,
5
11
  "main": "dist/index.js",
6
12
  "scripts": {