UNPKG

3.58 kBJavaScriptView Raw
1'use strict';
2
3const fs = require('fs');
4const path = require('path');
5const async = require('async');
6const merge = require('merge');
7const sorcery = require('sorcery');
8
9const FileReader = require('./file-reader');
10
11class TransformChain {
12
13 constructor(transforms, cacheChain) {
14 this.transforms = transforms;
15 this.cacheChain = cacheChain;
16 }
17
18 _buildChain(localFilename, remoteFilename) {
19 var result = [];
20 // We're going to mutate array - so we copy it using concat.
21 var transforms = this.transforms.concat();
22
23 var getDstFilename = function() {
24 return {
25 local: ((result[result.length - 1] || {}).srcFilename || {}).local || localFilename,
26 remote: ((result[result.length - 1] || {}).srcFilename || {}).remote || remoteFilename
27 };
28 };
29
30 // Loop until no more transforms are found.
31 do {
32 var found = false;
33 for (var idx in transforms) {
34 var transform = transforms[idx];
35 var dstFilename = getDstFilename();
36 if (transform.canTransform(dstFilename.local)) {
37 result.push({
38 srcFilename: {
39 local: transform.map(dstFilename.local),
40 remote: transform.map(dstFilename.remote)
41 },
42 dstFilename: dstFilename,
43 transform: transform
44 });
45 transforms.splice(idx, 1);
46 found = true;
47 break;
48 }
49 }
50 if (!found) break;
51 } while (true);
52 result.push({
53 srcFilename: getDstFilename(),
54 dstFilename: getDstFilename(),
55 transform: new FileReader()
56 });
57 return result.reverse();
58 }
59
60 render(localFilename, remoteFilename, ctx) {
61 return new Promise((resolved, rejected) => {
62 this.cacheChain.get(localFilename).then((result) => {
63 if (result) return resolved(merge(result, { cached: true }));
64 var renderChain = this._buildChain(localFilename, remoteFilename);
65 async.forEachOfSeries(renderChain, (item, idx, next) => {
66 var lastResult = (renderChain[idx - 1] || {}).result || {};
67 item.transform.compile(item.srcFilename.local, lastResult.data, lastResult.map, ctx).then((itemResult) => {
68 if (!itemResult) return resolved();
69 async.reduce(itemResult.files || [], [], (files, file, next) => {
70 fs.access(file, (err) => {
71 next(null, files.concat(!err ? [file] : []));
72 });
73 }, (err, files) => {
74 if (err) return rejected(err);
75 item.result = merge(itemResult, {
76 files: files.map((filename) => {
77 return path.relative(path.dirname(localFilename), filename);
78 }),
79 modificationDate: new Date()
80 });
81 next();
82 });
83 }, next);
84 }, (err) => {
85 if (err) return rejected(err);
86 var lastResult = renderChain[renderChain.length - 1].result;
87 var files = renderChain.reduce((files, item) => {
88 return (files || []).concat(item.result.files || []);
89 }, []);
90 var uniqueFiles = [];
91 files.forEach((file) => {
92 if (uniqueFiles.indexOf(file) == -1) uniqueFiles.push(file);
93 });
94 lastResult = merge(lastResult, {
95 filename: localFilename,
96 files: uniqueFiles
97 });
98 if (lastResult.map) {
99 lastResult.map.sources = lastResult.map.files = lastResult.files;
100 lastResult.map.file = path.basename(remoteFilename);
101 lastResult.data = new Buffer(lastResult.data.toString().replace(/# sourceMappingURL=.+($| |\*)/, '# sourceMappingURL=' + path.basename(remoteFilename) + '.map'));
102 }
103 this.cacheChain.set(localFilename, lastResult).then(() => {
104 resolved(merge(lastResult, { cached: false }));
105 }, rejected);
106 });
107 }, rejected);
108 });
109 }
110
111}
112
113module.exports = exports = TransformChain;