Skip to content

Commit 94348fc

Browse files
committed
Add the validate function
1 parent fe1ff62 commit 94348fc

4 files changed

Lines changed: 96 additions & 3 deletions

File tree

src/index.d.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,39 @@ export type ContainsRange = {
157157
minContains?: number;
158158
maxContains?: number;
159159
};
160+
161+
/**
162+
* Validate an instance against a schema and get error messages in one step instead
163+
* of getting output from validation and passing it to jsonSchemaErrors. The
164+
* function is curried so you can compile the schema one time and evaluate multiple
165+
* instances against the same compiled schema.
166+
*
167+
* Ideally, this function should be in @hyperjump/json-schema instead and this will
168+
* be removed in the future.
169+
*
170+
* @deprecated
171+
*/
172+
export const validate: (
173+
(schemaUri: string) => Promise<EvaluateInstance>
174+
) & (
175+
(schemaUri: string, instance: Json, options?: ValidationOptions) => Promise<ValidationResult>
176+
);
177+
178+
export type EvaluateInstance = (instance: Json, options?: ValidationOptions) => Promise<ValidationResult>;
179+
180+
export type ValidationOptions = {
181+
/**
182+
* A locale identifier in the form of "{language}-{region}".
183+
*
184+
* @example "en-US"
185+
*/
186+
locale?: string;
187+
plugins?: EvaluationPlugin[];
188+
};
189+
190+
export type ValidationResult = {
191+
valid: true;
192+
} | {
193+
valid: false;
194+
errors: JsonSchemaErrors;
195+
};

src/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,5 +173,6 @@ export {
173173
evaluateSchema,
174174
getErrors,
175175
jsonSchemaErrors,
176-
setNormalizationHandler
176+
setNormalizationHandler,
177+
validate
177178
} from "./json-schema-errors.js";

src/json-schema-errors.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { compile, getKeyword, getSchema } from "@hyperjump/json-schema/experimental";
1+
import { compile, getKeyword, getSchema, Validation } from "@hyperjump/json-schema/experimental";
22
import * as Instance from "@hyperjump/json-schema/instance/experimental";
33
import * as Schema from "@hyperjump/browser";
44
import { pointerSegments } from "@hyperjump/json-pointer";
55
import { toAbsoluteIri } from "@hyperjump/uri";
66
import { Localization } from "./localization.js";
7+
import { JsonSchemaErrorsOutputPlugin } from "./output-plugin.js";
78

89
/**
910
* @import * as API from "./index.d.ts"
1011
* @import { Browser } from "@hyperjump/browser";
11-
* @import { SchemaDocument } from "@hyperjump/json-schema/experimental";
12+
* @import { SchemaDocument, CompiledSchema } from "@hyperjump/json-schema/experimental";
1213
* @import { JsonNode } from "@hyperjump/json-schema/instance/experimental"
1314
*/
1415

@@ -194,3 +195,53 @@ export const getErrors = async (normalizedErrors, rootInstance, localization) =>
194195

195196
return errors;
196197
};
198+
199+
/**
200+
* @overload
201+
* @param {string} schemaUri
202+
* @returns {Promise<API.EvaluateInstance>}
203+
*
204+
* @overload
205+
* @param {string} schemaUri
206+
* @param {API.Json} instance
207+
* @param {API.JsonSchemaErrorsOptions} [options]
208+
* @returns {Promise<API.ValidationResult>}
209+
*
210+
* @param {string} schemaUri
211+
* @param {API.Json} instance
212+
* @param {API.JsonSchemaErrorsOptions} [options]
213+
*/
214+
export const validate = async (schemaUri, instance, options) => {
215+
const schema = await getSchema(schemaUri);
216+
const compiledSchema = await compile(schema);
217+
218+
if (instance === undefined) {
219+
/** @type API.EvaluateInstance */
220+
return (instance, options) => {
221+
return evaluateCompiledSchema(compiledSchema, instance, options);
222+
};
223+
} else {
224+
return evaluateCompiledSchema(compiledSchema, instance, options);
225+
}
226+
};
227+
228+
/** @type (compiledSchema: CompiledSchema, instance: API.Json, options?: API.ValidationOptions) => Promise<API.ValidationResult> */
229+
const evaluateCompiledSchema = async (compiledSchema, instance, options = {}) => {
230+
const localization = await Localization.forLocale(options.locale ?? "en-US");
231+
const jsonNode = Instance.fromJs(instance);
232+
const outputPlugin = new JsonSchemaErrorsOutputPlugin();
233+
const context = {
234+
ast: compiledSchema.ast,
235+
plugins: [...compiledSchema.ast.plugins, outputPlugin, ...options.plugins ?? []]
236+
};
237+
const valid = Validation.interpret(compiledSchema.schemaUri, jsonNode, context);
238+
239+
if (valid) {
240+
return { valid };
241+
} else {
242+
return {
243+
valid,
244+
errors: await getErrors(outputPlugin.output, jsonNode, localization)
245+
};
246+
}
247+
};

src/output-plugin.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import * as Instance from "@hyperjump/json-schema/instance/experimental";
1414

1515
/** @implements EvaluationPlugin<ErrorsContext> */
1616
export class JsonSchemaErrorsOutputPlugin {
17+
constructor() {
18+
/** @type NormalizedOutput */
19+
this.output = {};
20+
}
21+
1722
/** @type NonNullable<EvaluationPlugin<ErrorsContext>["beforeSchema"]> */
1823
beforeSchema(_url, _instance, context) {
1924
context.output = {};

0 commit comments

Comments
 (0)