🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@sjsf-lab/hyperjump-validator

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sjsf-lab/hyperjump-validator - npm Package Compare versions

Comparing version
3.0.0
to
3.1.0
+1
-1
dist/errors.d.ts

@@ -0,4 +1,4 @@

import type * as H from "@hyperjump/json-schema-errors";
import type { FormValue, ValidationResult } from "@sjsf/form";
import type * as H from "@hyperjump/json-schema-errors";
export declare function transformFormErrors<T>(out: H.ValidationResult, data: FormValue): ValidationResult<T>;
export declare function transformFieldErrors(out: H.ValidationResult): string[];

@@ -0,24 +1,31 @@

import type { Json as HyperjumpJson, ValidationOptions } from "@hyperjump/json-schema-errors";
import { type AST, type CompiledSchema } from "@hyperjump/json-schema/experimental";
import type { FormValue, Schema, SchemaValue } from "@sjsf/form";
import { type AST } from "@hyperjump/json-schema/experimental";
import { type JsonNode } from "@hyperjump/json-schema/instance/experimental";
import { type Localization } from "@hyperjump/json-schema-errors";
export interface ValidatorOptions {
import { type ValidatorRetrieverOptions } from "@sjsf/form/validators/precompile";
interface LegacyValidatorOptions {
/** @deprecated use `validatorRetriever` instead */
ast: AST;
localization: Localization;
/** @deprecated use `validatorRetriever` instead */
augmentSuffix?: string;
valueToJSON?: (value: FormValue) => SchemaValue;
validatorRetriever?: (schema: Schema) => CompiledSchema;
}
interface ModernValidatorOptions {
validatorRetriever: (schema: Schema) => CompiledSchema;
}
export type CoreValidatorOptions = (LegacyValidatorOptions | ModernValidatorOptions) & Partial<ValidationOptions>;
export declare function createRetriever(options: CoreValidatorOptions): (schema: Schema) => CompiledSchema;
export interface ValueToJSON {
valueToJSON: (value: FormValue) => SchemaValue;
}
export type ValidatorOptions = CoreValidatorOptions & ValueToJSON;
export declare function fromAst(ast: AST, options?: Partial<Omit<ValidatorRetrieverOptions<any>, "registry">>): ({ $id: id, allOf }: Schema) => {
schemaUri: string;
ast: AST;
};
export interface Context {
ast: AST;
schemaUri: string;
value: JsonNode;
compiledSchema: CompiledSchema;
value: HyperjumpJson;
}
export declare function createContext({ ast, augmentSuffix, valueToJSON, }: ValidatorOptions, { $id: id, allOf }: Schema, value: FormValue): Context;
export declare function validate(ctx: Context): boolean;
export declare function evaluateCompiledSchema(ctx: Context, localization: Localization): {
valid: true;
errors?: undefined;
} | {
valid: false;
errors: import("@hyperjump/json-schema-errors").ErrorObject[];
};
export declare function createContext(options: ValidatorOptions, schema: Schema, value: FormValue): Context;
export declare function validate({ compiledSchema, value }: Context): boolean;
export {};

@@ -1,47 +0,56 @@

import { DEFAULT_AUGMENT_SUFFIX } from "@sjsf/form/validators/precompile";
import { Validation } from "@hyperjump/json-schema/experimental";
import { fromJs, } from "@hyperjump/json-schema/instance/experimental";
import { getErrors, } from "@hyperjump/json-schema-errors";
import { JsonSchemaErrorsOutputPlugin } from "./output-plugin.js";
const defaultValueToJson = (v) => v === undefined || v === null
? null
: typeof v === "object"
? JSON.parse(JSON.stringify(v))
: v;
export function createContext({ ast, augmentSuffix = DEFAULT_AUGMENT_SUFFIX, valueToJSON = defaultValueToJson, }, { $id: id, allOf }, value) {
if (id === undefined) {
const firstAllOfItem = allOf?.[0];
if (typeof firstAllOfItem === "object" &&
firstAllOfItem.$id !== undefined) {
id = firstAllOfItem.$id + augmentSuffix;
}
else {
throw new Error("Schema id not found");
}
}
import { Validation, } from "@hyperjump/json-schema/experimental";
import { fromJs } from "@hyperjump/json-schema/instance/experimental";
import { createValidatorRetriever, } from "@sjsf/form/validators/precompile";
// TODO: Remove in v4
export function createRetriever(options) {
return "ast" in options
? (options.validatorRetriever ??
createValidatorRetriever({
registry: {
get: (id) => {
const schemaUri = `${id}#`;
return schemaUri in options.ast
? {
schemaUri,
ast: options.ast,
}
: undefined;
},
},
idAugmentations: options.augmentSuffix
? {
combination: (id) => id + options.augmentSuffix,
}
: undefined,
}))
: options.validatorRetriever;
}
export function fromAst(ast, options) {
return createValidatorRetriever({
registry: {
get(id) {
const schemaUri = `${id}#`;
return schemaUri in ast
? {
schemaUri,
ast,
}
: undefined;
},
},
...options,
});
}
export function createContext(options, schema, value) {
const getCompiledSchema = createRetriever(options);
return {
ast,
schemaUri: `${id}#`,
value: fromJs(valueToJSON(value)),
compiledSchema: getCompiledSchema(schema),
value: options.valueToJSON(value),
};
}
export function validate(ctx) {
return Validation.interpret(ctx.schemaUri, ctx.value, {
ast: ctx.ast,
plugins: [...ctx.ast.plugins],
export function validate({ compiledSchema, value }) {
return Validation.interpret(compiledSchema.schemaUri, fromJs(value), {
ast: compiledSchema.ast,
plugins: [...compiledSchema.ast.plugins],
});
}
export function evaluateCompiledSchema(ctx, localization) {
const outputPlugin = new JsonSchemaErrorsOutputPlugin();
const context = {
ast: ctx.ast,
plugins: [...ctx.ast.plugins, outputPlugin],
};
const valid = Validation.interpret(ctx.schemaUri, ctx.value, context);
return valid
? { valid }
: {
valid,
errors: getErrors(outputPlugin.output, ctx.value, localization, ctx.ast),
};
}

@@ -1,2 +0,2 @@

export { type ValidatorOptions } from "./model.js";
export { type ValidatorOptions, fromAst } from "./model.js";
export * from "./validator.js";

@@ -1,2 +0,2 @@

export {} from "./model.js";
export { fromAst } from "./model.js";
export * from "./validator.js";
import type { FieldValueValidator, FormValueValidator, Validator } from "@sjsf/form";
import { type ValidatorOptions } from "./model.js";
import { type CoreValidatorOptions, type ValidatorOptions, type ValueToJSON } from "./model.js";
export declare function createValidator(options: ValidatorOptions): Validator;
export interface FormValueValidatorOptions extends ValidatorOptions {
}
export type FormValueValidatorOptions = ValidatorOptions;
export declare function createFormValueValidator<T>(options: FormValueValidatorOptions): FormValueValidator<T>;
export declare function createFieldValueValidator(options: FormValidatorOptions): FieldValueValidator;
export interface FormValidatorOptions extends FormValueValidatorOptions {
}
export declare function createFormValidatorFactory<T>(vOptions: ValidatorOptions): (options: Omit<FormValidatorOptions, keyof ValidatorOptions>) => Validator & FormValueValidator<T> & FieldValueValidator;
export type FieldValueValidatorOptions = ValidatorOptions;
export declare function createFieldValueValidator(options: FieldValueValidatorOptions): FieldValueValidator;
export type FormValidatorOptions = ValidatorOptions & FormValueValidatorOptions & FieldValueValidatorOptions;
export declare function createFormValidatorFactory<T>(vOptions: CoreValidatorOptions & Partial<ValueToJSON>): (options: Omit<FormValidatorOptions, keyof ValidatorOptions>) => Validator & FormValueValidator<T> & FieldValueValidator;

@@ -0,3 +1,4 @@

import { evaluateCompiledSchema } from "@hyperjump/json-schema-errors";
import { transformFormErrors, transformFieldErrors } from "./errors.js";
import { createContext, evaluateCompiledSchema, validate, } from "./model.js";
import { createContext, createRetriever, validate, } from "./model.js";
export function createValidator(options) {

@@ -17,4 +18,4 @@ return {

validateFormValue(rootSchema, formValue) {
const ctx = createContext(options, rootSchema, formValue);
const out = evaluateCompiledSchema(ctx, options.localization);
const { compiledSchema, value } = createContext(options, rootSchema, formValue);
const out = evaluateCompiledSchema(compiledSchema, value, options);
return transformFormErrors(out, formValue);

@@ -27,4 +28,4 @@ },

validateFieldValue(field, fieldValue) {
const ctx = createContext(options, field.schema, fieldValue);
const out = evaluateCompiledSchema(ctx, options.localization);
const { compiledSchema, value } = createContext(options, field.schema, fieldValue);
const out = evaluateCompiledSchema(compiledSchema, value, options);
return transformFieldErrors(out);

@@ -37,4 +38,11 @@ },

const full = {
...options,
...vOptions,
...options,
validatorRetriever: vOptions.validatorRetriever ?? createRetriever(vOptions),
valueToJSON: vOptions.valueToJSON ??
((v) => v === undefined || v === null
? null
: typeof v === "object"
? JSON.parse(JSON.stringify(v))
: v),
};

@@ -41,0 +49,0 @@ return Object.assign(createValidator(full), createFormValueValidator(full), createFieldValueValidator(full));

{
"name": "@sjsf-lab/hyperjump-validator",
"version": "3.0.0",
"version": "3.1.0",
"description": "The @hyperjump/json-schema based validator for svelte-jsonschema-form",
"license": "MIT",
"keywords": [
"validator",
"hyperjump",
"jsonschema",
"hyperjump"
"validator"
],
"type": "module",
"homepage": "https://x0k.github.io/svelte-jsonschema-form/",
"bugs": "https://github.com/x0k/svelte-jsonschema-form/issues",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/x0k/svelte-jsonschema-form.git",
"directory": "lab/hyperjump-validator"
},
"files": [

@@ -17,14 +23,5 @@ "dist",

],
"publishConfig": {
"provenance": true
},
"repository": {
"type": "git",
"url": "git+https://github.com/x0k/svelte-jsonschema-form.git",
"directory": "lab/hyperjump-validator"
},
"bugs": "https://github.com/x0k/svelte-jsonschema-form/issues",
"homepage": "https://x0k.github.io/svelte-jsonschema-form/",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"main": "dist/index.js",
"exports": {

@@ -41,22 +38,19 @@ "./package.json": "./package.json",

"default": "./dist/precompile.js"
},
"./localizations/*": {
"types": "./dist/localizations/*.d.ts",
"default": "./dist/localizations/*.js"
}
},
"peerDependencies": {
"@fluent/bundle": "^0.19.0",
"@hyperjump/json-schema": "^1.17.0",
"@sjsf/form": "^3.5.0"
"publishConfig": {
"provenance": true
},
"dependencies": {
"@hyperjump/json-schema-errors": "github:hyperjump-io/json-schema-errors#21ec0ab303b986e052e5ff255bf41d01c54e886b"
},
"devDependencies": {
"@fluent/bundle": "^0.19.1",
"@hyperjump/json-schema": "^1.17.6",
"svelte": "^5.55.5",
"@sjsf/form": "3.6.0",
"validator-testing": "1.0.27"
"svelte": "^5.56.4",
"validator-testing": "1.0.28",
"@sjsf/form": "3.7.0"
},
"dependencies": {
"@hyperjump/json-schema-errors": "github:hyperjump-io/json-schema-errors#8bda546feeca780ae02c1ebd7247291424ea4a98"
"peerDependencies": {
"@hyperjump/json-schema": "^1.17.0",
"@sjsf/form": "^3.5.0"
},

@@ -66,4 +60,6 @@ "scripts": {

"build": "tsc && publint",
"dev": "tsc --watch"
"dev": "tsc --watch",
"format": "oxfmt .",
"format:check": "oxfmt --check ."
}
}

@@ -17,8 +17,12 @@ # @sjsf-lab/hyperjump-validator

```typescript
import { createFormValidatorFactory } from "@sjsf-lab/hyperjump-validator";
import { localization } from "@sjsf-lab/hyperjump-validator/localizations/en-us";
import {
createFormValidatorFactory,
fromAst,
} from "@sjsf-lab/hyperjump-validator/precompile";
import { ast } from "./ast";
const factory = createFormValidatorFactory({ ast, localization });
const factory = createFormValidatorFactory({
validatorRetriever: fromAst(ast),
});
```

@@ -25,0 +29,0 @@

import type { FluentBundle } from "@fluent/bundle";
import type { Json as HyperjumpJson, ContainsRange } from "@hyperjump/json-schema-errors";
export declare class Localization {
#private;
private readonly bundle;
private disjunction;
private conjunction;
constructor(bundle: FluentBundle);
getBooleanSchemaErrorMessage(): string;
getTypeErrorMessage(expectedTypes: string[]): string;
getEnumErrorMessage(expected: HyperjumpJson[]): string;
getFormatErrorMessage(format: string): string;
getExclusiveMaximumErrorMessage(exclusiveMaximum: number): string;
getMaximumErrorMessage(maximum: number): string;
getExclusiveMinimumErrorMessage(exclusiveMinimum: number): string;
getMinimumErrorMessage(minimum: number): string;
getMultipleOfErrorMessage(multipleOf: number): string;
getMaxLengthErrorMessage(maxLength: number): string;
getMinLengthErrorMessage(minLength: number): string;
getPatternErrorMessage(pattern: number): string;
getMaxItemsErrorMessage(maxItems: number): string;
getMinItemsErrorMessage(minItems: number): string;
getContainsErrorMessage(range: ContainsRange): string;
getUniqueItemsErrorMessage(): string;
getMaxPropertiesErrorMessage(maxProperties: number): string;
getMinPropertiesErrorMessage(minProperties: number): string;
getRequiredErrorMessage(required: string[]): string;
getAnyOfErrorMessage(): string;
getOneOfErrorMessage(matchCount: number): string;
getNotErrorMessage(): string;
getUnknownErrorMessage(keyword: string): string;
}
// This file is derived from:
// https://github.com/hyperjump-io/json-schema-errors/blob/8bda546feeca780ae02c1ebd7247291424ea4a98/src/localization.js
// Copyright (c) 2026 Hyperjump Software, LLC
// Licensed under the MIT License
// Modifications made by Roman Krasilnikov.
export class Localization {
bundle;
disjunction;
conjunction;
constructor(bundle) {
this.bundle = bundle;
const locale = bundle.locales[0];
this.disjunction = new Intl.ListFormat(locale, { type: "disjunction" });
this.conjunction = new Intl.ListFormat(locale, { type: "conjunction" });
}
#formatMessage(messageId, args) {
const message = this.bundle.getMessage(messageId);
if (!message?.value) {
throw Error(`Message '${messageId}' not found.`);
}
return this.bundle.formatPattern(message.value, args);
}
getBooleanSchemaErrorMessage() {
return this.#formatMessage("boolean-schema-message", {});
}
getTypeErrorMessage(expectedTypes) {
return this.#formatMessage("type-message", {
expectedTypes: this.disjunction.format(expectedTypes),
});
}
getEnumErrorMessage(expected) {
if (expected.length === 1) {
return this.#formatMessage("const-message", {
expected: JSON.stringify(expected[0], null, " "),
});
}
else {
const expectedJson = expected.map((value) => JSON.stringify(value));
return this.#formatMessage("enum-message", {
expected: this.disjunction.format(expectedJson),
});
}
}
getFormatErrorMessage(format) {
return this.#formatMessage("format-message", { format });
}
getExclusiveMaximumErrorMessage(exclusiveMaximum) {
return this.#formatMessage("exclusiveMaximum-message", {
exclusiveMaximum,
});
}
getMaximumErrorMessage(maximum) {
return this.#formatMessage("maximum-message", { maximum });
}
getExclusiveMinimumErrorMessage(exclusiveMinimum) {
return this.#formatMessage("exclusiveMinimum-message", {
exclusiveMinimum,
});
}
getMinimumErrorMessage(minimum) {
return this.#formatMessage("minimum-message", { minimum });
}
getMultipleOfErrorMessage(multipleOf) {
return this.#formatMessage("multipleOf-message", { multipleOf });
}
getMaxLengthErrorMessage(maxLength) {
return this.#formatMessage("maxLength-message", { maxLength });
}
getMinLengthErrorMessage(minLength) {
return this.#formatMessage("minLength-message", { minLength });
}
getPatternErrorMessage(pattern) {
return this.#formatMessage("pattern-message", { pattern });
}
getMaxItemsErrorMessage(maxItems) {
return this.#formatMessage("maxItems-message", { maxItems });
}
getMinItemsErrorMessage(minItems) {
return this.#formatMessage("minItems-message", { minItems });
}
getContainsErrorMessage(range) {
range.minContains ??= 1;
if (range.minContains === range.maxContains) {
return this.#formatMessage("contains-exact-message", range);
}
else if (range.maxContains) {
return this.#formatMessage("contains-range-message", range);
}
else {
return this.#formatMessage("contains-message", range);
}
}
getUniqueItemsErrorMessage() {
return this.#formatMessage("uniqueItems-message", {});
}
getMaxPropertiesErrorMessage(maxProperties) {
return this.#formatMessage("maxProperties-message", { maxProperties });
}
getMinPropertiesErrorMessage(minProperties) {
return this.#formatMessage("minProperties-message", { minProperties });
}
getRequiredErrorMessage(required) {
return this.#formatMessage("required-message", {
required: this.conjunction.format(required),
count: required.length,
});
}
getAnyOfErrorMessage() {
return this.#formatMessage("anyOf-message", {});
}
getOneOfErrorMessage(matchCount) {
return this.#formatMessage("oneOf-message", { matchCount });
}
getNotErrorMessage() {
return this.#formatMessage("not-message", {});
}
getUnknownErrorMessage(keyword) {
return this.#formatMessage("unknown-message", { keyword });
}
}
import { Localization } from "../localization.js";
export declare const localization: Localization;
// This file is derived from:
// https://github.com/hyperjump-io/json-schema-errors/blob/8bda546feeca780ae02c1ebd7247291424ea4a98/src/translations/en-US.ftl
// Copyright (c) 2026 Hyperjump Software, LLC
// Licensed under the MIT License
// Modifications made by Roman Krasilnikov.
import { FluentBundle, FluentResource } from "@fluent/bundle";
import { Localization } from "../localization.js";
const source = `// Any type keywords
boolean-schema-message = A value is not allowed here
type-message = Expected a {$expectedTypes}
const-message = Expected exactly {$expected}
enum-message = Expected one of {$expected}
format-message = Expected a value matching the '{$format}' format
unknown-message = Validation failed for '{$keyword}'
// Number keywords
exclusiveMaximum-message = Expected a number less than {$exclusiveMaximum}
exclusiveMinimum-message = Expected a number greater than {$exclusiveMinimum}
maximum-message = Expected a number less than or equal to {$maximum}
minimum-message = Expected a number greater than or equal to {$minimum}
multipleOf-message = Expected a number that is a multiple of {$multipleOf}
// String keywords
maxLength-message = Expected a string with no more than {$maxLength} characters
minLength-message = Expected a string with at least {$minLength} characters
pattern-message = Expected a string matching the regular expression /{$pattern}/
// Array keywords
maxItems-message = Expected an array with no more than {$maxItems} items
minItems-message = Expected an array with at least {$minItems} items
contains-message = Expected an array that contains {$minContains ->
[1] at least one item matching
*[other] at least {$minContains} items matching
} the 'contains' schema
contains-range-message = Expected an array containing between {$minContains} and {$maxContains} items matching the 'contains' schema
contains-exact-message = Expected an array containing {$minContains ->
[1] exactly one item matching
*[other] exactly {$minContains} items matching
} the 'contains' schema
uniqueItems-message = Array items must be unique
// Object keywords
maxProperties-message = Expected an object with no more than {$maxProperties} properties
minProperties-message = Expected an object with at least {$minProperties} properties
required-message = Missing required {$count ->
[one] property: {$required}
*[other] properties: {$required}
}
// Applicators
anyOf-message = Expected the value to match at least one alternative
oneOf-message = Expected the value to match exactly one alternative, {$matchCount ->
[0] but none
*[other] but more than one
} matched
not-message = Expected a value that doesn't match the 'not' schema
`;
const resource = new FluentResource(source);
const bundle = new FluentBundle("en-US");
bundle.addResource(resource);
export const localization = new Localization(bundle);
import type { NormalizedOutput } from "@hyperjump/json-schema-errors";
import type { EvaluationPlugin, Keyword, Node, ValidationContext } from "@hyperjump/json-schema/experimental";
import * as Instance from "@hyperjump/json-schema/instance/experimental";
type ErrorsContext = ValidationContext & {
output: NormalizedOutput;
subSchemaOutput?: NormalizedOutput[];
};
export declare class JsonSchemaErrorsOutputPlugin implements EvaluationPlugin<ErrorsContext> {
output: NormalizedOutput;
constructor();
beforeSchema(_url: string, _instance: Instance.JsonNode, context: ErrorsContext): void;
beforeKeyword(_keywordNode: Node<unknown>, _instance: Instance.JsonNode, context: ErrorsContext, schemaContext: ErrorsContext, _keyword: Keyword<unknown>): void;
afterKeyword(keywordNode: Node<unknown>, instance: Instance.JsonNode, context: ErrorsContext, valid: boolean, schemaContext: ErrorsContext, keyword: Keyword<unknown>): void;
afterSchema(url: string, instance: Instance.JsonNode, context: ErrorsContext, valid: boolean): void;
}
export {};
// This file is derived from:
// https://github.com/hyperjump-io/json-schema-errors/blob/8bda546feeca780ae02c1ebd7247291424ea4a98/src/output-plugin.js
// Copyright (c) 2026 Hyperjump Software, LLC
// Licensed under the MIT License
// Modifications made by Roman Krasilnikov.
import * as Instance from "@hyperjump/json-schema/instance/experimental";
export class JsonSchemaErrorsOutputPlugin {
output;
constructor() {
this.output = {};
}
beforeSchema(_url, _instance, context) {
context.output = {};
}
beforeKeyword(_keywordNode, _instance, context, schemaContext, _keyword) {
context.output = schemaContext.output;
}
afterKeyword(keywordNode, instance, context, valid, schemaContext, keyword) {
const [keywordUri, schemaLocation] = keywordNode;
if (keyword.simpleApplicator) {
for (const subSchemaOutput of context.subSchemaOutput ?? []) {
mergeOutput(schemaContext.output, subSchemaOutput);
}
}
else {
schemaContext.output[Instance.uri(instance)] ??= {};
schemaContext.output[Instance.uri(instance)][keywordUri] ??= {};
schemaContext.output[Instance.uri(instance)][keywordUri][schemaLocation] = valid || (context.subSchemaOutput ?? valid);
}
}
afterSchema(url, instance, context, valid) {
if (typeof context.ast[url] === "boolean" && !valid) {
context.output[Instance.uri(instance)] ??= {};
context.output[Instance.uri(instance)]["https://json-schema.org/validation"] ??= {};
context.output[Instance.uri(instance)]["https://json-schema.org/validation"][url] = valid;
}
context.subSchemaOutput ??= [];
context.subSchemaOutput.push(context.output);
this.output = context.output;
}
}
const mergeOutput = (a, b) => {
for (const instanceLocation in b) {
a[instanceLocation] ??= {};
for (const keywordUri in b[instanceLocation]) {
a[instanceLocation][keywordUri] ??= {};
Object.assign(a[instanceLocation][keywordUri], b[instanceLocation][keywordUri]);
}
}
};