Home | History | Annotate | Download | only in vinn
      1 // Copyright 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 /**
      8  * @fileoverview Provides tools for loading an HTML import file into D8.
      9  */
     10 (function(global) {
     11   var isNode = global.process && global.process.versions.node;
     12 
     13   var fs;
     14   if (isNode)
     15     fs = require('fs');
     16 
     17   var pathUtils = undefined;
     18   function setPathUtils(newPathUtils) {
     19     if (pathUtils !== undefined)
     20       throw new Error('Already set');
     21     pathUtils = newPathUtils;
     22   }
     23 
     24   function readFileContents(fileName) {
     25     if (!isNode)
     26       return read(fileName);
     27     return fs.readFileSync(fileName, 'utf8');
     28   }
     29 
     30   /**
     31    * Strips the starting '/' in file_path if |file_path| is meant to be a
     32    * relative path.
     33    *
     34    * @param {string} file_path path to some file, can be relative or absolute
     35    * path.
     36    * @return {string} the file_path with starting '/' removed if |file_path|
     37    * does not exist or the original |file_path| otherwise.
     38    */
     39   function _stripStartingSlashIfNeeded(file_path) {
     40     if (file_path.substring(0, 1) !== '/') {
     41       return file_path;
     42     }
     43     if (pathUtils.exists(file_path))
     44       return file_path;
     45     return file_path.substring(1);
     46   }
     47 
     48   var sourcePaths = [];
     49 
     50   function addArrayToSourcePath(paths) {
     51     for (var i = 0; i < paths.length; i++) {
     52       if (sourcePaths.indexOf(paths[i]) !== -1)
     53         continue;
     54       sourcePaths.push(paths[i]);
     55     }
     56   }
     57 
     58   function hrefToAbsolutePath(href) {
     59     var pathPart;
     60     if (!pathUtils.isAbs(href)) {
     61       throw new Error('Found a non absolute import and thats not supported: ' +
     62                       href);
     63     } else {
     64       pathPart = href.substring(1);
     65     }
     66 
     67     var candidates = [];
     68     for (var i = 0; i < sourcePaths.length; i++) {
     69       var candidate = pathUtils.join(sourcePaths[i], pathPart);
     70       if (pathUtils.exists(candidate))
     71         candidates.push(candidate);
     72     }
     73     if (candidates.length > 1) {
     74       throw new Error('Multiple candidates found for ' + href + ': ' +
     75           candidates + '\nSource paths:\n' + sourcePaths.join(',\n'));
     76     }
     77     if (candidates.length === 0) {
     78       throw new Error(href + ' not found!' +
     79           '\nSource paths:\n' + sourcePaths.join(',\n'));
     80     }
     81     return candidates[0];
     82   }
     83 
     84   var loadedModulesByFilePath = {};
     85 
     86   /**
     87    * Load a HTML file, which absolute path or path relative to <%search-path%>.
     88    * Unlike the native load() method of d8, variables declared in |file_path|
     89    * will not be hoisted to the caller environment. For example:
     90    *
     91    * a.html:
     92    * <script>
     93    *   var x = 1;
     94    * </script>
     95    *
     96    * test.js:
     97    * loadHTML("a.html");
     98    * print(x);  // <- ReferenceError is thrown because x is not defined.
     99    *
    100    * @param {string} file_path path to the HTML file to be loaded.
    101    */
    102   function loadHTML(href) {
    103     var absPath = hrefToAbsolutePath(href);
    104     loadHTMLFile.call(global, absPath, href);
    105   };
    106 
    107   function loadScript(href) {
    108     var absPath = hrefToAbsolutePath(href);
    109     loadFile.call(global, absPath, href);
    110   };
    111 
    112   function loadHTMLFile(absPath, opt_href) {
    113     var href = opt_href || absPath;
    114     if (loadedModulesByFilePath[absPath])
    115       return;
    116     loadedModulesByFilePath[absPath] = true;
    117     try {
    118       var html_content = readFileContents(absPath);
    119     } catch (err) {
    120       throw new Error('Error in loading html file ' + href +
    121           ': File does not exist');
    122     }
    123 
    124     try {
    125       var stripped_js = generateJsFromHTML(html_content);
    126     } catch (err) {
    127       throw new Error('Error in loading html file ' + href + ': ' + err);
    128     }
    129 
    130     // If there is blank line at the beginning of generated js, we add
    131     // "//@ sourceURL=|file_path|" to the beginning of generated source so
    132     // the stack trace show the source file even in case of syntax error.
    133     // If not, we add it to the end of generated source to preserve the line
    134     // number.
    135     if (stripped_js.startsWith('\n')) {
    136       stripped_js = '//@ sourceURL=' + href + stripped_js;
    137     } else {
    138       stripped_js = stripped_js + '\n//@ sourceURL=' + href;
    139     }
    140     eval(stripped_js);
    141   };
    142 
    143   function loadFile(absPath, opt_href) {
    144     var href = opt_href || absPath;
    145     try {
    146       if (!isNode) {
    147         load(absPath);
    148       } else {
    149         var relPath = pathUtils.relPath(absPath);
    150         var contents = readFileContents(relPath);
    151         eval(contents);
    152       }
    153     } catch (err) {
    154       throw new Error('Error in loading script file ' + href + ': ' + err);
    155     }
    156   };
    157 
    158   global.HTMLImportsLoader = {
    159     setPathUtils: setPathUtils,
    160     sourcePaths: sourcePaths,
    161     addArrayToSourcePath: addArrayToSourcePath,
    162     hrefToAbsolutePath: hrefToAbsolutePath,
    163     loadHTML: loadHTML,
    164     loadScript: loadScript,
    165     loadHTMLFile: loadHTMLFile,
    166     loadFile: loadFile
    167   };
    168 })(this);
    169