UNPKG

8.99 kBtext/coffeescriptView Raw
1# This file contains a number of "factories" which describe how Ninja should process various kinds
2# of files. To define a new factory, call `defineFactory`, passing a name for the factory and
3# an a factory object.
4#
5# A factory is an object with one or more of the following properties:
6#
7# * `active` is either `true` or `false`, or else a `(config, log) ->` which returns `true` or
8# `false`. Defaults to `true`.
9#
10# * `initialize(ninja, config, log)` is called to setup the factory.
11#
12# * `assignments(ninja, config)` should run any `ninja.assign()` calls required to setup the
13# factor.
14#
15# * `makeRules(ninja, config)` should run a `ninja.rule()` command for the rule name. For src
16# rules, this should make a rule with the same name as the factory. For asset rules, this
17# should make a `name-debug` and `name-release` rule.
18#
19# * `targetExt` is a string containing a target extension that files will compile to. Defalts to
20# ".js"
21#
22# * `files` is an array of globule patterns which this factory will attempt to compile. Patterns
23# are relative to /src for 'src' factories. e.g. `['**/*._coffee']` for streamline coffee files.
24#
25# * `makeSrcEdge(ninja, source, target)` should make a ninja edge or edges required to build the
26# target file from the source file. This is used for compiling files from "src" to "lib".
27# This will only be called if `files` is set. This should return a list of generated edge names.
28#
29# * `assetFiles` - Like `files`, but relative to /assets. Used for asset edges.
30#
31# * `makeAssetEdge(ninja, source, target, releaseType)` should make a ninja edge or edges required
32# to build the target file from the source file. This is used for compiling assets.
33# `releaseType` will be either 'debug' or 'release'. This will only be called if `assetFiles` is
34# set. This should return a list of generated edge names.
35#
36# The following properties will be added to the factory before any methods are called:
37#
38# * `config` - The configuration from build-configure-ninja.
39# * `ninja` - The ninja instance being used.
40# * `log` - A log to write to.
41#
42path = require 'path'
43ld = require 'lodash'
44fs = require 'fs'
45{findCommandIfExists, findScript, findLocalCommand} = require './ninjaCommands'
46
47getCommand = (config, log, commandName, desc) ->
48 desc ?= commandName
49 answer = findCommandIfExists commandName, config
50 if !answer
51 log.warn "#{commandName} not found - disabling #{desc} support."
52 return answer
53
54allFactories = []
55
56defineFactory = exports.defineFactory = (name, factory) ->
57 factory.name = name
58 allFactories.push factory
59
60isFactoryActive = (factory, config, log) ->
61 active = false
62 if !factory.active
63 active = true
64 else
65 if ld.isFunction factory.active
66 active = factory.active config, log
67 else
68 active = factory.active
69
70 return active
71
72exports.forEachFactory = (fn) ->
73 for factory in allFactories
74 fn(factory)
75
76# Run a command for every factory available.
77exports.forActiveFactory = (config, log, fn) ->
78 for factory in allFactories
79 if isFactoryActive(factory, config, log)
80 fn(factory)
81
82#
83# /src factories
84# --------------
85#
86
87# Coffee compiler
88defineFactory "coffee", {
89 initialize: (ninja, config, log) ->
90 @_command = getCommand config, log, 'coffee'
91
92 active: (config, log) ->
93 return @_command?
94
95 assignments: (ninja, config) ->
96 ninja.assign 'coffee', @_command
97
98 makeRules: (ninja, config) ->
99 ninja.rule('coffee')
100 .run('$coffee -c -m -o $outDir $in')
101 .description 'COFFEE $in'
102
103 files: ['**/*.coffee', '**/*.litcoffee', '**/*.coffee.md']
104
105 makeSrcEdge: (ninja, source, target) ->
106 ninja.edge(target)
107 .from(source)
108 .using('coffee')
109 .assign('outDir', path.dirname target)
110 return [target]
111}
112
113# JavaScript files are copied to their destination.
114defineFactory "js", {
115 active: true
116 files: '**/*.js'
117 assetFiles: 'js/**/[a-z0-9]*.js'
118 makeSrcEdge: (ninja, source, target) ->
119 ninja.edge(target).from(source).using('copy')
120 return [target]
121 makeAssetEdge: (ninja, source, target, releaseType) -> @makeSrcEdge ninja, source, target
122
123}
124
125# JS and Coffee streamline factories
126makeStreamlineFactory = (name, ext, commandName) ->
127 return {
128 initialize: (ninja, config, log) ->
129 @_command = getCommand config, log, commandName, name
130 @oldStreamline = config.streamlineVersion < 10
131
132 active: (config, log) ->
133 return @_command?
134
135 assignments: (ninja, config) ->
136 if @oldStreamline
137 ninja.assign name, "node --harmony #{@_command}"
138 else
139 ninja.assign name, @_command
140
141 makeRules: (ninja, config) ->
142 if @oldStreamline
143 # No source-maps for streamline. You can add `--source-map $mapFile` here, but
144 # streamline will often crash in 0.8.0.
145 streamlineOpts = "-lp -c"
146 else
147 streamlineOpts = "-m -o $outDir -f -c"
148
149 ninja.rule(name)
150 .run("$#{name} #{config.streamlineOpts} #{streamlineOpts} $in")
151 .description "#{name.toUpperCase()} $in"
152
153 files: "**/*#{ext}"
154
155 makeSrcEdge: (ninja, source, target) ->
156 targetDir = path.dirname target
157 base = path.basename target, ".js"
158 if @oldStreamline
159 buildSource = path.join targetDir, "#{base}#{path.extname source}"
160 mapFile = path.join targetDir, "#{base}.map"
161
162 # Streamline only compiles files in-place, so make one edge to copy the
163 # streamline file to the build dir...
164 ninja.edge(buildSource).from(source).using("copy")
165
166 # Make another edge to compile the file in the build dir.
167 ninja.edge(target)
168 .from(buildSource)
169 .using(name)
170 .assign("mapFile", mapFile)
171 else
172 # New streamline (as of 0.10.9) supports the -o option.
173 ninja.edge(target)
174 .from(source)
175 .using(name)
176 .assign('outDir', path.dirname target)
177 return [target]
178 }
179
180defineFactory "jsStreamline" , makeStreamlineFactory('jsStreamline', '._js', '_node')
181defineFactory "coffeeStreamline" ,
182 makeStreamlineFactory('coffeeStreamline', '._coffee', '_coffee')
183
184#
185# /assets factories
186# --------------
187#
188
189makeAssetRule = (ninja, name, releaseType, cli) ->
190 ninja.rule("#{name}-#{releaseType}")
191 .run(cli)
192 .depfile('$out.d')
193 .description "(#{releaseType}) #{name.toUpperCase()} $in"
194
195makeAssetEdgeFn = (name) ->
196 (ninja, source, target, releaseType) ->
197 ninja.edge(target)
198 .from(source)
199 .using("#{name}-#{releaseType}")
200
201 return [target]
202
203# Stylus compiler
204defineFactory "stylus", {
205 initialize: (ninja, config, log) ->
206 @_command = getCommand config, log, 'stylus'
207
208 active: (config, log) ->
209 return @_command?
210
211 assignments: (ninja, config) ->
212 ninja.assign 'stylus', @_command
213
214 makeRules: (ninja, config) ->
215 ['debug', 'release'].forEach (releaseType) ->
216 cli = "$node #{findScript "stylus-dep.js", config} $in --print #{config.stylusOpts}"
217 cli += if releaseType is 'release' then ' --compress' else ' --line-numbers'
218 cli += ' --dep-file $out.d'
219 cli += ' > $out'
220 makeAssetRule ninja, 'stylus', releaseType, cli
221
222 assetFiles: '**/[a-z0-9]*.styl'
223 targetExt: '.css'
224 makeAssetEdge: makeAssetEdgeFn 'stylus'
225
226}
227
228# snockets compiler
229defineFactory "snockets", {
230 initialize: (ninja, config, log) ->
231 @_command = getCommand config, log, 'snockets'
232
233 active: (config, log) ->
234 return @_command?
235
236 assignments: (ninja, config) ->
237 ninja.assign 'snockets', @_command, config
238
239 makeRules: (ninja, config) ->
240 ['debug', 'release'].forEach (releaseType) ->
241 cli = "$snockets $cliOptions $in -o $out --dep-file $out.d"
242 cli += ' --minify' if releaseType is 'release'
243 cli += " && #{findLocalCommand 'i18n-extract', config}"
244 cli += ' -f \'(i18n)\' -k \'$$1\' $out > $out.i18n'
245
246 makeAssetRule ninja, 'snockets', releaseType, cli
247
248 assetFiles: 'js/**/[a-z0-9]*.coffee'
249 makeAssetEdge: makeAssetEdgeFn 'snockets'
250
251}
252
253# Coffeelint tool
254defineFactory "coffeelint", {
255 active: (config, log) ->
256 return !config.noLint
257
258 assignments: (ninja, config) ->
259 ninja.assign 'coffeelint', "$node #{findScript "coffeelint.js", config}"
260
261 makeRules: (ninja, config) ->
262 ninja.rule("coffeelint")
263 .run("$coffeelint $cliOptions $in && touch $out")
264 .description "COFFEELINT $in"
265}