UNPKG

5.53 kBtext/coffeescriptView Raw
1_ = require 'lodash'
2async = require 'async'
3glob = require 'glob'
4path = require 'path'
5fs = require 'fs'
6eco = require 'eco'
7
8dir = __dirname
9
10# Place all moulds/templates here.
11moulds = {}
12
13# Place all source file handlers here.
14handlers = {}
15
16# We start not initialized yet.
17ready = no
18
19# Call these functions when we are ready.
20callbacks = []
21
22# Initialize the builder.
23async.parallel
24
25 # The moulds.
26 'moulds': (cb) ->
27 async.waterfall [ (cb) ->
28 glob dir + '/moulds/**/*.eco.js', cb
29
30 , (files, cb) ->
31 # Process in parallel.
32 async.each files, (file, cb) ->
33 # Is it a file?
34 fs.stat file, (err, stats) ->
35 return cb err if err
36
37 # Skip directories.
38 return cb null unless do stats.isFile
39
40 # Read the mould.
41 fs.readFile file, 'utf8', (err, mould) ->
42 return cb err if err
43
44 # Get a relative from the file.
45 pointer = moulds
46 for i, part of parts = file.match(/moulds\/(.*)\.eco\.js$/)[1].split('/')
47 if parts.length is +i + 1
48 # Make into an Eco function.
49 pointer[part] = (context) ->
50 eco.render mould, context
51 else
52 pointer = pointer[part] ?= {}
53
54 cb null
55 , cb
56
57 ], cb
58
59 # The handlers.
60 'handlers': (cb) ->
61 async.waterfall [ (cb) ->
62 glob dir + '/handlers/**/*.coffee', cb
63
64 , (files, cb) ->
65 # Require them.
66 for file in files
67 name = path.basename file, '.coffee'
68 handlers[name] = require file
69
70 do cb
71
72 ], cb
73
74
75, (err) ->
76 # Trouble?
77 process.exit(1) if err
78
79 # Dequeue.
80 ready = yes
81 ( do cb for cb in callbacks )
82
83commonjs = (grunt, cb) ->
84 pkg = grunt.config.data.pkg
85
86 # For each in/out config.
87 async.each @files, (file, cb) =>
88 sources = file.src
89 destination = path.normalize file.dest
90
91 # Any opts?
92 opts = @options
93 # Main index file.
94 'main': do ->
95 # A) Use the main file in `package.json`.
96 return pkg.main if pkg?.main
97
98 # B) Find the index file closest to the root.
99 _(sources)
100 .filter((source) ->
101 # Coffee and JS files supported.
102 source.match /index\.(coffee|js)$/
103 ).sort((a, b) ->
104 score = (input) -> input.split('/').length
105 score(a) - score(b)
106 ).value()[0]
107
108 # Package name.
109 'name': pkg.name if pkg?.name
110
111 # Make package name into names.
112 return cb 'Package name is not defined' unless opts.name
113
114 opts.name = [ opts.name ] unless _.isArray opts.name
115
116 # Not null?
117 return cb 'Main index file not defined' unless opts.main
118
119 # Does the index file actually exist?
120 return cb "Main index file #{opts.main.bold} does not exist" unless opts.main in sources
121
122 # Say we use this index file.
123 grunt.log.writeln "Using index file #{opts.main.bold}".yellow
124
125 # Remove the extension. It will be a `.js` one.
126 opts.main = opts.main.split('.')[0...-1].join('.')
127
128 # For each source.
129 async.map sources, (source, cb) ->
130 # Find the handler.
131 unless handler = handlers[ext = path.extname(source)[1...]] # sans dot
132 return cb "Unrecognized file extension #{ext.bold}"
133
134 # Run the handler.
135 handler source, (err, result) ->
136 return cb source + ': ' + do err.toString if err
137
138 # Wrap it in the module registry.
139 cb null, moulds.commonjs.module
140 'package': opts.name[0]
141 'path': source
142 'script': moulds.lines
143 'spaces': 2
144 'lines': result
145
146 # Merge it into a destination file.
147 , (err, modules) ->
148 return cb err if err
149
150 # Nicely format the modules.
151 modules = _.map modules, (module) ->
152 moulds.lines 'spaces': 4, 'lines': module
153
154 # Write a vanilla version and one packing a requirerer.
155 out = moulds.commonjs.loader
156 'modules': modules
157 'packages': opts.name
158 'main': opts.main
159
160 # Write it.
161 fs.writeFile destination, out, cb
162
163 , cb
164
165module.exports = (grunt) ->
166 grunt.registerMultiTask 'apps_c', 'Apps/C - CoffeeScript, JavaScript, Eco', ->
167 # Run in async.
168 done = do @async
169
170 # Wrapper for error logging.
171 cb = (err) ->
172 return do done unless err
173 grunt.log.error (do err.toString).red
174 done false
175
176 # Once our builder is ready...
177 onReady = =>
178 # The targets we support.
179 switch
180 when @target.match /^commonjs/
181 commonjs.apply @, [ grunt, cb ]
182 else
183 cb "Unsupported target `#{@target}`"
184
185 # Hold your horses?
186 return do onReady if ready
187 callbacks.push onReady
\No newline at end of file