Skip to content

Commit 08f9aaf

Browse files
committed
Add nodes option to Node API, that returns POJO representation of AST; starting point for toPlainObject method on node classes to return the serializable plain JavaScript object representation of each node
1 parent 12fcbfc commit 08f9aaf

File tree

4 files changed

+115
-5
lines changed

4 files changed

+115
-5
lines changed

lib/coffeescript/coffeescript.js

+8-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffeescript/nodes.js

+60-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/coffeescript.coffee

+7-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,13 @@ exports.compile = compile = withPrettyErrors (code, options = {}) ->
9494
options.bare = yes
9595
break
9696

97-
fragments = parser.parse(tokens).compileToFragments options
97+
nodes = parser.parse tokens
98+
# If all that was requested was a POJO representation of the nodes, e.g.
99+
# the abstract syntax tree (AST), we can stop now and just return that.
100+
if options.nodes
101+
return nodes.toPlainObject()
102+
103+
fragments = nodes.compileToFragments options
98104

99105
currentLine = 0
100106
currentLine += 1 if options.header

src/nodes.coffee

+40-1
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,53 @@ exports.Base = class Base
257257
lastNode: (list) ->
258258
if list.length is 0 then null else list[list.length - 1]
259259

260-
# `toString` representation of the node, for inspecting the parse tree.
260+
# Debugging representation of the node, for inspecting the parse tree.
261261
# This is what `coffee --nodes` prints out.
262262
toString: (idt = '', name = @constructor.name) ->
263263
tree = '\n' + idt + name
264264
tree += '?' if @soak
265265
@eachChild (node) -> tree += node.toString idt + TAB
266266
tree
267267

268+
# Plain JavaScript object representation of the node, that can be serialized
269+
# as JSON. This is used for generating an abstract syntax tree (AST).
270+
# This is what the `nodes` option in the Node API returns.
271+
toPlainObject: ->
272+
# We try to follow the [Babel AST spec](https://github.com/babel/babel/blob/master/packages/babylon/ast/spec.md)
273+
# as closely as possible, for improved interoperability with other tools.
274+
obj =
275+
type: @constructor.name
276+
# Convert `locationData` to Babel’s style.
277+
loc:
278+
start:
279+
line: @locationData.first_line
280+
column: @locationData.first_column
281+
end:
282+
line: @locationData.last_line
283+
column: @locationData.last_column
284+
285+
# Add serializable properties to the output. Properties that aren’t
286+
# automatically serializable (because they’re already a primitive type)
287+
# should be handled on a case-by-case basis in child node classes’ own
288+
# `toPlainObject` methods.
289+
for property, value of this
290+
continue if property in ['locationData', 'children']
291+
continue if value is undefined # Don’t skip `null` or `false` values.
292+
if typeof value is 'boolean' or typeof value is 'number' or typeof value is 'string'
293+
obj[property] = value
294+
295+
# Work our way down the tree. This is like `eachChild`, except that we
296+
# preserve the child node name, and arrays.
297+
for attr in @children when @[attr]
298+
if Array.isArray(@[attr])
299+
obj[attr] = []
300+
for child in flatten [@[attr]]
301+
obj[attr].push child.unwrap().toPlainObject()
302+
else
303+
obj[attr] = @[attr].unwrap().toPlainObject()
304+
305+
obj
306+
268307
# Passes each child to a function, breaking when the function returns `false`.
269308
eachChild: (func) ->
270309
return this unless @children

0 commit comments

Comments
 (0)