@oscarpalmer/jhunal 0.3.0 → 0.5.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,5 +1,7 @@
1
1
  # Jhunal
2
2
 
3
+ [![npm](https://badge.fury.io/js/@oscarpalmer%2Fjhunal.svg)](https://www.npmjs.com/package/@oscarpalmer/jhunal) [![Tests](https://github.com/oscarpalmer/jhunal/actions/workflows/test.yml/badge.svg)](https://github.com/oscarpalmer/jhunal/actions/workflows/test.yml)
4
+
3
5
  > Jhunal, sage God of Runes,
4
6
  > Flies free beneath the glistening moons.
5
7
  > A night owl who's so droll,
package/dist/helpers.js CHANGED
@@ -1,20 +1,39 @@
1
+ import { isSchematic } from "./is.js";
2
+ import { validateSchema } from "./validation/schema.validation.js";
1
3
  function getTypes(value) {
2
- return (Array.isArray(value) ? value : [value]).filter(
3
- (item) => types.has(item)
4
- );
4
+ const returned = [];
5
+ const values = Array.isArray(value) ? value : [value];
6
+ const { length } = values;
7
+ for (let index = 0; index < length; index += 1) {
8
+ const type = values[index];
9
+ switch (true) {
10
+ case isSchematic(type):
11
+ returned.push(type);
12
+ break;
13
+ case typeof type === "string" && types.has(type):
14
+ returned.push(type);
15
+ break;
16
+ case typeof type === "object" && type !== null:
17
+ returned.push(validateSchema(type));
18
+ break;
19
+ default: break;
20
+ }
21
+ }
22
+ return returned;
5
23
  }
6
- const types = /* @__PURE__ */ new Set([
7
- "array",
8
- "bigint",
9
- "boolean",
10
- "date",
11
- "function",
12
- "null",
13
- "number",
14
- "object",
15
- "string",
16
- "symbol",
17
- "undefined"
24
+ var types = new Set([
25
+ "array",
26
+ "bigint",
27
+ "boolean",
28
+ "date",
29
+ "date-like",
30
+ "function",
31
+ "null",
32
+ "number",
33
+ "numerical",
34
+ "object",
35
+ "string",
36
+ "symbol",
37
+ "undefined"
18
38
  ]);
19
-
20
39
  export { getTypes };
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- export { schematic } from './schematic.js';
1
+ import { schematic } from "./schematic.js";
2
+ export { schematic };
package/dist/is.js ADDED
@@ -0,0 +1,9 @@
1
+ function isDateLike(value) {
2
+ if (value instanceof Date) return true;
3
+ if (typeof value === "number") return value >= -864e13 && value <= 864e13;
4
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
5
+ }
6
+ function isSchematic(value) {
7
+ return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
8
+ }
9
+ export { isDateLike, isSchematic };
@@ -0,0 +1,134 @@
1
+ function isDateLike(value) {
2
+ if (value instanceof Date) return true;
3
+ if (typeof value === "number") return value >= -864e13 && value <= 864e13;
4
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
5
+ }
6
+ function isSchematic(value) {
7
+ return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
8
+ }
9
+ function getTypes(value) {
10
+ const returned = [];
11
+ const values = Array.isArray(value) ? value : [value];
12
+ const { length } = values;
13
+ for (let index = 0; index < length; index += 1) {
14
+ const type = values[index];
15
+ switch (true) {
16
+ case isSchematic(type):
17
+ returned.push(type);
18
+ break;
19
+ case typeof type === "string" && types.has(type):
20
+ returned.push(type);
21
+ break;
22
+ case typeof type === "object" && type !== null:
23
+ returned.push(validateSchema(type));
24
+ break;
25
+ default: break;
26
+ }
27
+ }
28
+ return returned;
29
+ }
30
+ const types = new Set([
31
+ "array",
32
+ "bigint",
33
+ "boolean",
34
+ "date",
35
+ "date-like",
36
+ "function",
37
+ "null",
38
+ "number",
39
+ "numerical",
40
+ "object",
41
+ "string",
42
+ "symbol",
43
+ "undefined"
44
+ ]);
45
+ function validateSchema(schema) {
46
+ if (validatedSchemas.has(schema)) return validatedSchemas.get(schema);
47
+ const validated = {
48
+ keys: [],
49
+ length: 0,
50
+ properties: {}
51
+ };
52
+ if (typeof schema !== "object" || schema === null) return validated;
53
+ const keys = Object.keys(schema);
54
+ const { length } = keys;
55
+ for (let index = 0; index < length; index += 1) {
56
+ const key = keys[index];
57
+ const value = schema[key];
58
+ let required = true;
59
+ let types$1;
60
+ if (Array.isArray(value)) types$1 = getTypes(value);
61
+ else if (typeof value === "object" && value !== null) {
62
+ if (typeof value.required === "boolean") required = value.required;
63
+ types$1 = getTypes(value.type);
64
+ } else types$1 = getTypes(value);
65
+ if (types$1.length > 0) {
66
+ if (!required && !types$1.includes("undefined")) types$1.push("undefined");
67
+ validated.keys.push(key);
68
+ validated.properties[key] = {
69
+ required,
70
+ types: types$1
71
+ };
72
+ validated.length += 1;
73
+ }
74
+ }
75
+ validatedSchemas.set(schema, validated);
76
+ return validated;
77
+ }
78
+ const validatedSchemas = /* @__PURE__ */ new WeakMap();
79
+ function validateType(type, value) {
80
+ if (typeof type === "string") return validators[type](value);
81
+ if (isSchematic(type)) return type.is(value);
82
+ return validateValue(type, value);
83
+ }
84
+ function validateValue(validated, obj) {
85
+ if (typeof obj !== "object" || obj === null) return false;
86
+ outer: for (let keyIndex = 0; keyIndex < validated.length; keyIndex += 1) {
87
+ const key = validated.keys[keyIndex];
88
+ const property = validated.properties[key];
89
+ const value = obj[key];
90
+ if (value === void 0 && property.required && !property.types.includes("undefined")) return false;
91
+ const typesLength = property.types.length;
92
+ if (typesLength === 1) {
93
+ if (!validateType(property.types[0], value)) return false;
94
+ continue;
95
+ }
96
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) if (validateType(property.types[typeIndex], value)) continue outer;
97
+ return false;
98
+ }
99
+ return true;
100
+ }
101
+ const validators = {
102
+ array: Array.isArray,
103
+ bigint: (value) => typeof value === "bigint",
104
+ boolean: (value) => typeof value === "boolean",
105
+ date: (value) => value instanceof Date,
106
+ "date-like": isDateLike,
107
+ function: (value) => typeof value === "function",
108
+ null: (value) => value === null,
109
+ number: (value) => typeof value === "number",
110
+ numerical: (value) => validators.bigint(value) || validators.number(value),
111
+ object: (value) => typeof value === "object" && value !== null,
112
+ string: (value) => typeof value === "string",
113
+ symbol: (value) => typeof value === "symbol",
114
+ undefined: (value) => value === void 0
115
+ };
116
+ var Schematic = class {
117
+ #schema;
118
+ #validatable;
119
+ get validatable() {
120
+ return this.#validatable;
121
+ }
122
+ constructor(schema) {
123
+ Object.defineProperty(this, "$schematic", { value: true });
124
+ this.#schema = validateSchema(schema);
125
+ this.#validatable = this.#schema.length > 0;
126
+ }
127
+ is(value) {
128
+ return this.#validatable && validateValue(this.#schema, value);
129
+ }
130
+ };
131
+ function schematic(schema) {
132
+ return new Schematic(schema);
133
+ }
134
+ export { schematic };
package/dist/model.js CHANGED
@@ -1 +0,0 @@
1
-
package/dist/schematic.js CHANGED
@@ -1,11 +1,21 @@
1
- import { getValidatedSchema, validate } from './validation.js';
2
-
1
+ import { validateSchema } from "./validation/schema.validation.js";
2
+ import { validateValue } from "./validation/value.validation.js";
3
+ var Schematic = class {
4
+ #schema;
5
+ #validatable;
6
+ get validatable() {
7
+ return this.#validatable;
8
+ }
9
+ constructor(schema) {
10
+ Object.defineProperty(this, "$schematic", { value: true });
11
+ this.#schema = validateSchema(schema);
12
+ this.#validatable = this.#schema.length > 0;
13
+ }
14
+ is(value) {
15
+ return this.#validatable && validateValue(this.#schema, value);
16
+ }
17
+ };
3
18
  function schematic(schema) {
4
- const validated = getValidatedSchema(schema);
5
- const canValidate = validated.length > 0;
6
- return Object.freeze({
7
- is: (value) => canValidate && validate(validated, value)
8
- });
19
+ return new Schematic(schema);
9
20
  }
10
-
11
- export { schematic };
21
+ export { Schematic, schematic };
@@ -0,0 +1,36 @@
1
+ import { getTypes } from "../helpers.js";
2
+ function validateSchema(schema) {
3
+ if (validatedSchemas.has(schema)) return validatedSchemas.get(schema);
4
+ const validated = {
5
+ keys: [],
6
+ length: 0,
7
+ properties: {}
8
+ };
9
+ if (typeof schema !== "object" || schema === null) return validated;
10
+ const keys = Object.keys(schema);
11
+ const { length } = keys;
12
+ for (let index = 0; index < length; index += 1) {
13
+ const key = keys[index];
14
+ const value = schema[key];
15
+ let required = true;
16
+ let types;
17
+ if (Array.isArray(value)) types = getTypes(value);
18
+ else if (typeof value === "object" && value !== null) {
19
+ if (typeof value.required === "boolean") required = value.required;
20
+ types = getTypes(value.type);
21
+ } else types = getTypes(value);
22
+ if (types.length > 0) {
23
+ if (!required && !types.includes("undefined")) types.push("undefined");
24
+ validated.keys.push(key);
25
+ validated.properties[key] = {
26
+ required,
27
+ types
28
+ };
29
+ validated.length += 1;
30
+ }
31
+ }
32
+ validatedSchemas.set(schema, validated);
33
+ return validated;
34
+ }
35
+ const validatedSchemas = /* @__PURE__ */ new WeakMap();
36
+ export { validateSchema, validatedSchemas };
@@ -0,0 +1,39 @@
1
+ import { isDateLike, isSchematic } from "../is.js";
2
+ function validateType(type, value) {
3
+ if (typeof type === "string") return validators[type](value);
4
+ if (isSchematic(type)) return type.is(value);
5
+ return validateValue(type, value);
6
+ }
7
+ function validateValue(validated, obj) {
8
+ if (typeof obj !== "object" || obj === null) return false;
9
+ outer: for (let keyIndex = 0; keyIndex < validated.length; keyIndex += 1) {
10
+ const key = validated.keys[keyIndex];
11
+ const property = validated.properties[key];
12
+ const value = obj[key];
13
+ if (value === void 0 && property.required && !property.types.includes("undefined")) return false;
14
+ const typesLength = property.types.length;
15
+ if (typesLength === 1) {
16
+ if (!validateType(property.types[0], value)) return false;
17
+ continue;
18
+ }
19
+ for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) if (validateType(property.types[typeIndex], value)) continue outer;
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+ var validators = {
25
+ array: Array.isArray,
26
+ bigint: (value) => typeof value === "bigint",
27
+ boolean: (value) => typeof value === "boolean",
28
+ date: (value) => value instanceof Date,
29
+ "date-like": isDateLike,
30
+ function: (value) => typeof value === "function",
31
+ null: (value) => value === null,
32
+ number: (value) => typeof value === "number",
33
+ numerical: (value) => validators.bigint(value) || validators.number(value),
34
+ object: (value) => typeof value === "object" && value !== null,
35
+ string: (value) => typeof value === "string",
36
+ symbol: (value) => typeof value === "symbol",
37
+ undefined: (value) => value === void 0
38
+ };
39
+ export { validateType, validateValue };
package/package.json CHANGED
@@ -4,31 +4,26 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.94",
8
- "type-fest": "^4.39"
7
+ "@oscarpalmer/atoms": "^0.118"
9
8
  },
10
9
  "description": "Flies free beneath the glistening moons…",
11
10
  "devDependencies": {
12
- "@biomejs/biome": "^1.9",
13
- "@types/node": "^22.14",
14
- "@vitest/coverage-istanbul": "^3.1",
15
- "dts-bundle-generator": "^9.5",
16
- "glob": "^11",
17
- "typescript": "^5.8",
18
- "vite": "^6.2",
19
- "vitest": "^3.1"
11
+ "@types/node": "^25",
12
+ "@vitest/coverage-istanbul": "^4",
13
+ "jsdom": "^27.3",
14
+ "oxfmt": "^0.20",
15
+ "oxlint": "^1.35",
16
+ "rolldown": "1.0.0-beta.57",
17
+ "tslib": "^2.8",
18
+ "typescript": "^5.9",
19
+ "vite": "8.0.0-beta.5",
20
+ "vitest": "^4"
20
21
  },
21
22
  "exports": {
22
23
  "./package.json": "./package.json",
23
24
  ".": {
24
- "import": {
25
25
  "types": "./types/index.d.ts",
26
26
  "default": "./dist/index.js"
27
- },
28
- "require": {
29
- "types": "./types/index.d.cts",
30
- "default": "./dist/index.cjs"
31
- }
32
27
  }
33
28
  },
34
29
  "files": ["dist", "src", "types"],
@@ -42,13 +37,14 @@
42
37
  "url": "git+https://github.com/oscarpalmer/jhunal.git"
43
38
  },
44
39
  "scripts": {
45
- "build": "npm run clean && npx vite build && npm run types",
40
+ "build": "npm run clean && npx vite build && npm run rolldown:build && npx tsc",
46
41
  "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
42
+ "rolldown:build": "npx rolldown -c",
43
+ "rolldown:watch": "npx rolldown -c ./rolldown.config.js --watch",
47
44
  "test": "npx vitest --coverage",
48
- "types": "npx tsc && npx dts-bundle-generator --config ./dts.config.cts --silent",
49
45
  "watch": "npx vite build --watch"
50
46
  },
51
47
  "type": "module",
52
48
  "types": "./types/index.d.cts",
53
- "version": "0.3.0"
49
+ "version": "0.5.0"
54
50
  }
package/src/helpers.ts CHANGED
@@ -1,9 +1,35 @@
1
- import type {Values} from './model';
1
+ import {isSchematic} from './is';
2
+ import type {ValidatedPropertyType, Values} from './model';
3
+ import {validateSchema} from './validation/schema.validation';
2
4
 
3
- export function getTypes(value: unknown): (keyof Values)[] {
4
- return (Array.isArray(value) ? value : [value]).filter(item =>
5
- types.has(item),
6
- );
5
+ export function getTypes(value: unknown): ValidatedPropertyType[] {
6
+ const returned: ValidatedPropertyType[] = [];
7
+ const values = Array.isArray(value) ? value : [value];
8
+ const {length} = values;
9
+
10
+ for (let index = 0; index < length; index += 1) {
11
+ const type = values[index];
12
+
13
+ switch (true) {
14
+ case isSchematic(type):
15
+ returned.push(type);
16
+ break;
17
+
18
+ case typeof type === 'string' && types.has(type as never):
19
+ returned.push(type as never);
20
+ break;
21
+
22
+ case typeof type === 'object' && type !== null: {
23
+ returned.push(validateSchema(type));
24
+ break;
25
+ }
26
+
27
+ default:
28
+ break;
29
+ }
30
+ }
31
+
32
+ return returned;
7
33
  }
8
34
 
9
35
  const types = new Set<keyof Values>([
@@ -11,9 +37,11 @@ const types = new Set<keyof Values>([
11
37
  'bigint',
12
38
  'boolean',
13
39
  'date',
40
+ 'date-like',
14
41
  'function',
15
42
  'null',
16
43
  'number',
44
+ 'numerical',
17
45
  'object',
18
46
  'string',
19
47
  'symbol',
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type {Schema, Schematic} from './model';
2
- export * from './schematic';
1
+ export type {Schema, TypedSchema} from './model';
2
+ export {schematic, type Schematic} from './schematic';
package/src/is.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type {Schematic} from './schematic';
2
+
3
+ export function isDateLike(value: unknown): value is Date {
4
+ if (value instanceof Date) {
5
+ return true;
6
+ }
7
+
8
+ if (typeof value === 'number') {
9
+ return value >= -8_640e12 && value <= 8_640e12;
10
+ }
11
+
12
+ return typeof value === 'string' && !Number.isNaN(Date.parse(value));
13
+ }
14
+
15
+ export function isSchematic(value: unknown): value is Schematic<never> {
16
+ return (
17
+ typeof value === 'object' &&
18
+ value !== null &&
19
+ '$schematic' in value &&
20
+ value.$schematic === true
21
+ );
22
+ }