UNPKG

2.75 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * Processor plugin. Useful for writing preprocessor plugins (like coffee). Compiled
5 * files are stored in cachePath
6 * @module Crixalis
7 * @submodule processor
8 * @for Controller
9 */
10
11var Crixalis = require('../controller'),
12 crypto = require('crypto'),
13 fs = require('fs'),
14 cache = {};
15
16function serveCache (filename) {
17 var result = this.results.pop(),
18 mtime = +result.mtime,
19 context = this.context,
20 error = this.error,
21 options = this.options,
22 cache = crypto.createHash('md5').update(filename + mtime).digest('hex'),
23 path = context.cachePath + '/' + cache + '.' + options.extension;
24
25 /* Try to serve compiled file */
26 context.serve(path, function (error) {
27 var chain = context.chain();
28
29 chain.context = context;
30 chain.error = error;
31 chain.options = options;
32 chain.path = path;
33
34 /*
35 * Compiled file was not found
36 * Setup new action chain to compile it
37 */
38 chain.append(fs.readFile, null, [filename]);
39 chain.append(before, chain);
40 chain.append(compile, chain, [filename]);
41 chain.append(after, chain);
42
43 chain.forward();
44 });
45
46 this.forward();
47}
48
49function before () {
50 this.data = this.results.pop().toString();
51
52 /* Change error handler */
53 this.error = onError;
54
55 this.forward();
56}
57
58function compile (filename) {
59 var result;
60
61 try {
62 result = this.options.compile.call(this, filename, this.data, this.options);
63 } catch (error) {
64 this.forward(error);
65 return;
66 }
67
68 if (!this.options.async) {
69 this.forward(undefined, result);
70 }
71}
72
73function after () {
74 var data = this.results.pop();
75
76 /* Write compiled file to disk */
77 this.append(fs.writeFile, undefined, [this.path, data]);
78
79 /* Finally send data ro client */
80 this.append(this.context.serve, this.context, [this.path]);
81
82 this.forward();
83}
84
85function notFound () {
86 this.context.emit('default');
87 this.context.render();
88}
89
90function onError (error) {
91 this.context.emit('error', error, true);
92}
93
94module.exports = function (options) {
95 if (!options || typeof options !== 'object') {
96 throw new Error('Options required');
97 }
98
99 if (typeof options.method !== 'string') {
100 throw new Error('options.method expected to be string');
101 }
102
103 if (typeof options.compile !== 'function') {
104 throw new Error('options.compile expected to be function');
105 }
106
107 options.extension = options.extension || method;
108
109 Crixalis.define('method', options.method, function (filename) {
110 var chain = this.chain();
111
112 if (typeof filename !== 'string') {
113 throw new Error('Filename expected to be string');
114 }
115
116 chain.context = this;
117 chain.error = notFound;
118 chain.options = options;
119
120 chain.append(fs.lstat, null, [filename]);
121 chain.append(serveCache, chain, [filename]);
122
123 chain.forward();
124
125 return this;
126 });
127};