UNPKG

5.85 kBJavaScriptView Raw
1var FS = require('fs'),
2 PATH = require('path'),
3 FREEZE = require('./freeze'),
4 INHERIT = require('inherit'),
5 U = require('./util'),
6 VOW = require('vow');
7
8function _inherit(d, s) {
9 return INHERIT(this, d, s);
10}
11
12exports.Tech = INHERIT({
13
14 __constructor: function(opts) {
15 this.opts = opts;
16
17 /**
18 * Hash of processed files to remove duplicates.
19 * @type {Object}
20 */
21 this.processedFiles = {};
22 },
23
24 createFile: function(path, type, parent) {
25 var file = new this.File(this, path, type, parent);
26 if (type == 'include') file.read();
27 return file;
28 },
29
30 process: function() {
31 var res;
32 var path = this.opts.input;
33 if (path) {
34 res = this.createFile(path, 'include').process(path);
35 } else {
36 var fakeFile = PATH.join(this.opts.basePath, 'borschik.fakefile');
37 var file = new this.File(this, fakeFile, 'include');
38 file.content = file.parse(this.opts.inputString);
39 //TODO: i call ctor with path and then call method with same path. WTF?
40 res = file.process(fakeFile);
41 }
42 // NOTE: Passing path of source file into process(). This could lead to
43 // incorrect paths in the resulting file if it will be stored in another
44 // directory then source file.
45
46 var out = this.opts.output;
47 if (this.opts.minimize) {
48 try {
49 res = this.minimize(res);
50
51 } catch(e) {
52 if (this.opts.inputString && !out.path) {
53 return VOW.reject(e);
54 }
55
56 var errorMessage = e.toString();
57
58 // if output is the path
59 if (out.path) {
60 // close current output stream
61 out.end();
62
63 if (path != out.path) {
64 try {
65 // remove empty output file if input != ouput
66 FS.unlinkSync(out.path);
67 } catch(e) {}
68 }
69 }
70
71 // open new stream for error result
72 var errorFilename;
73 if (out.path) {
74 errorFilename = out.path + '.borschik-error';
75 } else {
76 errorFilename = PATH.resolve(process.cwd(), 'borschik-error');
77 }
78
79 out = FS.createWriteStream(errorFilename, {
80 encoding: 'utf8'
81 });
82
83 errorMessage += '\nError result in ' + errorFilename;
84
85 return this.write(out, res).then(function() {
86 throw new Error(errorMessage);
87 });
88 }
89 }
90
91 if (this.opts.inputString && !this.opts.output.path) {
92 return VOW.resolve(res);
93 } else {
94 return this.write(out, res);
95 }
96 },
97
98 write: U.writeFile,
99
100 minimize: function(content) {
101 return content;
102 },
103
104 File: exports.File = INHERIT({
105
106 __constructor: function(tech, path, type, parent) {
107 this.tech = tech;
108 // realpathSync processes path with "follow_symlinks" directive
109 this.path = PATH.resolve(PATH.dirname(path), FREEZE.realpathSync(path));
110 this.childType = type || 'include';
111 this.parent = parent;
112 this.children = {};
113 },
114
115 read: function() {
116 this.content = this.parse(FS.readFileSync(this.processPath(this.path)));
117 return this;
118 },
119
120 processPath: function(path) {
121 return path;
122 },
123
124 parse: function(content) {
125 return this.childType == 'include'?
126 this.parseInclude(content) : this.parseLink(content);
127 },
128
129 parseInclude: function(content) {
130 return content;
131 },
132
133 parseLink: function(content) {
134 return this.path;
135 },
136
137 process: function(path) {
138 return this.childType == 'include'?
139 this.processInclude(path) : this.processLink(path);
140 },
141
142 processInclude: function(path) {
143 return this.content;
144 },
145
146 processLink: function(path) {
147 return this.pathFrom(path);
148 },
149
150 child: function(type, path) {
151 var children = this.children,
152 key = type + '|' + path;
153 return children[key] || (children[key] = this.tech.createFile(this.pathTo(path), type, this));
154 },
155
156 /**
157 * Returns absolute path to resource relative to current file.
158 * @param {string} resourcePath Path to resource relative to current file.
159 * @returns {string}
160 * @example
161 * // current file (this.path) /home/user/site/css/page.css
162 * this.pathTo(img/bg.png); // /home/user/site/css/img/bg.png
163 */
164 pathTo: function(resourcePath) {
165 return U.pathToUnix(PATH.resolve(PATH.dirname(this.path), resourcePath));
166 },
167
168 pathFrom: function(path) {
169 return U.pathToUnix(PATH.relative(PATH.dirname(path), this.path));
170 }
171
172 }, {
173 inherit: _inherit
174 })
175
176 }, {
177 inherit: _inherit
178 });