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

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: Moved functions to json_schema.js and fixed naming conventions. 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 13 matching lines...) Expand all
24 var internalAPIs = {}; 24 var internalAPIs = {};
25 chromeHidden.internalAPIs = internalAPIs; 25 chromeHidden.internalAPIs = internalAPIs;
26 26
27 function forEach(dict, f) { 27 function forEach(dict, f) {
28 for (key in dict) { 28 for (key in dict) {
29 if (dict.hasOwnProperty(key)) 29 if (dict.hasOwnProperty(key))
30 f(key, dict[key]); 30 f(key, dict[key]);
31 } 31 }
32 } 32 }
33 33
34 // Generate all possible signatures for a given API function schema.
35 function getSignatures(param_list) {
Matt Perry 2012/02/24 02:00:12 javascript style for variable names is paramList.
Matt Tytel 2012/02/24 02:29:36 Done.
36 if (param_list.length === 0)
37 return [[]];
38
39 var signatures = [];
40 var remaining = getSignatures(param_list.slice(1));
41 for (var i = 0; i < remaining.length; i++)
42 signatures.push([param_list[0]].concat(remaining[i]))
43
44 if (param_list[0].optional)
45 return signatures.concat(remaining);
46 return signatures;
47 };
48
49 // Return true if arguments match a given signature's schema.
50 function argumentsMatchSignature(args, param_list) {
51 if (args.length != param_list.length)
52 return false;
53
54 for (var i = 0; i < param_list.length; i++) {
55 if (!chromeHidden.schema_validator.isValidSchemaType(
56 chromeHidden.JSONSchemaValidator.getType(args[i]), param_list[i]))
57 return false;
58 }
59 return true;
60 };
61
62 // Finds the function signature for the given arguments.
63 function resolveSignature(args, param_list) {
64 var candidate_signatures = getSignatures(param_list);
65 for (var i = 0; i < candidate_signatures.length; i++) {
66 if (argumentsMatchSignature(args, candidate_signatures[i]))
67 return candidate_signatures[i];
68 }
69 return null;
70 };
71
72 // Validates that a given schema for an API function is not ambiguous.
73 function isParameterSchemaAmbiguous(parameter_schema) {
74 var signaturesAmbiguous = function(signature1, signature2) {
75 if (signature1.length != signature2.length)
76 return false;
77
78 for (var i = 0; i < signature1.length; i++) {
79 if (!chromeHidden.schema_validator.checkSchemaOverlap(signature1[i],
80 signature2[i]))
81 return false;
82 }
83 return true;
84 };
85
86 var signatures = getSignatures(parameter_schema);
87 for (var i = 0; i < signatures.length; i++) {
88 for (var j = i + 1; j < signatures.length; j++) {
89 if (signaturesAmbiguous(signatures[i], signatures[j]))
90 return true;
91 }
92 }
93 return false;
94 };
95
34 // Validate arguments. 96 // Validate arguments.
35 chromeHidden.validationTypes = []; 97 chromeHidden.schema_validator = new chromeHidden.JSONSchemaValidator();
36 chromeHidden.validate = function(args, schemas) { 98 chromeHidden.validate = function(args, param_list) {
37 if (args.length > schemas.length) 99 if (args.length > param_list.length)
38 throw new Error("Too many arguments."); 100 throw new Error("Too many arguments.");
39 101
40 for (var i = 0; i < schemas.length; i++) { 102 for (var i = 0; i < param_list.length; i++) {
41 if (i in args && args[i] !== null && args[i] !== undefined) { 103 if (i in args && args[i] !== null && args[i] !== undefined) {
42 var validator = new chromeHidden.JSONSchemaValidator(); 104 chromeHidden.schema_validator.resetErrors();
43 validator.addTypes(chromeHidden.validationTypes); 105 chromeHidden.schema_validator.validate(args[i], param_list[i]);
44 validator.validate(args[i], schemas[i]); 106 if (chromeHidden.schema_validator.errors.length == 0)
45 if (validator.errors.length == 0)
46 continue; 107 continue;
47 108
48 var message = "Invalid value for argument " + (i + 1) + ". "; 109 var message = "Invalid value for argument " + (i + 1) + ". ";
49 for (var i = 0, err; err = validator.errors[i]; i++) { 110 for (var i = 0; i < chromeHidden.schema_validator.length; i++) {
111 var err = chromeHidden.schema_validator.errors[i];
50 if (err.path) { 112 if (err.path) {
51 message += "Property '" + err.path + "': "; 113 message += "Property '" + err.path + "': ";
52 } 114 }
53 message += err.message; 115 message += err.message;
54 message = message.substring(0, message.length - 1); 116 message = message.substring(0, message.length - 1);
55 message += ", "; 117 message += ", ";
56 } 118 }
57 message = message.substring(0, message.length - 2); 119 message = message.substring(0, message.length - 2);
58 message += "."; 120 message += ".";
59 121
60 throw new Error(message); 122 throw new Error(message);
61 } else if (!schemas[i].optional) { 123 } else if (!param_list[i].optional) {
62 throw new Error("Parameter " + (i + 1) + " is required."); 124 throw new Error("Parameter " + (i + 1) + " is required.");
63 } 125 }
64 } 126 }
65 }; 127 };
66 128
129 // Returns a string representing the defined signature of the API function.
130 // Example return value for chrome.windows.getCurrent:
131 // "windows.getCurrent(optional object populate, function callback)"
132 function getParameterSignatureString(name, param_list) {
133 var getSchemaTypeString = function(schema) {
134 var schema_types =
135 chromeHidden.schema_validator.getAllTypesForSchema(schema);
136 var type_name = schema_types.join(" or ") + " " + schema.name;
137 if (schema.optional)
138 return "optional " + type_name;
139 return type_name;
140 };
141
142 var type_names = param_list.map(getSchemaTypeString);
143 return name +" (" + type_names.join(", ") + ")";
Matt Perry 2012/02/24 02:00:12 space before " ("
Matt Tytel 2012/02/24 02:29:36 Done. I misinterpreted your last comment on this a
144 };
145
146 // Returns a string representing a call to an API function.
147 // Example return value for call: chrome.windows.get(1, callback) is:
148 // "windows.get(int, function)"
149 function getArgumentSignatureString(name, args) {
150 var type_names = args.map(chromeHidden.JSONSchemaValidator.getType);
151 return name +" (" + type_names.join(", ") + ")";
Matt Perry 2012/02/24 02:00:12 ditto
Matt Tytel 2012/02/24 02:29:36 Done.
152 };
153
154 // Finds the correct signature for the given arguments, then validates the
155 // arguments against that signature. Returns a 'normalized' arguments list
156 // where nulls are inserted where optional parameters were omitted.
157 chromeHidden.updateArgumentsValidate = function(args, fun_def) {
158 var param_list = fun_def.definition.parameters;
159 var resolved_signature = resolveSignature(args, param_list);
160 if (!resolved_signature)
161 throw new Error("Invocation of form " +
162 getArgumentSignatureString(fun_def.name, args) +
163 " doesn't match definition " +
164 getParameterSignatureString(fun_def.name, param_list));
165 chromeHidden.validate(args, resolved_signature);
166
167 var normalized_args = [];
168 var ai = 0;
169 for (var si = 0; si < param_list.length; si++) {
170 if (param_list[si] === resolved_signature[ai])
171 normalized_args.push(args[ai++]);
172 else
173 normalized_args.push(null);
174 }
175 return normalized_args;
176 };
177
67 // Callback handling. 178 // Callback handling.
68 var requests = []; 179 var requests = [];
69 chromeHidden.handleResponse = function(requestId, name, 180 chromeHidden.handleResponse = function(requestId, name,
70 success, response, error) { 181 success, response, error) {
71 try { 182 try {
72 var request = requests[requestId]; 183 var request = requests[requestId];
73 if (success) { 184 if (success) {
74 delete chrome.extension.lastError; 185 delete chrome.extension.lastError;
75 } else { 186 } else {
76 if (!error) { 187 if (!error) {
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 495
385 // See comment on internalAPIs at the top. 496 // See comment on internalAPIs at the top.
386 var mod = apiDef.internal ? internalAPIs : chrome; 497 var mod = apiDef.internal ? internalAPIs : chrome;
387 498
388 var namespaces = apiDef.namespace.split('.'); 499 var namespaces = apiDef.namespace.split('.');
389 for (var index = 0, name; name = namespaces[index]; index++) { 500 for (var index = 0, name; name = namespaces[index]; index++) {
390 mod[name] = mod[name] || {}; 501 mod[name] = mod[name] || {};
391 mod = mod[name]; 502 mod = mod[name];
392 } 503 }
393 504
394 // Add types to global validationTypes 505 // Add types to global schema_validator
395 if (apiDef.types) { 506 if (apiDef.types) {
396 apiDef.types.forEach(function(t) { 507 apiDef.types.forEach(function(t) {
397 if (!isSchemaNodeSupported(t, platform, manifestVersion)) 508 if (!isSchemaNodeSupported(t, platform, manifestVersion))
398 return; 509 return;
399 510
400 chromeHidden.validationTypes.push(t); 511 chromeHidden.schema_validator.addTypes(t);
401 if (t.type == 'object' && customTypes[t.id]) { 512 if (t.type == 'object' && customTypes[t.id]) {
402 customTypes[t.id].prototype.setSchema(t); 513 customTypes[t.id].prototype.setSchema(t);
403 } 514 }
404 }); 515 });
405 } 516 }
406 517
407 // Returns whether access to the content of a schema should be denied, 518 // Returns whether access to the content of a schema should be denied,
408 // based on the presence of "unprivileged" and whether this is an 519 // based on the presence of "unprivileged" and whether this is an
409 // extension process (versus e.g. a content script). 520 // extension process (versus e.g. a content script).
410 function isSchemaAccessAllowed(itemSchema) { 521 function isSchemaAccessAllowed(itemSchema) {
(...skipping 22 matching lines...) Expand all
433 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) 544 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion))
434 return; 545 return;
435 if (!isSchemaAccessAllowed(functionDef)) { 546 if (!isSchemaAccessAllowed(functionDef)) {
436 addUnprivilegedAccessGetter(mod, functionDef.name); 547 addUnprivilegedAccessGetter(mod, functionDef.name);
437 return; 548 return;
438 } 549 }
439 550
440 var apiFunction = {}; 551 var apiFunction = {};
441 apiFunction.definition = functionDef; 552 apiFunction.definition = functionDef;
442 apiFunction.name = apiDef.namespace + "." + functionDef.name; 553 apiFunction.name = apiDef.namespace + "." + functionDef.name;
554
555 // Validate API for ambiguity only in DEBUG mode.
556 // TODO(aa): It would be best to run this in a unit test, but in order
557 // to do that we would need to better factor this code so that it
558 // didn't depend on so much v8::Extension machinery.
559 if (chromeHidden.validateAPI &&
560 isParameterSchemaAmbiguous(apiFunction.definition.parameters))
561 throw new Error(apiFunction.name + " is ambiguous");
562
443 apiFunctions.register(apiFunction.name, apiFunction); 563 apiFunctions.register(apiFunction.name, apiFunction);
444
445 mod[functionDef.name] = (function() { 564 mod[functionDef.name] = (function() {
446 var args = arguments; 565 var args = Array.prototype.slice.call(arguments);
447 if (this.updateArgumentsPreValidate) 566 if (this.updateArgumentsPreValidate)
448 args = this.updateArgumentsPreValidate.apply(this, args); 567 args = this.updateArgumentsPreValidate.apply(this, args);
449 chromeHidden.validate(args, this.definition.parameters); 568
569 args = chromeHidden.updateArgumentsValidate(args, this);
450 if (this.updateArgumentsPostValidate) 570 if (this.updateArgumentsPostValidate)
451 args = this.updateArgumentsPostValidate.apply(this, args); 571 args = this.updateArgumentsPostValidate.apply(this, args);
452 572
453 var retval; 573 var retval;
454 if (this.handleRequest) { 574 if (this.handleRequest) {
455 retval = this.handleRequest.apply(this, args); 575 retval = this.handleRequest.apply(this, args);
456 } else { 576 } else {
457 retval = sendRequest(this.name, args, 577 retval = sendRequest(this.name, args,
458 this.definition.parameters, 578 this.definition.parameters,
459 {customCallback: this.customCallback}); 579 {customCallback: this.customCallback});
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 // See http://crbug.com/100242 696 // See http://crbug.com/100242
577 if (chrome.webstorePrivate) { 697 if (chrome.webstorePrivate) {
578 chrome.webstorePrivate.beginInstallWithManifest2 = 698 chrome.webstorePrivate.beginInstallWithManifest2 =
579 chrome.webstorePrivate.beginInstallWithManifest3; 699 chrome.webstorePrivate.beginInstallWithManifest3;
580 } 700 }
581 701
582 if (chrome.test) 702 if (chrome.test)
583 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; 703 chrome.test.getApiDefinitions = GetExtensionAPIDefinition;
584 }); 704 });
585 })(); 705 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698