@serum-enterprises/schema 3.2.0-beta.0 → 4.0.0-alpha.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,22 +1,38 @@
1
- # Schema
1
+ # Schema Framework
2
2
 
3
- Modern Schema Validation Library inspired by Joi.dev
3
+ A flexible Schema Framework for building validation libraries.
4
+
5
+ This library provides the core infrastructure for schema validation, including base classes, error handling, and logical operations (Union, Intersect, etc.). To use it for actual data validation (like JSON, Strings, Numbers), you should use a plugin library like `@serum-enterprises/schema-json`.
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
- npm install --save @serum-enterprises/schema@3.0.0-beta.1
10
+ npm install @serum-enterprises/schema
9
11
  ```
10
12
 
11
- ## Usage
13
+ You will likely also want a plugin:
12
14
 
13
- ```typescript
14
- import {Schema} from '@serum-enterprises/schema';
15
+ ```bash
16
+ npm install @serum-enterprises/schema-json
17
+ ```
15
18
 
16
- const schema = Schema.Object.nullable().shape({
17
- name: Schema.String,
18
- age: Schema.Number.integer().min(18).max(99),
19
- friends: Schema.Array.every(Schema.String)
19
+ ## Example (with Schema-JSON)
20
+
21
+ ```typescript
22
+ import {Domain} from '@serum-enterprises/schema';
23
+ import * as JSONSchema from '@serum-enterprises/schema-json';
24
+
25
+ // Create a Domain with the JSON Plugin
26
+ const Schema = Domain.create({
27
+ JSON: JSONSchema.Registry
28
+ }, [
29
+ JSONSchema.Operations
30
+ ]);
31
+
32
+ const schema = Schema.JSON.Object.shape({
33
+ name: Schema.JSON.String,
34
+ age: Schema.JSON.Number.integer().min(18).max(99),
35
+ friends: Schema.JSON.Array.every(Schema.JSON.String)
20
36
  }).exact();
21
37
 
22
38
  const person = schema.validate({name: 'John', age: 20, friends: ["Jane", "Mary"]});
@@ -26,9 +42,15 @@ console.log(person.age);
26
42
  console.log(person.friends.join(', '));
27
43
  ```
28
44
 
29
- ## API
45
+ ## Features
46
+
47
+ - **Extensible**: Register custom validators and operations through the Domain system.
48
+ - **Composable**: Build complex schemas using logical operations like `Union` and `Intersect`.
49
+ - **Plugin-based**: Keep your bundle small by only including the validators you need.
50
+
51
+ ## Plugin Libraries
30
52
 
31
- Please check [index.d.ts](./types/index.d.ts) for the full API.
53
+ - [`@serum-enterprises/schema-json`](../Schema-JSON): Validators for standard JSON types (String, Number, Object, Array, etc.).
32
54
 
33
55
  ## LICENSE
34
56
 
package/dist/index.cjs ADDED
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
+ AssertError: () => import_errors.AssertError,
22
+ DefinitionError: () => import_errors.DefinitionError,
23
+ Domain: () => import_Domain.Domain,
24
+ DomainError: () => import_errors.DomainError,
25
+ InferDefinitionType: () => import_types.InferDefinitionType,
26
+ InferValidatorReturnType: () => import_types.InferValidatorReturnType,
27
+ IntersectValidator: () => import_validators.IntersectValidator,
28
+ IntersectValidatorDefinition: () => import_validators.IntersectValidatorDefinition,
29
+ NeverValidator: () => import_validators.NeverValidator,
30
+ NeverValidatorDefinition: () => import_validators.NeverValidatorDefinition,
31
+ UnionValidator: () => import_validators.UnionValidator,
32
+ UnionValidatorDefinition: () => import_validators.UnionValidatorDefinition,
33
+ UnknownValidator: () => import_validators.UnknownValidator,
34
+ UnknownValidatorDefinition: () => import_validators.UnknownValidatorDefinition,
35
+ Validator: () => import_Validator.Validator,
36
+ ValidatorClass: () => import_Validator.ValidatorClass
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+ var import_Validator = require("./Validator");
40
+ var import_errors = require("./lib/errors");
41
+ var import_Domain = require("./Domain");
42
+ var import_validators = require("./validators");
43
+ var import_types = require("./lib/types");
44
+ // Annotate the CommonJS export names for ESM import in node:
45
+ 0 && (module.exports = {
46
+ AssertError,
47
+ DefinitionError,
48
+ Domain,
49
+ DomainError,
50
+ InferDefinitionType,
51
+ InferValidatorReturnType,
52
+ IntersectValidator,
53
+ IntersectValidatorDefinition,
54
+ NeverValidator,
55
+ NeverValidatorDefinition,
56
+ UnionValidator,
57
+ UnionValidatorDefinition,
58
+ UnknownValidator,
59
+ UnknownValidatorDefinition,
60
+ Validator,
61
+ ValidatorClass
62
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,32 @@
1
+ import { Validator, ValidatorClass } from "./Validator";
2
+ import { AssertError, DefinitionError, DomainError } from "./lib/errors";
3
+ import { Domain } from "./Domain";
4
+ import {
5
+ NeverValidator,
6
+ NeverValidatorDefinition,
7
+ UnknownValidator,
8
+ UnknownValidatorDefinition,
9
+ UnionValidator,
10
+ UnionValidatorDefinition,
11
+ IntersectValidator,
12
+ IntersectValidatorDefinition
13
+ } from "./validators";
14
+ import { InferDefinitionType, InferValidatorReturnType } from "./lib/types";
15
+ export {
16
+ AssertError,
17
+ DefinitionError,
18
+ Domain,
19
+ DomainError,
20
+ InferDefinitionType,
21
+ InferValidatorReturnType,
22
+ IntersectValidator,
23
+ IntersectValidatorDefinition,
24
+ NeverValidator,
25
+ NeverValidatorDefinition,
26
+ UnionValidator,
27
+ UnionValidatorDefinition,
28
+ UnknownValidator,
29
+ UnknownValidatorDefinition,
30
+ Validator,
31
+ ValidatorClass
32
+ };
@@ -0,0 +1,23 @@
1
+ import { Validator, ValidatorClass } from "./Validator";
2
+ import { Operations } from "./lib/Operations";
3
+ import { IntersectValidator, NeverValidator, UnionValidator, UnknownValidator } from "./validators";
4
+ export type ReadonlyValidatorRegistry = {
5
+ readonly validators: Readonly<Record<string, ValidatorClass>>;
6
+ };
7
+ type DynamicDomain<R extends Readonly<Record<string, ReadonlyValidatorRegistry>>> = Domain & R;
8
+ export declare class Domain {
9
+ static create<const R extends Readonly<Record<string, ReadonlyValidatorRegistry>>>(registries: R, operations: readonly Operations[]): DynamicDomain<R>;
10
+ private readonly _registry;
11
+ private readonly _operations;
12
+ constructor(validatorRegistries: Readonly<Record<string, ReadonlyValidatorRegistry>>, operations: readonly Operations[]);
13
+ get Never(): NeverValidator;
14
+ get Unknown(): UnknownValidator;
15
+ get Union(): UnionValidator;
16
+ get Intersect(): IntersectValidator;
17
+ normalize(validator: Validator): Validator;
18
+ merge(a: Validator, b: Validator): Validator;
19
+ isEqual(a: Validator, b: Validator): boolean;
20
+ isSubset(a: Validator, b: Validator): boolean;
21
+ fromJSON(definition: unknown, path?: string): Validator;
22
+ }
23
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { Domain } from './Domain';
2
+ import type { Definition, UnknownDefinition } from './lib/types';
3
+ export interface ValidatorClass<V extends Validator = Validator> {
4
+ fromJSON(data: UnknownDefinition, path: string, domain: Domain): V;
5
+ new (): V;
6
+ }
7
+ export declare abstract class Validator<T = unknown> {
8
+ abstract assert(data: unknown, path?: string): asserts data is T;
9
+ validate(data: unknown, path?: string): T;
10
+ test(data: unknown, path?: string): data is T;
11
+ abstract clone(): this;
12
+ abstract toJSON(): Definition;
13
+ }
@@ -0,0 +1,5 @@
1
+ export { Validator, ValidatorClass } from './Validator';
2
+ export { AssertError, DefinitionError, DomainError } from './lib/errors';
3
+ export { Domain } from './Domain';
4
+ export { NeverValidator, NeverValidatorDefinition, UnknownValidator, UnknownValidatorDefinition, UnionValidator, UnionValidatorDefinition, IntersectValidator, IntersectValidatorDefinition } from './validators';
5
+ export { InferDefinitionType, InferValidatorReturnType } from './lib/types';
@@ -0,0 +1,36 @@
1
+ import { Validator, ValidatorClass } from '../Validator';
2
+ export type UnaryValidatorOperation = (validator: Validator, registry: Operations) => Validator;
3
+ export type BinaryValidatorOperation = (a: Validator, b: Validator, registry: Operations) => Validator;
4
+ export type BinaryBooleanOperation = (a: Validator, b: Validator, registry: Operations) => boolean;
5
+ export interface ReadonlyOperationsRegistry {
6
+ normalize: ReadonlyMap<ValidatorClass, UnaryValidatorOperation>;
7
+ merge: ReadonlyMap<ValidatorClass, ReadonlyMap<ValidatorClass, BinaryValidatorOperation>>;
8
+ isEqual: ReadonlyMap<ValidatorClass, ReadonlyMap<ValidatorClass, BinaryBooleanOperation>>;
9
+ isSubset: ReadonlyMap<ValidatorClass, ReadonlyMap<ValidatorClass, BinaryBooleanOperation>>;
10
+ }
11
+ export declare class Operations {
12
+ readonly registry: ReadonlyOperationsRegistry;
13
+ static merge(operations: readonly Operations[]): Operations;
14
+ private static _cloneMap;
15
+ private static _cloneMatrix;
16
+ private static _mergeMaps;
17
+ private static _mergeMatrices;
18
+ constructor(registry?: ReadonlyOperationsRegistry);
19
+ private _lookupNormalizeOperation;
20
+ private _lookupMergeOperation;
21
+ private _lookupIsEqualOperation;
22
+ private _lookupIsSubsetOperation;
23
+ normalize(validator: Validator): Validator;
24
+ merge(a: Validator, b: Validator): Validator;
25
+ isEqual(a: Validator, b: Validator): boolean;
26
+ isSubset(a: Validator, b: Validator): boolean;
27
+ private _normalizeUnion;
28
+ private _normalizeIntersect;
29
+ private _flattenUnion;
30
+ private _flattenIntersect;
31
+ private _deduplicateValidators;
32
+ private _isEqual;
33
+ private _isEqualValidatorSet;
34
+ private _merge;
35
+ private _isSubset;
36
+ }
@@ -0,0 +1,11 @@
1
+ export declare class AssertError extends Error {
2
+ constructor(message: string, path?: string, cause?: Record<string, unknown>);
3
+ }
4
+ export declare class DefinitionError extends Error {
5
+ constructor(message: string, path?: string, cause?: Record<string, unknown>);
6
+ }
7
+ export declare class MergeError extends Error {
8
+ constructor(message: string, path?: string, cause?: Record<string, unknown>);
9
+ }
10
+ export declare class DomainError extends Error {
11
+ }
@@ -0,0 +1,13 @@
1
+ import type { Validator, ValidatorClass } from '../Validator';
2
+ export interface Definition {
3
+ type: string;
4
+ }
5
+ export type UnknownDefinition = Definition & Record<string, unknown>;
6
+ export type InferDefinitionType<V> = V extends {
7
+ toJSON(): infer D;
8
+ } ? D : never;
9
+ export type InferValidatorInstanceType<C> = C extends ValidatorClass<infer V> ? V : never;
10
+ export type InferValidatorReturnType<V> = V extends Validator<infer T> ? T : unknown;
11
+ export type InferListDefinitionType<T extends readonly Validator[]> = {
12
+ [K in keyof T]: InferDefinitionType<T[K]>;
13
+ };
@@ -0,0 +1,20 @@
1
+ import { Validator } from '../Validator';
2
+ import type { Domain } from '../Domain';
3
+ import { Definition, InferListDefinitionType, InferValidatorReturnType, UnknownDefinition } from '../lib/types';
4
+ export interface IntersectValidatorDefinition<VARIANTS extends readonly Definition[] = readonly Definition[]> extends Definition {
5
+ type: 'intersect';
6
+ variants: VARIANTS;
7
+ }
8
+ export declare class IntersectValidator<VARIANTS = unknown, VARIANTSDEFINITION extends readonly Definition[] = readonly Definition[]> extends Validator<VARIANTS> {
9
+ readonly rules: {
10
+ readonly variants: readonly Validator[];
11
+ };
12
+ static fromJSON(definition: UnknownDefinition, path: string | undefined, domain: Domain): IntersectValidator;
13
+ constructor(rules?: {
14
+ readonly variants: readonly Validator[];
15
+ });
16
+ variants<const V extends Validator[]>(variants: V): IntersectValidator<InferValidatorReturnType<V[number]>, InferListDefinitionType<V>>;
17
+ assert(data: unknown, path?: string): asserts data is VARIANTS;
18
+ clone(): this;
19
+ toJSON(): IntersectValidatorDefinition<VARIANTSDEFINITION>;
20
+ }
@@ -0,0 +1,12 @@
1
+ import { Validator } from '../Validator';
2
+ import type { Domain } from '../Domain';
3
+ import type { Definition, UnknownDefinition } from "../lib/types";
4
+ export interface NeverValidatorDefinition extends Definition {
5
+ type: 'never';
6
+ }
7
+ export declare class NeverValidator extends Validator<never> {
8
+ static fromJSON(_definition: UnknownDefinition, _path: string | undefined, _domain: Domain): NeverValidator;
9
+ assert(_data: unknown, path?: string): asserts _data is never;
10
+ clone(): this;
11
+ toJSON(): NeverValidatorDefinition;
12
+ }
@@ -0,0 +1,20 @@
1
+ import { Validator } from '../Validator';
2
+ import type { Domain } from '../Domain';
3
+ import { Definition, InferListDefinitionType, InferValidatorReturnType, UnknownDefinition } from '../lib/types';
4
+ export interface UnionValidatorDefinition<VARIANTS extends readonly Definition[] = readonly Definition[]> extends Definition {
5
+ type: 'union';
6
+ variants: VARIANTS;
7
+ }
8
+ export declare class UnionValidator<VARIANTS = unknown, VARIANTSDEFINITION extends readonly Definition[] = readonly Definition[]> extends Validator<VARIANTS> {
9
+ readonly rules: {
10
+ readonly variants: readonly Validator[];
11
+ };
12
+ static fromJSON(definition: UnknownDefinition, path: string | undefined, schemaDomain: Domain): UnionValidator;
13
+ constructor(rules?: {
14
+ readonly variants: readonly Validator[];
15
+ });
16
+ variants<const V extends Validator[]>(variants: V): UnionValidator<InferValidatorReturnType<V[number]>, InferListDefinitionType<V>>;
17
+ assert(data: unknown, path?: string): asserts data is VARIANTS;
18
+ clone(): this;
19
+ toJSON(): UnionValidatorDefinition<VARIANTSDEFINITION>;
20
+ }
@@ -0,0 +1,12 @@
1
+ import { Validator } from '../Validator';
2
+ import type { Domain } from '../Domain';
3
+ import type { Definition, UnknownDefinition } from "../lib/types";
4
+ export interface UnknownValidatorDefinition extends Definition {
5
+ type: 'unknown';
6
+ }
7
+ export declare class UnknownValidator extends Validator {
8
+ static fromJSON(_definition: UnknownDefinition, _path: string | undefined, _domain: Domain): UnknownValidator;
9
+ assert(_data: unknown, _path?: string): asserts _data is unknown;
10
+ clone(): this;
11
+ toJSON(): UnknownValidatorDefinition;
12
+ }
@@ -0,0 +1,4 @@
1
+ export { NeverValidator, NeverValidatorDefinition } from './Never';
2
+ export { UnionValidator, UnionValidatorDefinition } from './Union';
3
+ export { IntersectValidator, IntersectValidatorDefinition } from './Intersect';
4
+ export { UnknownValidator, UnknownValidatorDefinition } from './Unknown';
package/package.json CHANGED
@@ -1,16 +1,27 @@
1
1
  {
2
2
  "name": "@serum-enterprises/schema",
3
- "version": "3.2.0-beta.0",
3
+ "version": "4.0.0-alpha.0",
4
4
  "engines": {
5
- "node": ">=24.0.0"
5
+ "node": ">=16.0.0"
6
6
  },
7
7
  "description": "Modern Schema Validation Library inspired by Joi.dev",
8
- "main": "./build/index.js",
9
- "types": "./types/index.d.ts",
8
+ "main": "./dist/index.cjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "import": "./dist/index.esm",
14
+ "require": "./dist/index.cjs",
15
+ "default": "./dist/index.esm"
16
+ }
17
+ },
10
18
  "scripts": {
11
- "prebuild": "tsc",
12
- "build": "esbuild src/index.ts --bundle --platform=node --format=cjs --outfile=build/index.js --sourcemap",
13
- "test": "jest"
19
+ "build:types": "tsc -p tsconfig.build.json",
20
+ "build:cjs": "esbuild src/index.ts --platform=node --format=cjs --outfile=./dist/index.cjs",
21
+ "build:esm": "esbuild src/index.ts --platform=neutral --format=esm --outfile=./dist/index.mjs",
22
+ "build": "npm run build:types && npm run build:cjs && npm run build:esm",
23
+ "pretest": "esbuild './src/index.ts' './tests/**/*.test.ts' --sourcemap --platform=node --format=cjs --outdir=./build",
24
+ "test": "jest --testMatch '**/*.test.js' --roots build/tests"
14
25
  },
15
26
  "repository": {
16
27
  "type": "git",
@@ -23,13 +34,13 @@
23
34
  },
24
35
  "devDependencies": {
25
36
  "@types/jest": "^30.0.0",
26
- "@types/node": "^25.3.0",
27
- "esbuild": "^0.27.3",
28
- "jest": "^30.2.0",
29
- "typescript": "^5.9.3"
37
+ "@types/node": "^25.6.0",
38
+ "esbuild": "^0.28.0",
39
+ "jest": "^30.3.0",
40
+ "typescript": "^6.0.2"
30
41
  },
31
42
  "dependencies": {
32
43
  "@serum-enterprises/json": "^3.1.0",
33
- "@serum-enterprises/option": "^3.0.1"
44
+ "@serum-enterprises/option": "^3.4.1"
34
45
  }
35
46
  }