{"id":22660772,"url":"https://github.com/buxlabs/abstract-syntax-tree","last_synced_at":"2025-04-05T13:10:02.901Z","repository":{"id":40659953,"uuid":"76797104","full_name":"buxlabs/abstract-syntax-tree","owner":"buxlabs","description":"A library for working with abstract syntax trees.","archived":false,"fork":false,"pushed_at":"2024-03-28T12:32:31.000Z","size":4277,"stargazers_count":112,"open_issues_count":1,"forks_count":13,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T12:08:44.935Z","etag":null,"topics":["abstract-syntax-tree","ast","generate","javascript","parse","syntax-tree"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buxlabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"emilos"}},"created_at":"2016-12-18T17:37:23.000Z","updated_at":"2025-03-01T00:07:54.000Z","dependencies_parsed_at":"2024-06-18T14:04:32.083Z","dependency_job_id":null,"html_url":"https://github.com/buxlabs/abstract-syntax-tree","commit_stats":{"total_commits":380,"total_committers":12,"mean_commits":"31.666666666666668","dds":0.3631578947368421,"last_synced_commit":"59e64d92c42843edec5b550dcdec8a7ad6fa170c"},"previous_names":["buxlabs/ast"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buxlabs%2Fabstract-syntax-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buxlabs%2Fabstract-syntax-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buxlabs%2Fabstract-syntax-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buxlabs%2Fabstract-syntax-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buxlabs","download_url":"https://codeload.github.com/buxlabs/abstract-syntax-tree/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339158,"owners_count":20923014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract-syntax-tree","ast","generate","javascript","parse","syntax-tree"],"created_at":"2024-12-09T11:11:59.063Z","updated_at":"2025-04-05T13:10:02.870Z","avatar_url":"https://github.com/buxlabs.png","language":"JavaScript","readme":"# abstract-syntax-tree\n\n[![npm](https://img.shields.io/npm/v/abstract-syntax-tree.svg)](https://www.npmjs.com/package/abstract-syntax-tree) [![build](https://github.com/buxlabs/abstract-syntax-tree/workflows/build/badge.svg)](https://github.com/buxlabs/abstract-syntax-tree/actions)\n\n🧰 A library for working with abstract syntax trees.\n\n🔗 Checkout the [REPL](https://buxlabs.pl/en/tools/js/abstract-syntax-tree/repl).\n\n### Key features\n\n- [parse](#parse), [transform](#replace) and [generate](#generate) code with a single dependency\n- offers both [functional](#functional-programming-style) and [class](#object-oriented-programming-style) interfaces\n- built-in ast \u003c-\u003e js types helpers - [serialize](#serialize) and [template](#template)\n- built-in [find](#find), [has](#has),\n- built-in transformations like [append](#append), [prepend](#prepend)\n- 20+ methods total\n\n## Table of Contents\n\n- [Background](#background)\n- [Installation](#installation)\n- [Usage](#usage)\n- [API](#api)\n- [REPL](https://buxlabs.pl/en/tools/js/abstract-syntax-tree/repl)\n- [Nodes](#nodes)\n- [Optimizations](#optimizations)\n- [Maintainers](#maintainers)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Background\n\nAn abstract syntax tree is a way to represent the source code. In case of this library it is represented in the [estree](https://github.com/estree/estree) format.\n\nFor example, the following source code:\n\n```js\nconst answer = 42\n```\n\nHas the following representation:\n\n```json\n{\n  \"type\": \"Program\",\n  \"body\": [\n    {\n      \"type\": \"VariableDeclaration\",\n      \"declarations\": [\n        {\n          \"type\": \"VariableDeclarator\",\n          \"id\": {\n            \"type\": \"Identifier\",\n            \"name\": \"answer\"\n          },\n          \"init\": {\n            \"type\": \"Literal\",\n            \"value\": 42\n          }\n        }\n      ],\n      \"kind\": \"const\"\n    }\n  ]\n}\n```\n\nThe goal of this library is to consolidate common abstract syntax tree operations in one place. It uses a variety of libraries under the hood based on their performance and flexibility, e.g. [meriyah](https://github.com/meriyah/meriyah) for parsing and [astring](https://github.com/davidbonnet/astring) for source code generation.\n\nThe library exposes a set of utility methods that can be useful for analysis or transformation of abstract syntax trees. It supports functional and object-oriented programming style.\n\n## Installation\n\n```bash\nnpm install abstract-syntax-tree\n```\n\n## Usage\n\n### Functional programming style\n\n```js\nconst { parse, find } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(find(tree, \"Literal\")) // [ { type: 'Literal', value: 42 } ]\n```\n\n### Object oriented programming style\n\n```js\nconst AbstractSyntaxTree = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = new AbstractSyntaxTree(source)\nconsole.log(tree.find(\"Literal\")) // [ { type: 'Literal', value: 42 } ]\n```\n\n## API\n\n### Static Methods\n\n#### parse\n\nThe library uses [meriyah](https://github.com/meriyah/meriyah) to create an [estree](https://github.com/estree/estree) compatible abstract syntax tree. All [meriyah parsing options](https://github.com/meriyah/meriyah#api) can be passed to the parse method.\n\n```js\nconst { parse } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(tree) // { type: 'Program', body: [ ... ] }\n```\n\n```js\nconst { parse } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source, {\n  loc: true,\n  ranges: true,\n})\nconsole.log(tree) // { type: 'Program', body: [ ... ], loc: {...} }\n```\n\n#### generate\n\nThe library uses [astring](https://github.com/davidbonnet/astring) to generate the source code. All [astring generate options](https://github.com/davidbonnet/astring#api) can be passed to the generate method.\n\n```js\nconst { parse, generate } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(generate(tree)) // 'const answer = 42;'\n```\n\n#### walk\n\nWalk method is a thin layer over [estraverse](https://github.com/estools/estraverse).\n\n```js\nconst { parse, walk } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nwalk(tree, (node, parent) =\u003e {\n  console.log(node)\n  console.log(parent)\n})\n```\n\n#### find\n\nFind supports two traversal methods. You can pass a string selector or pass an object that will be compared to every node in the tree. The method returns an array of nodes.\n\nThe following selectors are supported:\n\n- node type (`Identifier`)\n- node attribute (`[name=\"foo\"]`)\n- node attribute existence (`[name]`)\n- wildcard (`*`)\n\n```js\nconst { parse, find } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(find(tree, \"VariableDeclaration\")) // [ { type: 'VariableDeclaration', ... } ]\nconsole.log(find(tree, { type: \"VariableDeclaration\" })) // [ { type: 'VariableDeclaration', ... } ]\n```\n\n#### serialize\n\nSerialize can transform nodes into values. Works for: Array, Boolean, Error, Infinity, Map, NaN, Number, Object, RegExp, Set, String, Symbol, WeakMap, WeakSet, null and undefined.\n\n```js\nconst { serialize } = require(\"abstract-syntax-tree\")\nconst node = {\n  type: \"ArrayExpression\",\n  elements: [\n    { type: \"Literal\", value: 1 },\n    { type: \"Literal\", value: 2 },\n    { type: \"Literal\", value: 3 },\n    { type: \"Literal\", value: 4 },\n    { type: \"Literal\", value: 5 },\n  ],\n}\nconst array = serialize(node) // [1, 2, 3, 4, 5]\n```\n\n#### traverse\n\nTraverse method accepts a configuration object with enter and leave callbacks. It allows multiple transformations in one traversal.\n\n```js\nconst { parse, traverse } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\ntraverse(tree, {\n  enter(node) {},\n  leave(node) {},\n})\n```\n\n#### replace\n\nReplace extends [estraverse](https://github.com/estools/estraverse) by handling replacement of give node with multiple nodes. It will also remove given node if `null` is returned.\n\n```js\nconst { parse, replace } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nreplace(tree, (node) =\u003e {\n  if (node.type === \"VariableDeclaration\") {\n    node.kind = \"let\"\n  }\n  return node\n})\n```\n\n#### remove\n\nRemove uses [estraverse](https://github.com/estools/estraverse) and ensures that no useless nodes are left in the tree. It accepts a string, object or callback as the matching strategy.\n\n```js\nconst { parse, remove, generate } = require(\"abstract-syntax-tree\")\nconst source = '\"use strict\"; const b = 4;'\nconst tree = parse(source)\nremove(tree, 'Literal[value=\"use strict\"]')\n\n// or\n// remove(tree, { type: 'Literal', value: 'use strict' })\n\n// or\n// remove(tree, (node) =\u003e {\n//   if (node.type === 'Literal' \u0026\u0026 node.value === 'use strict') return null\n//   return node\n// })\n\nconsole.log(generate(tree)) // 'const b = 4;'\n```\n\n#### each\n\n```js\nconst { parse, each } = require(\"abstract-syntax-tree\")\nconst source = \"const foo = 1; const bar = 2;\"\nconst tree = parse(source)\neach(tree, \"VariableDeclaration\", (node) =\u003e {\n  console.log(node)\n})\n```\n\n#### first\n\n```js\nconst { parse, first } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(first(tree, \"VariableDeclaration\")) // { type: 'VariableDeclaration', ... }\n```\n\n#### last\n\n```js\nconst { parse, last } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(last(tree, \"VariableDeclaration\")) // { type: 'VariableDeclaration', ... }\n```\n\n#### reduce\n\n```js\nconst { parse, reduce } = require(\"abstract-syntax-tree\")\nconst source = \"const a = 1, b = 2\"\nconst tree = parse(source)\nconst value = reduce(\n  tree,\n  (sum, node) =\u003e {\n    if (node.type === \"Literal\") {\n      sum += node.value\n    }\n    return sum\n  },\n  0\n)\nconsole.log(value) // 3\n```\n\n#### has\n\n```js\nconst { parse, has } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(has(tree, \"VariableDeclaration\")) // true\nconsole.log(has(tree, { type: \"VariableDeclaration\" })) // true\n```\n\n#### count\n\n```js\nconst { parse, count } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nconsole.log(count(tree, \"VariableDeclaration\")) // 1\nconsole.log(count(tree, { type: \"VariableDeclaration\" })) // 1\n```\n\n#### append\n\nAppend pushes nodes to the body of the abstract syntax tree. It accepts estree nodes as input.\n\n```js\nconst { parse, append } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nappend(tree, {\n  type: \"ExpressionStatement\",\n  expression: {\n    type: \"CallExpression\",\n    callee: {\n      type: \"MemberExpression\",\n      object: {\n        type: \"Identifier\",\n        name: \"console\",\n      },\n      property: {\n        type: \"Identifier\",\n        name: \"log\",\n      },\n      computed: false,\n    },\n    arguments: [\n      {\n        type: \"Identifier\",\n        name: \"answer\",\n      },\n    ],\n  },\n})\n```\n\nStrings will be converted into abstract syntax tree under the hood. Please note that this approach might make the code run a bit slower due to an extra interpretation step.\n\n```js\nconst { parse, append } = require(\"abstract-syntax-tree\")\nconst source = \"const answer = 42\"\nconst tree = parse(source)\nappend(tree, \"console.log(answer)\")\n```\n\n#### prepend\n\nPrepend unshifts nodes to the body of the abstract syntax tree. Accepts estree nodes or strings as input, same as append.\n\n```js\nconst { parse, prepend } = require(\"abstract-syntax-tree\")\nconst source = \"const a = 1;\"\nconst tree = parse(source)\nprepend(tree, {\n  type: \"ExpressionStatement\",\n  expression: {\n    type: \"Literal\",\n    value: \"use strict\",\n  },\n})\n```\n\n#### equal\n\n```js\nconst { equal } = require(\"abstract-syntax-tree\")\nconsole.log(\n  equal({ type: \"Literal\", value: 42 }, { type: \"Literal\", value: 42 })\n) // true\nconsole.log(\n  equal({ type: \"Literal\", value: 41 }, { type: \"Literal\", value: 42 })\n) // false\n```\n\n#### match\n\n```js\nconst { match } = require(\"abstract-syntax-tree\")\nconsole.log(match({ type: \"Literal\", value: 42 }, \"Literal[value=42]\")) // true\nconsole.log(match({ type: \"Literal\", value: 41 }, \"Literal[value=42]\")) // false\n```\n\n#### template\n\nThe function converts the input to an equivalent abstract syntax tree representation. The function uses a `\u003c%= %\u003e` syntax to insert nodes.\n\nYou can also use standard javascript types and they're going to be transformed automatically.\n\n```js\nconst { template } = require(\"abstract-syntax-tree\")\nconst literal = template(42)\nconst nodes = template(\"const foo = \u003c%= bar %\u003e;\", {\n  bar: { type: \"Literal\", value: 1 },\n})\n```\n\n```js\nconst { template } = require(\"abstract-syntax-tree\")\nconst nodes = template(\"function foo(\u003c%= bar %\u003e) {}\", {\n  bar: [\n    { type: \"Identifier\", name: \"baz\" },\n    { type: \"Identifier\", name: \"qux\" },\n  ],\n})\n```\n\n```js\nconst { template } = require(\"abstract-syntax-tree\")\nconst literal = template(42)\nconst nodes = template(\"const foo = \u003c%= bar %\u003e;\", {\n  bar: 1,\n})\n```\n\n#### program\n\nCreates an abstract syntax tree with a blank program.\n\n```js\nconst { program } = require(\"abstract-syntax-tree\")\nconst tree = program() // { type: 'Program', sourceType: 'module', body: [] }\n```\n\n#### iife\n\nCreates an abstract syntax tree for an immediately invoked function expression.\n\n```js\nconst { iife } = require(\"abstract-syntax-tree\")\nconst node = iife() // { type: 'ExpressionStatement', expression: { ... } }\n```\n\n### Instance Methods\n\nAlmost all of the static methods (excluding parse, generate, template and match) have their instance equivalents. There are few extra instance methods:\n\n#### mark\n\n```js\nconst AbstractSyntaxTree = require(\"abstract-syntax-tree\")\nconst tree = new AbstractSyntaxTree(\"const a = 1\")\ntree.mark()\nconsole.log(tree.first(\"Program\").cid) // 1\nconsole.log(tree.first(\"VariableDeclaration\").cid) // 2\n```\n\n#### wrap\n\n```js\nconst AbstractSyntaxTree = require(\"abstract-syntax-tree\")\nconst source = \"const a = 1\"\nconst tree = new AbstractSyntaxTree(source)\ntree.wrap((body) =\u003e {\n  return [\n    {\n      type: \"ExpressionStatement\",\n      expression: {\n        type: \"CallExpression\",\n        callee: {\n          type: \"FunctionExpression\",\n          params: [],\n          body: {\n            type: \"BlockStatement\",\n            body,\n          },\n        },\n        arguments: [],\n      },\n    },\n  ]\n})\n```\n\n#### unwrap\n\n```js\nconst AbstractSyntaxTree = require(\"abstract-syntax-tree\")\nconst source = \"(function () { console.log(1); }())\"\nconst tree = new AbstractSyntaxTree(source)\ntree.unwrap()\nconsole.log(tree.source) // console.log(1);\n```\n\n### Getters\n\n#### body\n\nGives the body of the root node.\n\n#### source\n\nGives access to the source code representation of the abstract syntax tree.\n\n```js\nconst AbstractSyntaxTree = require(\"abstract-syntax-tree\")\nconst source = 'const foo = \"bar\";'\nconst tree = new AbstractSyntaxTree(source)\nconsole.log(tree.source) // const foo = \"bar\";\n```\n\n#### map\n\nGives the source map of the source code.\n\n### Setters\n\n#### body\n\nSets the body of the root node.\n\n## Transformations\n\n#### toBinaryExpression\n\n```js\nconst { toBinaryExpression } = require(\"abstract-syntax-tree\")\nconst expression = {\n  type: \"ArrayExpression\",\n  elements: [\n    { type: \"Literal\", value: \"foo\" },\n    { type: \"Literal\", value: \"bar\" },\n    { type: \"Literal\", value: \"baz\" },\n  ],\n}\nconsole.log(toBinaryExpression(expression)) // { type: 'BinaryExpression', ... }\n```\n\n## Nodes\n\nYou can also use classes to create nodes.\n\n```js\nconst { ArrayExpression, Literal } = require(\"abstract-syntax-tree\")\nconst expression = new ArrayExpression([\n  new Literal(\"foo\"),\n  new Literal(\"bar\"),\n  new Literal(\"baz\"),\n])\n```\n\nHere's a list of all available nodes, with examples.\n\n| Type                     |                             Example                              |\n| ------------------------ | :--------------------------------------------------------------: |\n| ArrayExpression          |                   \u003ccode\u003econst foo = []\u003c/code\u003e                    |\n| ArrayPattern             |               \u003ccode\u003econst [foo, bar] = bar\u003c/code\u003e                |\n| ArrowFunctionExpression  |                     \u003ccode\u003e(() =\u003e {})\u003c/code\u003e                      |\n| AssignmentExpression     |                      \u003ccode\u003efoo = bar\u003c/code\u003e                      |\n| AssignmentOperator       |                                                                  |\n| AssignmentPattern        |             \u003ccode\u003efunction foo(bar = baz) {} \u003c/code\u003e             |\n| AwaitExpression          |           \u003ccode\u003e(async () =\u003e { await foo() })()\u003c/code\u003e           |\n| BigIntLiteral            |                                                                  |\n| BinaryExpression         |                      \u003ccode\u003efoo + bar\u003c/code\u003e                      |\n| BinaryOperator           |                                                                  |\n| BlockStatement           |                \u003ccode\u003e{ console.log(foo) }\u003c/code\u003e                 |\n| BreakStatement           |               \u003ccode\u003efor (foo in bar) break\u003c/code\u003e                |\n| CallExpression           |                        \u003ccode\u003efoo()\u003c/code\u003e                        |\n| CatchClause              |               \u003ccode\u003etry {} catch (error) {}\u003c/code\u003e               |\n| ChainElement             |                                                                  |\n| ChainExpression          |                       \u003ccode\u003efoo?.()\u003c/code\u003e                       |\n| Class                    |                                                                  |\n| ClassBody                |                    \u003ccode\u003eclass Foo {}\u003c/code\u003e                     |\n| ClassDeclaration         |                    \u003ccode\u003eclass Foo {}\u003c/code\u003e                     |\n| ClassExpression          |                     \u003ccode\u003e(class {})\u003c/code\u003e                      |\n| ConditionalExpression    |                   \u003ccode\u003efoo ? bar : baz\u003c/code\u003e                   |\n| ContinueStatement        |              \u003ccode\u003ewhile(true) { continue }\u003c/code\u003e               |\n| DebuggerStatement        |                      \u003ccode\u003edebugger\u003c/code\u003e                       |\n| Declaration              |                                                                  |\n| Directive                |                                                                  |\n| DoWhileStatement         |                \u003ccode\u003edo {} while (true) {}\u003c/code\u003e                |\n| EmptyStatement           |                          \u003ccode\u003e;\u003c/code\u003e                          |\n| ExportAllDeclaration     |                \u003ccode\u003eexport \\* from \"foo\"\u003c/code\u003e                 |\n| ExportDefaultDeclaration |                 \u003ccode\u003eexport default foo\u003c/code\u003e                  |\n| ExportNamedDeclaration   |                \u003ccode\u003eexport { foo as bar }\u003c/code\u003e                |\n| ExportSpecifier          |                   \u003ccode\u003eexport { foo }\u003c/code\u003e                    |\n| Expression               |                                                                  |\n| ExpressionStatement      |                         \u003ccode\u003efoo\u003c/code\u003e                         |\n| ForInStatement           |                 \u003ccode\u003efor (foo in bar) {}\u003c/code\u003e                 |\n| ForOfStatement           |                 \u003ccode\u003efor (foo of bar) {}\u003c/code\u003e                 |\n| ForStatement             |          \u003ccode\u003efor (let i = 0; i \u003c 10; i ++) {}\u003c/code\u003e           |\n| Function                 |                                                                  |\n| FunctionBody             |                                                                  |\n| FunctionDeclaration      |                 \u003ccode\u003efunction foo () {}\u003c/code\u003e                  |\n| FunctionExpression       |                  \u003ccode\u003e(function () {})\u003c/code\u003e                   |\n| Identifier               |                         \u003ccode\u003efoo\u003c/code\u003e                         |\n| IfStatement              |                     \u003ccode\u003eif (foo) {}\u003c/code\u003e                     |\n| ImportDeclaration        |                    \u003ccode\u003eimport \"foo\"\u003c/code\u003e                     |\n| ImportDefaultSpecifier   |                \u003ccode\u003eimport foo from \"bar\"\u003c/code\u003e                |\n| ImportExpression         |                \u003ccode\u003eimport(foo).then(bar)\u003c/code\u003e                |\n| ImportNamespaceSpecifier |             \u003ccode\u003eimport \\* as foo from \"bar\"\u003c/code\u003e             |\n| ImportSpecifier          |              \u003ccode\u003eimport { foo } from \"bar\"\u003c/code\u003e              |\n| LabeledStatement         |                     \u003ccode\u003elabel: foo\u003c/code\u003e                      |\n| Literal                  |                         \u003ccode\u003e42\u003c/code\u003e                          |\n| LogicalExpression        |                    \u003ccode\u003etrue \u0026\u0026 false\u003c/code\u003e                    |\n| LogicalOperator          |                                                                  |\n| MemberExpression         |                       \u003ccode\u003efoo.bar\u003c/code\u003e                       |\n| MetaProperty             |           \u003ccode\u003efunction foo () { new.target }\u003c/code\u003e            |\n| MethodDefinition         |               \u003ccode\u003eclass Foo { bar() {} }\u003c/code\u003e                |\n| ModuleDeclaration        |                                                                  |\n| ModuleSpecifier          |                                                                  |\n| NewExpression            |                      \u003ccode\u003enew Foo()\u003c/code\u003e                      |\n| Node                     |                                                                  |\n| ObjectExpression         |                        \u003ccode\u003e({})\u003c/code\u003e                         |\n| ObjectPattern            |                \u003ccode\u003efunction foo ({}) {}\u003c/code\u003e                 |\n| Pattern                  |                                                                  |\n| Position                 |                                                                  |\n| Program                  |                         \u003ccode\u003e42\u003c/code\u003e                          |\n| Property                 |                                                                  |\n| RegExpLiteral            |                                                                  |\n| RestElement              |              \u003ccode\u003efunction foo (...bar) {}\u003c/code\u003e               |\n| ReturnStatement          |           \u003ccode\u003efunction foo () { return bar }\u003c/code\u003e            |\n| SequenceExpression       |                      \u003ccode\u003efoo, bar\u003c/code\u003e                       |\n| SourceLocation           |                                                                  |\n| SpreadElement            |                                                                  |\n| Statement                |                                                                  |\n| Super                    | \u003ccode\u003eclass Foo extends Bar { constructor() { super() } }\u003c/code\u003e |\n| SwitchCase               |            \u003ccode\u003eswitch (foo) { case 'bar': }\u003c/code\u003e             |\n| SwitchStatement          |                   \u003ccode\u003eswitch(foo) {}\u003c/code\u003e                    |\n| TaggedTemplateExpression |              \u003ccode\u003ecss`.foo { color: red; }`\u003c/code\u003e              |\n| TemplateLiteral          |              \u003ccode\u003ecss`.foo { color: red; }`\u003c/code\u003e              |\n| ThisExpression           |                  \u003ccode\u003ethis.foo = 'bar'\u003c/code\u003e                   |\n| ThrowStatement           |               \u003ccode\u003ethrow new Error(\"foo\")\u003c/code\u003e                |\n| TryStatement             |      \u003ccode\u003etry { foo() } catch (exception) { bar() }\u003c/code\u003e      |\n| UnaryExpression          |                        \u003ccode\u003e!foo\u003c/code\u003e                         |\n| UnaryOperator            |                                                                  |\n| UpdateExpression         |                        \u003ccode\u003efoo++\u003c/code\u003e                        |\n| UpdateOperator           |                                                                  |\n| VariableDeclaration      |                  \u003ccode\u003econst answer = 42\u003c/code\u003e                  |\n| VariableDeclarator       |                  \u003ccode\u003econst foo = 'bar'\u003c/code\u003e                  |\n| WhileStatement           |                   \u003ccode\u003ewhile (true) {}\u003c/code\u003e                   |\n| WithStatement            |                    \u003ccode\u003ewith (foo) {}\u003c/code\u003e                    |\n| YieldExpression          |           \u003ccode\u003efunction\\* foo() { yield bar }\u003c/code\u003e            |\n\n## Optimizations\n\n### How can you optimize an abstract syntax tree?\n\nAbstract syntax tree is a tree-like structure that represents your program. The program is interpreted at some point, e.g. in your browser. Everything takes time, and the same applies to the interpretation. Some of the operations, e.g. adding numbers can be done at compile time, so that the interpreter has less work to do. Having less work to do means that your program will run faster.\n\n### Usage\n\n```js\nconst { binaryExpressionReduction } = require(\"abstract-syntax-tree\")\n```\n\n### What optimization techniques are available?\n\n#### binaryExpressionReduction\n\n```js\nconst number = 2 + 2\n```\n\nIn the example above we have added two numbers. We could optimize the code by:\n\n```js\nconst number = 4\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"BinaryExpression\",\n  \"operator\": \"+\",\n  \"left\": { \"type\": \"Literal\", \"value\": 2 },\n  \"right\": { \"type\": \"Literal\", \"value\": 2 }\n}\n```\n\nto\n\n```json\n{ \"type\": \"Literal\", \"value\": 4 }\n```\n\n#### ifStatementRemoval\n\n```js\nif (true) {\n  console.log(\"foo\")\n} else {\n  console.log(\"bar\")\n}\n```\n\nIt seems that we'll only enter the true path. We can simplify the code to:\n\n```js\nconsole.log(\"foo\")\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"IfStatement\",\n  \"test\": {\n    \"type\": \"Literal\",\n    \"value\": true\n  },\n  \"consequent\": {\n    \"type\": \"BlockStatement\",\n    \"body\": [\n      {\n        \"type\": \"ExpressionStatement\",\n        \"expression\": {\n          \"type\": \"CallExpression\",\n          \"callee\": {\n            \"type\": \"MemberExpression\",\n            \"object\": {\n              \"type\": \"Identifier\",\n              \"name\": \"console\"\n            },\n            \"property\": {\n              \"type\": \"Identifier\",\n              \"name\": \"log\"\n            },\n            \"computed\": false\n          },\n          \"arguments\": [\n            {\n              \"type\": \"Literal\",\n              \"value\": \"foo\"\n            }\n          ]\n        }\n      }\n    ]\n  },\n  \"alternate\": {\n    \"type\": \"BlockStatement\",\n    \"body\": [\n      {\n        \"type\": \"ExpressionStatement\",\n        \"expression\": {\n          \"type\": \"CallExpression\",\n          \"callee\": {\n            \"type\": \"MemberExpression\",\n            \"object\": {\n              \"type\": \"Identifier\",\n              \"name\": \"console\"\n            },\n            \"property\": {\n              \"type\": \"Identifier\",\n              \"name\": \"log\"\n            },\n            \"computed\": false\n          },\n          \"arguments\": [\n            {\n              \"type\": \"Literal\",\n              \"value\": \"bar\"\n            }\n          ]\n        }\n      }\n    ]\n  }\n}\n```\n\nto:\n\n```js\n{\n        \"type\": \"CallExpression\",\n        \"callee\": {\n          \"type\": \"MemberExpression\",\n          \"object\": {\n            \"type\": \"Identifier\",\n            \"name\": \"console\"\n          },\n          \"property\": {\n            \"type\": \"Identifier\",\n            \"name\": \"log\"\n          },\n          \"computed\": false\n        },\n        \"arguments\": [\n          {\n            \"type\": \"Literal\",\n            \"value\": \"foo\"\n          }\n        ]\n      }\n```\n\n#### negationOperatorRemoval\n\n```js\nif (!(foo === bar)) {\n  console.log(\"foo\")\n}\n```\n\nIt seems that our negation operator could be a part of the condition inside the brackets.\n\n```js\nif (foo !== bar) {\n  console.log(\"foo\")\n}\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"UnaryExpression\",\n  \"operator\": \"!\",\n  \"prefix\": true,\n  \"argument\": {\n    \"type\": \"BinaryExpression\",\n    \"left\": {\n      \"type\": \"Identifier\",\n      \"name\": \"foo\"\n    },\n    \"operator\": \"===\",\n    \"right\": {\n      \"type\": \"Identifier\",\n      \"name\": \"bar\"\n    }\n  }\n}\n```\n\nto\n\n```json\n{\n  \"type\": \"BinaryExpression\",\n  \"left\": {\n    \"type\": \"Identifier\",\n    \"name\": \"foo\"\n  },\n  \"operator\": \"!==\",\n  \"right\": {\n    \"type\": \"Identifier\",\n    \"name\": \"bar\"\n  }\n}\n```\n\n#### logicalExpressionReduction\n\n```js\nconst foo = \"bar\" || \"baz\"\n```\n\nThe first value is truthy so it's safe to simplify the code.\n\n```js\nconst foo = \"bar\"\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"LogicalExpression\",\n  \"left\": {\n    \"type\": \"Literal\",\n    \"value\": \"bar\"\n  },\n  \"operator\": \"||\",\n  \"right\": {\n    \"type\": \"Literal\",\n    \"value\": \"baz\"\n  }\n}\n```\n\nTo:\n\n```json\n{\n  \"type\": \"Literal\",\n  \"value\": \"bar\"\n}\n```\n\n#### ternaryOperatorReduction\n\n```js\nconst foo = true ? \"bar\" : \"baz\"\n```\n\nGiven a known value of the conditional expression it's possible to get the right value immediately.\n\n```js\nconst foo = \"bar\"\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"ConditionalExpression\",\n  \"test\": {\n    \"type\": \"Literal\",\n    \"value\": true\n  },\n  \"consequent\": {\n    \"type\": \"Literal\",\n    \"value\": \"bar\"\n  },\n  \"alternate\": {\n    \"type\": \"Literal\",\n    \"value\": \"baz\"\n  }\n}\n```\n\nTo:\n\n```json\n{\n  \"type\": \"Literal\",\n  \"value\": \"bar\"\n}\n```\n\n#### typeofOperatorReduction\n\n```js\nconst foo = typeof \"bar\"\n```\n\nIt's possible to determine the type of some variables during analysis.\n\n```js\nconst foo = \"string\"\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"UnaryExpression\",\n  \"operator\": \"typeof\",\n  \"prefix\": true,\n  \"argument\": {\n    \"type\": \"Literal\",\n    \"value\": \"foo\"\n  }\n}\n```\n\nTo:\n\n```json\n{\n  \"type\": \"Literal\",\n  \"value\": \"string\"\n}\n```\n\n#### memberExpressionReduction\n\n```js\nconst foo = { bar: \"baz\" }.bar\n```\n\nGiven an inlined object expression it's possible to retrieve the value immediately.\n\n```js\nconst foo = \"baz\"\n```\n\nThe tree would be translated from:\n\n```json\n{\n  \"type\": \"MemberExpression\",\n  \"object\": {\n    \"type\": \"ObjectExpression\",\n    \"properties\": [\n      {\n        \"type\": \"Property\",\n        \"method\": false,\n        \"shorthand\": false,\n        \"computed\": false,\n        \"key\": {\n          \"type\": \"Identifier\",\n          \"name\": \"bar\"\n        },\n        \"value\": {\n          \"type\": \"Literal\",\n          \"value\": \"baz\"\n        },\n        \"kind\": \"init\"\n      }\n    ]\n  },\n  \"property\": {\n    \"type\": \"Identifier\",\n    \"name\": \"baz\"\n  },\n  \"computed\": false\n}\n```\n\nTo:\n\n```json\n{\n  \"type\": \"Literal\",\n  \"value\": \"baz\"\n}\n```\n\n## Browser\n\nThe library is not intended to work inside of a browser. This might change in the future, but it's a bigger lift, pretty time consuming. For now, consider exposing and using an API endpoint instead.\n\n## Maintainers\n\n[@emilos](https://github.com/emilos).\n\n## Contributing\n\nAll contributions are highly appreciated! [Open an issue](https://github.com/buxlabs/abstract-syntax-tree/issues/new) or a submit PR.\n\nThe lib follows the tdd approach and is expected to have a high code coverage. Please follow the [Contributor Covenant Code of Conduct](https://github.com/buxlabs/abstract-syntax-tree/blob/master/CODE_OF_CONDUCT.md).\n\n## License\n\nMIT © buxlabs\n","funding_links":["https://github.com/sponsors/emilos"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuxlabs%2Fabstract-syntax-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbuxlabs%2Fabstract-syntax-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuxlabs%2Fabstract-syntax-tree/lists"}