1 | "use strict";
|
2 |
|
3 | var series = require('async').series;
|
4 | var clone = require('clone');
|
5 | var compile = require('es6-templates').compile;
|
6 | var extend = require('extend');
|
7 | var fs = require('fs');
|
8 | var isarray = require('isarray');
|
9 | var join = require('path').join;
|
10 | var dirname = require('path').dirname;
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | var defaults = {
|
16 | base: '/',
|
17 | target: 'es6',
|
18 | indent: 2,
|
19 | useRelativePaths: false,
|
20 | removeLineBreaks: false,
|
21 | templateExtension: '.html',
|
22 | templateFunction: false,
|
23 | templateProcessor: defaultProcessor,
|
24 | styleProcessor: defaultProcessor,
|
25 | customFilePath: defaultCustomFilePath,
|
26 | supportNonExistentFiles: false
|
27 | };
|
28 |
|
29 | function defaultProcessor(path, file, cb) {
|
30 | return cb(null, file);
|
31 | }
|
32 |
|
33 | function defaultCustomFilePath(ext, path) {
|
34 | return path;
|
35 | }
|
36 |
|
37 | var htmlOptions = function (opts) {
|
38 | return {
|
39 | type: 'html',
|
40 | prop_url: 'templateUrl',
|
41 | prop: 'template',
|
42 | start_pattern: /templateUrl\s*:.*/,
|
43 | end_pattern: new RegExp('.*\\' + opts.templateExtension + '\s*(\'\\)|\')|.*\\' + opts.templateExtension + '\s*("\\)|")'),
|
44 | oneliner_pattern: new RegExp('templateUrl.*(\\' + opts.templateExtension + '\s*(\'\\)|\')|\\' + opts.templateExtension + 's*("\\)|"))')
|
45 | };
|
46 | };
|
47 |
|
48 | var cssOptions = function () {
|
49 | return {
|
50 | type: 'css',
|
51 | prop_url: 'styleUrls',
|
52 | prop: 'styles',
|
53 | start_pattern: /styleUrls\s*:.*/,
|
54 | end_pattern: /.*]/,
|
55 | oneliner_pattern: /styleUrls(.*?)]/
|
56 | };
|
57 | };
|
58 |
|
59 |
|
60 | module.exports = function parser(file, options) {
|
61 | var opts = extend({}, defaults, (options || {}));
|
62 | var lines = file.contents.toString().replace(/\r/g, '').split('\n');
|
63 | var start_line_idx, end_line_idx, frag;
|
64 | var HTML = false;
|
65 | var CSS = false;
|
66 |
|
67 | return function parse(done) {
|
68 | series([
|
69 | processTemplate,
|
70 | processStyles
|
71 | ], function () {
|
72 | done(null, lines.join('\n'));
|
73 | });
|
74 | };
|
75 |
|
76 |
|
77 | function processTemplate(done) {
|
78 | if (opts.templateProcessor) {
|
79 | HTML = true;
|
80 | extend(opts, htmlOptions(opts));
|
81 | execute(function () {
|
82 | reset();
|
83 | done(null);
|
84 | });
|
85 | }
|
86 | }
|
87 |
|
88 | function processStyles(done) {
|
89 | if (opts.styleProcessor) {
|
90 | CSS = true;
|
91 | extend(opts, cssOptions());
|
92 | execute(function () {
|
93 | reset();
|
94 | done(null);
|
95 | });
|
96 | }
|
97 | }
|
98 |
|
99 | function execute(done) {
|
100 | var seriesArray = [];
|
101 |
|
102 | for(var i = 0; i < lines.length; i++) {
|
103 | (function (i) {
|
104 | seriesArray.push(function (cb) {
|
105 | var idx = i;
|
106 | var line = lines[idx];
|
107 | getIndexes(line, idx);
|
108 | if (i === end_line_idx && start_line_idx) {
|
109 | series([
|
110 | getFragment,
|
111 | replaceFrag
|
112 | ], cb);
|
113 | } else {
|
114 | cb(null);
|
115 | }
|
116 | });
|
117 | }(i));
|
118 | }
|
119 |
|
120 | series(seriesArray, done);
|
121 | }
|
122 |
|
123 | function getIndexes(line, i) {
|
124 | if (opts.start_pattern.test(line)) {
|
125 | start_line_idx = i;
|
126 | }
|
127 | if (opts.end_pattern.test(line)) {
|
128 |
|
129 |
|
130 | if (start_line_idx <= end_line_idx) return;
|
131 | end_line_idx = i;
|
132 | }
|
133 | }
|
134 |
|
135 | function getFragment(cb) {
|
136 | var fragStart, fragEnd;
|
137 | if (start_line_idx < 0 || end_line_idx < 0) return cb();
|
138 |
|
139 | if (start_line_idx === end_line_idx) {
|
140 | frag = opts.oneliner_pattern.exec(lines[start_line_idx])[0];
|
141 | }
|
142 |
|
143 | if (start_line_idx < end_line_idx) {
|
144 | fragStart = opts.start_pattern.exec(lines[start_line_idx])[0];
|
145 | fragEnd = opts.end_pattern.exec(lines[end_line_idx])[0];
|
146 | frag = concatLines();
|
147 | }
|
148 |
|
149 | cb();
|
150 |
|
151 | function concatLines() {
|
152 | var _lines = clone(lines);
|
153 | _lines[start_line_idx] = fragStart;
|
154 | _lines[end_line_idx] = fragEnd;
|
155 | return _lines.splice(start_line_idx, end_line_idx - start_line_idx + 1).join('');
|
156 | }
|
157 | }
|
158 |
|
159 | function replaceFrag(cb) {
|
160 | var _urls;
|
161 | var fnIndex = frag.indexOf('(');
|
162 | if (fnIndex > -1 && opts.templateFunction) {
|
163 |
|
164 | _urls = opts.templateFunction(/'(.*)'/.exec(frag)[1]);
|
165 | } else {
|
166 | _urls = eval('({' + frag + '})')[opts.prop_url];
|
167 | }
|
168 |
|
169 | var urls = isarray(_urls) ? _urls : [_urls];
|
170 | var line = lines[start_line_idx];
|
171 | var indentation = /^\s*/.exec(line)[0];
|
172 | var assetFiles = '';
|
173 | var startOfInsertionBlock = '\n';
|
174 | var endOfInsertionBlock = '\n';
|
175 |
|
176 | series([
|
177 | getFilesAndApplyCustomProcessor,
|
178 | _replaceFrag
|
179 | ], cb);
|
180 |
|
181 | function _replaceFrag(cb) {
|
182 |
|
183 | assetFiles = assetFiles.replace(/(\n*)$/, '').replace(/`/g, '\\`');
|
184 |
|
185 |
|
186 | if(!opts.removeLineBreaks) {
|
187 |
|
188 | assetFiles = indent(assetFiles);
|
189 | }
|
190 |
|
191 | if(opts.removeLineBreaks) {
|
192 | assetFiles = removeLineBreaks(assetFiles);
|
193 |
|
194 | indentation = '';
|
195 | startOfInsertionBlock = '';
|
196 | endOfInsertionBlock = '';
|
197 | }
|
198 |
|
199 |
|
200 | if ('html' === opts.type)
|
201 | assetFiles = opts.prop + ': `' + startOfInsertionBlock + assetFiles + endOfInsertionBlock + indentation + '`';
|
202 | if ('css' === opts.type)
|
203 | assetFiles = opts.prop + ': [`' + startOfInsertionBlock + assetFiles + endOfInsertionBlock + indentation + '`]';
|
204 | if ('es5' === opts.target) assetFiles = compile(assetFiles).code;
|
205 |
|
206 |
|
207 | if (start_line_idx === end_line_idx) {
|
208 | lines[start_line_idx] = line.replace(opts.oneliner_pattern, assetFiles);
|
209 | }
|
210 |
|
211 | if (start_line_idx < end_line_idx) {
|
212 | if (/(,)$/.test(lines[end_line_idx])) assetFiles += ',';
|
213 | lines[start_line_idx] = line.replace(opts.start_pattern, assetFiles);
|
214 | lines.splice(start_line_idx + 1, end_line_idx - start_line_idx);
|
215 | }
|
216 |
|
217 | cb(null);
|
218 | }
|
219 |
|
220 | function getFilesAndApplyCustomProcessor(cb) {
|
221 | series(urls.map(function (url) {
|
222 | return function (cb) {
|
223 | var file = getFile(url);
|
224 | var ext = /\.[0-9a-z]+$/i.exec(url);
|
225 | if (HTML && opts.templateProcessor) {
|
226 | process.nextTick(function () {
|
227 | opts.templateProcessor(ext, file, customProcessorCallback(cb));
|
228 | });
|
229 | }
|
230 | if (CSS && opts.styleProcessor) {
|
231 | process.nextTick(function () {
|
232 | opts.styleProcessor(ext, file, customProcessorCallback(cb));
|
233 | });
|
234 | }
|
235 | };
|
236 | }), cb);
|
237 |
|
238 | function customProcessorCallback(cb) {
|
239 | return function (err, file) {
|
240 | if (err) return cb(err);
|
241 | assetFiles += file;
|
242 | process.nextTick(cb);
|
243 | };
|
244 | }
|
245 | }
|
246 |
|
247 | function getFile(filepath) {
|
248 | var absPath = opts.useRelativePaths ? join(dirname(file.path), filepath)
|
249 | : join(process.cwd(), opts.base, filepath);
|
250 |
|
251 | if(opts.supportNonExistentFiles && !fs.existsSync(absPath)) {
|
252 | return '';
|
253 | }
|
254 |
|
255 | var ext = /\.[0-9a-z]+$/i.exec(absPath);
|
256 | absPath = opts.customFilePath(ext, absPath);
|
257 |
|
258 | return fs.readFileSync(absPath)
|
259 | .toString()
|
260 | .replace(/\r/g, '')
|
261 | .replace(/[\u200B-\u200D\uFEFF]/g, '');
|
262 | }
|
263 |
|
264 | function indent(str) {
|
265 | var lines = [];
|
266 | var spaces = '';
|
267 | for (var i = 0; i < indentation.length + opts.indent; i++) { spaces += ' '; }
|
268 | str.split('\n').forEach(function (line) {
|
269 |
|
270 | lines.push((/^(\s*)$/.test(line) ? '' : spaces) + line);
|
271 | });
|
272 | return lines.join('\n');
|
273 | }
|
274 |
|
275 | function removeLineBreaks(str) {
|
276 | return str.replace(/(\r\n|\n|\r)/gm," ");
|
277 | }
|
278 | }
|
279 |
|
280 | function reset() {
|
281 | start_line_idx = undefined;
|
282 | end_line_idx = undefined;
|
283 | frag = undefined;
|
284 | HTML = false;
|
285 | CSS = false;
|
286 | }
|
287 | };
|