{"id":22096000,"url":"https://github.com/perimeterx/flast","last_synced_at":"2025-04-13T05:13:24.556Z","repository":{"id":41607861,"uuid":"510275293","full_name":"PerimeterX/flast","owner":"PerimeterX","description":"Provides a flat Abstract Syntax Tree and an Arborist to trim and modify the tree","archived":false,"fork":false,"pushed_at":"2025-01-12T09:06:12.000Z","size":268,"stargazers_count":22,"open_issues_count":0,"forks_count":9,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-13T05:13:15.944Z","etag":null,"topics":[],"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/PerimeterX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-04T08:31:26.000Z","updated_at":"2025-04-06T16:01:39.000Z","dependencies_parsed_at":"2024-06-18T22:59:30.793Z","dependency_job_id":"de387b21-fda5-4487-aa0e-da2b590afbe3","html_url":"https://github.com/PerimeterX/flast","commit_stats":{"total_commits":76,"total_committers":8,"mean_commits":9.5,"dds":"0.48684210526315785","last_synced_commit":"b2f7e1b34b9bd8e9dbcab5910e6dd244fd544882"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fflast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fflast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fflast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerimeterX%2Fflast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PerimeterX","download_url":"https://codeload.github.com/PerimeterX/flast/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248665746,"owners_count":21142123,"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":[],"created_at":"2024-12-01T04:09:20.903Z","updated_at":"2025-04-13T05:13:24.522Z","avatar_url":"https://github.com/PerimeterX.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flAST - FLat Abstract Syntax Tree\n[![Run Tests](https://github.com/PerimeterX/flast/actions/workflows/node.js.yml/badge.svg?branch=main)](https://github.com/PerimeterX/flast/actions/workflows/node.js.yml)\n[![Downloads](https://img.shields.io/npm/dm/flast.svg?maxAge=43200)](https://www.npmjs.com/package/flast)\n\nFlatten an Abstract Syntax Tree by placing all the nodes in a single flat array.\n\nFor comments and suggestions feel free to open an issue or find me on Twitter - [@ctrl__esc](https://twitter.com/ctrl__esc)\n\n## Table of Contents\n* [Installation](#installation)\n  * [npm](#npm)\n  * [Clone The Repo](#clone-the-repo)\n* [Features](#features)\n  * [flAST Data Structure](#flast-data-structure)\n* [Usage](#usage)\n  * [flAST](#flast)\n    * [generateFlatAST Options](#generateflatast-options)\n    * [generateCode Options](#generatecode-options)\n  * [Arborist](#arborist)\n* [How to Contribute](#how-to-contribute)\n***\n\n## Installation\n### npm\n```bash\nnpm install flast\n```\n\n### Clone The Repo\nRequires Node 18 or newer.\n```bash\ngit clone git@github.com:PerimeterX/flast.git\ncd flast\nnpm install\n```\n\n***\n\n## Features\n- Keeps all relations between parent and child nodes.\n- Tracks scope and connects each declaration to its references.  \n  See [eslint-scope](https://github.com/eslint/eslint-scope) for more info on the scopes used.\n- Adds a unique id to each node to simplify tracking and understanding relations between nodes.\n- Maps the types to the nodes for easier access.\n- \u003cu\u003eArborist\u003c/u\u003e - marks nodes for replacement or deletion and applies all changes in a single iteration over the tree.\n\n### flAST Data Structure\n\u003cdetails\u003e\n  \u003csummary\u003eExample of how a flat AST would look like.\u003c/summary\u003e\n\nInput code: `console.log('flAST');`.\nOutput object:\n```javascript\nconst tree = [\n  {\n    type: 'program',\n    start: 0,\n    end: 21,\n    range: [0, 21],\n    body: [\n      '\u003cref to nodeId#2\u003e'\n    ],\n    sourceType: 'script',\n    comments: [],\n    nodeId: 0,\n    src: \"console.log('flAST');\",\n    childNodes: [\n      '\u003cref to nodeId#1\u003e'\n    ],\n    parentNode: null,\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'ExpressionStatement',\n    start: 0,\n    end: 21,\n    range: [0, 21],\n    expression: '\u003cref to nodeId#2\u003e',\n    nodeId: 1,\n    src: \"console.log('flAST');\",\n    childNodes: [\n      '\u003cref to nodeId#2\u003e'\n    ],\n    parentNode: '\u003cref to nodeId#0\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'CallExpression',\n    start: 0,\n    end: 20,\n    range: [0, 20],\n    callee: '\u003cref to nodeId#3\u003e',\n    arguments: [\n      '\u003cref to nodeId#6\u003e'\n    ],\n    optional: false,\n    nodeId: 2,\n    src: \"console.log('flAST')\",\n    childNodes: [\n      '\u003cref to nodeId#3\u003e',\n      '\u003cref to nodeId#6\u003e'\n    ],\n    parentNode: '\u003cref to nodeId#1\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'MemberExpression',\n    start: 0,\n    end: 11,\n    range: [0, 11],\n    object: '\u003cref to nodeId#4\u003e',\n    property: '\u003cref to nodeId#5\u003e',\n    computed: false,\n    optional: false,\n    nodeId: 3,\n    src: 'console.log',\n    childNodes: [\n      '\u003cref to nodeId#4\u003e',\n      '\u003cref to nodeId#5\u003e'\n    ],\n    parentNode: '\u003cref to nodeId#2\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'Identifier',\n    start: 0,\n    end: 7,\n    range: [0, 7],\n    name: 'console',\n    nodeId: 4,\n    src: 'console',\n    childNodes: [],\n    parentNode: '\u003cref to nodeId#3\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'Identifier',\n    start: 8,\n    end: 11,\n    range: [8, 11],\n    name: 'log',\n    nodeId: 5,\n    src: 'log',\n    childNodes: [],\n    parentNode: '\u003cref to nodeId#3\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  },\n  {\n    type: 'Literal',\n    start: 12,\n    end: 19,\n    range: [12, 19],\n    value: \"flAST\",\n    raw: \"'flAST'\",\n    nodeId: 6,\n    src: \"'flAST'\",\n    childNodes: [],\n    parentNode: '\u003cref to nodeId#2\u003e',\n    scope: '\u003cGlobalScope scopeId#0\u003e'\n  }\n];\n```\n\u003c/details\u003e\n\n## Usage\n### flAST\n\n```javascript\nimport {generateFlatAST, generateCode} from 'flast';\nconst ast = generateFlatAST(`console.log('flAST')`);\nconst reconstructedCode = generateCode(ast[0]); // rebuild from root node\n```\n#### generateFlatAST Options\n```javascript\nconst generateFlatASTDefaultOptions = {\n  detailed: true,   // If false, include only original node without any further details\n  includeSrc: true, // If false, do not include node src. Only available when `detailed` option is true\n};\n```\n\n#### generateCode Options\nSee [Espree's documentation](https://github.com/eslint/espree#options) for more information\n```javascript\nconst generateCodeDefaultOptions = {\n  format: {\n    indent: {\n      style: '  ',\n      adjustMultilineComment: true,\n    },\n    quotes: 'auto',\n    escapeless: true,\n    compact: false,\n  },\n  comment: true,\n};\n```\n\n### Arborist\n\n```javascript\nimport {generateFlatAST, generateCode, Arborist} from 'flast';\nconst ast = generateFlatAST(`console.log('Hello' + ' ' + 'there!');`);\nconst replacements = {\n  'Hello': 'General',\n  'there!': 'Kenobi',\n};\nconst arborist = new Arborist(ast);\n// Mark all relevant nodes for replacement.\nast.filter(n =\u003e n.type === 'Literal' \u0026\u0026 replacements[n.value]).forEach(n =\u003e arborist.markNode(n, {\n  type: 'Literal',\n  value: replacements[n.value],\n  raw: `'${replacements[n.value]}'`,\n}));\nconst numberOfChangesMade = arborist.applyChanges();\nconsole.log(generateCode(arborist.ast[0]));  // console.log('General' + ' ' + 'Kenobi');\n```\nThe Arborist can be called with an extra argument - logFunc - which can be used to override the log\nfunction inside the arborist. \n\n## How to Contribute\nTo contribute to this project see our [contribution guide](CONTRIBUTING.md)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperimeterx%2Fflast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fperimeterx%2Fflast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperimeterx%2Fflast/lists"}