1 | fs = require 'fs'
|
2 | path = require 'path'
|
3 | Stream = require 'stream'
|
4 |
|
5 | coffee = require 'coffee-script'
|
6 | coffee_helpers = require 'coffee-script/lib/coffee-script/helpers'
|
7 | convert = require 'convert-source-map'
|
8 | optparse = require 'optparse'
|
9 |
|
10 | conf =
|
11 | quiet: false
|
12 | progname: path.basename process.argv[1]
|
13 |
|
14 | maps: true
|
15 | output: process.stdout
|
16 | stdin_literate: false
|
17 | bare: false
|
18 | header: true
|
19 |
|
20 | errx = (exit_code, msg) ->
|
21 | console.error "#{conf.progname} error: #{msg}" unless conf.quiet
|
22 | process.exit exit_code if exit_code
|
23 |
|
24 | user_agent = ->
|
25 | ver = JSON.parse(fs.readFileSync "#{__dirname}/../package.json").version
|
26 | ver_cs = require('coffee-script/lib/coffee-script/coffee-script').VERSION
|
27 | "#{conf.progname}/#{ver} (CoffeeScript #{ver_cs}; #{process.platform}; #{process.arch}) node/#{process.versions.node}"
|
28 |
|
29 | parse_opts = (src) ->
|
30 | opt = [
|
31 | ["-h", "--help", "output usage information & exit"]
|
32 | ["-V", "--version", "output the version number & exit"]
|
33 | ["-o", "--output [FILE]", "write result to a FILE instead of stdout"]
|
34 | ["-l", "--literate", "treat stdin as literate style coffee-script"]
|
35 | ["-b", "--bare", "compile without a top-level function wrapper"]
|
36 | ["--no-map", "don't include inline source map (why?)"]
|
37 | ]
|
38 | p = new optparse.OptionParser opt
|
39 | p.banner = "Usage: #{conf.progname} [options] [file.coffee]"
|
40 |
|
41 | p.on 'no-map', -> conf.maps = false
|
42 |
|
43 | p.on 'bare', -> conf.bare = true
|
44 |
|
45 | p.on 'help', ->
|
46 | console.log p.toString()
|
47 | process.exit 0
|
48 |
|
49 | p.on 'version', ->
|
50 | console.log user_agent()
|
51 | process.exit 0
|
52 |
|
53 | p.on 'output', (unused, val) -> conf.output = val
|
54 |
|
55 | p.on 'literate', -> conf.stdin_literate = true
|
56 |
|
57 | p.on (o) -> errx 1, "unknown option #{o}"
|
58 |
|
59 | [(p.parse src), p]
|
60 |
|
61 | read_file = (fname) ->
|
62 | try
|
63 | fs.readFileSync(fname).toString()
|
64 | catch e
|
65 | errx 1, "#{fname} reading: #{e.message}"
|
66 |
|
67 |
|
68 | read_stdin = ->
|
69 | read_file '/dev/stdin'
|
70 |
|
71 |
|
72 | compile = (fname, fcontent, opt = {}) ->
|
73 | return '' if fcontent.match /^\s*$/
|
74 |
|
75 | options = {
|
76 | sourceMap: conf.maps
|
77 | generatedFile: fname
|
78 | filename: fname
|
79 | bare: conf.bare
|
80 | header: conf.header
|
81 | inline: true
|
82 | literate: coffee_helpers.isLiterate(fname)
|
83 | }
|
84 |
|
85 | options[key] = val for key,val of opt
|
86 |
|
87 | try
|
88 | compiled = coffee.compile fcontent, options
|
89 | catch e
|
90 | console.error coffee_helpers.updateSyntaxError e.toString(), fcontent, fname
|
91 | process.exit 1
|
92 |
|
93 | if conf.maps
|
94 | comment = convert
|
95 | .fromJSON(compiled.v3SourceMap)
|
96 | .setProperty('sources', [fname])
|
97 | .toComment()
|
98 |
|
99 | "#{compiled.js}\n#{comment}"
|
100 | else
|
101 | compiled.toString()
|
102 |
|
103 |
|
104 | exports.main = ->
|
105 | [args, p] = parse_opts process.argv
|
106 | args = args[2..-1]
|
107 |
|
108 | if args.length
|
109 | js = compile args[0], read_file args[0]
|
110 | else
|
111 | js = compile '[stdin]', read_stdin(), { literate: conf.stdin_literate }
|
112 |
|
113 |
|
114 | unless conf.output instanceof Stream
|
115 | conf.output = fs.createWriteStream conf.output
|
116 |
|
117 | conf.output.on 'error', (err) ->
|
118 | errx 1, "output stream: #{err.message}"
|
119 |
|
120 | conf.output.write js
|
121 | conf.output.end() if conf.output.path
|