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

Side by Side 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: Don't need this custom binding anymore. 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This script contains privileged chrome extension related javascript APIs. 5 // This script contains privileged chrome extension related javascript APIs.
6 // It is loaded by pages whose URL has the chrome-extension protocol. 6 // It is loaded by pages whose URL has the chrome-extension protocol.
7 7
8 var chrome = chrome || {}; 8 var chrome = chrome || {};
9 (function() { 9 (function() {
10 native function GetChromeHidden(); 10 native function GetChromeHidden();
(...skipping 16 matching lines...) Expand all
27 return !!resolved; 27 return !!resolved;
28 } 28 }
29 29
30 function forEach(dict, f) { 30 function forEach(dict, f) {
31 for (key in dict) { 31 for (key in dict) {
32 if (dict.hasOwnProperty(key)) 32 if (dict.hasOwnProperty(key))
33 f(key, dict[key]); 33 f(key, dict[key]);
34 } 34 }
35 } 35 }
36 36
37 // Returns the defined signature of the API function.
38 chromeHidden.fullSignature = function(name, schemas) {
Aaron Boodman 2012/02/06 01:30:52 Function names should be a verb phrase, like getFu
39 var getTypeName = function(schema) {
40 var typeName = schema.type + " " + schema.name;
41 if (schema.optional)
42 return "optional " + typeName;
43 return typeName;
44 };
45
46 var typeNames = schemas.map(getTypeName);
47 return name +"(" + typeNames.join(", ") + ")";
48 };
49
50 // Return true if arguments match a given candidate's schema.
51 chromeHidden.matchCandidate = function(args, schemas) {
Aaron Boodman 2012/02/06 01:30:52 argumentsMatchSignature()?
52 if (args.length != schemas.length)
53 return false;
54
55 var validator = new chromeHidden.JSONSchemaValidator();
56 validator.addTypes(chromeHidden.validationTypes);
57 for (var i = 0; i < schemas.length; i++) {
58 if (args[i] !== null || !schemas[i].optional)
59 validator.validate(args[i], schemas[i]);
Aaron Boodman 2012/02/06 01:30:52 This does not do the right thing. It will check al
60 }
61 return validator.errors.length == 0;
62 };
63
64 // Generate candidates for a given API function scehma.
65 chromeHidden.getCandidates = function(schemas) {
Aaron Boodman 2012/02/06 01:30:52 Can we call this something other than 'candidate'.
66 if (schemas.length === 0)
67 return [[]];
68
69 var candidates = [];
70 var remaining = chromeHidden.getCandidates(schemas.slice(1));
71 for (var i = 0; i < remaining.length; i++) {
72 var candidate = remaining[i].slice(0);
73 candidate.unshift(schemas[0]);
74 candidates.push(candidate);
75 }
76 if (schemas[0].optional)
77 return candidates.concat(remaining);
78 return candidates;
79 };
80
37 // Validate arguments. 81 // Validate arguments.
38 chromeHidden.validationTypes = []; 82 chromeHidden.validationTypes = [];
39 chromeHidden.validate = function(args, schemas) { 83 chromeHidden.validate = function(args, schemas) {
40 if (args.length > schemas.length) 84 var candidates = chromeHidden.getCandidates(schemas);
41 throw new Error("Too many arguments."); 85 var match = null;
86 for (var i = 0; i < candidates.length && match === null; i++) {
87 if (chromeHidden.matchCandidate(args, candidates[i]))
88 match = candidates[i];
89 }
90 if (match === null)
91 throw new Error("Invocation does not match definition.");
42 92
43 for (var i = 0; i < schemas.length; i++) { 93 // Insert nulls into omitted optional parameters.
44 if (i in args && args[i] !== null && args[i] !== undefined) { 94 var normalized_args = [];
45 var validator = new chromeHidden.JSONSchemaValidator(); 95 var ai = 0;
46 validator.addTypes(chromeHidden.validationTypes); 96 for (var si = 0; si < schemas.length; si++) {
47 validator.validate(args[i], schemas[i]); 97 if (schemas[si] === match[ai])
48 if (validator.errors.length == 0) 98 normalized_args.push(args[ai++]);
49 continue; 99 else
100 normalized_args.push(null);
101 }
102 return normalized_args;
Aaron Boodman 2012/02/06 01:30:52 Hm. This doesn't seem right. We never throw the va
103 };
50 104
51 var message = "Invalid value for argument " + (i + 1) + ". "; 105 // Returns true if there is a non-null value that both would accept.
52 for (var i = 0, err; err = validator.errors[i]; i++) { 106 chromeHidden.schemaOverlap = function(schema1, schema2) {
53 if (err.path) { 107 if (schema1.choices) {
54 message += "Property '" + err.path + "': "; 108 for (var i = 0; i < schema1.choices.length; i++)
55 } 109 if (chromeHidden.schemaOverlap(schema1.choices[i], schema2))
56 message += err.message; 110 return true;
57 message = message.substring(0, message.length - 1); 111 } else if (schema2.choices) {
58 message += ", "; 112 for (var i = 0; i < schema2.choices.length; i++)
59 } 113 if (chromeHidden.schemaOverlap(schema1, schema2.choices[i]))
60 message = message.substring(0, message.length - 2); 114 return true;
61 message += "."; 115 } else {
116 var type1 = schema1.type ||
117 chromeHidden.validationTypes[schema1['$ref']].type;
118 var type2 = schema2.type ||
119 chromeHidden.validationTypes[schema2['$ref']].type;
62 120
63 throw new Error(message); 121 if (type1 == "any" || type2 == "any")
64 } else if (!schemas[i].optional) { 122 return true;
65 throw new Error("Parameter " + (i + 1) + " is required."); 123 return type1 == type2;
124 }
125 return false;
126 };
127
128 // Validate schema for API function.
129 chromeHidden.schemaAmbiguous = function(schema) {
130 var candidatesAmbiguous = function(candidate1, candidate2) {
131 if (candidate1.length != candidate2.length)
132 return false;
133
134 for (var i = 0; i < candidate1.length; i++) {
135 if (!chromeHidden.schemaOverlap(candidate1[i], candidate2[i]))
136 return false;
137 }
138 return true;
139 };
140
141 candidates = chromeHidden.getCandidates(schema);
142 for (var i = 0; i < candidates.length; i++) {
143 for (var j = i + 1; j < candidates.length; j++) {
144 if (candidatesAmbiguous(candidates[i], candidates[j]))
145 return true;
66 } 146 }
67 } 147 }
148 return false;
68 }; 149 };
69 150
70 // Callback handling. 151 // Callback handling.
71 var requests = []; 152 var requests = [];
72 chromeHidden.handleResponse = function(requestId, name, 153 chromeHidden.handleResponse = function(requestId, name,
73 success, response, error) { 154 success, response, error) {
74 try { 155 try {
75 var request = requests[requestId]; 156 var request = requests[requestId];
76 if (success) { 157 if (success) {
77 delete chrome.extension.lastError; 158 delete chrome.extension.lastError;
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 511
431 if (functionDef.name in module || 512 if (functionDef.name in module ||
432 addUnprivilegedAccessGetter(module, functionDef.name, 513 addUnprivilegedAccessGetter(module, functionDef.name,
433 functionDef.unprivileged)) { 514 functionDef.unprivileged)) {
434 return; 515 return;
435 } 516 }
436 517
437 var apiFunction = {}; 518 var apiFunction = {};
438 apiFunction.definition = functionDef; 519 apiFunction.definition = functionDef;
439 apiFunction.name = apiDef.namespace + "." + functionDef.name; 520 apiFunction.name = apiDef.namespace + "." + functionDef.name;
521 if (chromeHidden.validateAPI &&
522 chromeHidden.schemaAmbiguous(apiFunction.definition.parameters))
523 throw new Error(apiFunction.name + " is ambiguous");
524
440 apiFunctions.register(apiFunction.name, apiFunction); 525 apiFunctions.register(apiFunction.name, apiFunction);
441 526
442 module[functionDef.name] = (function() { 527 module[functionDef.name] = (function() {
443 var args = arguments; 528 var args = arguments;
444 if (this.updateArgumentsPreValidate) 529 if (this.updateArgumentsPreValidate)
445 args = this.updateArgumentsPreValidate.apply(this, args); 530 args = this.updateArgumentsPreValidate.apply(this, args);
446 chromeHidden.validate(args, this.definition.parameters); 531 try {
Aaron Boodman 2012/02/06 01:30:52 I think it would be a bit cleaner to just have val
532 args = chromeHidden.validate(args, this.definition.parameters);
533 } catch (err) {
534 throw new Error("Invocation doesn't match definition " +
535 chromeHidden.fullSignature(this.name,
Aaron Boodman 2012/02/06 01:30:52 Can we also include the signature that was actuall
536 this.definition.parameters));
537 }
447 if (this.updateArgumentsPostValidate) 538 if (this.updateArgumentsPostValidate)
448 args = this.updateArgumentsPostValidate.apply(this, args); 539 args = this.updateArgumentsPostValidate.apply(this, args);
449 540
450 var retval; 541 var retval;
451 if (this.handleRequest) { 542 if (this.handleRequest) {
452 retval = this.handleRequest.apply(this, args); 543 retval = this.handleRequest.apply(this, args);
453 } else { 544 } else {
454 retval = sendRequest(this.name, args, 545 retval = sendRequest(this.name, args,
455 this.definition.parameters, 546 this.definition.parameters,
456 {customCallback: this.customCallback}); 547 {customCallback: this.customCallback});
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 // See http://crbug.com/100242 665 // See http://crbug.com/100242
575 if (apiExists("webstorePrivate")) { 666 if (apiExists("webstorePrivate")) {
576 chrome.webstorePrivate.beginInstallWithManifest2 = 667 chrome.webstorePrivate.beginInstallWithManifest2 =
577 chrome.webstorePrivate.beginInstallWithManifest3; 668 chrome.webstorePrivate.beginInstallWithManifest3;
578 } 669 }
579 670
580 if (apiExists("test")) 671 if (apiExists("test"))
581 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; 672 chrome.test.getApiDefinitions = GetExtensionAPIDefinition;
582 }); 673 });
583 })(); 674 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698