Last active
November 6, 2023 12:53
-
-
Save nikolaskhodov/5e6f815288c52d9fa840f9914b9f96ee to your computer and use it in GitHub Desktop.
Print AST ESLint Rule
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module.exports = { | |
| root: true, | |
| parser: '@typescript-eslint/parser' | |
| plugins: [ | |
| 'nk' | |
| ], | |
| extends: [ ], | |
| settings: { }, | |
| rules: { | |
| 'nk/print-ast': 'error' | |
| } | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module.exports = { | |
| rules: { | |
| 'print-ast': require('./printAST'), | |
| }, | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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" | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ./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); | |
| }, | |
| }; | |
| }, | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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