@oscarpalmer/jhunal 0.6.0 → 0.7.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.
@@ -0,0 +1,21 @@
1
+ const PROPERTY_REQUIRED = "$required";
2
+ const PROPERTY_TYPE = "$type";
3
+ const SCHEMATIC_NAME = "$schematic";
4
+ const TYPE_OBJECT = "object";
5
+ const TYPE_UNDEFINED = "undefined";
6
+ const TYPE_ALL = new Set([
7
+ "array",
8
+ "bigint",
9
+ "boolean",
10
+ "date",
11
+ "date-like",
12
+ "function",
13
+ "null",
14
+ "number",
15
+ "numerical",
16
+ "string",
17
+ "symbol",
18
+ TYPE_OBJECT,
19
+ TYPE_UNDEFINED
20
+ ]);
21
+ export { PROPERTY_REQUIRED, PROPERTY_TYPE, SCHEMATIC_NAME, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED };
package/dist/is.js CHANGED
@@ -1,9 +1,10 @@
1
+ import { SCHEMATIC_NAME } from "./constants.js";
1
2
  function isDateLike(value) {
2
3
  if (value instanceof Date) return true;
3
4
  if (typeof value === "number") return value >= -864e13 && value <= 864e13;
4
5
  return typeof value === "string" && !Number.isNaN(Date.parse(value));
5
6
  }
6
7
  function isSchematic(value) {
7
- return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
8
+ return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
8
9
  }
9
10
  export { isDateLike, isSchematic };
@@ -1,11 +1,31 @@
1
+ const PROPERTY_REQUIRED = "$required";
2
+ const PROPERTY_TYPE = "$type";
3
+ const SCHEMATIC_NAME = "$schematic";
4
+ const TYPE_OBJECT = "object";
5
+ const TYPE_UNDEFINED = "undefined";
6
+ const TYPE_ALL = new Set([
7
+ "array",
8
+ "bigint",
9
+ "boolean",
10
+ "date",
11
+ "date-like",
12
+ "function",
13
+ "null",
14
+ "number",
15
+ "numerical",
16
+ "string",
17
+ "symbol",
18
+ TYPE_OBJECT,
19
+ TYPE_UNDEFINED
20
+ ]);
1
21
  function compact(array, strict) {
2
22
  if (!Array.isArray(array)) return [];
23
+ if (strict === true) return array.filter(Boolean);
3
24
  const { length } = array;
4
- const isStrict = strict ?? false;
5
25
  const compacted = [];
6
26
  for (let index = 0; index < length; index += 1) {
7
27
  const item = array[index];
8
- if (isStrict && !!item || !isStrict && item != null) compacted.push(item);
28
+ if (item != null) compacted.push(item);
9
29
  }
10
30
  return compacted;
11
31
  }
