@schema-ts/core 0.1.3 → 0.1.4

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/dist/index.d.cts CHANGED
@@ -191,6 +191,7 @@ interface FieldNode {
191
191
  dependencies?: Set<string>;
192
192
  canRemove: boolean;
193
193
  canAdd: boolean;
194
+ isRequired: boolean;
194
195
  }
195
196
  type SchemaChangeEvent = {
196
197
  type: "schema" | "value" | "error";
@@ -205,6 +206,14 @@ interface SchemaRuntimeOptions {
205
206
  * @default 'explicit'
206
207
  */
207
208
  autoFillDefaults?: "always" | "explicit" | "never";
209
+ /**
210
+ * Control behavior when removing the last element from an array or object.
211
+ * - 'never': Always keep empty containers ([] or {})
212
+ * - 'auto': Remove empty container only if the field is optional (not in parent's required array)
213
+ * - 'always': Always remove empty containers (may cause validation errors for required fields)
214
+ * @default 'auto'
215
+ */
216
+ removeEmptyContainers?: "never" | "auto" | "always";
208
217
  }
209
218
  declare class SchemaRuntime {
210
219
  private validator;
@@ -318,13 +327,34 @@ declare class SchemaRuntime {
318
327
  * @returns true if successful, false if the path cannot be set
319
328
  */
320
329
  private setValueAtPath;
330
+ /**
331
+ * Internal method to remove a value at a path.
332
+ * Shared logic for removeValue and setValue(undefined).
333
+ * @param path - The normalized path to remove
334
+ * @param canRemove - Whether the removal is allowed (pre-checked by caller)
335
+ * @returns true if successful, false if removal failed
336
+ */
337
+ private removeValueInternal;
321
338
  /**
322
339
  * Remove a node at the specified path.
323
340
  * This deletes the value from the data structure (array splice or object delete).
341
+ * After removal, may also remove empty parent containers based on removeEmptyContainers option.
324
342
  * @param path - The path to remove
325
343
  * @returns true if successful, false if the path cannot be removed
326
344
  */
327
345
  removeValue(path: string): boolean;
346
+ /**
347
+ * Clean up empty parent containers after element removal.
348
+ * Recursively removes empty arrays/objects based on removeEmptyContainers option.
349
+ * @param path - The path to check for empty container
350
+ * @returns The topmost parent path for reconciliation
351
+ */
352
+ private cleanupEmptyContainers;
353
+ /**
354
+ * Get default value for a schema, respecting autoFillDefaults option.
355
+ * Falls back to 'always' strategy if configured strategy returns undefined.
356
+ */
357
+ private getDefaultValueForAdd;
328
358
  /**
329
359
  * Add a new child to an array or object at the specified parent path.
330
360
  * For arrays, appends a new item with default value based on items schema.
@@ -340,13 +370,17 @@ declare class SchemaRuntime {
340
370
  * Creates intermediate containers (objects/arrays) as needed.
341
371
  * Triggers reconciliation and notifies subscribers.
342
372
  *
373
+ * When value is undefined and the field is not required, the field will be
374
+ * removed from the parent container (similar to removeValue behavior).
375
+ *
343
376
  * @param path - The JSON Pointer path (e.g., "/user/name", "" for root)
344
- * @param value - The new value to set
377
+ * @param value - The new value to set. If undefined and field is optional, removes the field.
345
378
  * @returns true if successful, false if the path cannot be set
346
379
  *
347
380
  * @example
348
381
  * runtime.setValue("/name", "Bob"); // set name to "Bob"
349
382
  * runtime.setValue("", { name: "Alice" }); // replace entire root value
383
+ * runtime.setValue("/optional", undefined); // remove optional field
350
384
  */
351
385
  setValue(path: string, value: unknown): boolean;
352
386
  /**
@@ -372,9 +406,14 @@ declare class SchemaRuntime {
372
406
  * This handles cases like if-then-else where new properties with defaults
373
407
  * may appear when conditions change.
374
408
  *
409
+ * Container initialization rules:
410
+ * - Root node is always considered required and will be initialized if it has defaults or required properties
411
+ * - Nested containers are initialized only if they are in parent's required array
412
+ *
375
413
  * @param instanceLocation - The path to the node
376
414
  * @param newSchema - The new effective schema
377
415
  * @param type - The schema type
416
+ * @param isRequired - Whether this node is required by its parent
378
417
  */
379
418
  private applySchemaDefaults;
380
419
  /**
@@ -386,6 +425,7 @@ declare class SchemaRuntime {
386
425
  * Build/update a FieldNode in place.
387
426
  * Updates the node's schema, type, error, and children based on the current value.
388
427
  * @param schema - Optional. If provided, updates node.originalSchema. Otherwise uses existing.
428
+ * @param isRequired - Whether this node is required by its parent schema.
389
429
  */
390
430
  private buildNode;
391
431
  }
@@ -460,6 +500,16 @@ declare function collectDependencies(schema: Schema, instanceLocation: string):
460
500
  */
461
501
  declare function extractReferencedPaths(conditionSchema: Schema, basePath?: string, depth?: number): string[];
462
502
 
503
+ interface GetDefaultValueOptions {
504
+ /** Optional existing value to fill defaults into */
505
+ value?: unknown;
506
+ /**
507
+ * Controls type-based default behavior:
508
+ * - 'always': Returns type-based defaults (e.g., "" for string, [] for array)
509
+ * - 'explicit' (default): Only returns explicitly declared schema.const or schema.default
510
+ */
511
+ strategy?: "always" | "explicit";
512
+ }
463
513
  /**
464
514
  * Generate a default value for a schema based on its type and constraints.
465
515
  *
@@ -474,24 +524,21 @@ declare function extractReferencedPaths(conditionSchema: Schema, basePath?: stri
474
524
  * If a value is provided, it will be used as the base and missing defaults will be filled in.
475
525
  *
476
526
  * @param schema - The JSON Schema to generate a default value for
477
- * @param value - Optional existing value to fill defaults into
478
- * @param strategy - Controls type-based default behavior:
479
- * - 'always' (default): Returns type-based defaults (e.g., "" for string, [] for array)
480
- * - 'explicit': Only returns explicitly declared schema.const or schema.default
527
+ * @param options - Optional configuration for default value generation
481
528
  * @returns The generated default value, or undefined if type cannot be determined
482
529
  *
483
530
  * @example
484
- * getDefaultValue({ type: "string" }) // returns ""
485
- * getDefaultValue({ type: "string" }, undefined, 'explicit') // returns undefined
531
+ * getDefaultValue({ type: "string" }) // returns undefined (explicit mode)
532
+ * getDefaultValue({ type: "string" }, { strategy: 'always' }) // returns ""
486
533
  * getDefaultValue({ type: "number", default: 42 }) // returns 42
487
534
  * getDefaultValue({ const: "fixed" }) // returns "fixed"
488
535
  * getDefaultValue({
489
536
  * type: "object",
490
537
  * properties: { name: { type: "string" } },
491
538
  * required: ["name"]
492
- * }) // returns { name: "" }
493
- * getDefaultValue({ type: "object", properties: { a: { default: 1 } } }, {}) // returns { a: 1 }
539
+ * }, { strategy: 'always' }) // returns { name: "" }
540
+ * getDefaultValue({ type: "object", properties: { a: { default: 1 } } }, { value: {} }) // returns { a: 1 }
494
541
  */
495
- declare function getDefaultValue(schema: Schema, value?: unknown, strategy?: "always" | "explicit"): unknown;
542
+ declare function getDefaultValue(schema: Schema, options?: GetDefaultValueOptions): unknown;
496
543
 
497
- export { DRAFT_URIS, type ErrorFormatter, type ErrorMessage, type FieldNode, MESSAGES, type NormalizerOptions, type Output, type Schema, type SchemaChangeEvent, type SchemaDraft, SchemaRuntime, type SchemaRuntimeOptions, type SchemaType, StringFormatValidator, type StringFormatValidatorInterface, Validator, type ValidatorConfig, type ValidatorOptions, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, validateSchema };
544
+ export { DRAFT_URIS, type ErrorFormatter, type ErrorMessage, type FieldNode, type GetDefaultValueOptions, MESSAGES, type NormalizerOptions, type Output, type Schema, type SchemaChangeEvent, type SchemaDraft, SchemaRuntime, type SchemaRuntimeOptions, type SchemaType, StringFormatValidator, type StringFormatValidatorInterface, Validator, type ValidatorConfig, type ValidatorOptions, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, validateSchema };
package/dist/index.d.ts CHANGED
@@ -191,6 +191,7 @@ interface FieldNode {
191
191
  dependencies?: Set<string>;
192
192
  canRemove: boolean;
193
193
  canAdd: boolean;
194
+ isRequired: boolean;
194
195
  }
195
196
  type SchemaChangeEvent = {
196
197
  type: "schema" | "value" | "error";
@@ -205,6 +206,14 @@ interface SchemaRuntimeOptions {
205
206
  * @default 'explicit'
206
207
  */
207
208
  autoFillDefaults?: "always" | "explicit" | "never";
209
+ /**
210
+ * Control behavior when removing the last element from an array or object.
211
+ * - 'never': Always keep empty containers ([] or {})
212
+ * - 'auto': Remove empty container only if the field is optional (not in parent's required array)
213
+ * - 'always': Always remove empty containers (may cause validation errors for required fields)
214
+ * @default 'auto'
215
+ */
216
+ removeEmptyContainers?: "never" | "auto" | "always";
208
217
  }
209
218
  declare class SchemaRuntime {
210
219
  private validator;
@@ -318,13 +327,34 @@ declare class SchemaRuntime {
318
327
  * @returns true if successful, false if the path cannot be set
319
328
  */
320
329
  private setValueAtPath;
330
+ /**
331
+ * Internal method to remove a value at a path.
332
+ * Shared logic for removeValue and setValue(undefined).
333
+ * @param path - The normalized path to remove
334
+ * @param canRemove - Whether the removal is allowed (pre-checked by caller)
335
+ * @returns true if successful, false if removal failed
336
+ */
337
+ private removeValueInternal;
321
338
  /**
322
339
  * Remove a node at the specified path.
323
340
  * This deletes the value from the data structure (array splice or object delete).
341
+ * After removal, may also remove empty parent containers based on removeEmptyContainers option.
324
342
  * @param path - The path to remove
325
343
  * @returns true if successful, false if the path cannot be removed
326
344
  */
327
345
  removeValue(path: string): boolean;
346
+ /**
347
+ * Clean up empty parent containers after element removal.
348
+ * Recursively removes empty arrays/objects based on removeEmptyContainers option.
349
+ * @param path - The path to check for empty container
350
+ * @returns The topmost parent path for reconciliation
351
+ */
352
+ private cleanupEmptyContainers;
353
+ /**
354
+ * Get default value for a schema, respecting autoFillDefaults option.
355
+ * Falls back to 'always' strategy if configured strategy returns undefined.
356
+ */
357
+ private getDefaultValueForAdd;
328
358
  /**
329
359
  * Add a new child to an array or object at the specified parent path.
330
360
  * For arrays, appends a new item with default value based on items schema.
@@ -340,13 +370,17 @@ declare class SchemaRuntime {
340
370
  * Creates intermediate containers (objects/arrays) as needed.
341
371
  * Triggers reconciliation and notifies subscribers.
342
372
  *
373
+ * When value is undefined and the field is not required, the field will be
374
+ * removed from the parent container (similar to removeValue behavior).
375
+ *
343
376
  * @param path - The JSON Pointer path (e.g., "/user/name", "" for root)
344
- * @param value - The new value to set
377
+ * @param value - The new value to set. If undefined and field is optional, removes the field.
345
378
  * @returns true if successful, false if the path cannot be set
346
379
  *
347
380
  * @example
348
381
  * runtime.setValue("/name", "Bob"); // set name to "Bob"
349
382
  * runtime.setValue("", { name: "Alice" }); // replace entire root value
383
+ * runtime.setValue("/optional", undefined); // remove optional field
350
384
  */
351
385
  setValue(path: string, value: unknown): boolean;
352
386
  /**
@@ -372,9 +406,14 @@ declare class SchemaRuntime {
372
406
  * This handles cases like if-then-else where new properties with defaults
373
407
  * may appear when conditions change.
374
408
  *
409
+ * Container initialization rules:
410
+ * - Root node is always considered required and will be initialized if it has defaults or required properties
411
+ * - Nested containers are initialized only if they are in parent's required array
412
+ *
375
413
  * @param instanceLocation - The path to the node
376
414
  * @param newSchema - The new effective schema
377
415
  * @param type - The schema type
416
+ * @param isRequired - Whether this node is required by its parent
378
417
  */
379
418
  private applySchemaDefaults;
380
419
  /**
@@ -386,6 +425,7 @@ declare class SchemaRuntime {
386
425
  * Build/update a FieldNode in place.
387
426
  * Updates the node's schema, type, error, and children based on the current value.
388
427
  * @param schema - Optional. If provided, updates node.originalSchema. Otherwise uses existing.
428
+ * @param isRequired - Whether this node is required by its parent schema.
389
429
  */
390
430
  private buildNode;
391
431
  }
@@ -460,6 +500,16 @@ declare function collectDependencies(schema: Schema, instanceLocation: string):
460
500
  */
461
501
  declare function extractReferencedPaths(conditionSchema: Schema, basePath?: string, depth?: number): string[];
462
502
 
503
+ interface GetDefaultValueOptions {
504
+ /** Optional existing value to fill defaults into */
505
+ value?: unknown;
506
+ /**
507
+ * Controls type-based default behavior:
508
+ * - 'always': Returns type-based defaults (e.g., "" for string, [] for array)
509
+ * - 'explicit' (default): Only returns explicitly declared schema.const or schema.default
510
+ */
511
+ strategy?: "always" | "explicit";
512
+ }
463
513
  /**
464
514
  * Generate a default value for a schema based on its type and constraints.
465
515
  *
@@ -474,24 +524,21 @@ declare function extractReferencedPaths(conditionSchema: Schema, basePath?: stri
474
524
  * If a value is provided, it will be used as the base and missing defaults will be filled in.
475
525
  *
476
526
  * @param schema - The JSON Schema to generate a default value for
477
- * @param value - Optional existing value to fill defaults into
478
- * @param strategy - Controls type-based default behavior:
479
- * - 'always' (default): Returns type-based defaults (e.g., "" for string, [] for array)
480
- * - 'explicit': Only returns explicitly declared schema.const or schema.default
527
+ * @param options - Optional configuration for default value generation
481
528
  * @returns The generated default value, or undefined if type cannot be determined
482
529
  *
483
530
  * @example
484
- * getDefaultValue({ type: "string" }) // returns ""
485
- * getDefaultValue({ type: "string" }, undefined, 'explicit') // returns undefined
531
+ * getDefaultValue({ type: "string" }) // returns undefined (explicit mode)
532
+ * getDefaultValue({ type: "string" }, { strategy: 'always' }) // returns ""
486
533
  * getDefaultValue({ type: "number", default: 42 }) // returns 42
487
534
  * getDefaultValue({ const: "fixed" }) // returns "fixed"
488
535
  * getDefaultValue({
489
536
  * type: "object",
490
537
  * properties: { name: { type: "string" } },
491
538
  * required: ["name"]
492
- * }) // returns { name: "" }
493
- * getDefaultValue({ type: "object", properties: { a: { default: 1 } } }, {}) // returns { a: 1 }
539
+ * }, { strategy: 'always' }) // returns { name: "" }
540
+ * getDefaultValue({ type: "object", properties: { a: { default: 1 } } }, { value: {} }) // returns { a: 1 }
494
541
  */
495
- declare function getDefaultValue(schema: Schema, value?: unknown, strategy?: "always" | "explicit"): unknown;
542
+ declare function getDefaultValue(schema: Schema, options?: GetDefaultValueOptions): unknown;
496
543
 
497
- export { DRAFT_URIS, type ErrorFormatter, type ErrorMessage, type FieldNode, MESSAGES, type NormalizerOptions, type Output, type Schema, type SchemaChangeEvent, type SchemaDraft, SchemaRuntime, type SchemaRuntimeOptions, type SchemaType, StringFormatValidator, type StringFormatValidatorInterface, Validator, type ValidatorConfig, type ValidatorOptions, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, validateSchema };
544
+ export { DRAFT_URIS, type ErrorFormatter, type ErrorMessage, type FieldNode, type GetDefaultValueOptions, MESSAGES, type NormalizerOptions, type Output, type Schema, type SchemaChangeEvent, type SchemaDraft, SchemaRuntime, type SchemaRuntimeOptions, type SchemaType, StringFormatValidator, type StringFormatValidatorInterface, Validator, type ValidatorConfig, type ValidatorOptions, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, validateSchema };