Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / toolkit / modules / JsonSchema.sys.mjs
blob62b063ec8affa7bbbc98f34a3196ffb462bcce0c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
6  * A facade around @cfworker/json-schema that provides additional formats and
7  * convenience methods whil executing inside a sandbox.
8  */
10 const sandbox = new Cu.Sandbox(null, {
11   wantComponents: false,
12   wantGlobalProperties: ["URL"],
13 });
15 Services.scriptloader.loadSubScript(
16   "chrome://global/content/third_party/cfworker/json-schema.js",
17   sandbox
20 /**
21  * A JSON Schema string format for URLs intended to go through Services.urlFormatter.
22  */
23 Cu.exportFunction(
24   function validateMozUrlFormat(input) {
25     try {
26       const formatted = Services.urlFormatter.formatURL(input);
27       return Cu.waiveXrays(sandbox.fastFormat).uri(formatted);
28     } catch {
29       return false;
30     }
31   },
32   sandbox.fastFormat,
33   { defineAs: "moz-url-format" }
36 // initialBaseURI defaults to github.com/cfworker, which will be confusing.
37 Cu.evalInSandbox(
38   `this.initialBaseURI = initialBaseURI = new URL("http://mozilla.org");`,
39   sandbox
42 /**
43  * A JSONSchema validator that performs validation inside a sandbox.
44  */
45 class Validator {
46   #inner;
47   #draft;
49   /**
50    * Create a new validator.
51    *
52    * @param {object} schema The schema to validate with.
53    * @param {object} options  Options for the validator.
54    * @param {string} options.draft  The draft to validate against. Should be one
55    *                                of "4", "6", "7", "2019-09", or "2020-12".
56    *
57    *                                If the |$schema| key is present in the
58    *                                |schema|, it will be used to auto-detect the
59    *                                correct version.  Otherwise, 2019-09 will be
60    *                                used.
61    * @param {boolean} options.shortCircuit  Whether or not the validator should
62    *                                        return after a single error occurs.
63    */
64   constructor(
65     schema,
66     { draft = detectSchemaDraft(schema), shortCircuit = true } = {}
67   ) {
68     this.#draft = draft;
69     this.#inner = Cu.waiveXrays(
70       new sandbox.Validator(Cu.cloneInto(schema, sandbox), draft, shortCircuit)
71     );
72   }
74   /**
75    * Validate the instance against the known schemas.
76    *
77    * @param {object} instance  The instance to validate.
78    *
79    * @return {object}  An object with |valid| and |errors| keys that indicates
80    *                   the success of validation.
81    */
82   validate(instance) {
83     return this.#inner.validate(Cu.cloneInto(instance, sandbox));
84   }
86   /**
87    * Add a schema to the validator.
88    *
89    * @param {object} schema  A JSON schema object.
90    * @param {string} id  An optional ID to identify the schema if it does not
91    *                     provide an |$id| field.
92    */
93   addSchema(schema, id) {
94     const draft = detectSchemaDraft(schema, undefined);
95     if (draft && this.#draft != draft) {
96       console.error(
97         `Adding a draft "${draft}" schema to a draft "${
98           this.#draft
99         }" validator.`
100       );
101     }
102     this.#inner.addSchema(Cu.cloneInto(schema, sandbox), id);
103   }
107  * A wrapper around validate that provides some options as an object
108  * instead of positional arguments.
110  * @param {object} instance  The instance to validate.
111  * @param {object} schema  The JSON schema to validate against.
112  * @param {object} options  Options for the validator.
113  * @param {string} options.draft  The draft to validate against. Should
114  *                                be one of "4", "6", "7", "2019-09", or "2020-12".
116  *                               If the |$schema| key is present in the |schema|, it
117  *                               will be used to auto-detect the correct version.
118  *                               Otherwise, 2019-09 will be used.
119  * @param {boolean} options.shortCircuit  Whether or not the validator should
120  *                                        return after a single error occurs.
122  * @returns {object} An object with |valid| and |errors| keys that indicates the
123  *                   success of validation.
124  */
125 function validate(
126   instance,
127   schema,
128   { draft = detectSchemaDraft(schema), shortCircuit = true } = {}
129 ) {
130   const clonedSchema = Cu.cloneInto(schema, sandbox);
132   return sandbox.validate(
133     Cu.cloneInto(instance, sandbox),
134     clonedSchema,
135     draft,
136     sandbox.dereference(clonedSchema),
137     shortCircuit
138   );
141 function detectSchemaDraft(schema, defaultDraft = "2019-09") {
142   const { $schema } = schema;
144   if (typeof $schema === "undefined") {
145     return defaultDraft;
146   }
148   switch ($schema) {
149     case "http://json-schema.org/draft-04/schema#":
150       return "4";
152     case "http://json-schema.org/draft-06/schema#":
153       return "6";
155     case "http://json-schema.org/draft-07/schema#":
156       return "7";
158     case "https://json-schema.org/draft/2019-09/schema":
159       return "2019-09";
161     case "https://json-schema.org/draft/2020-12/schema":
162       return "2020-12";
164     default:
165       console.error(
166         `Unexpected $schema "${$schema}", defaulting to ${defaultDraft}.`
167       );
168       return defaultDraft;
169   }
172 export const JsonSchema = {
173   Validator,
174   validate,
175   detectSchemaDraft,