@@ -51,11 +71,17 @@ function flattenObject(value, depth, smushed, prefix) {
51
71
  for (let index = 0; index < length; index += 1) {
52
72
  const key = keys[index];
53
73
  const val = value[key];
54
- if (isArrayOrPlainObject(val)) Object.assign(flattened, {
55
- [join([prefix, key], ".")]: Array.isArray(val) ? [...val] : { ...val },
56
- ...flattenObject(val, depth + 1, smushed, join([prefix, key], "."))
57
- });
58
- else flattened[join([prefix, key], ".")] = val;
74
+ if (isArrayOrPlainObject(val)) {
75
+ const prefixedKey = join([prefix, key], ".");
76
+ flattened[prefixedKey] = Array.isArray(val) ? [...val] : { ...val };
77
+ const nested = flattenObject(val, depth + 1, smushed, prefixedKey);
78
+ const nestedKeys = Object.keys(nested);
79
+ const nestedLength = nestedKeys.length;
80
+ for (let nestedIndex = 0; nestedIndex < nestedLength; nestedIndex += 1) {
81
+ const nestedKey = nestedKeys[nestedIndex];
82
+ flattened[nestedKey] = nested[nestedKey];
83
+ }
84
+ } else flattened[join([prefix, key], ".")] = val;
59
85
  }
60
86
  smushed.set(value, flattened);
61
87
  return flattened;
@@ -70,11 +96,13 @@ function isDateLike(value) {
70
96
  return typeof value === "string" && !Number.isNaN(Date.parse(value));
71
97
  }
72
98
  function isSchematic(value) {
73
- return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
99
+ return typeof value === "object" && value !== null && SCHEMATIC_NAME in value && value[SCHEMATIC_NAME] === true;
74
100
  }
75
101
  function addPropertyType(to, key, values, required) {
76
- if (to.keys.set.has(key)) to.properties[key].types.push(...values);
77
- else {
102
+ if (to.keys.set.has(key)) {
103
+ const property = to.properties[key];
104
+ for (const type of values) if (!property.types.includes(type)) property.types.push(type);
105
+ } else {
78
106
  to.keys.array.push(key);
79
107
  to.keys.set.add(key);
80
108
  to.properties[key] = {
@@ -82,7 +110,7 @@ function addPropertyType(to, key, values, required) {
82
110
  types: values
83
111
  };
84
112
  }
85
- if (!required && !to.properties[key].types.includes("undefined")) to.properties[key].types.push("undefined");
113
+ if (!required && !to.properties[key].types.includes(TYPE_UNDEFINED)) to.properties[key].types.push(TYPE_UNDEFINED);
86
114
  }
87
115
  function getTypes(value, validated, prefix) {
88
116
  const propertyTypes = [];
@@ -90,17 +118,17 @@ function getTypes(value, validated, prefix) {
90
118
  const { length } = values;
91
119
  for (let index = 0; index < length; index += 1) {
92
120
  const type = values[index];
93
- if (isSchematic(type) || typeof type === "string" && types.has(type)) {
121
+ if (isSchematic(type) || typeof type === "string" && TYPE_ALL.has(type)) {
94
122
  propertyTypes.push(type);
95
123
  continue;
96
124
  }
97
125
  if (typeof type !== "object" || type === null) continue;
98
- if ("$type" in type) {
99
- propertyTypes.push(...getTypes(type.$type, validated, prefix));
126
+ if (PROPERTY_TYPE in type) {
127
+ propertyTypes.push(...getTypes(type[PROPERTY_TYPE], validated, prefix));
100
128
  continue;
101
129
  }
102
- addPropertyType(validated, prefix, ["object"], typeof type.$required === "boolean" ? type.$required : true);
103
- propertyTypes.push("object");
130
+ addPropertyType(validated, prefix, [TYPE_OBJECT], type[PROPERTY_REQUIRED] !== false);
131
+ propertyTypes.push(TYPE_OBJECT);
104
132
  getValidatedSchema(type, validated, prefix);
105
133
  }
106
134
  return propertyTypes;
@@ -119,10 +147,10 @@ function getValidatedSchema(schema, validated, prefix) {
119
147
  if (/\.\$(required|type)(\.|$)/.test(key)) continue;
120
148
  if (/\d+/.test(key) && arrayKeys.has(key.replace(/\.\d+$/, ""))) continue;
121
149
  let required = true;
122
- if (typeof value === "object" && value !== null && "$required" in value) required = typeof value.$required === "boolean" ? value.$required : true;
150
+ if (typeof value === "object" && value !== null && PROPERTY_REQUIRED in value) required = typeof value[PROPERTY_REQUIRED] === "boolean" ? value[PROPERTY_REQUIRED] : true;
123
151
  const prefixedKey = `${prefix}${key}`;
124
- const types$1 = getTypes(value, validated, prefixedKey);
125
- if (types$1.length > 0) addPropertyType(validated, prefixedKey, types$1, required);
152
+ const types = getTypes(value, validated, prefixedKey);
153
+ if (types.length > 0) addPropertyType(validated, prefixedKey, types, required);
126
154
  }
127
155
  if (noPrefix) validated.keys.array.sort();
128
156
  return validated;
@@ -137,21 +165,6 @@ function validateSchema(schema) {
137
165
  };
138
166
  return typeof schema === "object" && schema !== null ? getValidatedSchema(schema, validated) : validated;
139
167
  }
140
- const types = new Set([
141
- "array",
142
- "bigint",
143
- "boolean",
144
- "date",
145
- "date-like",
146
- "function",
147
- "null",
148
- "number",
149
- "numerical",
150
- "object",
151
- "string",
152
- "symbol",
153
- "undefined"
154
- ]);
155
168
  function validateType(type, value) {
156
169
  return typeof type === "string" ? validators[type](value) : type.is(value);
157
170
  }
@@ -159,22 +172,32 @@ function validateValue(validated, obj) {
159
172
  if (typeof obj !== "object" || obj === null) return false;
160
173
  const { keys, properties } = validated;
161
174
  const keysLength = keys.array.length;
175
+ const ignore = /* @__PURE__ */ new Set();
162
176
  const smushed = smush(obj);
163
177
  outer: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
164
178
  const key = keys.array[keyIndex];
179
+ const prefix = key.replace(EXPRESSION_SUFFIX, "");
180
+ if (ignore.has(prefix)) continue;
165
181
  const property = properties[key];
166
182
  const value = smushed[key];
167
- if (value === void 0 && property.required && !property.types.includes("undefined")) return false;
183
+ if (value === void 0 && property.required && !property.types.includes(TYPE_UNDEFINED)) return false;
168
184
  const typesLength = property.types.length;
169
185
  if (typesLength === 1) {
170
186
  if (!validateType(property.types[0], value)) return false;
171
187
  continue;
172
188
  }
173
- for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) if (validateType(property.types[typeIndex], value)) continue outer;
189
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
190
+ const type = property.types[typeIndex];
191
+ if (validateType(type, value)) {
192
+ if (type !== TYPE_OBJECT) ignore.add(key);
193
+ continue outer;
194
+ }
195
+ }
174
196
  return false;
175
197
  }
176
198
  return true;
177
199
  }
200
+ const EXPRESSION_SUFFIX = /\.\w+$/;
178
201
  const validators = {
179
202
  array: Array.isArray,
180
203
  bigint: (value) => typeof value === "bigint",
@@ -197,7 +220,7 @@ var Schematic = class {
197
220
  return this.#validatable;
198
221
  }
199
222
  constructor(schema) {
200
- Object.defineProperty(this, "$schematic", { value: true });
223
+ Object.defineProperty(this, SCHEMATIC_NAME, { value: true });
201
224
  this.#schema = validateSchema(schema);
202
225
  this.#validatable = this.#schema.keys.array.length > 0;
203
226
  }
package/dist/schematic.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { SCHEMATIC_NAME } from "./constants.js";
1
2
  import { validateSchema } from "./validation/schema.validation.js";
2
3
  import { validateValue } from "./validation/value.validation.js";
3
4
  var Schematic = class {
@@ -7,7 +8,7 @@ var Schematic = class {
7
8
  return this.#validatable;
8
9
  }
9
10
  constructor(schema) {
10
- Object.defineProperty(this, "$schematic", { value: true });
11
+ Object.defineProperty(this, SCHEMATIC_NAME, { value: true });
11
12
  this.#schema = validateSchema(schema);
12
13
  this.#validatable = this.#schema.keys.array.length > 0;
13
14
  }
@@ -1,8 +1,11 @@
1
+ import { PROPERTY_REQUIRED, PROPERTY_TYPE, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED } from "../constants.js";
1
2
  import { isSchematic } from "../is.js";
2
3
  import { smush } from "@oscarpalmer/atoms/value";
3
4
  function addPropertyType(to, key, values, required) {
4
- if (to.keys.set.has(key)) to.properties[key].types.push(...values);
5
- else {
5
+ if (to.keys.set.has(key)) {
6
+ const property = to.properties[key];
7
+ for (const type of values) if (!property.types.includes(type)) property.types.push(type);
8
+ } else {
6
9
  to.keys.array.push(key);
7
10
  to.keys.set.add(key);
8
11
  to.properties[key] = {
@@ -10,7 +13,7 @@ function addPropertyType(to, key, values, required) {
10
13
  types: values
11
14
  };
12
15
  }
13
- if (!required && !to.properties[key].types.includes("undefined")) to.properties[key].types.push("undefined");
16
+ if (!required && !to.properties[key].types.includes("undefined")) to.properties[key].types.push(TYPE_UNDEFINED);
14
17
  }
15
18
  function getTypes(value, validated, prefix) {
16
19
  const propertyTypes = [];
@@ -18,17 +21,17 @@ function getTypes(value, validated, prefix) {
18
21
  const { length } = values;
19
22
  for (let index = 0; index < length; index += 1) {
20
23
  const type = values[index];
21
- if (isSchematic(type) || typeof type === "string" && types.has(type)) {
24
+ if (isSchematic(type) || typeof type === "string" && TYPE_ALL.has(type)) {
22
25
  propertyTypes.push(type);
23
26
  continue;
24
27
  }
25
28
  if (typeof type !== "object" || type === null) continue;
26
29
  if ("$type" in type) {
27
- propertyTypes.push(...getTypes(type.$type, validated, prefix));
30
+ propertyTypes.push(...getTypes(type[PROPERTY_TYPE], validated, prefix));
28
31
  continue;
29
32
  }
30
- addPropertyType(validated, prefix, ["object"], typeof type.$required === "boolean" ? type.$required : true);
31
- propertyTypes.push("object");
33
+ addPropertyType(validated, prefix, [TYPE_OBJECT], type[PROPERTY_REQUIRED] !== false);
34
+ propertyTypes.push(TYPE_OBJECT);
32
35
  getValidatedSchema(type, validated, prefix);
33
36
  }
34
37
  return propertyTypes;
@@ -47,10 +50,10 @@ function getValidatedSchema(schema, validated, prefix) {
47
50
  if (/\.\$(required|type)(\.|$)/.test(key)) continue;
48
51
  if (/\d+/.test(key) && arrayKeys.has(key.replace(/\.\d+$/, ""))) continue;
49
52
  let required = true;
50
- if (typeof value === "object" && value !== null && "$required" in value) required = typeof value.$required === "boolean" ? value.$required : true;
53
+ if (typeof value === "object" && value !== null && "$required" in value) required = typeof value["$required"] === "boolean" ? value[PROPERTY_REQUIRED] : true;
51
54
  const prefixedKey = `${prefix}${key}`;
52
- const types$1 = getTypes(value, validated, prefixedKey);
53
- if (types$1.length > 0) addPropertyType(validated, prefixedKey, types$1, required);
55
+ const types = getTypes(value, validated, prefixedKey);
56
+ if (types.length > 0) addPropertyType(validated, prefixedKey, types, required);
54
57
  }
55
58
  if (noPrefix) validated.keys.array.sort();
56
59
  return validated;
@@ -65,19 +68,4 @@ function validateSchema(schema) {
65
68
  };
66
69
  return typeof schema === "object" && schema !== null ? getValidatedSchema(schema, validated) : validated;
67
70
  }
68
- var types = new Set([
69
- "array",
70
- "bigint",
71
- "boolean",
72
- "date",
73
- "date-like",
74
- "function",
75
- "null",
76
- "number",
77
- "numerical",
78
- "object",
79
- "string",
80
- "symbol",
81
- "undefined"
82
- ]);
83
71
  export { validateSchema };
@@ -1,3 +1,4 @@
1
+ import { TYPE_OBJECT, TYPE_UNDEFINED } from "../constants.js";
1
2
  import { isDateLike } from "../is.js";
2
3
  import { smush } from "@oscarpalmer/atoms/value";
3
4
  function validateType(type, value) {
@@ -7,9 +8,12 @@ function validateValue(validated, obj) {
7
8
  if (typeof obj !== "object" || obj === null) return false;
8
9
  const { keys, properties } = validated;
9
10
  const keysLength = keys.array.length;
11
+ const ignore = /* @__PURE__ */ new Set();
10
12
  const smushed = smush(obj);
11
13
  outer: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
12
14
  const key = keys.array[keyIndex];
15
+ const prefix = key.replace(EXPRESSION_SUFFIX, "");
16
+ if (ignore.has(prefix)) continue;
13
17
  const property = properties[key];
14
18
  const value = smushed[key];
15
19
  if (value === void 0 && property.required && !property.types.includes("undefined")) return false;
@@ -18,11 +22,18 @@ function validateValue(validated, obj) {
18
22
  if (!validateType(property.types[0], value)) return false;
19
23
  continue;
20
24
  }
21
- for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) if (validateType(property.types[typeIndex], value)) continue outer;
25
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
26
+ const type = property.types[typeIndex];
27
+ if (validateType(type, value)) {
28
+ if (type !== "object") ignore.add(key);
29
+ continue outer;
30
+ }
31
+ }
22
32
  return false;
23
33
  }
24
34
  return true;
25
35
  }
36
+ var EXPRESSION_SUFFIX = /\.\w+$/;
26
37
  var validators = {
27
38
  array: Array.isArray,
28
39
  bigint: (value) => typeof value === "bigint",
package/package.json CHANGED
@@ -4,15 +4,15 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.118"
7
+ "@oscarpalmer/atoms": "^0.123"
8
8
  },
9
9
  "description": "Flies free beneath the glistening moons…",
10
10
  "devDependencies": {
11
11
  "@types/node": "^25",
12
12
  "@vitest/coverage-istanbul": "^4",
13
13
  "jsdom": "^27.4",
14
- "oxfmt": "^0.20",
15
- "oxlint": "^1.35",
14
+ "oxfmt": "^0.21",
15
+ "oxlint": "^1.36",
16
16
  "rolldown": "1.0.0-beta.57",
17
17
  "tslib": "^2.8",
18
18
  "typescript": "^5.9",
@@ -45,5 +45,5 @@
45
45
  },
46
46
  "type": "module",
47
47
  "types": "./types/index.d.ts",
48
- "version": "0.6.0"
48
+ "version": "0.7.0"
49
49
  }
@@ -0,0 +1,27 @@
1
+ import type {Values} from './models';
2
+
3
+ export const PROPERTY_REQUIRED = '$required';
4
+
5
+ export const PROPERTY_TYPE = '$type';
6
+
7
+ export const SCHEMATIC_NAME = '$schematic';
8
+
9
+ export const TYPE_OBJECT = 'object';
10
+
11
+ export const TYPE_UNDEFINED = 'undefined';
12
+
13
+ export const TYPE_ALL = new Set<keyof Values>([
14
+ 'array',
15
+ 'bigint',
16
+ 'boolean',
17
+ 'date',
18
+ 'date-like',
19
+ 'function',
20
+ 'null',
21
+ 'number',
22
+ 'numerical',
23
+ 'string',
24
+ 'symbol',
25
+ TYPE_OBJECT,
26
+ TYPE_UNDEFINED,
27
+ ]);
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type {Schema, TypedSchema} from './model';
1
+ export type {Schema, TypedSchema} from './models';
2
2
  export {schematic, type Schematic} from './schematic';
package/src/is.ts CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ import {SCHEMATIC_NAME} from './constants';
2
2
  import type {Schematic} from './schematic';
3
3
 
4
4
  export function isDateLike(value: unknown): value is Date {
@@ -17,7 +17,7 @@ export function isSchematic(value: unknown): value is Schematic<never> {
17
17
  return (
18
18
  typeof value === 'object' &&
19
19
  value !== null &&
20
- '$schematic' in value &&
21
- value.$schematic === true
20
+ SCHEMATIC_NAME in value &&
21
+ value[SCHEMATIC_NAME] === true
22
22
  );
23
23
  }
package/src/schematic.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type {PlainObject} from '@oscarpalmer/atoms';
2
- import type {Infer, Schema, TypedSchema, ValidatedSchema} from './model';
1
+ import type {PlainObject} from '@oscarpalmer/atoms/models';
2
+ import {SCHEMATIC_NAME} from './constants';
3
+ import type {Infer, Schema, TypedSchema, ValidatedSchema} from './models';
3
4
  import {validateSchema} from './validation/schema.validation';
4
5
  import {validateValue} from './validation/value.validation';
5
6
 
@@ -17,11 +18,11 @@ export class Schematic<Model> {
17
18
  }
18
19
 
19
20
  constructor(schema: Model) {
20
- Object.defineProperty(this, '$schematic', {
21
+ Object.defineProperty(this, SCHEMATIC_NAME, {
21
22
  value: true,
22
23
  });
23
24
 
24
- this.#schema = validateSchema(schema as unknown as Schema);
25
+ this.#schema = validateSchema(schema);
25
26
 
26
27
  this.#validatable = this.#schema.keys.array.length > 0;
27
28
  }
@@ -1,7 +1,14 @@
1
1
  import type {PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {smush} from '@oscarpalmer/atoms/value';
3
+ import {
4
+ PROPERTY_REQUIRED,
5
+ PROPERTY_TYPE,
6
+ TYPE_ALL,
7
+ TYPE_OBJECT,
8
+ TYPE_UNDEFINED,
9
+ } from '../constants';
3
10
  import {isSchematic} from '../is';
4
- import type {Schema, ValidatedPropertyType, ValidatedSchema, Values} from '../model';
11
+ import type {Schema, ValidatedPropertyType, ValidatedSchema} from '../models';
5
12
 
6
13
  function addPropertyType(
7
14
  to: ValidatedSchema,
@@ -12,7 +19,11 @@ function addPropertyType(
12
19
  if (to.keys.set.has(key)) {
13
20
  const property = to.properties[key];
14
21
 
15
- property.types.push(...values);
22
+ for (const type of values) {
23
+ if (!property.types.includes(type)) {
24
+ property.types.push(type);
25
+ }
26
+ }
16
27
  } else {
17
28
  to.keys.array.push(key);
18
29
  to.keys.set.add(key);
@@ -23,8 +34,8 @@ function addPropertyType(
23
34
  };
24
35
  }
25
36
 
26
- if (!required && !to.properties[key].types.includes('undefined')) {
27
- to.properties[key].types.push('undefined');
37
+ if (!required && !to.properties[key].types.includes(TYPE_UNDEFINED)) {
38
+ to.properties[key].types.push(TYPE_UNDEFINED);
28
39
  }
29
40
  }
30
41
 
@@ -41,7 +52,7 @@ function getTypes(
41
52
  for (let index = 0; index < length; index += 1) {
42
53
  const type = values[index];
43
54
 
44
- if (isSchematic(type) || (typeof type === 'string' && types.has(type as never))) {
55
+ if (isSchematic(type) || (typeof type === 'string' && TYPE_ALL.has(type as never))) {
45
56
  propertyTypes.push(type as never);
46
57
 
47
58
  continue;
@@ -51,20 +62,15 @@ function getTypes(
51
62
  continue;
52
63
  }
53
64
 
54
- if ('$type' in type) {
55
- propertyTypes.push(...getTypes(type.$type, validated, prefix));
65
+ if (PROPERTY_TYPE in type) {
66
+ propertyTypes.push(...getTypes(type[PROPERTY_TYPE], validated, prefix));
56
67
 
57
68
  continue;
58
69
  }
59
70
 
60
- addPropertyType(
61
- validated,
62
- prefix,
63
- ['object'],
64
- typeof type.$required === 'boolean' ? type.$required : true,
65
- );
71
+ addPropertyType(validated, prefix, [TYPE_OBJECT], type[PROPERTY_REQUIRED] !== false);
66
72
 
67
- propertyTypes.push('object');
73
+ propertyTypes.push(TYPE_OBJECT);
68
74
 
69
75
  getValidatedSchema(type as Schema, validated, prefix);
70
76
  }
@@ -104,8 +110,8 @@ function getValidatedSchema(
104
110
 
105
111
  let required = true;
106
112
 
107
- if (typeof value === 'object' && value !== null && '$required' in value) {
108
- required = typeof value.$required === 'boolean' ? value.$required : true;
113
+ if (typeof value === 'object' && value !== null && PROPERTY_REQUIRED in value) {
114
+ required = typeof value[PROPERTY_REQUIRED] === 'boolean' ? value[PROPERTY_REQUIRED] : true;
109
115
  }
110
116
 
111
117
  const prefixedKey = `${prefix}${key}`;
@@ -137,21 +143,3 @@ export function validateSchema(schema: unknown): ValidatedSchema {
137
143
  ? getValidatedSchema(schema as Schema, validated)
138
144
  : validated;
139
145
  }
140
-
141
- //
142
-
143
- const types = new Set<keyof Values>([
144
- 'array',
145
- 'bigint',
146
- 'boolean',
147
- 'date',
148
- 'date-like',
149
- 'function',
150
- 'null',
151
- 'number',
152
- 'numerical',
153
- 'object',
154
- 'string',
155
- 'symbol',
156
- 'undefined',
157
- ]);
@@ -1,7 +1,8 @@
1
1
  import type {PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {smush} from '@oscarpalmer/atoms/value';
3
+ import {TYPE_OBJECT, TYPE_UNDEFINED} from '../constants';
3
4
  import {isDateLike} from '../is';
4
- import type {ValidatedPropertyType, ValidatedSchema, Values} from '../model';
5
+ import type {ValidatedPropertyType, ValidatedSchema, Values} from '../models';
5
6
 
6
7
  export function validateType(type: ValidatedPropertyType, value: unknown): boolean {
7
8
  return typeof type === 'string' ? validators[type](value) : type.is(value);
@@ -15,14 +16,23 @@ export function validateValue(validated: ValidatedSchema, obj: unknown): boolean
15
16
  const {keys, properties} = validated;
16
17
  const keysLength = keys.array.length;
17
18
 
19
+ const ignore = new Set<string>();
20
+
18
21
  const smushed = smush(obj as PlainObject);
19
22
 
20
23
  outer: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
21
24
  const key = keys.array[keyIndex];
25
+
26
+ const prefix = key.replace(EXPRESSION_SUFFIX, '');
27
+
28
+ if (ignore.has(prefix)) {
29
+ continue;
30
+ }
31
+
22
32
  const property = properties[key];
23
33
  const value = smushed[key];
24
34
 
25
- if (value === undefined && property.required && !property.types.includes('undefined')) {
35
+ if (value === undefined && property.required && !property.types.includes(TYPE_UNDEFINED)) {
26
36
  return false;
27
37
  }
28
38
 
@@ -37,7 +47,13 @@ export function validateValue(validated: ValidatedSchema, obj: unknown): boolean
37
47
  }
38
48
 
39
49
  for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
40
- if (validateType(property.types[typeIndex], value)) {
50
+ const type = property.types[typeIndex];
51
+
52
+ if (validateType(type, value)) {
53
+ if (type !== TYPE_OBJECT) {
54
+ ignore.add(key);
55
+ }
56
+
41
57
  continue outer;
42
58
  }
43
59
  }
@@ -50,6 +66,10 @@ export function validateValue(validated: ValidatedSchema, obj: unknown): boolean
50
66
 
51
67
  //
52
68
 
69
+ const EXPRESSION_SUFFIX = /\.\w+$/;
70
+
71
+ //
72
+
53
73
  const validators: Record<keyof Values, (value: unknown) => boolean> = {
54
74
  array: Array.isArray,
55
75
  bigint: value => typeof value === 'bigint',
@@ -0,0 +1,7 @@
1
+ import type { Values } from './models';
2
+ export declare const PROPERTY_REQUIRED = "$required";
3
+ export declare const PROPERTY_TYPE = "$type";
4
+ export declare const SCHEMATIC_NAME = "$schematic";
5
+ export declare const TYPE_OBJECT = "object";
6
+ export declare const TYPE_UNDEFINED = "undefined";
7
+ export declare const TYPE_ALL: Set<keyof Values>;
package/types/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { Schema, TypedSchema } from './model';
1
+ export type { Schema, TypedSchema } from './models';
2
2
  export { schematic, type Schematic } from './schematic';
@@ -1,5 +1,5 @@
1
- import type { PlainObject } from '@oscarpalmer/atoms';
2
- import type { Infer, Schema, TypedSchema } from './model';
1
+ import type { PlainObject } from '@oscarpalmer/atoms/models';
2
+ import type { Infer, Schema, TypedSchema } from './models';
3
3
  /**
4
4
  * A schematic for validating objects
5
5
  */
@@ -1,2 +1,2 @@
1
- import type { ValidatedSchema } from '../model';
1
+ import type { ValidatedSchema } from '../models';
2
2
  export declare function validateSchema(schema: unknown): ValidatedSchema;
@@ -1,3 +1,3 @@
1
- import type { ValidatedPropertyType, ValidatedSchema } from '../model';
1
+ import type { ValidatedPropertyType, ValidatedSchema } from '../models';
2
2
  export declare function validateType(type: ValidatedPropertyType, value: unknown): boolean;
3
3
  export declare function validateValue(validated: ValidatedSchema, obj: unknown): boolean;
File without changes
File without changes
File without changes