# _base.js

    1// Copyright 2012 Selenium committers2// Copyright 2012 Software Freedom Conservancy3//4// Licensed under the Apache License, Version 2.0 (the "License");5// you may not use this file except in compliance with the License.6//     You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing, software11// distributed under the License is distributed on an "AS IS" BASIS,12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13// See the License for the specific language governing permissions and14// limitations under the License.1516/**17 * @fileoverview The base module responsible for bootstrapping the Closure18 * library and providing a means of loading Closure-based modules.19 *20 * <p>Each script loaded by this module will be granted access to this module's21 * {@code require} function; all required non-native modules must be specified22 * relative to <em>this</em> module.23 *24 * <p>This module will load all scripts from the "lib" subdirectory, unless the25 * SELENIUM_DEV_MODE environment variable has been set to 1, in which case all26 * scripts will be loaded from the Selenium client containing this script.27 */2829'use strict';3031var fs = require('fs'),32    path = require('path'),33    vm = require('vm');343536/**37 * If this script was loaded from the Selenium project repo, it will operate in38 * development mode, adjusting how it loads Closure-based dependencies.39 * @type {boolean}40 */41var devMode = (function() {42  var buildDescFile = path.join(__dirname, '..', 'build.desc');43  return fs.existsSync(buildDescFile);44})();454647/** @return {boolean} Whether this script was loaded in dev mode. */48function isDevMode() {49  return devMode;50}515253/**54 * @type {string} Path to Closure's base file, relative to this module.55 * @const56 */57var CLOSURE_BASE_FILE_PATH = (function() {58  var relativePath = isDevMode() ?59      '../../../third_party/closure/goog/base.js' :60      './lib/goog/base.js';61  return path.join(__dirname, relativePath);62})();636465/**66 * @type {string} Path to Closure's base file, relative to this module.67 * @const68 */69var DEPS_FILE_PATH = (function() {70  var relativePath = isDevMode() ?71      '../../../javascript/deps.js' :72      './lib/goog/deps.js';73  return path.join(__dirname, relativePath);74})();757677/**78 * Maintains a unique context for Closure library-based code.79 * @param {boolean=} opt_configureForTesting Whether to configure a fake DOM80 *     for Closure-testing code that (incorrectly) assumes a DOM is always81 *     present.82 * @constructor83 */84function Context(opt_configureForTesting) {85  var closure = this.closure = vm.createContext({86    console: console,87    setTimeout: setTimeout,88    setInterval: setInterval,89    clearTimeout: clearTimeout,90    clearInterval: clearInterval,91    process: process,92    require: require,93    Buffer: Buffer,94    Error: Error,95    CLOSURE_BASE_PATH: path.dirname(CLOSURE_BASE_FILE_PATH) + '/',96    CLOSURE_IMPORT_SCRIPT: function(src) {97      loadScript(src);98      return true;99    },100    CLOSURE_NO_DEPS: !isDevMode(),101    goog: {}102  });103  closure.window = closure.top = closure;104105  if (opt_configureForTesting) {106    closure.document = {107      body: {},108      createElement: function() { return {}; },109      getElementsByTagName: function() { return []; }110    };111    closure.document.body.ownerDocument = closure.document;112  }113114  loadScript(CLOSURE_BASE_FILE_PATH);115  loadScript(DEPS_FILE_PATH);116117  /**118   * Synchronously loads a script into the protected Closure context.119   * @param {string} src Path to the file to load.120   */121  function loadScript(src) {122    src = path.normalize(src);123    var contents = fs.readFileSync(src, 'utf8');124    vm.runInContext(contents, closure, src);125  }126}127128129var context = new Context();130131132/**133 * Loads a symbol by name from the protected Closure context.134 * @param {string} symbol The symbol to load.135 * @return {?} The loaded symbol, or {@code null} if not found.136 * @throws {Error} If the symbol has not been defined.137 */138function closureRequire(symbol) {139  context.closure.goog.require(symbol);140  return context.closure.goog.getObjectByName(symbol);141}142143144// PUBLIC API145146147/**148 * Loads a symbol by name from the protected Closure context and exports its149 * public API to the provided object. This function relies on Closure code150 * conventions to define the public API of an object as those properties whose151 * name does not end with "_".152 * @param {string} symbol The symbol to load. This must resolve to an object.153 * @return {!Object} An object with the exported API.154 * @throws {Error} If the symbol has not been defined or does not resolve to155 *     an object.156 */157exports.exportPublicApi = function(symbol) {158  var src = closureRequire(symbol);159  if (typeof src != 'object' || src === null) {160    throw Error('"' + symbol + '" must resolve to an object');161  }162163  var dest = {};164  Object.keys(src).forEach(function(key) {165    if (key[key.length - 1] != '_') {166      dest[key] = src[key];167    }168  });169170  return dest;171};172173174if (isDevMode()) {175  exports.closure = context.closure;176}177exports.Context = Context;178exports.isDevMode = isDevMode;179exports.require = closureRequire;