• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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