1 |
|
2 | (function() {
|
3 | var EventEmitter, async, crypto, extend, fs, mime, pathutil, zlib,
|
4 | __hasProp = {}.hasOwnProperty,
|
5 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
6 |
|
7 | async = require('async');
|
8 |
|
9 | crypto = require('crypto');
|
10 |
|
11 | pathutil = require('path');
|
12 |
|
13 | fs = require('fs');
|
14 |
|
15 | zlib = require('zlib');
|
16 |
|
17 | mime = require('mime');
|
18 |
|
19 | extend = require('./util').extend;
|
20 |
|
21 | EventEmitter = require('events').EventEmitter;
|
22 |
|
23 | mime.types.js = 'text/javascript';
|
24 |
|
25 | mime.extensions['text/javascript'] = 'js';
|
26 |
|
27 | exports.Asset = (function(_super) {
|
28 | __extends(Asset, _super);
|
29 |
|
30 | Asset.prototype.defaultMaxAge = 60 * 60 * 24 * 365;
|
31 |
|
32 | function Asset(options) {
|
33 | var headers, key, value, _ref, _ref1, _ref2, _ref3,
|
34 | _this = this;
|
35 |
|
36 | Asset.__super__.constructor.call(this);
|
37 | if (options == null) {
|
38 | options = {};
|
39 | }
|
40 | if (options.url != null) {
|
41 | this.url = options.url;
|
42 | }
|
43 | if (options.contents != null) {
|
44 | this.contents = options.contents;
|
45 | }
|
46 | this.headers = options.headers ? options.headers : {};
|
47 | headers = {};
|
48 | _ref = this.headers;
|
49 | for (key in _ref) {
|
50 | value = _ref[key];
|
51 | headers[key.toLowerCase()] = value;
|
52 | }
|
53 | this.headers = headers;
|
54 | this.ext = pathutil.extname(this.url);
|
55 | this.watch = options.watch;
|
56 | if ((_ref1 = this.watch) == null) {
|
57 | this.watch = false;
|
58 | }
|
59 | if (options.mimetype != null) {
|
60 | this.mimetype = options.mimetype;
|
61 | }
|
62 | if ((_ref2 = this.mimetype) == null) {
|
63 | this.mimetype = mime.types[this.ext.slice(1, this.ext.length)];
|
64 | }
|
65 | if ((_ref3 = this.mimetype) == null) {
|
66 | this.mimetype = 'text/plain';
|
67 | }
|
68 | this.gzip = options.gzip;
|
69 | if (options.hash != null) {
|
70 | this.hash = options.hash;
|
71 | }
|
72 | if (options.maxAge != null) {
|
73 | this.maxAge = options.maxAge;
|
74 | }
|
75 | if (options.allowNoHashCache != null) {
|
76 | this.allowNoHashCache = options.allowNoHashCache;
|
77 | }
|
78 | this.on('newListener', function(event, listener) {
|
79 | if (event === 'complete' && _this.completed === true) {
|
80 | return listener();
|
81 | }
|
82 | });
|
83 | this.on('created', function(data) {
|
84 | if ((data != null ? data.contents : void 0) != null) {
|
85 | _this.contents = data.contents;
|
86 | }
|
87 | if ((data != null ? data.assets : void 0) != null) {
|
88 | _this.assets = data.assets;
|
89 | }
|
90 | if (_this.contents != null) {
|
91 | _this.createSpecificUrl();
|
92 | _this.createHeaders();
|
93 | }
|
94 | if (_this.assets != null) {
|
95 | async.forEach(_this.assets, function(asset, done) {
|
96 | asset.on('error', done);
|
97 | return asset.on('complete', done);
|
98 | }, function(error) {
|
99 | if (error != null) {
|
100 | return _this.emit('error', error);
|
101 | }
|
102 | _this.completed = true;
|
103 | return _this.emit('complete');
|
104 | });
|
105 | } else {
|
106 | _this.completed = true;
|
107 | if (_this.gzip) {
|
108 | zlib.gzip(_this.contents, function(error, gzip) {
|
109 | _this.gzipContents = gzip;
|
110 | return _this.emit('complete');
|
111 | });
|
112 | } else {
|
113 | _this.emit('complete');
|
114 | }
|
115 | }
|
116 | if (_this.watch) {
|
117 | return _this.watcher = fs.watch(_this.toWatch, function(event, filename) {
|
118 | if (event === 'change') {
|
119 | _this.watcher.close();
|
120 | _this.completed = false;
|
121 | _this.assets = false;
|
122 | return process.nextTick(function() {
|
123 | return _this.emit('start');
|
124 | });
|
125 | }
|
126 | });
|
127 | }
|
128 | });
|
129 | this.on('error', function(error) {
|
130 | if (_this.listeners('error') === 1) {
|
131 | throw error;
|
132 | }
|
133 | });
|
134 | this.on('start', function() {
|
135 | var _ref4, _ref5, _ref6, _ref7, _ref8;
|
136 |
|
137 | if ((_ref4 = _this.maxAge) == null) {
|
138 | _this.maxAge = (_ref5 = _this.rack) != null ? _ref5.maxAge : void 0;
|
139 | }
|
140 | if (_this.hash !== false) {
|
141 | if ((_ref6 = _this.maxAge) == null) {
|
142 | _this.maxAge = _this.defaultMaxAge;
|
143 | }
|
144 | }
|
145 | if ((_ref7 = _this.allowNoHashCache) == null) {
|
146 | _this.allowNoHashCache = (_ref8 = _this.rack) != null ? _ref8.allowNoHashCache : void 0;
|
147 | }
|
148 | return _this.create(options);
|
149 | });
|
150 | process.nextTick(function() {
|
151 | var _ref4;
|
152 |
|
153 | if ((_ref4 = _this.maxAge) == null) {
|
154 | _this.maxAge = _this.defaultMaxAge;
|
155 | }
|
156 | if (_this.rack == null) {
|
157 | return _this.create(options);
|
158 | }
|
159 | });
|
160 | }
|
161 |
|
162 | Asset.prototype.addAsset = function(asset) {
|
163 | if (this.assets == null) {
|
164 | this.assets = [];
|
165 | }
|
166 | return this.assets.push(asset);
|
167 | };
|
168 |
|
169 | Asset.prototype.respond = function(request, response) {
|
170 | var headers, key, value, _ref;
|
171 |
|
172 | headers = {};
|
173 | if (request.path === this.url && this.allowNoHashCache !== true) {
|
174 | _ref = this.headers;
|
175 | for (key in _ref) {
|
176 | value = _ref[key];
|
177 | headers[key] = value;
|
178 | }
|
179 | delete headers['cache-control'];
|
180 | } else {
|
181 | headers = this.headers;
|
182 | }
|
183 | for (key in headers) {
|
184 | value = headers[key];
|
185 | response.header(key, value);
|
186 | }
|
187 | if (this.gzip) {
|
188 | return response.send(this.gzipContents);
|
189 | } else {
|
190 | return response.send(this.contents);
|
191 | }
|
192 | };
|
193 |
|
194 | Asset.prototype.checkUrl = function(url) {
|
195 | return url === this.specificUrl || ((this.hash == null) && url === this.url);
|
196 | };
|
197 |
|
198 | Asset.prototype.handle = function(request, response, next) {
|
199 | var handle,
|
200 | _this = this;
|
201 |
|
202 | handle = function() {
|
203 | var asset, _i, _len, _ref;
|
204 |
|
205 | if (_this.assets != null) {
|
206 | _ref = _this.assets;
|
207 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
208 | asset = _ref[_i];
|
209 | if (asset.checkUrl(request.path)) {
|
210 | return asset.respond(request, response);
|
211 | }
|
212 | }
|
213 | }
|
214 | if (_this.checkUrl(request.path)) {
|
215 | return _this.respond(request, response);
|
216 | } else {
|
217 | return next();
|
218 | }
|
219 | };
|
220 | if (this.completed === true) {
|
221 | return handle();
|
222 | } else {
|
223 | return this.on('complete', function() {
|
224 | return handle();
|
225 | });
|
226 | }
|
227 | };
|
228 |
|
229 | Asset.prototype.create = function(options) {
|
230 | return this.emit('created');
|
231 | };
|
232 |
|
233 | Asset.prototype.createHeaders = function() {
|
234 | var _base, _base1, _base2, _ref, _ref1, _ref2;
|
235 |
|
236 | if ((_ref = (_base = this.headers)['content-type']) == null) {
|
237 | _base['content-type'] = "" + this.mimetype;
|
238 | }
|
239 | if (this.gzip) {
|
240 | if ((_ref1 = (_base1 = this.headers)['content-encoding']) == null) {
|
241 | _base1['content-encoding'] = 'gzip';
|
242 | }
|
243 | }
|
244 | if (this.maxAge != null) {
|
245 | return (_ref2 = (_base2 = this.headers)['cache-control']) != null ? _ref2 : _base2['cache-control'] = "public, max-age=" + this.maxAge;
|
246 | }
|
247 | };
|
248 |
|
249 | Asset.prototype.tag = function() {
|
250 | var tag;
|
251 |
|
252 | switch (this.mimetype) {
|
253 | case 'text/javascript':
|
254 | tag = "\n<script type=\"" + this.mimetype + "\" ";
|
255 | return tag += "src=\"" + this.specificUrl + "\"></script>";
|
256 | case 'text/css':
|
257 | return "\n<link rel=\"stylesheet\" href=\"" + this.specificUrl + "\">";
|
258 | }
|
259 | };
|
260 |
|
261 | Asset.prototype.createSpecificUrl = function() {
|
262 | this.md5 = crypto.createHash('md5').update(this.contents).digest('hex');
|
263 | if (this.hash === false) {
|
264 | this.useDefaultMaxAge = false;
|
265 | return this.specificUrl = this.url;
|
266 | }
|
267 | this.specificUrl = "" + (this.url.slice(0, this.url.length - this.ext.length)) + "-" + this.md5 + this.ext;
|
268 | if (this.hostname != null) {
|
269 | return this.specificUrl = "//" + this.hostname + this.specificUrl;
|
270 | }
|
271 | };
|
272 |
|
273 | Asset.extend = extend;
|
274 |
|
275 | return Asset;
|
276 |
|
277 | })(EventEmitter);
|
278 |
|
279 | }).call(this);
|