1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | Object.defineProperty(exports, "__esModule", { value: true });
|
16 | const dom5 = require("dom5/lib/index-next");
|
17 | const htmlMinifier = require("html-minifier");
|
18 | const parse5 = require("parse5");
|
19 | const externalJs = require("./external-js");
|
20 | const html_splitter_1 = require("./html-splitter");
|
21 | const js_transform_1 = require("./js-transform");
|
22 | const p = dom5.predicates;
|
23 | const isJsScript = p.AND(p.hasTagName('script'), p.OR(p.NOT(p.hasAttr('type')), p.hasAttrValue('type', 'text/javascript'), p.hasAttrValue('type', 'application/javascript'), p.hasAttrValue('type', 'module')));
|
24 | const isJsScriptOrHtmlImport = p.OR(isJsScript, p.AND(p.hasTagName('link'), p.hasSpaceSeparatedAttrValue('rel', 'import')));
|
25 |
|
26 |
|
27 |
|
28 | function htmlTransform(html, options) {
|
29 | if (options.js && options.js.moduleResolution === 'node' &&
|
30 | !options.js.filePath) {
|
31 | throw new Error('Cannot perform node module resolution without filePath.');
|
32 | }
|
33 | const document = parse5.parse(html, {
|
34 | locationInfo: true,
|
35 | });
|
36 | removeFakeNodes(document);
|
37 | const allScripts = [...dom5.queryAll(document, isJsScript)];
|
38 | const shouldTransformEsModuleToAmd = options.js &&
|
39 | options.js.transformModulesToAmd &&
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | !allScripts.some((node) => dom5.hasAttribute(node, 'nomodule'));
|
45 | let wctScript, firstModuleScript;
|
46 | for (const script of allScripts) {
|
47 | const isModule = dom5.getAttribute(script, 'type') === 'module';
|
48 | if (isModule) {
|
49 | if (firstModuleScript === undefined) {
|
50 | firstModuleScript = script;
|
51 | }
|
52 | if (shouldTransformEsModuleToAmd) {
|
53 | transformEsModuleToAmd(script, options.js);
|
54 | continue;
|
55 | }
|
56 | }
|
57 | const isInline = !dom5.hasAttribute(script, 'src');
|
58 | if (isInline) {
|
59 |
|
60 |
|
61 | const newJs = js_transform_1.jsTransform(dom5.getTextContent(script), Object.assign({}, options.js, { transformModulesToAmd: false }));
|
62 | dom5.setTextContent(script, newJs);
|
63 | }
|
64 | else if (wctScript === undefined) {
|
65 | const src = dom5.getAttribute(script, 'src') || '';
|
66 | if (src.includes('web-component-tester/browser.js') ||
|
67 | src.includes('wct-browser-legacy/browser.js') ||
|
68 | src.includes('wct-mocha/wct-mocha.js')) {
|
69 | wctScript = script;
|
70 | }
|
71 | }
|
72 | }
|
73 | if (options.injectAmdLoader && shouldTransformEsModuleToAmd &&
|
74 | firstModuleScript !== undefined) {
|
75 | const fragment = parse5.parseFragment('<script></script>\n');
|
76 | dom5.setTextContent(fragment.childNodes[0], externalJs.getAmdLoader());
|
77 | const amdLoaderScript = fragment.childNodes[0];
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | dom5.insertBefore(firstModuleScript.parentNode, firstModuleScript, fragment);
|
84 | if (wctScript !== undefined) {
|
85 | addWctTimingHack(wctScript, amdLoaderScript);
|
86 | }
|
87 | }
|
88 | const injectScript = (js) => {
|
89 | const fragment = parse5.parseFragment('<script></script>\n');
|
90 | dom5.setTextContent(fragment.childNodes[0], js);
|
91 | const firstJsScriptOrHtmlImport = dom5.query(document, isJsScriptOrHtmlImport);
|
92 | if (firstJsScriptOrHtmlImport) {
|
93 | dom5.insertBefore(firstJsScriptOrHtmlImport.parentNode, firstJsScriptOrHtmlImport, fragment);
|
94 | }
|
95 | else {
|
96 | const headOrDocument = dom5.query(document, dom5.predicates.hasTagName('head')) || document;
|
97 | dom5.append(headOrDocument, fragment);
|
98 | }
|
99 | };
|
100 | let babelHelpers;
|
101 | switch (options.injectBabelHelpers) {
|
102 | case undefined:
|
103 | case 'none':
|
104 | break;
|
105 | case 'full':
|
106 | babelHelpers = externalJs.getBabelHelpersFull();
|
107 | break;
|
108 | case 'amd':
|
109 | babelHelpers = externalJs.getBabelHelpersAmd();
|
110 | break;
|
111 | default:
|
112 | const never = options.injectBabelHelpers;
|
113 | throw new Error(`Unknown injectBabelHelpers value: ${never}`);
|
114 | }
|
115 | if (babelHelpers !== undefined) {
|
116 | injectScript(babelHelpers);
|
117 | }
|
118 | if (options.injectRegeneratorRuntime === true) {
|
119 | injectScript(externalJs.getRegeneratorRuntime());
|
120 | }
|
121 | html = parse5.serialize(document);
|
122 | if (options.minifyHtml) {
|
123 | html = htmlMinifier.minify(html, {
|
124 | collapseWhitespace: true,
|
125 | removeComments: true,
|
126 | });
|
127 | }
|
128 | return html;
|
129 | }
|
130 | exports.htmlTransform = htmlTransform;
|
131 | function transformEsModuleToAmd(script, jsOptions) {
|
132 |
|
133 | dom5.removeAttribute(script, 'type');
|
134 | if (html_splitter_1.scriptWasSplitByHtmlSplitter(script)) {
|
135 |
|
136 |
|
137 | return;
|
138 | }
|
139 | const isExternal = dom5.hasAttribute(script, 'src');
|
140 | if (isExternal) {
|
141 | const src = dom5.getAttribute(script, 'src');
|
142 | dom5.removeAttribute(script, 'src');
|
143 | dom5.setTextContent(script, `define(['${src}']);`);
|
144 | }
|
145 | else {
|
146 |
|
147 | const newJs = js_transform_1.jsTransform(dom5.getTextContent(script), Object.assign({}, jsOptions, { transformModulesToAmd: true }));
|
148 | dom5.setTextContent(script, newJs);
|
149 | }
|
150 | }
|
151 | function addWctTimingHack(wctScript, amdLoaderScript) {
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | dom5.insertBefore(wctScript.parentNode, wctScript, parse5.parseFragment(`
|
167 | <script>
|
168 | // Injected by polymer-build to defer WCT until all AMD modules are loaded.
|
169 | (function() {
|
170 | window.WCT = window.WCT || {};
|
171 | var originalWaitFor = window.WCT.waitFor;
|
172 | window.WCT.waitFor = function(cb) {
|
173 | window._wctCallback = function() {
|
174 | if (originalWaitFor) {
|
175 | originalWaitFor(cb);
|
176 | } else {
|
177 | cb();
|
178 | }
|
179 | };
|
180 | };
|
181 | }());
|
182 | </script>
|
183 | `));
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | dom5.insertAfter(amdLoaderScript.parentNode, amdLoaderScript, parse5.parseFragment(`
|
189 | <script>
|
190 | // Injected by polymer-build to defer WCT until all AMD modules are loaded.
|
191 | (function() {
|
192 | var originalDefine = window.define;
|
193 | var moduleCount = 0;
|
194 | window.define = function(deps, factory) {
|
195 | moduleCount++;
|
196 | originalDefine(deps, function() {
|
197 | if (factory) {
|
198 | factory.apply(undefined, arguments);
|
199 | }
|
200 | moduleCount--;
|
201 | if (moduleCount === 0) {
|
202 | window._wctCallback();
|
203 | }
|
204 | });
|
205 | };
|
206 | })();
|
207 | </script>
|
208 | `));
|
209 | }
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | function removeFakeNodes(document) {
|
220 | const suspects = [];
|
221 | const html = (document.childNodes || []).find((child) => child.tagName === 'html');
|
222 | if (html !== undefined) {
|
223 | suspects.push(html);
|
224 | for (const child of html.childNodes || []) {
|
225 | if (child.tagName === 'head' || child.tagName === 'body') {
|
226 | suspects.push(child);
|
227 | }
|
228 | }
|
229 | }
|
230 | for (const suspect of suspects) {
|
231 |
|
232 | if (!suspect.__location) {
|
233 | dom5.removeNodeSaveChildren(suspect);
|
234 | }
|
235 | }
|
236 | }
|
237 |
|
\ | No newline at end of file |