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