Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Unified Diff: chrome/renderer/resources/extensions/schema_generated_bindings.js

Issue 9317072: Allow omitting optional parameters for Extensions API functions (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Better error message distinguishing signature errors and type validation errors. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/resources/extensions/schema_generated_bindings.js
diff --git a/chrome/renderer/resources/extensions/schema_generated_bindings.js b/chrome/renderer/resources/extensions/schema_generated_bindings.js
index df126906ea7050abd57103c9fb40392d055c07ae..d613d616f17c17da67a5c7f144e1aa6251881ebb 100644
--- a/chrome/renderer/resources/extensions/schema_generated_bindings.js
+++ b/chrome/renderer/resources/extensions/schema_generated_bindings.js
@@ -31,6 +31,105 @@ var chrome = chrome || {};
}
}
+ // Returns a list of types that this schema allows.
+ chromeHidden.getAllTypesForSchema = function(schema) {
+ var validator = new chromeHidden.JSONSchemaValidator();
+ validator.addTypes(chromeHidden.validationTypes);
+ var schema_types = [];
+ if (schema.type)
+ schema_types.push(schema.type);
+ if (schema.choices) {
+ for (var i = 0; i < schema.choices.length; i++)
+ schema_types.push(schema.choices[i].type);
+ }
+ if (schema['$ref'])
+ schema_types.push(validator.types[schema['$ref']].type);
+ return schema_types;
+ };
+
+ // Returns true if |schema| would accept an argument of type |type|.
+ chromeHidden.isValidSchemaType = function(type, schema) {
+ schema_types = chromeHidden.getAllTypesForSchema(schema);
+ for (var i = 0; i < schema_types.length; i++) {
+ if (schema_types[i] == "any" || type == schema_types[i])
+ return true;
+ }
+ return type == "any";
+ };
+
+ // Returns true if there is a non-null value that both schemas would accept.
+ chromeHidden.checkSchemaOverlap = function(schema1, schema2) {
+ schema_types1 = chromeHidden.getAllTypesForSchema(schema1);
+ for (var i = 0; i < schema_types1.length; i++) {
+ if (chromeHidden.isValidSchemaType(schema_types1[i], schema2))
+ return true;
+ }
+ return false;
+ };
+
+ // Generate all possible signatures for a given API function scehma.
Matt Perry 2012/02/16 00:31:08 schema*
Matt Tytel 2012/02/24 01:29:27 Done.
+ chromeHidden.getSignatures = function(schemas) {
+ if (schemas.length === 0)
+ return [[]];
+
+ var signatures = [];
+ var remaining = chromeHidden.getSignatures(schemas.slice(1));
+ for (var i = 0; i < remaining.length; i++) {
+ var signature = remaining[i].slice(0);
+ signature.unshift(schemas[0]);
+ signatures.push(signature);
Matt Perry 2012/02/16 00:31:08 could do this more simply as signatures.push([sche
Matt Tytel 2012/02/24 01:29:27 Done.
+ }
+ if (schemas[0].optional)
+ return signatures.concat(remaining);
+ return signatures;
+ };
+
+ // Return true if arguments match a given signature's schema.
+ chromeHidden.argumentsMatchSignature = function(args, schemas) {
+ if (args.length != schemas.length)
+ return false;
+
+ for (var i = 0; i < schemas.length; i++) {
+ if (!chromeHidden.isValidSchemaType(
+ chromeHidden.JSONSchemaValidator.getType(args[i]), schemas[i]))
+ return false;
+ }
+ return true;
+ };
+
+ // Finds the function signature for the given arguments.
+ chromeHidden.matchSignature = function(args, schemas) {
Matt Perry 2012/02/16 00:31:08 The implementation here is somewhat wasteful. You
Matt Tytel 2012/02/16 04:35:02 I think this a code efficiency vs code simplicity
Matt Perry 2012/02/16 19:21:29 Yep. I think you made the right tradeoff here.
+ var signatures = chromeHidden.getSignatures(schemas);
+ for (var i = 0; i < signatures.length; i++) {
+ if (chromeHidden.argumentsMatchSignature(args, signatures[i]))
+ return signatures[i];
+ }
+ return null;
+ };
+
+ // Validates that a given schema for an API function is not ambiguous.
+ chromeHidden.isSchemaAmbiguous = function(schema) {
+ var signaturesAmbiguous = function(signature1, signature2) {
+ if (signature1.length != signature2.length)
+ return false;
+
+ for (var i = 0; i < signature1.length; i++) {
+ if (!chromeHidden.checkSchemaOverlap(signature1[i], signature2[i]))
+ return false;
+ }
+ return true;
+ };
+
+ var signatures = chromeHidden.getSignatures(schema);
+ for (var i = 0; i < signatures.length; i++) {
+ for (var j = i + 1; j < signatures.length; j++) {
+ if (signaturesAmbiguous(signatures[i], signatures[j]))
+ return true;
+ }
+ }
+ return false;
+ };
+
// Validate arguments.
chromeHidden.validationTypes = [];
chromeHidden.validate = function(args, schemas) {
@@ -64,6 +163,52 @@ var chrome = chrome || {};
}
};
+ // Returns a string representing the defined signature of the API function.
+ // Example return value for chrome.windows.getCurrent:
+ // "windows.getCurrent(optional object populate, function callback)"
+ chromeHidden.getSchemaSignatureString = function(name, schemas) {
+ var getSchemaTypeString = function(schema) {
+ var schema_types = chromeHidden.getAllTypesForSchema(schema);
+ var type_name = schema_types.join(" or ") + " " + schema.name;
+ if (schema.optional)
+ return "optional " + type_name;
+ return type_name;
+ };
+
+ var type_names = schemas.map(getSchemaTypeString);
+ return name +"(" + type_names.join(", ") + ")";
Matt Perry 2012/02/16 00:31:08 space before "("
Matt Tytel 2012/02/24 01:29:27 Done.
+ };
+
+ // Returns a string representing a call to an API function
+ // Example return value for call: chrome.windows.get(1, callback) is:
+ // "windows.get(int, function)"
+ chromeHidden.getArgumentSignatureString = function(name, args) {
+ var type_names = args.map(chromeHidden.JSONSchemaValidator.getType);
+ return name +"(" + type_names.join(", ") + ")";
Matt Perry 2012/02/16 00:31:08 space before "("
Matt Tytel 2012/02/24 01:29:27 Done.
+ };
+
+ // Finds the correct signature for the given arguments
Matt Perry 2012/02/16 00:31:08 end sentence with .
Matt Tytel 2012/02/24 01:29:27 Done.
+ chromeHidden.matchSignatureAndValidate = function(args, fun_def) {
+ var schemas = fun_def.definition.parameters;
+ var match = chromeHidden.matchSignature(args, schemas);
+ if (!match)
+ throw new Error("Invocation of form " +
+ chromeHidden.getArgumentSignatureString(fun_def.name, args) +
+ " doesn't match definition " +
+ chromeHidden.getSchemaSignatureString(fun_def.name, schemas));
+ chromeHidden.validate(args, match);
+
+ var normalized_args = [];
+ var ai = 0;
+ for (var si = 0; si < schemas.length; si++) {
+ if (schemas[si] === match[ai])
+ normalized_args.push(args[ai++]);
+ else
+ normalized_args.push(null);
+ }
+ return normalized_args;
+ };
+
// Callback handling.
var requests = [];
chromeHidden.handleResponse = function(requestId, name,
@@ -436,13 +581,19 @@ var chrome = chrome || {};
var apiFunction = {};
apiFunction.definition = functionDef;
apiFunction.name = apiDef.namespace + "." + functionDef.name;
+
+ // Validate API for ambiguity only in DEBUG mode.
+ if (chromeHidden.validateAPI &&
+ chromeHidden.isSchemaAmbiguous(apiFunction.definition.parameters))
+ throw new Error(apiFunction.name + " is ambiguous");
apiFunctions.register(apiFunction.name, apiFunction);
module[functionDef.name] = (function() {
- var args = arguments;
+ var args = Array.prototype.slice.call(arguments);
if (this.updateArgumentsPreValidate)
args = this.updateArgumentsPreValidate.apply(this, args);
- chromeHidden.validate(args, this.definition.parameters);
+
+ args = chromeHidden.matchSignatureAndValidate(args, this);
if (this.updateArgumentsPostValidate)
args = this.updateArgumentsPostValidate.apply(this, args);
« no previous file with comments | « chrome/renderer/renderer_resources.grd ('k') | chrome/renderer/resources/extensions/tabs_custom_bindings.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698