Skip to content

Commit 8598e3d

Browse files
committed
Add attached comments, list of comments
1 parent 8325970 commit 8598e3d

File tree

4 files changed

+274
-111
lines changed

4 files changed

+274
-111
lines changed

index.js

Lines changed: 89 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module.exports = toEstree
44

55
var commas = require('comma-separated-tokens')
6+
var attachComments = require('estree-util-attach-comments')
67
var whitespace = require('hast-util-whitespace')
78
var find = require('property-information/find')
89
var hastToReact = require('property-information/hast-to-react.json')
@@ -31,6 +32,7 @@ var handlers = {
3132
function toEstree(tree, options) {
3233
var context = {
3334
schema: options && options.space === 'svg' ? svg : html,
35+
comments: [],
3436
esm: [],
3537
handle: zwitch('type', {
3638
invalid: invalid,
@@ -49,7 +51,12 @@ function toEstree(tree, options) {
4951
body.push(create(tree, {type: 'ExpressionStatement', expression: result}))
5052
}
5153

52-
return create(tree, {type: 'Program', body: body, sourceType: 'module'})
54+
return create(tree, {
55+
type: 'Program',
56+
body: body,
57+
sourceType: 'module',
58+
comments: context.comments
59+
})
5360
}
5461

5562
function invalid(value) {
@@ -62,22 +69,16 @@ function unknown(node) {
6269

6370
function ignore() {}
6471

65-
function comment(node) {
72+
function comment(node, context) {
73+
var esnode = create(node, {type: 'Block', value: node.value})
74+
75+
context.comments.push(esnode)
76+
6677
return create(node, {
6778
type: 'JSXExpressionContainer',
6879
expression: create(node, {
6980
type: 'JSXEmptyExpression',
70-
// Babel.
71-
innerComments: [create(node, {type: 'CommentBlock', value: node.value})],
72-
// Recast.
73-
comments: [
74-
create(node, {
75-
type: 'Block',
76-
value: node.value,
77-
leading: false,
78-
trailing: true
79-
})
80-
]
81+
comments: [Object.assign({}, esnode, {leading: false, trailing: true})]
8182
})
8283
})
8384
}
@@ -185,21 +186,28 @@ function element(node, context) {
185186
}
186187

187188
function mdxjsEsm(node, context) {
188-
push.apply(
189-
context.esm,
190-
(node.data && node.data.estree && node.data.estree.body) || []
191-
)
189+
var estree = node.data && node.data.estree
190+
191+
if (estree) {
192+
push.apply(context.comments, estree.comments)
193+
attachComments(estree, estree.comments)
194+
push.apply(context.esm, estree.body)
195+
}
192196
}
193197

194-
function mdxExpression(node) {
198+
function mdxExpression(node, context) {
199+
var estree = node.data && node.data.estree
200+
var expression
201+
202+
if (estree) {
203+
push.apply(context.comments, estree.comments)
204+
attachComments(estree, estree.comments)
205+
expression = estree.body[0] && estree.body[0].expression
206+
}
207+
195208
return create(node, {
196209
type: 'JSXExpressionContainer',
197-
expression:
198-
(node.data &&
199-
node.data.estree &&
200-
node.data.estree.body[0] &&
201-
node.data.estree.body[0].expression) ||
202-
create(node, {type: 'JSXEmptyExpression'})
210+
expression: expression || create(node, {type: 'JSXEmptyExpression'})
203211
})
204212
}
205213

@@ -212,6 +220,8 @@ function mdxJsxElement(node, context) {
212220
var index = -1
213221
var children
214222
var attr
223+
var value
224+
var estree
215225

216226
if (
217227
node.name &&
@@ -226,49 +236,68 @@ function mdxJsxElement(node, context) {
226236

227237
while (++index < attrs.length) {
228238
attr = attrs[index]
239+
value = attr.value
229240

230241
if (attr.type === 'mdxJsxAttribute') {
242+
if (value == null) {
243+
// Empty.
244+
}
245+
// MDXJsxAttributeValueExpression.
246+
else if (typeof value === 'object') {
247+
estree = value.data && value.data.estree
248+
value = null
249+
250+
if (estree) {
251+
push.apply(context.comments, estree.comments)
252+
attachComments(estree, estree.comments)
253+
value = estree.body[0] && estree.body[0].expression
254+
}
255+
256+
// To do: `node` is wrong.
257+
value = create(node, {
258+
type: 'JSXExpressionContainer',
259+
expression: value || create(null, {type: 'JSXEmptyExpression'})
260+
})
261+
}
262+
// Anything else.
263+
else {
264+
// To do: use `value`?
265+
value = create(null, {
266+
type: 'Literal',
267+
value: String(value),
268+
raw: JSON.stringify(String(value))
269+
})
270+
}
271+
231272
attributes.push(
232273
create(null, {
233274
type: 'JSXAttribute',
234275
name: createJsxName(attr.name),
235-
value:
236-
attr.value == null
237-
? null
238-
: typeof attr.value === 'object'
239-
? // MDXJsxAttributeValueExpression.
240-
create(node, {
241-
type: 'JSXExpressionContainer',
242-
expression:
243-
(attr.value.data &&
244-
attr.value.data.estree &&
245-
attr.value.data.estree.body[0] &&
246-
attr.value.data.estree.body[0].expression) ||
247-
create(null, {type: 'JSXEmptyExpression'})
248-
})
249-
: // Anything else.
250-
create(null, {
251-
type: 'Literal',
252-
value: String(attr.value),
253-
raw: JSON.stringify(String(attr.value))
254-
})
276+
value: value
255277
})
256278
)
257279
}
258280
// MDXJsxExpressionAttribute.
259281
else {
282+
estree = attr.data && attr.data.estree
283+
value = null
284+
285+
if (estree) {
286+
push.apply(context.comments, estree.comments)
287+
attachComments(estree, estree.comments)
288+
value =
289+
estree.body[0] &&
290+
estree.body[0].expression &&
291+
estree.body[0].expression.properties &&
292+
estree.body[0].expression.properties[0] &&
293+
estree.body[0].expression.properties[0].argument
294+
}
295+
260296
attributes.push(
261297
create(null, {
262298
type: 'JSXSpreadAttribute',
263299
argument:
264-
(attr.data &&
265-
attr.data.estree &&
266-
attr.data.estree.body[0] &&
267-
attr.data.estree.body[0].expression &&
268-
attr.data.estree.body[0].expression.properties &&
269-
attr.data.estree.body[0].expression.properties[0] &&
270-
attr.data.estree.body[0].expression.properties[0].argument) ||
271-
create(null, {type: 'ObjectExpression', properties: {}})
300+
value || create(null, {type: 'ObjectExpression', properties: {}})
272301
})
273302
)
274303
}
@@ -396,17 +425,19 @@ function all(parent, context) {
396425
return results
397426
}
398427

399-
function create(hast, esnode) {
428+
function create(hast, esnode, fromStart, fromEnd) {
400429
var p = position(hast)
430+
var left = fromStart || 0
431+
var right = fromEnd || 0
401432

402433
if (p.start.line) {
403-
esnode.start = p.start.offset
404-
esnode.end = p.end.offset
434+
esnode.start = p.start.offset + left
435+
esnode.end = p.end.offset - right
405436
esnode.loc = {
406-
start: {line: p.start.line, column: p.start.column - 1},
407-
end: {line: p.end.line, column: p.end.column - 1}
437+
start: {line: p.start.line, column: p.start.column - 1 + left},
438+
end: {line: p.end.line, column: p.end.column - 1 - right}
408439
}
409-
esnode.range = [p.start.offset, p.end.offset]
440+
esnode.range = [p.start.offset + left, p.end.offset - right]
410441
}
411442

412443
return esnode

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@
5050
"acorn": "^8.0.0",
5151
"acorn-jsx": "^5.0.0",
5252
"estree-to-babel": "^3.0.0",
53+
"estree-util-attach-comments": "^1.0.0",
54+
"estree-util-build-jsx": "^1.0.0",
55+
"hast-util-from-parse5": "^6.0.1",
5356
"hastscript": "^6.0.0",
5457
"mdast-util-from-markdown": "^0.8.0",
5558
"mdast-util-mdx": "^0.1.0",
5659
"mdast-util-to-hast": "^10.1.0",
5760
"micromark-extension-mdxjs": "^0.3.0",
5861
"nyc": "^15.0.0",
62+
"parse5": "^6.0.1",
5963
"prettier": "^2.0.0",
6064
"recast": "^0.20.0",
6165
"remark-cli": "^9.0.0",

readme.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,8 @@ var hast = fromParse5(parse5.parse(String(fs.readFileSync('example.html'))))
5555

5656
var estree = toEstree(hast)
5757

58-
var js = recast.prettyPrint(estree).code
59-
60-
console.log(js)
58+
estree.comments = null // `recast` doesn’t like comments on the root.
59+
console.log(recast.prettyPrint(estree).code)
6160
```
6261

6362
Now, `node example` (and prettier), yields:
@@ -67,23 +66,33 @@ Now, `node example` (and prettier), yields:
6766
<html lang="en">
6867
<head>
6968
<title>{'Hi!'}</title>
69+
{'\n'}
7070
<link rel="stylesheet" href="index.css" />
71+
{'\n'}
7172
</head>
7273
<body>
7374
<h1>{'Hello, world!'}</h1>
75+
{'\n'}
7476
<a
7577
download
7678
style={{
7779
width: '1',
7880
height: '10px'
7981
}}
8082
/>
83+
{'\n'}
8184
{/*commentz*/}
85+
{'\n'}
8286
<svg xmlns="http://www.w3.org/2000/svg">
87+
{'\n '}
8388
<title>{'SVG `<ellipse>` element'}</title>
89+
{'\n '}
8490
<ellipse cx="120" cy="70" rx="100" ry="50" />
91+
{'\n'}
8592
</svg>
93+
{'\n'}
8694
<script src="index.js" />
95+
{'\n'}
8796
</body>
8897
</html>
8998
</>
@@ -117,10 +126,15 @@ or element in body.
117126

118127
###### Note
119128

129+
Comments are both attached to the tree in their neighbouring nodes (recast and
130+
babel style), and added as a `comments` array on the program node (espree
131+
style).
132+
You may have to do `program.comments = null` for certain compilers.
133+
120134
There aren’t many great estree serializers out there that support JSX.
121135
[recast][] does a fine job.
122-
Or [`estree-util-build-jsx`][build-jsx] to turn JSX into function
123-
calls
136+
Or use [`estree-util-build-jsx`][build-jsx] to turn JSX into function
137+
calls and then serialize with whatever (astring, escodegen).
124138

125139
## Security
126140

0 commit comments

Comments
 (0)