--- a/toolkit/components/extensions/Schemas.jsm
+++ b/toolkit/components/extensions/Schemas.jsm
@@ -625,17 +625,25 @@ class ObjectType extends Type {
result[prop] = null;
}
};
let result = {};
for (let prop of Object.keys(this.properties)) {
let error = checkProperty(prop, this.properties[prop], result);
if (error) {
- return error;
+ let {onError} = this.properties[prop];
+ if (onError == "warn") {
+ context.logError(error.error);
+ } else if (onError != "ignore") {
+ return error;
+ }
+
+ result[prop] = null;
+ remainingProps.delete(prop);
}
}
for (let prop of Object.keys(properties)) {
for (let {pattern, type} of this.patternProperties) {
if (pattern.test(prop)) {
let error = checkProperty(prop, type, result);
if (error) {
@@ -1149,19 +1157,20 @@ this.Schemas = {
// The path we pass in here is only used for error messages.
let functions = type.functions.map(fun => this.parseFunction(path.concat(type.id), fun));
return new SubModuleType(functions);
} else if (type.type == "object") {
let parseProperty = (type, extraProps = []) => {
return {
type: this.parseType(path, type,
- ["unsupported", ...extraProps]),
+ ["unsupported", "onError", ...extraProps]),
optional: type.optional || false,
unsupported: type.unsupported || false,
+ onError: type.onError || null,
};
};
let properties = Object.create(null);
for (let propName of Object.keys(type.properties || {})) {
properties[propName] = parseProperty(type.properties[propName], ["optional"]);
}
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_schemas.js
@@ -258,16 +258,46 @@ let json = [
},
},
},
},
],
},
{
+ name: "errors",
+ type: "function",
+ parameters: [
+ {
+ name: "arg",
+ type: "object",
+ properties: {
+ warn: {
+ type: "string",
+ pattern: "^\\d+$",
+ optional: true,
+ onError: "warn",
+ },
+ ignore: {
+ type: "string",
+ pattern: "^\\d+$",
+ optional: true,
+ onError: "ignore",
+ },
+ default: {
+ type: "string",
+ pattern: "^\\d+$",
+ optional: true,
+ },
+ },
+ },
+ ],
+ },
+
+ {
name: "localize",
type: "function",
parameters: [
{
name: "arg",
type: "object",
properties: {
foo: {type: "string", "preprocess": "localize", "optional": true},
@@ -627,16 +657,34 @@ add_task(function* () {
Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {optional: "42"}}]}}),
/Type error for parameter arg \(Error processing foo\.bar\.0\.baz: Property "required" is required\) for testing\.deep/,
"should throw with the correct object path");
Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {required: 12, optional: 42}}]}}),
/Type error for parameter arg \(Error processing foo\.bar\.0\.baz\.optional: Expected string instead of 42\) for testing\.deep/,
"should throw with the correct object path");
+
+ talliedErrors.length = 0;
+
+ root.testing.errors({warn: "0123", ignore: "0123", default: "0123"});
+ verify("call", "testing", "errors", [{warn: "0123", ignore: "0123", default: "0123"}]);
+ checkErrors([]);
+
+ root.testing.errors({warn: "0123", ignore: "x123", default: "0123"});
+ verify("call", "testing", "errors", [{warn: "0123", ignore: null, default: "0123"}]);
+ checkErrors([]);
+
+ root.testing.errors({warn: "x123", ignore: "0123", default: "0123"});
+ verify("call", "testing", "errors", [{warn: null, ignore: "0123", default: "0123"}]);
+ checkErrors([
+ 'String "x123" must match /^\\d+$/',
+ ]);
+
+
root.testing.onFoo.addListener(f);
do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onFoo"]));
do_check_eq(tallied[3][0], f);
do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([]));
tallied = null;
root.testing.onFoo.removeListener(f);
do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["removeListener", "testing", "onFoo"]));