Bug 1254194: [webext] Add 'onError' schema option to make manifest errors non-fatal. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 14 Apr 2016 16:39:09 -0700
changeset 351734 960591b1f9722404d7a278fba090f1d6afb8c387
parent 351733 c737f5009c93f2fc32aaae999142e5e10c1ff496
child 351735 c838bf5eabe23b0f929f8e9ff58361afe5374bae
push id15524
push usermaglione.k@gmail.com
push dateFri, 15 Apr 2016 01:09:46 +0000
reviewersaswan
bugs1254194
milestone48.0a1
Bug 1254194: [webext] Add 'onError' schema option to make manifest errors non-fatal. r?aswan MozReview-Commit-ID: ByGsO4WFcOU
toolkit/components/extensions/Schemas.jsm
toolkit/components/extensions/test/xpcshell/test_ext_schemas.js
--- 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"]));