-
Notifications
You must be signed in to change notification settings - Fork 1
/
make.coffee
285 lines (232 loc) · 7.95 KB
/
make.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
require 'coffee-script/register'
_ = require 'lodash'
minimist = require 'minimist'
path = require 'path'
fs = require 'fs-extra'
glob = (require 'glob').sync
hound = require 'hound'
coffee = require 'coffee-script'
jade = require 'jade'
stylus = require 'stylus'
nib = require 'nib'
yaml = require 'js-yaml'
marked = require 'marked'
highlight = require 'highlight.js'
esprima = require 'esprima'
escodegen = require 'escodegen'
Uglify = require 'uglify-js'
desugar = require 'desugar'
EOL = "\n"
words = (str) -> str.split /\s+/g
trimArray = (lines) -> lines.join(EOL).trim().split(EOL)
locate = (names...) -> path.join.apply null, [ __dirname ].concat names
read = (src) ->
console.log "Reading #{src}"
fs.readFileSync src, encoding: 'utf8'
write = (src, data) ->
console.log "Writing #{src}"
fs.outputFileSync src, data
rm = (src) ->
console.log "Removing #{src}"
fs.removeSync src
cp = (src, dest) ->
console.log "Copying #{src} #{dest}"
fs.copySync src, dest
cpn = (src, dest) ->
cp src, dest unless fs.existsSync dest
desugarSymbols = yaml.safeLoad read 'desugar.yml'
compileCoffee = (script) ->
desugar desugarSymbols, coffee.compile script
node_header_js = """
var _ = require('lodash');
var d3 = require('d3');
var chroma = require('chroma-js');
"""
node_test_header_js = """
var test = require('tape');
var _ = require('lodash');
var d3 = require('d3');
var chroma = require('chroma-js');
"""
blockCommentPattern = /^\s*\#\#\#\s*$/
headerPattern = /^(plot)\s+([\w-]+)\s*$/
defaultArticleData = width: 640, height: 240
requiredFrontMatter = [ 'data' ]
defaultSettings = '''
plot.settings.axisLabelFont = '11px Lekton, monospace';
plot.settings.axisTitleFont = 'bold 11px Lekton, monospace';
'''
parseArticles = (compileScript, lines) ->
# group into comment / code blocks
blocks = []
block = null
code = yes
for line in lines
if blockCommentPattern.test line
code = not code
blocks.push block if block
block =
type: if code then 'code' else null
lines: []
else
block.lines.push line.trimRight()
# last block
blocks.push block
# parse comments and nest code
articles = []
articleSymbols = {}
for block in blocks
if block.type isnt 'code'
# trim off empty top/bottom lines
lines = trimArray block.lines
# parse descriptor
descriptor = lines.shift()
if matches = headerPattern.exec descriptor
block.type = matches[1]
block.symbol = matches[2]
else
throw new Error "Invalid descriptor '#{descriptor}'"
block.title = lines.shift()
if block.type is 'plot'
[ description, frontmatter ] = (lines.join EOL).split /[-]{3,}/
# parse front matter
block.data = if frontmatter then yaml.safeLoad frontmatter else {}
_.defaults block.data, defaultArticleData
# check required attrs
for attr in requiredFrontMatter
console.warn "Article '#{block.symbol}' is missing attribute '#{attr}'." unless block.data[attr]
# parse description
block.description = if description then marked description
console.warn "Article '#{block.symbol}' is missing a description." unless block.description
# clean up
delete block.lines
if articleSymbols[block.symbol]
throw new Error "Duplicate Article '#{block.symbol}'."
else
articleSymbols[block.symbol] = yes
articles.push block
else
article = articles[articles.length - 1]
article.coffeescript = coffeescript = (trimArray block.lines).join EOL
article.coffeescriptListing = (highlight.highlightAuto coffeescript, [ 'coffeescript' ]).value
article.javascript = javascript = coffee.compile coffeescript, bare: yes
article.javascriptListing = (highlight.highlightAuto javascript, [ 'javascript' ]).value
article.script = defaultSettings + compileScript javascript.trim().substr(0, javascript.length - 2) + "(document.getElementById('example'));"
article.scriptListing = (highlight.highlightAuto article.script, [ 'javascript' ]).value
articles
buildDoc = ->
console.log "Building docs..."
for datapackage_yml in glob 'data/**/datapackage.yml'
rawSchema = yaml.safeLoad read datapackage_yml
datapackageFields = for name, descriptor of rawSchema.schema
if _.isArray descriptor
type = 'string'
domain = descriptor
else
type = descriptor
domain = undefined
field =
name: name
type: type
field.lightningDomain = domain if domain
field
datapackage_json =
name: rawSchema.name
resources: [
path: rawSchema.location
schema: datapackageFields
]
cpn "data/#{rawSchema.name}/#{rawSchema.name}.csv", "build/data/#{rawSchema.name}/#{rawSchema.name}.csv"
write "build/data/#{rawSchema.name}/datapackage.json", JSON.stringify datapackage_json, null, 2
cpn 'lib/jquery/dist/jquery.js', 'build/js/jquery.js'
jsLibs = [
'lib/lodash/dist/lodash.js'
'lib/d3/d3.js'
'lib/chroma-js/chroma.js'
'lib/papaparse/papaparse.js'
'lib/diecut/diecut.js'
]
write 'build/js/lightning-lib.js', (read lib for lib in jsLibs).join EOL
cpn 'node_modules/highlight.js/styles/tomorrow.css', 'build/css/syntax.css'
cpn 'lib/HTML5-Reset/assets/css/reset.css', 'build/css/reset.css'
stylus.render (read 'src/doc.styl'), { filename: 'build/doc.css' }, (error, css) ->
throw error if error
write 'build/css/doc.css', css
templatePath = 'src/doc.jade'
renderPage = jade.compileFile templatePath,
filename: templatePath
pretty: yes
plot_coffee = locate 'build/js/lightning-node.js'
if key = require.resolve plot_coffee
delete require.cache[ key ]
plot = require plot_coffee
compileScript = plot.parse esprima, escodegen
articles = parseArticles compileScript, (read 'src/doc.coffee').split EOL
for article, i in articles
write "build/#{article.symbol}.html", renderPage
type: 'article'
article: article
previousArticle: if i > 0 then articles[i - 1] else null
nextArticle: if i < articles.length - 1 then articles[i + 1] else null
write 'build/index.html', renderPage
type: 'articles'
articles: articles
return
build = (argv) ->
console.log "Building..."
lightning_coffee = read 'src/lightning.coffee'
tests_coffee = read 'src/tests.coffee'
lightning = compileCoffee lightning_coffee
write 'build/js/lightning.js', lightning
write 'build/js/lightning-node.js', node_header_js + EOL + lightning
#TODO compile lightning only once.
write 'build/js/tests.js', node_test_header_js + EOL + compileCoffee [ lightning_coffee, tests_coffee ].join(EOL)
# *** DANGER ***
# cp 'build/js/lightning.js', 'dist/lightning.js'
# cp 'dist/lightning.js', '../h2o-flow/vendor/h2oai/lightning.min.js'
if argv.m
cp 'build/js/lightning.js', 'dist/lightning.js'
uglification = Uglify.minify [ 'dist/lightning.js' ], warnings: yes
write 'dist/lightning.min.js', uglification.code
cp 'dist/lightning.min.js', '../h2o-flow/vendor/h2oai/lightning.min.js'
return
test = ->
console.log 'Testing...'
testFile = locate 'build/js/tests.js'
if key = require.resolve testFile
delete require.cache[ key ]
require testFile
serve = ->
port = 8080
console.log "Starting server at localhost:#{port} ..."
connect = require 'connect'
server = require 'serve-static'
connect()
.use server locate 'build'
.listen port
watch = (argv) ->
console.log 'Watching...'
hound
.watch locate 'src'
.on 'change', (file, stats) ->
console.log file
if /\.(coffee)$/.test file
console.log "#{file} changed..."
try
build argv
test()
catch error
console.error error
serve()
clean = ->
console.log 'Cleaning...'
rm 'build'
main = (argv) ->
clean() if argv.c
build argv if argv.b or argv.d
buildDoc() if argv.d
test() if argv.t
watch argv if argv.w
main minimist (process.argv.slice 2),
default:
env: 'prod'