rustica 1.0.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 +21 -0
- package/README.md +289 -0
- package/dist/form/index.d.ts +60 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +194 -0
- package/dist/form/index.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +55 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +120 -0
- package/dist/react/index.js.map +1 -0
- package/dist/schema/builders.d.ts +126 -0
- package/dist/schema/builders.d.ts.map +1 -0
- package/dist/schema/builders.js +193 -0
- package/dist/schema/builders.js.map +1 -0
- package/dist/schema/index.d.ts +35 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +42 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/types.d.ts +71 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +5 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/validator/index.d.ts +71 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +149 -0
- package/dist/validator/index.js.map +1 -0
- package/package.json +71 -0
- package/pkg/.gitignore +1 -0
- package/pkg/.npmignore +3 -0
- package/pkg/README.md +289 -0
- package/pkg/package.json +17 -0
- package/pkg/rustica.d.ts +42 -0
- package/pkg/rustica.js +9 -0
- package/pkg/rustica_bg.js +193 -0
- package/pkg/rustica_bg.wasm +0 -0
- package/pkg/rustica_bg.wasm.d.ts +10 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Schema, ValidationResult, ValidationError } from "../schema/types";
|
|
2
|
+
import type { SchemaBuilder } from "../schema/builders";
|
|
3
|
+
/**
|
|
4
|
+
* WASM module interface
|
|
5
|
+
* Auto-generated by wasm-pack
|
|
6
|
+
*/
|
|
7
|
+
export interface WasmModule {
|
|
8
|
+
WasmValidator: {
|
|
9
|
+
validate(schema_json: string, value_json: string): string;
|
|
10
|
+
validate_at_path(schema_json: string, value_json: string, path_json: string): string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize WASM module
|
|
15
|
+
* Can be called explicitly for eager loading, or will auto-initialize on first use
|
|
16
|
+
*/
|
|
17
|
+
export declare function initWasm(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Core validator using WASM
|
|
20
|
+
*/
|
|
21
|
+
export declare class Validator {
|
|
22
|
+
/**
|
|
23
|
+
* Validate data against a schema
|
|
24
|
+
* Auto-initializes WASM on first use
|
|
25
|
+
*
|
|
26
|
+
* @param schema - Schema definition (builder or JSON)
|
|
27
|
+
* @param value - Data to validate
|
|
28
|
+
* @returns Validation result with errors if any
|
|
29
|
+
*/
|
|
30
|
+
static validate<T>(schema: SchemaBuilder<T> | Schema, value: unknown): Promise<ValidationResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Validate data at a specific path in the schema
|
|
33
|
+
* Useful for field-level validation in forms
|
|
34
|
+
* Auto-initializes WASM on first use
|
|
35
|
+
*
|
|
36
|
+
* @param schema - Schema definition
|
|
37
|
+
* @param value - Complete data object
|
|
38
|
+
* @param path - Path to validate (e.g., ['user', 'email'])
|
|
39
|
+
* @returns Validation result for the specific field
|
|
40
|
+
*/
|
|
41
|
+
static validateAtPath<T>(schema: SchemaBuilder<T> | Schema, value: unknown, path: string[]): Promise<ValidationResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Validate and throw on error (for convenience)
|
|
44
|
+
* Auto-initializes WASM on first use
|
|
45
|
+
*/
|
|
46
|
+
static parse<T>(schema: SchemaBuilder<T> | Schema, value: unknown): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Safe parse that returns result object
|
|
49
|
+
* Auto-initializes WASM on first use
|
|
50
|
+
*/
|
|
51
|
+
static safeParse<T>(schema: SchemaBuilder<T> | Schema, value: unknown): Promise<{
|
|
52
|
+
success: true;
|
|
53
|
+
data: T;
|
|
54
|
+
} | {
|
|
55
|
+
success: false;
|
|
56
|
+
errors: ValidationError[];
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validation exception for parse() method
|
|
61
|
+
*/
|
|
62
|
+
export declare class ValidationException extends Error {
|
|
63
|
+
errors: ValidationError[];
|
|
64
|
+
constructor(errors: ValidationError[]);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Auto-initialization wrapper
|
|
68
|
+
* Automatically initializes WASM on first use
|
|
69
|
+
*/
|
|
70
|
+
export declare function createValidator(): Promise<typeof Validator>;
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validator/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,gBAAgB,EAChB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE;QACb,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;QAC1D,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC;KACX,CAAC;CACH;AAQD;;;GAGG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAsC9C;AA0BD;;GAEG;AACH,qBAAa,SAAS;IACpB;;;;;;;OAOG;WACU,QAAQ,CAAC,CAAC,EACrB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,EACjC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,gBAAgB,CAAC;IAkB5B;;;;;;;;;OASG;WACU,cAAc,CAAC,CAAC,EAC3B,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,EACjC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,gBAAgB,CAAC;IAqB5B;;;OAGG;WACU,KAAK,CAAC,CAAC,EAClB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,EACjC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,CAAC,CAAC;IAUb;;;OAGG;WACU,SAAS,CAAC,CAAC,EACtB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,EACjC,KAAK,EAAE,OAAO,GACb,OAAO,CACR;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,eAAe,EAAE,CAAA;KAAE,CAC3E;CASF;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,MAAM,EAAE,eAAe,EAAE;gBAAzB,MAAM,EAAE,eAAe,EAAE;CAO7C;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAGjE"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy-loaded WASM module singleton
|
|
3
|
+
*/
|
|
4
|
+
let wasmModule = null;
|
|
5
|
+
let wasmInitPromise = null;
|
|
6
|
+
/**
|
|
7
|
+
* Initialize WASM module
|
|
8
|
+
* Can be called explicitly for eager loading, or will auto-initialize on first use
|
|
9
|
+
*/
|
|
10
|
+
export async function initWasm() {
|
|
11
|
+
if (wasmModule)
|
|
12
|
+
return;
|
|
13
|
+
if (wasmInitPromise)
|
|
14
|
+
return wasmInitPromise;
|
|
15
|
+
wasmInitPromise = (async () => {
|
|
16
|
+
try {
|
|
17
|
+
// Dynamic import of WASM module
|
|
18
|
+
// Use package-relative path that works both in development and when installed
|
|
19
|
+
const module = (await import("rustica/pkg/rustica.js"));
|
|
20
|
+
console.log("WASM module loaded:", module);
|
|
21
|
+
console.log("Has WasmValidator?", !!module.WasmValidator);
|
|
22
|
+
console.log("Has default?", typeof module.default);
|
|
23
|
+
// For bundler/web target with async init, call default function
|
|
24
|
+
if (typeof module.default === "function") {
|
|
25
|
+
await module.default();
|
|
26
|
+
}
|
|
27
|
+
// Always set wasmModule to the imported module (it has WasmValidator)
|
|
28
|
+
wasmModule = module;
|
|
29
|
+
// Verify WasmValidator is accessible
|
|
30
|
+
if (!module.WasmValidator) {
|
|
31
|
+
throw new Error("WasmValidator not found in WASM module");
|
|
32
|
+
}
|
|
33
|
+
console.log("WASM initialization complete");
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error("WASM initialization failed:", error);
|
|
37
|
+
wasmInitPromise = null; // Reset on error so it can be retried
|
|
38
|
+
throw new Error(`Failed to load WASM module. Make sure to run 'npm run build:wasm' first. Error: ${error}`);
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
return wasmInitPromise;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get initialized WASM module (auto-initializes if needed)
|
|
45
|
+
*/
|
|
46
|
+
async function getWasm() {
|
|
47
|
+
// If initialization is in progress, wait for it
|
|
48
|
+
if (wasmInitPromise && !wasmModule) {
|
|
49
|
+
await wasmInitPromise;
|
|
50
|
+
}
|
|
51
|
+
// If not initialized at all, start initialization
|
|
52
|
+
if (!wasmModule) {
|
|
53
|
+
await initWasm();
|
|
54
|
+
}
|
|
55
|
+
// Final check
|
|
56
|
+
if (!wasmModule) {
|
|
57
|
+
throw new Error("WASM module not initialized. Call initWasm() before validation.");
|
|
58
|
+
}
|
|
59
|
+
return wasmModule;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Core validator using WASM
|
|
63
|
+
*/
|
|
64
|
+
export class Validator {
|
|
65
|
+
/**
|
|
66
|
+
* Validate data against a schema
|
|
67
|
+
* Auto-initializes WASM on first use
|
|
68
|
+
*
|
|
69
|
+
* @param schema - Schema definition (builder or JSON)
|
|
70
|
+
* @param value - Data to validate
|
|
71
|
+
* @returns Validation result with errors if any
|
|
72
|
+
*/
|
|
73
|
+
static async validate(schema, value) {
|
|
74
|
+
const wasm = await getWasm();
|
|
75
|
+
// Serialize schema to JSON
|
|
76
|
+
const schemaJson = JSON.stringify(schema instanceof Object && "toJSON" in schema ? schema.toJSON() : schema);
|
|
77
|
+
// Serialize value to JSON
|
|
78
|
+
const valueJson = JSON.stringify(value);
|
|
79
|
+
// Call WASM validator (single call, zero-copy)
|
|
80
|
+
const resultJson = wasm.WasmValidator.validate(schemaJson, valueJson);
|
|
81
|
+
// Parse result
|
|
82
|
+
return JSON.parse(resultJson);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Validate data at a specific path in the schema
|
|
86
|
+
* Useful for field-level validation in forms
|
|
87
|
+
* Auto-initializes WASM on first use
|
|
88
|
+
*
|
|
89
|
+
* @param schema - Schema definition
|
|
90
|
+
* @param value - Complete data object
|
|
91
|
+
* @param path - Path to validate (e.g., ['user', 'email'])
|
|
92
|
+
* @returns Validation result for the specific field
|
|
93
|
+
*/
|
|
94
|
+
static async validateAtPath(schema, value, path) {
|
|
95
|
+
const wasm = await getWasm();
|
|
96
|
+
// Serialize inputs
|
|
97
|
+
const schemaJson = JSON.stringify(schema instanceof Object && "toJSON" in schema ? schema.toJSON() : schema);
|
|
98
|
+
const valueJson = JSON.stringify(value);
|
|
99
|
+
const pathJson = JSON.stringify(path);
|
|
100
|
+
// Call WASM validator (single call)
|
|
101
|
+
const resultJson = wasm.WasmValidator.validate_at_path(schemaJson, valueJson, pathJson);
|
|
102
|
+
// Parse result
|
|
103
|
+
return JSON.parse(resultJson);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Validate and throw on error (for convenience)
|
|
107
|
+
* Auto-initializes WASM on first use
|
|
108
|
+
*/
|
|
109
|
+
static async parse(schema, value) {
|
|
110
|
+
const result = await this.validate(schema, value);
|
|
111
|
+
if (!result.success) {
|
|
112
|
+
throw new ValidationException(result.errors || []);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Safe parse that returns result object
|
|
118
|
+
* Auto-initializes WASM on first use
|
|
119
|
+
*/
|
|
120
|
+
static async safeParse(schema, value) {
|
|
121
|
+
const result = await this.validate(schema, value);
|
|
122
|
+
if (result.success) {
|
|
123
|
+
return { success: true, data: value };
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
return { success: false, errors: result.errors || [] };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Validation exception for parse() method
|
|
132
|
+
*/
|
|
133
|
+
export class ValidationException extends Error {
|
|
134
|
+
constructor(errors) {
|
|
135
|
+
super("Validation failed:\n" +
|
|
136
|
+
errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n"));
|
|
137
|
+
this.errors = errors;
|
|
138
|
+
this.name = "ValidationException";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Auto-initialization wrapper
|
|
143
|
+
* Automatically initializes WASM on first use
|
|
144
|
+
*/
|
|
145
|
+
export async function createValidator() {
|
|
146
|
+
await initWasm();
|
|
147
|
+
return Validator;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validator/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rustica",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-grade schema validation powered by Rust and WebAssembly",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./pkg/*": "./pkg/*"
|
|
14
|
+
},
|
|
15
|
+
"author": "fourth-ally",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/fourth-ally/rustica.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/fourth-ally/rustica/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/fourth-ally/rustica#readme",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"pkg",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build:wasm": "wasm-pack build --target bundler --out-dir pkg",
|
|
33
|
+
"build:wasm:node": "wasm-pack build --target nodejs --out-dir pkg",
|
|
34
|
+
"build:ts": "tsc",
|
|
35
|
+
"build": "npm run build:wasm && npm run build:ts",
|
|
36
|
+
"dev": "tsc --watch",
|
|
37
|
+
"test": "cargo test && npm run test:ts",
|
|
38
|
+
"test:ts": "npm run build:wasm:node && node --import tsx --test tests/*.test.ts && npm run build:wasm",
|
|
39
|
+
"prepublishOnly": "npm run build && npm test"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"validation",
|
|
43
|
+
"schema",
|
|
44
|
+
"wasm",
|
|
45
|
+
"rust",
|
|
46
|
+
"zod",
|
|
47
|
+
"forms",
|
|
48
|
+
"react",
|
|
49
|
+
"typescript",
|
|
50
|
+
"webassembly",
|
|
51
|
+
"form-validation"
|
|
52
|
+
],
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^25.0.9",
|
|
55
|
+
"@types/react": "^18.2.0",
|
|
56
|
+
"react": "^18.2.0",
|
|
57
|
+
"tsx": "^4.7.0",
|
|
58
|
+
"typescript": "^5.3.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": ">=18.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"react": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18.0.0"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/pkg/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
package/pkg/.npmignore
ADDED
package/pkg/README.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# Rustica
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://www.rust-lang.org/)
|
|
8
|
+
[](https://webassembly.org/)
|
|
9
|
+
|
|
10
|
+
Production-grade schema and form validation system powered by Rust and WebAssembly.
|
|
11
|
+
|
|
12
|
+
## ✨ Features
|
|
13
|
+
|
|
14
|
+
<table>
|
|
15
|
+
<tr>
|
|
16
|
+
<td width="50%">
|
|
17
|
+
|
|
18
|
+
### 🦀 Rust Core
|
|
19
|
+
|
|
20
|
+
- **WASM-powered** validation
|
|
21
|
+
- **Zero-copy** architecture
|
|
22
|
+
- **~0.1-0.5ms** per validation
|
|
23
|
+
- **Single call** per validation
|
|
24
|
+
|
|
25
|
+
</td>
|
|
26
|
+
<td width="50%">
|
|
27
|
+
|
|
28
|
+
### 📝 TypeScript API
|
|
29
|
+
|
|
30
|
+
- **Fluent API** like Zod
|
|
31
|
+
- **Full type inference**
|
|
32
|
+
- **Schema serialization**
|
|
33
|
+
- **UI metadata** support
|
|
34
|
+
|
|
35
|
+
</td>
|
|
36
|
+
</tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td width="50%">
|
|
39
|
+
|
|
40
|
+
### ⚛️ React Integration
|
|
41
|
+
|
|
42
|
+
- **useWasmForm** hook
|
|
43
|
+
- **Field registration**
|
|
44
|
+
- **Auto re-rendering**
|
|
45
|
+
- **RHF-compatible** API
|
|
46
|
+
|
|
47
|
+
</td>
|
|
48
|
+
<td width="50%">
|
|
49
|
+
|
|
50
|
+
### 🔧 Framework Agnostic
|
|
51
|
+
|
|
52
|
+
- **createForm** for any framework
|
|
53
|
+
- **Vanilla JS** support
|
|
54
|
+
- **Node.js** compatible
|
|
55
|
+
- **Browser** ready
|
|
56
|
+
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
</table>
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install rustica
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { r, useWasmForm } from 'rustica';
|
|
71
|
+
|
|
72
|
+
// Define schema with optional custom error messages
|
|
73
|
+
// WASM auto-initializes on first validation - no setup needed!
|
|
74
|
+
const loginSchema = r.object({
|
|
75
|
+
email: r.string()
|
|
76
|
+
.min(3)
|
|
77
|
+
.email()
|
|
78
|
+
.ui({ label: "Email" })
|
|
79
|
+
.messages({
|
|
80
|
+
email: "Please enter a valid email address",
|
|
81
|
+
min: "Email must be at least 3 characters"
|
|
82
|
+
}),
|
|
83
|
+
password: r.string()
|
|
84
|
+
.min(8)
|
|
85
|
+
.ui({ label: "Password" })
|
|
86
|
+
.messages({
|
|
87
|
+
min: "Password must be at least 8 characters for security"
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Infer types
|
|
92
|
+
type LoginForm = r.Infer<typeof loginSchema>;
|
|
93
|
+
|
|
94
|
+
// Use in React - works immediately!
|
|
95
|
+
function LoginForm() {
|
|
96
|
+
const form = useWasmForm({
|
|
97
|
+
schema: loginSchema,
|
|
98
|
+
defaultValues: { email: '', password: '' },
|
|
99
|
+
onSubmit: async (data) => {
|
|
100
|
+
console.log('Valid data:', data);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<form onSubmit={form.handleSubmit}>
|
|
106
|
+
<input {...form.register('email')} />
|
|
107
|
+
{form.errors.email && <span>{form.errors.email.message}</span>}
|
|
108
|
+
|
|
109
|
+
<input type="password" {...form.register('password')} />
|
|
110
|
+
{form.errors.password && <span>{form.errors.password.message}</span>}
|
|
111
|
+
|
|
112
|
+
<button type="submit">Login</button>
|
|
113
|
+
</form>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Note**: WASM auto-initializes on the first validation call. For eager loading (optional), you can manually call `await initWasm()` at app startup.
|
|
119
|
+
|
|
120
|
+
````
|
|
121
|
+
|
|
122
|
+
## Custom Error Messages (Optional)
|
|
123
|
+
|
|
124
|
+
Customize validation error messages for better UX:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// String validation with custom messages
|
|
128
|
+
const usernameSchema = r.string().min(3).max(20).messages({
|
|
129
|
+
invalid_type: "Username must be text",
|
|
130
|
+
min: "Username is too short - minimum 3 characters",
|
|
131
|
+
max: "Username is too long - maximum 20 characters",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Number validation with custom messages
|
|
135
|
+
const ageSchema = r.number().min(18).integer().messages({
|
|
136
|
+
invalid_type: "Age must be a number",
|
|
137
|
+
min: "You must be at least 18 years old",
|
|
138
|
+
integer: "Age must be a whole number",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Object validation with custom messages
|
|
142
|
+
const formSchema = r
|
|
143
|
+
.object({
|
|
144
|
+
email: r.string().email().messages({
|
|
145
|
+
email: "Please enter a valid email like user@example.com",
|
|
146
|
+
}),
|
|
147
|
+
terms: r.boolean().messages({
|
|
148
|
+
invalid_type: "You must accept the terms and conditions",
|
|
149
|
+
}),
|
|
150
|
+
})
|
|
151
|
+
.messages({
|
|
152
|
+
invalid_type: "Form data must be an object",
|
|
153
|
+
required: "This field is required",
|
|
154
|
+
});
|
|
155
|
+
````
|
|
156
|
+
|
|
157
|
+
**Available message keys by type:**
|
|
158
|
+
|
|
159
|
+
- **String**: `invalid_type`, `min`, `max`, `email`, `url`, `pattern`
|
|
160
|
+
- **Number**: `invalid_type`, `min`, `max`, `integer`, `positive`
|
|
161
|
+
- **Boolean**: `invalid_type`
|
|
162
|
+
- **Object**: `invalid_type`, `required`
|
|
163
|
+
|
|
164
|
+
If not provided, default messages are used. See [examples/custom-messages.ts](./examples/custom-messages.ts) for more examples.
|
|
165
|
+
|
|
166
|
+
## Building from Source
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Quick setup (recommended)
|
|
170
|
+
chmod +x scripts/setup.sh
|
|
171
|
+
./scripts/setup.sh
|
|
172
|
+
|
|
173
|
+
# Or manual setup
|
|
174
|
+
npm install
|
|
175
|
+
npm run build
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [Getting Started Guide](./docs/GETTING_STARTED.md) for detailed instructions.
|
|
179
|
+
|
|
180
|
+
## Architecture
|
|
181
|
+
|
|
182
|
+
- **Rust Core** (`src/lib.rs`, `src/schema.rs`, `src/validator.rs`) - Schema definitions and validation logic
|
|
183
|
+
- **WASM Interface** (`src/wasm.rs`) - WebAssembly bindings with wasm-bindgen
|
|
184
|
+
- **TypeScript Schema Builder** (`src/schema/`) - Fluent API for schema definition
|
|
185
|
+
- **Form Runtime** (`src/form/`) - Form state management
|
|
186
|
+
- **React Hook** (`src/react/`) - React integration
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
- 📖 **[Complete Documentation Index](./docs/INDEX.md)** - All docs in one place
|
|
191
|
+
- 🚀 **[Getting Started Guide](./docs/GETTING_STARTED.md)** - Quick start tutorial
|
|
192
|
+
- 📚 **[API Reference](./docs/API.md)** - Complete API documentation
|
|
193
|
+
- 🏗️ **[Architecture Guide](./docs/ARCHITECTURE.md)** - How it works
|
|
194
|
+
- 📊 **[Feature Comparison](./docs/COMPARISON.md)** - vs Zod, Yup, Joi
|
|
195
|
+
- 🤝 **[Contributing Guide](./CONTRIBUTING.md)** - How to contribute
|
|
196
|
+
|
|
197
|
+
## Project Structure
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
rustica/
|
|
201
|
+
├── src/ # Rust source (validation core)
|
|
202
|
+
│ ├── lib.rs # Module exports
|
|
203
|
+
│ ├── schema.rs # Schema AST types
|
|
204
|
+
│ ├── validator.rs # Validation engine
|
|
205
|
+
│ └── wasm.rs # WASM bindings
|
|
206
|
+
├── src/ # TypeScript source
|
|
207
|
+
│ ├── schema/ # Schema builders (r.string(), etc.)
|
|
208
|
+
│ ├── validator/ # WASM wrapper
|
|
209
|
+
│ ├── form/ # Form runtime
|
|
210
|
+
│ ├── react/ # React hooks
|
|
211
|
+
│ └── index.ts # Main entry point
|
|
212
|
+
├── examples/ # Usage examples
|
|
213
|
+
│ ├── quick-test.ts # Basic validation tests
|
|
214
|
+
│ ├── standalone.ts # Standalone examples
|
|
215
|
+
│ ├── forms.tsx # Form component examples
|
|
216
|
+
│ └── react-form-app/ # Full React app with API integration
|
|
217
|
+
├── tests/ # Test suite
|
|
218
|
+
├── docs/ # Documentation
|
|
219
|
+
└── scripts/ # Build scripts
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Commands
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Development
|
|
226
|
+
make install # Install dependencies
|
|
227
|
+
make build # Build WASM + TypeScript
|
|
228
|
+
make test # Run all tests
|
|
229
|
+
make dev # Watch mode
|
|
230
|
+
|
|
231
|
+
# Quick Commands
|
|
232
|
+
make example # Run quick test
|
|
233
|
+
make clean # Clean build artifacts
|
|
234
|
+
make help # Show all commands
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Performance
|
|
238
|
+
|
|
239
|
+
<table>
|
|
240
|
+
<tr>
|
|
241
|
+
<td><b>Metric</b></td>
|
|
242
|
+
<td><b>Value</b></td>
|
|
243
|
+
<td><b>Notes</b></td>
|
|
244
|
+
</tr>
|
|
245
|
+
<tr>
|
|
246
|
+
<td>Validation Speed</td>
|
|
247
|
+
<td>~0.1-0.5ms</td>
|
|
248
|
+
<td>Per validation (warm)</td>
|
|
249
|
+
</tr>
|
|
250
|
+
<tr>
|
|
251
|
+
<td>Throughput</td>
|
|
252
|
+
<td>5,000-10,000/sec</td>
|
|
253
|
+
<td>1000 validations in ~100-200ms</td>
|
|
254
|
+
</tr>
|
|
255
|
+
<tr>
|
|
256
|
+
<td>WASM Size</td>
|
|
257
|
+
<td>~15-20KB</td>
|
|
258
|
+
<td>Gzipped: ~8-10KB</td>
|
|
259
|
+
</tr>
|
|
260
|
+
<tr>
|
|
261
|
+
<td>Overhead</td>
|
|
262
|
+
<td>Single call</td>
|
|
263
|
+
<td>Zero-copy where possible</td>
|
|
264
|
+
</tr>
|
|
265
|
+
</table>
|
|
266
|
+
|
|
267
|
+
See [Performance Comparison](./docs/COMPARISON.md) for detailed benchmarks.
|
|
268
|
+
|
|
269
|
+
## Contributing
|
|
270
|
+
|
|
271
|
+
We welcome contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
272
|
+
|
|
273
|
+
## Roadmap
|
|
274
|
+
|
|
275
|
+
- [x] Core validation (string, number, boolean, object)
|
|
276
|
+
- [x] React hooks
|
|
277
|
+
- [x] Form runtime
|
|
278
|
+
- [x] Type inference
|
|
279
|
+
- [x] Custom error messages (optional)
|
|
280
|
+
- [ ] Array/tuple schemas
|
|
281
|
+
- [ ] Union/intersection types
|
|
282
|
+
- [ ] Async validation helpers
|
|
283
|
+
- [ ] i18n support
|
|
284
|
+
|
|
285
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
MIT
|
package/pkg/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rustica",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"files": [
|
|
6
|
+
"rustica_bg.wasm",
|
|
7
|
+
"rustica.js",
|
|
8
|
+
"rustica_bg.js",
|
|
9
|
+
"rustica.d.ts"
|
|
10
|
+
],
|
|
11
|
+
"main": "rustica.js",
|
|
12
|
+
"types": "rustica.d.ts",
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./rustica.js",
|
|
15
|
+
"./snippets/*"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/pkg/rustica.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WASM interface for validation
|
|
6
|
+
*
|
|
7
|
+
* This module exposes exactly two functions to JavaScript:
|
|
8
|
+
* - validate: validates entire data against schema
|
|
9
|
+
* - validate_at_path: validates data at a specific path
|
|
10
|
+
*
|
|
11
|
+
* Both functions accept and return JSON strings for zero-copy performance
|
|
12
|
+
*/
|
|
13
|
+
export class WasmValidator {
|
|
14
|
+
private constructor();
|
|
15
|
+
free(): void;
|
|
16
|
+
[Symbol.dispose](): void;
|
|
17
|
+
/**
|
|
18
|
+
* Validate data against a schema
|
|
19
|
+
*
|
|
20
|
+
* # Arguments
|
|
21
|
+
* * `schema_json` - JSON string representing the schema AST
|
|
22
|
+
* * `value_json` - JSON string representing the data to validate
|
|
23
|
+
*
|
|
24
|
+
* # Returns
|
|
25
|
+
* JSON string with validation result:
|
|
26
|
+
* - Success: `{"success": true}`
|
|
27
|
+
* - Error: `{"success": false, "errors": [...]}`
|
|
28
|
+
*/
|
|
29
|
+
static validate(schema_json: string, value_json: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Validate data at a specific path in the schema
|
|
32
|
+
*
|
|
33
|
+
* # Arguments
|
|
34
|
+
* * `schema_json` - JSON string representing the schema AST
|
|
35
|
+
* * `value_json` - JSON string representing the data to validate
|
|
36
|
+
* * `path_json` - JSON array of path segments as strings
|
|
37
|
+
*
|
|
38
|
+
* # Returns
|
|
39
|
+
* JSON string with validation result (same format as validate)
|
|
40
|
+
*/
|
|
41
|
+
static validate_at_path(schema_json: string, value_json: string, path_json: string): string;
|
|
42
|
+
}
|