Skip to content

Instantly share code, notes, and snippets.

@nikolaskhodov
Last active November 6, 2023 12:53
Show Gist options
  • Select an option

  • Save nikolaskhodov/5e6f815288c52d9fa840f9914b9f96ee to your computer and use it in GitHub Desktop.

Select an option

Save nikolaskhodov/5e6f815288c52d9fa840f9914b9f96ee to your computer and use it in GitHub Desktop.
Print AST ESLint Rule
module.exports = {
root: true,
parser: '@typescript-eslint/parser'
plugins: [
'nk'
],
extends: [ ],
settings: { },
rules: {
'nk/print-ast': 'error'
}
};
module.exports = {
rules: {
'print-ast': require('./printAST'),
},
};
{
"name": "eslint-plugin-nk",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"esquery": "^1.5.0",
"input": "^1.0.1",
"uuid": "^9.0.1"
}
}
// ./node_modules/.bin/eslint <filepath.js> > <filename>.ast.json
const { v4 } = require('uuid');
function serializeAST(node) {
if (!node) {
return;
}
if (typeof node === 'object' && !node.__id) {
node.__id = v4();
}
const clonedNode = { ...node };
if (node.parent) {
delete clonedNode.parent;
clonedNode.__parentNodeId = node.parent.__id;
}
for (const propertyName in clonedNode) {
if (propertyName.startsWith('__')) {
continue;
}
const obj = clonedNode[propertyName];
if (Array.isArray(obj)) {
clonedNode[propertyName] = obj.map((property) =>
serializeAST(property)
);
} else if (typeof obj === 'object') {
clonedNode[propertyName] = serializeAST(obj);
}
}
return clonedNode;
}
function findRootNode(node) {
let currentNode = node;
while (currentNode.parent) {
currentNode = currentNode.parent;
}
return currentNode;
}
function printAST(node) {
const parentMap = new WeakMap();
const ast = serializeAST(findRootNode(node), parentMap);
console.log(JSON.stringify(ast, null, 4));
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
"Outputs the file's AST to the console. Requires a single import declaration at least.",
},
fixable: 'code',
schema: [], // no options
},
create: function () {
return {
ImportDeclaration: (node) => {
printAST(node);
process.exit(0);
},
};
},
};
const input = require('input');
const esquery = require('esquery');
const path = require('path');
function deserializeAST(node, nodeMap) {
if (!node) {
return;
}
if (node.__id) {
nodeMap.set(node.__id, node);
}
if (node.__parentNodeId) {
node.parent = nodeMap.get(node.__parentNodeId);
}
for (const propertyName in node) {
if (propertyName.startsWith('__') || propertyName === 'parent') {
continue;
}
const obj = node[propertyName];
if (Array.isArray(obj)) {
node[propertyName] = obj.map((property) =>
deserializeAST(property, nodeMap)
);
} else if (typeof obj === 'object') {
node[propertyName] = deserializeAST(obj, nodeMap);
}
}
return node;
}
function cleanUpNodes(node) {
if (!node) {
return;
}
const clonedNode = { ...node };
if (clonedNode.parent) {
delete clonedNode.parent;
}
delete clonedNode.__id;
delete clonedNode.__parentNodeId;
for (const propertyName in clonedNode) {
const obj = node[propertyName];
if (Array.isArray(obj)) {
clonedNode[propertyName] = obj.map((property) =>
cleanUpNodes(property)
);
} else if (typeof obj === 'object') {
clonedNode[propertyName] = cleanUpNodes(obj);
}
}
return clonedNode;
}
(async () => {
const nodeMap = new Map();
const ast = deserializeAST(require(path.resolve(process.argv[2])), nodeMap);
while (true) {
const selector = await input.text('Selector:');
const matches = esquery(ast, selector);
console.log(
JSON.stringify(
{ matches: matches.map((match) => cleanUpNodes(match)) },
null,
4
)
);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment