binding.js revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)require('json_schema'); 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)require('event_bindings'); 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var chrome = requireNative('chrome').GetChrome(); 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var forEach = require('utils').forEach; 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var GetAvailability = requireNative('v8_context').GetAvailability; 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var logging = requireNative('logging'); 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var process = requireNative('process'); 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var contextType = process.GetContextType(); 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var extensionId = process.GetExtensionId(); 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var manifestVersion = process.GetManifestVersion(); 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var schemaRegistry = requireNative('schema_registry'); 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var schemaUtils = require('schemaUtils'); 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var utils = require('utils'); 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var CHECK = requireNative('logging').CHECK; 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var sendRequestHandler = require('sendRequest'); 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var sendRequest = sendRequestHandler.sendRequest; 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var logActivity = requireNative('activityLogger'); 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Stores the name and definition of each API function, with methods to 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// modify their behaviour (such as a custom way to handle requests to the 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// API, a custom callback, etc). 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function APIFunctions(namespace) { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_ = {}; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.unavailableApiFunctions_ = {}; 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this.namespace = namespace; 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.register = function(apiName, apiFunction) { 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_[apiName] = apiFunction; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Registers a function as existing but not available, meaning that calls to 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the set* methods that reference this function should be ignored rather 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// than throwing Errors. 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.registerUnavailable = function(apiName) { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.unavailableApiFunctions_[apiName] = apiName; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.setHook_ = 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(apiName, propertyName, customizedFunction) { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.unavailableApiFunctions_.hasOwnProperty(apiName)) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!this.apiFunctions_.hasOwnProperty(apiName)) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error('Tried to set hook for unknown API "' + apiName + '"'); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_[apiName][propertyName] = customizedFunction; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.setHandleRequest = 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(apiName, customizedFunction) { 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) var prefix = this.namespace; 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(ataly): Need to replace/redefine apply and slice. 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return this.setHook_(apiName, 'handleRequest', 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) function() { 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) var ret = customizedFunction.apply(this, arguments); 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Logs API calls to the Activity Log if it doesn't go through an 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // ExtensionFunction. 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!sendRequestHandler.getCalledSendRequest()) 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) logActivity.LogAPICall(extensionId, prefix + "." + apiName, 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Array.prototype.slice.call(arguments)); 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ret; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) }); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.setUpdateArgumentsPostValidate = 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(apiName, customizedFunction) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return this.setHook_( 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiName, 'updateArgumentsPostValidate', customizedFunction); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.setUpdateArgumentsPreValidate = 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(apiName, customizedFunction) { 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return this.setHook_( 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiName, 'updateArgumentsPreValidate', customizedFunction); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)APIFunctions.prototype.setCustomCallback = 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function(apiName, customizedFunction) { 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return this.setHook_(apiName, 'customCallback', customizedFunction); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function CustomBindingsObject() { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CustomBindingsObject.prototype.setSchema = function(schema) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The functions in the schema are in list form, so we move them into a 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // dictionary for easier access. 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var self = this; 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.functionSchemas = {}; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schema.functions.forEach(function(f) { 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.functionSchemas[f.name] = { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) name: f.name, 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) definition: f 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Get the platform from navigator.appVersion. 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function getPlatform() { 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var platforms = [ 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [/CrOS Touch/, "chromeos touch"], 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [/CrOS/, "chromeos"], 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [/Linux/, "linux"], 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [/Mac/, "mac"], 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [/Win/, "win"], 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ]; 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (var i = 0; i < platforms.length; i++) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (platforms[i][0].test(navigator.appVersion)) { 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return platforms[i][1]; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "unknown"; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function isPlatformSupported(schemaNode, platform) { 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return !schemaNode.platforms || 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schemaNode.platforms.indexOf(platform) > -1; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function isManifestVersionSupported(schemaNode, manifestVersion) { 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return !schemaNode.maximumManifestVersion || 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manifestVersion <= schemaNode.maximumManifestVersion; 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function isSchemaNodeSupported(schemaNode, platform, manifestVersion) { 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return isPlatformSupported(schemaNode, platform) && 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) isManifestVersionSupported(schemaNode, manifestVersion); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function createCustomType(type) { 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var jsModuleName = type.js_module; 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(jsModuleName, 'Custom type ' + type.id + 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ' has no "js_module" property.'); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var jsModule = require(jsModuleName); 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(jsModule, 'No module ' + jsModuleName + ' found for ' + type.id + '.'); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var customType = jsModule[jsModuleName]; 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(customType, jsModuleName + ' must export itself.'); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) customType.prototype = new CustomBindingsObject(); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) customType.prototype.setSchema(type); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return customType; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var platform = getPlatform(); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function Binding(schema) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.schema_ = schema; 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this.apiFunctions_ = new APIFunctions(schema.namespace); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.customEvent_ = null; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.customHooks_ = []; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Binding.create = function(apiName) { 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new Binding(schemaRegistry.GetSchema(apiName)); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Binding.prototype = { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The API through which the ${api_name}_custom_bindings.js files customize 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // their API bindings beyond what can be generated. 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There are 2 types of customizations available: those which are required in 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // order to do the schema generation (registerCustomEvent and 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // registerCustomType), and those which can only run after the bindings have 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // been generated (registerCustomHook). 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Registers a custom event type for the API identified by |namespace|. 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |event| is the event's constructor. 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registerCustomEvent: function(event) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.customEvent_ = event; 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Registers a function |hook| to run after the schema for all APIs has been 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // generated. The hook is passed as its first argument an "API" object to 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // interact with, and second the current extension ID. See where 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |customHooks| is used. 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registerCustomHook: function(fn) { 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.customHooks_.push(fn); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(kalman/cduvall): Refactor this so |runHooks_| is not needed. 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) runHooks_: function(api) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEach(this.customHooks_, function(i, hook) { 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(this.schema_, platform, manifestVersion)) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!hook) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hook({ 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiFunctions: this.apiFunctions_, 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schema: this.schema_, 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) compiledApi: api 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, extensionId, contextType); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, this); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Generates the bindings from |this.schema_| and integrates any custom 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // bindings that might be present. 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) generate: function() { 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var schema = this.schema_; 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // supporting code. 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(schema, platform, manifestVersion)) { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) console.error('chrome.' + schema.namespace + ' is not supported on ' + 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'this platform or manifest version'); 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return undefined; 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var availability = GetAvailability(schema.namespace); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!availability.is_available) { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) console.error('chrome.' + schema.namespace + ' is not available: ' + 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) availability.message); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return undefined; 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // See comment on internalAPIs at the top. 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var mod = {}; 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var namespaces = schema.namespace.split('.'); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (var index = 0, name; name = namespaces[index]; index++) { 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod[name] = mod[name] || {}; 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod = mod[name]; 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add types to global schemaValidator, the types we depend on from other 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // namespaces will be added as needed. 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (schema.types) { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEach(schema.types, function(i, t) { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(t, platform, manifestVersion)) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schemaUtils.schemaValidator.addTypes(t); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, this); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns whether access to the content of a schema should be denied, 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // based on the presence of "unprivileged" and whether this is an 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // extension process (versus e.g. a content script). 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function isSchemaAccessAllowed(itemSchema) { 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (contextType == 'BLESSED_EXTENSION') || 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schema.unprivileged || 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) itemSchema.unprivileged; 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds a getter that throws an access denied error to object |mod| 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // for property |name|. 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function addUnprivilegedAccessGetter(mod, name) { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod.__defineGetter__(name, function() { 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error( 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) '"' + name + '" can only be used in extension processes. See ' + 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'the content scripts documentation for more details.'); 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Setup Functions. 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (schema.functions) { 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEach(schema.functions, function(i, functionDef) { 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (functionDef.name in mod) { 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error('Function ' + functionDef.name + 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ' already defined in ' + schema.namespace); 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_.registerUnavailable(functionDef.name); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaAccessAllowed(functionDef)) { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_.registerUnavailable(functionDef.name); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addUnprivilegedAccessGetter(mod, functionDef.name); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var apiFunction = {}; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiFunction.definition = functionDef; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiFunction.name = schema.namespace + '.' + functionDef.name; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(aa): It would be best to run this in a unit test, but in order 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to do that we would need to better factor this code so that it 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // doesn't depend on so much v8::Extension machinery. 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (chromeHidden.validateAPI && 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schemaUtils.isFunctionSignatureAmbiguous( 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiFunction.definition)) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error( 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apiFunction.name + ' has ambiguous optional arguments. ' + 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'To implement custom disambiguation logic, add ' + 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) '"allowAmbiguousOptionalArguments" to the function\'s schema.'); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.apiFunctions_.register(functionDef.name, apiFunction); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod[functionDef.name] = (function() { 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var args = Array.prototype.slice.call(arguments); 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.updateArgumentsPreValidate) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args = this.updateArgumentsPreValidate.apply(this, args); 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args = schemaUtils.normalizeArgumentsAndValidate(args, this); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.updateArgumentsPostValidate) 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args = this.updateArgumentsPostValidate.apply(this, args); 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) sendRequestHandler.clearCalledSendRequest(); 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var retval; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.handleRequest) { 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) retval = this.handleRequest.apply(this, args); 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var optArgs = { 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) customCallback: this.customCallback 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) retval = sendRequest(this.name, args, 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.definition.parameters, 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) optArgs); 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) sendRequestHandler.clearCalledSendRequest(); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Validate return value if defined - only in debug. 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (chromeHidden.validateCallbacks && 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.definition.returns) { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) schemaUtils.validate([retval], [this.definition.returns]); 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return retval; 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }).bind(apiFunction); 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, this); 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Setup Events 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (schema.events) { 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEach(schema.events, function(i, eventDef) { 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (eventDef.name in mod) { 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error('Event ' + eventDef.name + 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ' already defined in ' + schema.namespace); 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(eventDef, platform, manifestVersion)) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaAccessAllowed(eventDef)) { 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addUnprivilegedAccessGetter(mod, eventDef.name); 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var eventName = schema.namespace + "." + eventDef.name; 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var options = eventDef.options || {}; 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (eventDef.filters && eventDef.filters.length > 0) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) options.supportsFilters = true; 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this.customEvent_) { 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod[eventDef.name] = new this.customEvent_( 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) eventName, eventDef.parameters, eventDef.extraParameters, 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) options); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (eventDef.anonymous) { 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod[eventDef.name] = new chrome.Event(); 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod[eventDef.name] = new chrome.Event( 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) eventName, eventDef.parameters, options); 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }, this); 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) function addProperties(m, parentDef) { 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var properties = parentDef.properties; 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!properties) 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEach(properties, function(propertyName, propertyDef) { 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (propertyName in m) 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // TODO(kalman): be strict like functions/events somehow. 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaNodeSupported(propertyDef, platform, manifestVersion)) 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!isSchemaAccessAllowed(propertyDef)) { 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addUnprivilegedAccessGetter(m, propertyName); 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var value = propertyDef.value; 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (value) { 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Values may just have raw types as defined in the JSON, such 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here. 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(kalman): enforce that things with a "value" property can't 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // define their own types. 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var type = propertyDef.type || typeof(value); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (type === 'integer' || type === 'number') { 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value = parseInt(value); 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (type === 'boolean') { 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value = value === 'true'; 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (propertyDef['$ref']) { 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var ref = propertyDef['$ref']; 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var type = utils.loadTypeSchema(propertyDef['$ref'], schema); 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(type, 'Schema for $ref type ' + ref + ' not found'); 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var constructor = createCustomType(type); 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var args = value; 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // For an object propertyDef, |value| is an array of constructor 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // arguments, but we want to pass the arguments directly (i.e. 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // not as an array), so we have to fake calling |new| on the 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // constructor. 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value = { __proto__: constructor.prototype }; 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) constructor.apply(value, args); 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Recursively add properties. 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addProperties(value, propertyDef); 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (type === 'object') { 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Recursively add properties. 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addProperties(value, propertyDef); 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (type !== 'string') { 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error('NOT IMPLEMENTED (extension_api.json error): ' + 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'Cannot parse values for type "' + type + '"'); 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) m[propertyName] = value; 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) addProperties(mod, schema); 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.runHooks_(mod); 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mod; 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)exports.Binding = Binding; 422