-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdashboard.coffee
180 lines (157 loc) · 5.35 KB
/
dashboard.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
http = require 'http'
fs = require 'fs'
url = require 'url'
{side_by_side} = require './side_by_side'
{source_line_mappings} = require './cs_js_source_mapping'
{list_files} = require './list_files'
file_utils = require './file_utils'
DIR = null # will be cmd-line arg
GIT_REPO = "https://github.com/showell/CoffeeScriptLineMatcher"
JQUERY_CDN = """
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
"""
COFFEE_FILE_REGEX = /\.(coffee|cof)$/
relative_path = (fn) -> file_utils.relative_path DIR, fn
get_files = (regex) -> file_utils.get_files DIR, regex
worst_match = (matches) ->
# debugging code
last = 0
max = 0
worst = null
for match in matches
[cs, js] = match
if cs - last > max
max = cs - last
worst = cs - max + 1
last = cs
"The longest CS section starts at cs:#{worst} (#{max} lines)."
timestamps = (cs_fn, cb) ->
# Return timestamps of our files. Mostly used by AJAX calls to avoid
# unnecessary page refreshes.
cs_files = get_files COFFEE_FILE_REGEX
ts = (fn) -> fs.statSync(fn).mtime.toISOString()
js_files = get_files /\.js$/
js_fn = file_utils.js_file_for cs_fn, js_files
cb get_fingerprint cs_fn, js_fn
get_fingerprint = (cs_fn, js_fn) ->
ts = (fn) -> fs.statSync(fn).mtime.toISOString()
data =
cs: ts cs_fn
if js_fn
data.js = ts js_fn
data
view_file = (cs_fn, cb) ->
html = """
<head>
<title>#{relative_path cs_fn}</title>
<link rel="stylesheet" href="./dashboard.css" />
#{JQUERY_CDN}
<script type="text/javascript" src="view_file.js"></script>
</head>
<h4>#{relative_path cs_fn}</h4>
<a href="./">View files</a> (#{DIR})
<br>
<a href="./about">About</a>
<hr>
"""
cs_files = get_files COFFEE_FILE_REGEX
js_files = get_files /\.js$/
throw "illegal file #{cs_fn}" unless cs_fn in cs_files
js_fn = file_utils.js_file_for cs_fn, js_files
add_metadata = ->
finger_print = get_fingerprint cs_fn, js_fn
finger_print = JSON.stringify finger_print, null, " "
html += """
<script>
CS_FN = #{JSON.stringify cs_fn};
FINGERPRINT = #{finger_print};
</script>
"""
if js_fn is null
html += "<b>No current JS file was found for #{cs_fn}</b>"
add_metadata()
return cb html
html += "<b>JS file</b>: #{relative_path js_fn}<br>"
coffee_lines = file_utils.file_lines(cs_fn)
js_lines = file_utils.file_lines(js_fn)
matches = source_line_mappings coffee_lines, js_lines
html += worst_match(matches)
html += side_by_side matches, coffee_lines, js_lines
add_metadata()
cb html
about = (cb) ->
cb """
<head>
<title>About CoffeeScriptLineMatcher</title>
<link rel="stylesheet" href="./dashboard.css" />
</head>
<h2>About</h2>
<a href="./">View files</a>
<p>
GIT Repository: <a href="#{GIT_REPO}">CoffeeScriptLineMatcher</a>.
</p>
<p>
This tool lets you view CS and JS code side by side.
</p>
<p>
The algorithm for matching up CS lines to JS lines is
independent of the compiler itself. I've tested the
algorithm on several CS examples, but unorthodox coding
styles will likely confuse the algorithm. (Long term,
CS itself will have line number support, so this tool
can eventually be patched to use native mappings.)
</p>
"""
run_dashboard = (port) ->
server = http.createServer (req, res) ->
serve_page = (html) ->
res.writeHeader 200, 'Content-Type': 'text/html'
res.write html
res.end()
serve_css = (fn) ->
res.writeHeader 200, 'Content-Type': 'text/css'
res.write fs.readFileSync fn
res.end()
serve_js = (fn) ->
res.writeHeader 200, 'Content-Type': 'text/javascript'
res.write fs.readFileSync fn
res.end()
serve_json = (data) ->
res.writeHeader 200, 'Content-Type': 'text/json'
res.write JSON.stringify data, null, ' '
res.end()
parts = url.parse(req.url, true)
# console.log "Serving #{parts.pathname} #{JSON.stringify parts.query}"
try
if parts.pathname == '/view'
view_file parts.query.FILE, serve_page
else if parts.pathname == '/timestamps'
timestamps parts.query.FILE, serve_json
else if parts.pathname == '/about'
about serve_page
else if parts.pathname == '/dashboard.css'
serve_css './assets/dashboard.css'
else if parts.pathname == '/view_file.js'
serve_js './assets/view_file.js'
else if parts.pathname == '/'
list_files DIR, get_files, COFFEE_FILE_REGEX, serve_page
else if parts.pathname == '/favicon.ico'
# Patches welcome here, but favicon.ico is kind of pointless
# in a localhost dev tool. Sending the 404 does nothing of
# substance, so this is really just a placeholder.
res.writeHeader 404
res.end();
else
res.end()
catch e
# Right now our code is mostly synchronous, but this won't
# catch async exceptions, so it's just a band-aid for now.
serve_page "Exception: #{e}"
server.listen port
console.log "Server running at http://localhost:#{port}/"
do ->
[ignore, ignore, DIR, port] = process.argv
unless port? and port.match /^\d+/
console.warn "You must supply a directory and port number."
return
run_dashboard(port)