1 | 'use strict';
|
2 |
|
3 | var path = require('path');
|
4 | var join = path.join;
|
5 | var mime = require('mime');
|
6 | var File = require('vinyl');
|
7 | var urlparse = require('url').parse;
|
8 | var debug = require('debug')('serve-spm:koa');
|
9 |
|
10 | var util = require('./util');
|
11 | var parse = require('./parse');
|
12 | var transport = require('./transport');
|
13 |
|
14 | module.exports = function(root, opts) {
|
15 | opts = opts || {};
|
16 | var log = opts.log || function() {};
|
17 | var ignore = Array.isArray(opts.ignore) ? opts.ignore : [];
|
18 |
|
19 | return function*(next) {
|
20 | if (Array.isArray(opts.paths)) {
|
21 | opts.paths.forEach(function(p) {
|
22 | this.url = this.url.replace(p[0], p[1]);
|
23 | }.bind(this));
|
24 | }
|
25 |
|
26 | if (opts.base) {
|
27 | var basepath = urlparse(opts.base).pathname;
|
28 | basepath = basepath.replace(/\/$/, '');
|
29 | this.url = this.url.replace(basepath, '');
|
30 | }
|
31 |
|
32 | debug('parse url %s', this.url);
|
33 | var pkg = util.getPackage(root);
|
34 | var rootPkg = pkg;
|
35 | var match;
|
36 | if (pkg && (match = util.matchNameVersion(this.url))) {
|
37 | pkg = pkg.getPackage(match.name + '@' + match.version);
|
38 | }
|
39 | if (!pkg) {
|
40 | debug('can not find local module of %s', this.url);
|
41 | return yield* next;
|
42 | }
|
43 |
|
44 | var file;
|
45 | if (this.body) {
|
46 | file = new File({
|
47 | base: pkg.dest,
|
48 | path: join(pkg.dest, this.url),
|
49 | contents: new Buffer(this.body)
|
50 | });
|
51 | file.url = urlparse(this.url);
|
52 | file.pkg = pkg;
|
53 | file.wrap = true;
|
54 | } else {
|
55 | file = parse(this.url, {
|
56 | rootPkg: rootPkg,
|
57 | pkg: pkg,
|
58 | rules: opts.rules
|
59 | });
|
60 | }
|
61 |
|
62 | if (!file) {
|
63 | debug('cat not find matched file of %s', this.url);
|
64 | return yield* next;
|
65 | }
|
66 |
|
67 | if (opts.cache) {
|
68 | var modifiedTime = util.getModifiedTime(file);
|
69 | this.set('Last-Modified', modifiedTime);
|
70 | if (!util.isModified(this.header, modifiedTime)) {
|
71 | debug('file %s is not modified', file.path);
|
72 | this.status = 304;
|
73 | return;
|
74 | }
|
75 | }
|
76 |
|
77 | log('>> ServeSPM %s < ./%s',
|
78 | file.url.pathname, path.relative(process.cwd(), file.path));
|
79 |
|
80 |
|
81 | var data, ext;
|
82 | if (!file.wrap || this.headers['x-requested-with'] === 'XMLHttpRequest') {
|
83 | debug('return unwrapped file %s', file.path);
|
84 | data = file.contents;
|
85 | ext = path.extname(file.path);
|
86 | }
|
87 |
|
88 | else {
|
89 |
|
90 | debug('return transported file %s', file.path);
|
91 | file = yield transportThunk(file, {
|
92 | pkg: pkg,
|
93 | ignore: ignore,
|
94 | base: opts.base
|
95 | });
|
96 | data = file.contents;
|
97 | ext = path.extname(file.path);
|
98 | }
|
99 |
|
100 | if (['.tpl', '.json', '.handlebars'].indexOf(ext) > -1) {
|
101 | ext = '.js';
|
102 | }
|
103 | this.set('Content-Type', mime.lookup(ext));
|
104 | this.body = data;
|
105 | this.status = 200;
|
106 | };
|
107 | };
|
108 |
|
109 | module.exports.util = util;
|
110 |
|
111 | function transportThunk(file, opt) {
|
112 | return function(cb) {
|
113 | transport(file, opt, cb);
|
114 | };
|
115 | }
|