1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
16 | return new (P || (P = Promise))(function (resolve, reject) {
|
17 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
18 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
19 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
20 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
21 | });
|
22 | };
|
23 | var __asyncValues = (this && this.__asyncValues) || function (o) {
|
24 | if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
25 | var m = o[Symbol.asyncIterator], i;
|
26 | return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
27 | function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
28 | function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
29 | };
|
30 | var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
31 | var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
32 | if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
33 | var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
34 | return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
35 | function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
36 | function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
37 | function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
38 | function fulfill(value) { resume("next", value); }
|
39 | function reject(value) { resume("throw", value); }
|
40 | function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
41 | };
|
42 | Object.defineProperty(exports, "__esModule", { value: true });
|
43 | const assert = require("assert");
|
44 | const dom5 = require("dom5/lib/index-next");
|
45 | const parse5 = require("parse5");
|
46 | const osPath = require("path");
|
47 | const File = require("vinyl");
|
48 | const streams_1 = require("./streams");
|
49 | const pred = dom5.predicates;
|
50 | const extensionsForType = {
|
51 | 'text/ecmascript-6': 'js',
|
52 | 'application/javascript': 'js',
|
53 | 'text/javascript': 'js',
|
54 | 'application/x-typescript': 'ts',
|
55 | 'text/x-typescript': 'ts',
|
56 | 'module': 'js',
|
57 | };
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 | class HtmlSplitter {
|
66 | constructor() {
|
67 | this._splitFiles = new Map();
|
68 | this._parts = new Map();
|
69 | }
|
70 | |
71 |
|
72 |
|
73 |
|
74 | split() {
|
75 | return new HtmlSplitTransform(this);
|
76 | }
|
77 | |
78 |
|
79 |
|
80 |
|
81 |
|
82 | rejoin() {
|
83 | return new HtmlRejoinTransform(this);
|
84 | }
|
85 | isSplitFile(parentPath) {
|
86 | return this._splitFiles.has(parentPath);
|
87 | }
|
88 | getSplitFile(parentPath) {
|
89 |
|
90 |
|
91 |
|
92 | let splitFile = this._splitFiles.get(parentPath);
|
93 | if (!splitFile) {
|
94 | splitFile = new SplitFile(parentPath);
|
95 | this._splitFiles.set(parentPath, splitFile);
|
96 | }
|
97 | return splitFile;
|
98 | }
|
99 | addSplitPath(parentPath, childPath) {
|
100 | const splitFile = this.getSplitFile(parentPath);
|
101 | splitFile.addPartPath(childPath);
|
102 | this._parts.set(childPath, splitFile);
|
103 | }
|
104 | getParentFile(childPath) {
|
105 | return this._parts.get(childPath);
|
106 | }
|
107 | }
|
108 | exports.HtmlSplitter = HtmlSplitter;
|
109 | const htmlSplitterAttribute = 'html-splitter';
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | function scriptWasSplitByHtmlSplitter(script) {
|
115 | return dom5.hasAttribute(script, htmlSplitterAttribute);
|
116 | }
|
117 | exports.scriptWasSplitByHtmlSplitter = scriptWasSplitByHtmlSplitter;
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | function isHtmlSplitterFile(file) {
|
123 | return file.fromHtmlSplitter === true;
|
124 | }
|
125 | exports.isHtmlSplitterFile = isHtmlSplitterFile;
|
126 |
|
127 |
|
128 |
|
129 | class SplitFile {
|
130 | constructor(path) {
|
131 | this.parts = new Map();
|
132 | this.outstandingPartCount = 0;
|
133 | this.vinylFile = null;
|
134 | this.path = path;
|
135 | }
|
136 | addPartPath(path) {
|
137 | this.parts.set(path, null);
|
138 | this.outstandingPartCount++;
|
139 | }
|
140 | setPartContent(path, content) {
|
141 | assert(this.parts.get(path) !== undefined, `Trying to save unexpected file part "${path}".`);
|
142 | assert(this.parts.get(path) === null, `Trying to save already-saved file part "${path}".`);
|
143 | assert(this.outstandingPartCount > 0, `Trying to save valid file part "${path}", ` +
|
144 | `but somehow no file parts are outstanding.`);
|
145 | this.parts.set(path, content);
|
146 | this.outstandingPartCount--;
|
147 | }
|
148 | get isComplete() {
|
149 | return this.outstandingPartCount === 0 && this.vinylFile != null;
|
150 | }
|
151 | }
|
152 | exports.SplitFile = SplitFile;
|
153 |
|
154 |
|
155 |
|
156 | class HtmlSplitTransform extends streams_1.AsyncTransformStream {
|
157 | constructor(splitter) {
|
158 | super({ objectMode: true });
|
159 | this._state = splitter;
|
160 | }
|
161 | _transformIter(files) {
|
162 | return __asyncGenerator(this, arguments, function* _transformIter_1() {
|
163 | var e_1, _a;
|
164 | try {
|
165 | for (var files_1 = __asyncValues(files), files_1_1; files_1_1 = yield __await(files_1.next()), !files_1_1.done;) {
|
166 | const file = files_1_1.value;
|
167 | const filePath = osPath.normalize(file.path);
|
168 | if (!(file.contents && filePath.endsWith('.html'))) {
|
169 | yield yield __await(file);
|
170 | continue;
|
171 | }
|
172 | const contents = yield __await(streams_1.getFileContents(file));
|
173 | const doc = parse5.parse(contents, { locationInfo: true });
|
174 | dom5.removeFakeRootElements(doc);
|
175 | const scriptTags = [...dom5.queryAll(doc, pred.hasTagName('script'))];
|
176 | for (let i = 0; i < scriptTags.length; i++) {
|
177 | const scriptTag = scriptTags[i];
|
178 | const source = dom5.getTextContent(scriptTag);
|
179 | const typeAttribute = dom5.getAttribute(scriptTag, 'type') || 'application/javascript';
|
180 | const extension = extensionsForType[typeAttribute];
|
181 |
|
182 |
|
183 | if (!extension) {
|
184 | continue;
|
185 | }
|
186 | const isInline = !dom5.hasAttribute(scriptTag, 'src');
|
187 | if (isInline) {
|
188 | const childFilename = `${osPath.basename(filePath)}_script_${i}.${extension}`;
|
189 | const childPath = osPath.join(osPath.dirname(filePath), childFilename);
|
190 | scriptTag.childNodes = [];
|
191 | dom5.setAttribute(scriptTag, 'src', childFilename);
|
192 | dom5.setAttribute(scriptTag, htmlSplitterAttribute, '');
|
193 | const scriptFile = new File({
|
194 | cwd: file.cwd,
|
195 | base: file.base,
|
196 | path: childPath,
|
197 | contents: Buffer.from(source),
|
198 | });
|
199 | scriptFile.fromHtmlSplitter = true;
|
200 | scriptFile.isModule = typeAttribute === 'module';
|
201 | this._state.addSplitPath(filePath, childPath);
|
202 | this.push(scriptFile);
|
203 | }
|
204 | }
|
205 | const splitContents = parse5.serialize(doc);
|
206 | const newFile = new File({
|
207 | cwd: file.cwd,
|
208 | base: file.base,
|
209 | path: filePath,
|
210 | contents: Buffer.from(splitContents),
|
211 | });
|
212 | yield yield __await(newFile);
|
213 | }
|
214 | }
|
215 | catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
216 | finally {
|
217 | try {
|
218 | if (files_1_1 && !files_1_1.done && (_a = files_1.return)) yield __await(_a.call(files_1));
|
219 | }
|
220 | finally { if (e_1) throw e_1.error; }
|
221 | }
|
222 | });
|
223 | }
|
224 | }
|
225 |
|
226 |
|
227 |
|
228 |
|
229 | class HtmlRejoinTransform extends streams_1.AsyncTransformStream {
|
230 | constructor(splitter) {
|
231 | super({ objectMode: true });
|
232 | this._state = splitter;
|
233 | }
|
234 | _transformIter(files) {
|
235 | return __asyncGenerator(this, arguments, function* _transformIter_2() {
|
236 | var e_2, _a;
|
237 | try {
|
238 | for (var files_2 = __asyncValues(files), files_2_1; files_2_1 = yield __await(files_2.next()), !files_2_1.done;) {
|
239 | const file = files_2_1.value;
|
240 | const filePath = osPath.normalize(file.path);
|
241 | if (this._state.isSplitFile(filePath)) {
|
242 |
|
243 | const splitFile = this._state.getSplitFile(filePath);
|
244 | splitFile.vinylFile = file;
|
245 | if (splitFile.isComplete) {
|
246 | yield yield __await(yield __await(this._rejoin(splitFile)));
|
247 | }
|
248 | else {
|
249 | splitFile.vinylFile = file;
|
250 | }
|
251 | }
|
252 | else {
|
253 | const parentFile = this._state.getParentFile(filePath);
|
254 | if (parentFile) {
|
255 |
|
256 | parentFile.setPartContent(filePath, file.contents.toString());
|
257 | if (parentFile.isComplete) {
|
258 | yield yield __await(yield __await(this._rejoin(parentFile)));
|
259 | }
|
260 | }
|
261 | else {
|
262 | yield yield __await(file);
|
263 | }
|
264 | }
|
265 | }
|
266 | }
|
267 | catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
268 | finally {
|
269 | try {
|
270 | if (files_2_1 && !files_2_1.done && (_a = files_2.return)) yield __await(_a.call(files_2));
|
271 | }
|
272 | finally { if (e_2) throw e_2.error; }
|
273 | }
|
274 | });
|
275 | }
|
276 | _rejoin(splitFile) {
|
277 | return __awaiter(this, void 0, void 0, function* () {
|
278 | const file = splitFile.vinylFile;
|
279 | if (file == null) {
|
280 | throw new Error(`Internal error: no vinylFile found for splitfile: ${splitFile.path}`);
|
281 | }
|
282 | const filePath = osPath.normalize(file.path);
|
283 | const contents = yield streams_1.getFileContents(file);
|
284 | const doc = parse5.parse(contents, { locationInfo: true });
|
285 | dom5.removeFakeRootElements(doc);
|
286 | const scriptTags = dom5.queryAll(doc, HtmlRejoinTransform.isExternalScript);
|
287 | for (const scriptTag of scriptTags) {
|
288 | const srcAttribute = dom5.getAttribute(scriptTag, 'src');
|
289 | const scriptPath = osPath.join(osPath.dirname(splitFile.path), srcAttribute);
|
290 | const scriptSource = splitFile.parts.get(scriptPath);
|
291 | if (scriptSource != null) {
|
292 | dom5.setTextContent(scriptTag, scriptSource);
|
293 | dom5.removeAttribute(scriptTag, 'src');
|
294 | dom5.removeAttribute(scriptTag, htmlSplitterAttribute);
|
295 | }
|
296 | }
|
297 | const joinedContents = parse5.serialize(doc);
|
298 | return new File({
|
299 | cwd: file.cwd,
|
300 | base: file.base,
|
301 | path: filePath,
|
302 | contents: Buffer.from(joinedContents),
|
303 | });
|
304 | });
|
305 | }
|
306 | }
|
307 | HtmlRejoinTransform.isExternalScript = pred.AND(pred.hasTagName('script'), pred.hasAttr('src'));
|
308 |
|
\ | No newline at end of file |