@marianmeres/modelize
v2.0.3
Published
[](https://www.npmjs.com/package/@marianmeres/modelize) [](https://jsr.io/@marianmeres/modelize) [;
// Track changes
user.name = "Jane";
user.__isDirty; // true
user.__dirty; // Set { 'name' }
// Reset dirty state (keeps values)
user.__reset();
user.__isDirty; // false
// Reset to initial values
user.__resetToInitial();
user.name; // 'John'Features
- Dirty tracking - know which properties have changed
- Validation - JSON Schema and/or custom validator functions
- Field-level errors - detailed validation error reports
- Reset to initial - restore original values
- Svelte-compatible - works with
$auto-subscription - Lightweight - minimal API, no magic
Main API
modelize(source, options?)
Wraps source object with a proxy.
interface ModelizeOptions<T> {
schema?: JSONSchema; // JSON Schema for validation
validate?: (model: T) => true | string; // Custom validator
strict?: boolean; // Disallow new properties (default: true)
}Properties (read-only)
| Property | Type | Description |
| ----------- | ------------------- | ------------------------------------------------ |
| __dirty | Set<keyof T> | Set of modified property keys (empty when clean) |
| __isDirty | boolean | true if any property has been modified |
| __isValid | boolean | true if model passes validation |
| __errors | ValidationError[] | Last validation errors (empty if valid) |
| __source | T | The original unwrapped source object |
| __initial | T | Deep clone of original values (for reset) |
Methods
| Method | Description |
| --------------------------- | -------------------------------------------------------------------- |
| __validate() | Throws ModelizeValidationError if invalid, returns true if valid |
| __reset() | Clears dirty state (values unchanged) |
| __resetToInitial() | Restores all properties to initial values and clears dirty state |
| __hydrate(data, options?) | Bulk update properties. Options: { resetDirty?: boolean } |
| subscribe(callback) | Svelte-compatible subscription. Returns unsubscribe function |
Dirty Tracking
const model = modelize({ name: "John", age: 30 });
model.name = "Jane";
model.__isDirty; // true
model.__dirty; // Set { 'name' }
model.__dirty.has("name"); // true
model.__dirty.has("age"); // false
// Clear dirty state (values stay changed)
model.__reset();
model.__isDirty; // false
model.name; // 'Jane' (still changed)
// Or reset to initial values
model.name = "Modified";
model.__resetToInitial();
model.name; // 'John' (original value)
model.__isDirty; // falseValidation
JSON Schema
const user = modelize(
{ age: 25 },
{
schema: {
type: "object",
properties: {
age: { type: "number", minimum: 0, maximum: 120 },
},
},
},
);
user.age = -5;
user.__isValid; // false
user.__errors; // [{ path: '/age', message: 'must be >= 0' }]
try {
user.__validate();
} catch (e) {
// ModelizeValidationError with e.errors array
}Custom Validator
const form = modelize(
{ password: "", confirmPassword: "" },
{
validate: (m) => m.password === m.confirmPassword ? true : "Passwords must match",
},
);
form.password = "secret";
form.confirmPassword = "different";
form.__isValid; // false
form.__errors; // [{ path: '/', message: 'Passwords must match' }]Combined Validation
Both JSON Schema and custom validator can be used together. All errors are collected.
const user = modelize(
{ age: -5, status: "invalid" },
{
schema: {
type: "object",
properties: { age: { minimum: 0 } },
},
validate: (m) =>
["active", "inactive"].includes(m.status) ? true : "Invalid status",
},
);
user.__errors; // Contains both schema and custom validation errorsBulk Updates with __hydrate
const model = modelize({ name: "John", age: 30, city: "NYC" });
// Update multiple properties at once (single notification)
model.__hydrate({ name: "Jane", age: 25 });
// Hydrate and clear dirty state
model.__hydrate({ name: "Bob" }, { resetDirty: true });
model.__isDirty; // falseStrict Mode
By default, adding new properties is not allowed:
const model = modelize({ name: "John" });
model.extra = "value"; // throws Error
// Allow dynamic properties
const flexible = modelize({ name: "John" }, { strict: false });
flexible.extra = "value"; // worksTypes
import type {
JSONSchema,
Modelized,
ModelizeOptions,
ModelizeValidationError,
ValidationError,
} from "@marianmeres/modelize";Why the __ Prefix?
You'll notice that most methods and properties added by modelize use a double underscore
prefix (e.g., __isDirty, __validate()). This is intentional:
Avoid collisions: Your source object might have properties like
dirty,valid, orreset. The__prefix ensures our meta-properties never conflict with your data.Clear distinction: When reading code,
model.nameis obviously your data, whilemodel.__isDirtyis clearly a framework feature.
The only exception is subscribe, which has no prefix to maintain compatibility with the
Svelte store contract (allowing $model auto-subscription syntax).
Notes
- Shallow tracking: Only direct property changes are tracked. Nested object mutations
(e.g.,
model.nested.prop = x) don't trigger dirty state on the parent. - Reserved names: Properties
__dirty,__isDirty,__isValid,__source,__initial,__errors,__validate,__reset,__resetToInitial,__hydrate, andsubscribeare reserved and cannot be used in source objects. - Validation is lazy: Only runs when you access
__isValidor call__validate().
For complete API specification, see API.md.
License
MIT
