Skip to content

Commit

Permalink
feat: add estree-util-attach-comments
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Apr 25, 2021
1 parent 4c13a39 commit a7c23da
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"doctrine": "3.0.0",
"eslint": "7.18.0",
"espree": "^4",
"estree-util-attach-comments": "^2.0.0",
"fs-extra": "9.1.0",
"lodash": "4.17.20"
},
Expand Down
13 changes: 13 additions & 0 deletions vendor/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
We cannot use Pure ESM packages (e.g. `estree-util-attach-comments`) because:

- Node doesn't support mixing `require` and `import`.
- Some people are shipping pure ESM without properly fixing Node.

This means we should regress to the old days of `vendor` folders.

See these for more information:

https://github.com/wooorm/estree-util-attach-comments/issues/2
https://github.com/unifiedjs/unified/issues/121
https://github.com/sindresorhus/meta/discussions/15
https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
150 changes: 150 additions & 0 deletions vendor/estree-util-attach-comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"use strict"

exports.__esModule = true
exports.attachComments = attachComments
var push = [].push
/**
* @typedef {import('estree').BaseNode} EstreeNode
* @typedef {import('estree').Comment} EstreeComment
*
* @typedef State
* @property {EstreeComment[]} comments
* @property {number} index
*
* @typedef Fields
* @property {boolean} leading
* @property {boolean} trailing
*/

/**
* Attach semistandard estree comment nodes to the tree.
*
* @param {EstreeNode} tree
* @param {EstreeComment[]} [comments]
*/

function attachComments(tree, comments) {
var list = (comments || []).concat().sort(compare)
if (list.length)
walk(tree, {
comments: list,
index: 0,
})
return tree
}
/**
* Attach semistandard estree comment nodes to the tree.
*
* @param {EstreeNode} node
* @param {State} state
*/

function walk(node, state) {
/** @type {EstreeNode[]} */
var children = []
/** @type {EstreeComment[]} */

var comments = []
/** @type {string} */

var key
/** @type {EstreeNode|EstreeNode[]} */

var value
/** @type {number} */

var index // Done, we can quit.

if (state.index === state.comments.length) {
return
} // Find all children of `node`

for (key in node) {
value = node[key] // Ignore comments.

if (value && typeof value === "object" && key !== "comments") {
if (Array.isArray(value)) {
index = -1

while (++index < value.length) {
if (value[index] && typeof value[index].type === "string") {
children.push(value[index])
}
}
} else if (typeof value.type === "string") {
children.push(value)
}
}
} // Sort the children.

children.sort(compare) // Initial comments.

push.apply(
comments,
slice(state, node, false, {
leading: true,
trailing: false,
})
)
index = -1

while (++index < children.length) {
walk(children[index], state)
} // Dangling or trailing comments.

push.apply(
comments,
slice(state, node, true, {
leading: false,
trailing: Boolean(children.length),
})
)

if (comments.length) {
// @ts-ignore, yes, because they’re nonstandard.
node.comments = comments
}
}
/**
* @param {State} state
* @param {EstreeNode} node
* @param {boolean} compareEnd
* @param {Fields} fields
*/

function slice(state, node, compareEnd, fields) {
/** @type {EstreeComment[]} */
var result = []

while (state.comments[state.index] && compare(state.comments[state.index], node, compareEnd) < 1) {
result.push(Object.assign({}, state.comments[state.index++], fields))
}

return result
}
/**
* @param {EstreeNode|EstreeComment} left
* @param {EstreeNode|EstreeComment} right
* @param {boolean} [compareEnd]
* @returns {number}
*/

function compare(left, right, compareEnd) {
var field = compareEnd ? "end" : "start" // Offsets.

if (left.range && right.range) {
return left.range[0] - right.range[compareEnd ? 1 : 0]
} // Points.

if (left.loc && left.loc.start && right.loc && right.loc[field]) {
return left.loc.start.line - right.loc[field].line || left.loc.start.column - right.loc[field].column
} // Just `start` (and `end`) on nodes.
// Default in most parsers.

if ("start" in left && field in right) {
// @ts-ignore Added by Acorn
return left.start - right[field]
}

return NaN
}

0 comments on commit a7c23da

Please sign in to comment.