{"id":13482738,"url":"https://github.com/davidbonnet/astring","last_synced_at":"2025-05-13T15:09:59.785Z","repository":{"id":35835878,"uuid":"40119039","full_name":"davidbonnet/astring","owner":"davidbonnet","description":"🌳 Tiny and fast JavaScript code generator from an ESTree-compliant AST.","archived":false,"fork":false,"pushed_at":"2024-12-01T12:16:56.000Z","size":2810,"stargazers_count":1204,"open_issues_count":35,"forks_count":56,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-23T18:55:59.582Z","etag":null,"topics":["ast","code-generator","codegen","estree","javascript"],"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/davidbonnet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/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":"2015-08-03T10:28:29.000Z","updated_at":"2025-04-22T12:40:48.000Z","dependencies_parsed_at":"2025-04-01T22:11:07.103Z","dependency_job_id":"4c51f051-f6f8-415d-b238-de97e55a2883","html_url":"https://github.com/davidbonnet/astring","commit_stats":{"total_commits":815,"total_committers":17,"mean_commits":47.94117647058823,"dds":0.4503067484662576,"last_synced_commit":"96dfb2b347fc7e4f359b26579198097b9f0b1256"},"previous_names":[],"tags_count":89,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidbonnet%2Fastring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidbonnet%2Fastring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidbonnet%2Fastring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidbonnet%2Fastring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davidbonnet","download_url":"https://codeload.github.com/davidbonnet/astring/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253969243,"owners_count":21992262,"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":["ast","code-generator","codegen","estree","javascript"],"created_at":"2024-07-31T17:01:05.041Z","updated_at":"2025-05-13T15:09:54.768Z","avatar_url":"https://github.com/davidbonnet.png","language":"JavaScript","readme":"# Astring\n\n[![NPM Version](https://img.shields.io/npm/v/astring.svg)](https://www.npmjs.org/package/astring)\n[![Coverage](https://codecov.io/gh/davidbonnet/astring/branch/master/graph/badge.svg)](https://codecov.io/gh/davidbonnet/astring)\n\n🌳 Tiny and fast JavaScript code generator from an [ESTree](https://github.com/estree/estree)-compliant AST.\n\n### Key features\n\n- Generates JavaScript code up to [version 15 (2024)](https://tc39.github.io/ecma262/) and [stage 3 proposals](https://github.com/tc39/proposals#stage-3).\n- Works on [ESTree](https://github.com/estree/estree)-compliant ASTs such as the ones produced by [Meriyah](https://github.com/meriyah/meriyah) or [Acorn](https://github.com/acornjs/acorn).\n- Extendable with custom AST node handlers.\n- Considerably faster than [Bublé](https://gitlab.com/Rich-Harris/buble) (up to 5×), [Escodegen](https://github.com/estools/escodegen) (up to 10×), [Babel](https://github.com/babel/babel) (up to 50×), [UglifyJS](https://github.com/mishoo/UglifyJS2) (up to 125×), and [Prettier](https://github.com/prettier/prettier) (up to 380×).\n- Supports source map generation with [Source Map](https://github.com/mozilla/source-map#sourcemapgenerator).\n- Supports comment generation with [Astravel](https://github.com/davidbonnet/astravel).\n- No dependencies and small footprint (≈ 16 KB minified, ≈ 4 KB gziped).\n- Runs on [🦕 Deno](https://deno.land/x/astring).\n\n## Installation\n\n\u003e :warning: Astring relies on `String.prototype.repeat(amount)` and `String.prototype.endsWith(string)`. If the environment running Astring does not define these methods, use [`string.prototype.repeat`](https://www.npmjs.com/package/string.prototype.repeat), [`string.prototype.endsWith`](https://www.npmjs.com/package/string.prototype.endswith) or [`babel-polyfill`](https://www.npmjs.com/package/babel-polyfill).\n\nInstall with the [Node Package Manager](https://www.npmjs.com/package/astring):\n\n```bash\nnpm install astring\n```\n\nOr install with [JSR](https://jsr.io/@davidbonnet/astring):\n\n```bash\ndeno add @davidbonnet/astring\n```\n\nAlternatively, checkout this repository and install the development dependencies to build the module file:\n\n```bash\ngit clone https://github.com/davidbonnet/astring.git\ncd astring\nnpm install\n```\n\n## Import\n\nImport it from [Deno's third party module repository](https://deno.land/x/astring/src/astring.js):\n\n```js\nconst { generate } = await import('https://deno.land/x/astring/src/astring.js')\n```\n\nWith JavaScript 6 modules:\n\n```js\nimport { generate } from 'astring'\n```\n\nWith CommonJS:\n\n```js\nconst { generate } = require('astring')\n```\n\nA browser-ready minified bundle containing Astring is available at `dist/astring.min.js`. The module exposes a global variable `astring`:\n\n```html\n\u003cscript src=\"astring.min.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\"\u003e\n  var generate = astring.generate\n\u003c/script\u003e\n```\n\n## API\n\nThe `astring` module exposes the following properties:\n\n### `generate(node: object, options: object): string | object`\n\nReturns a string representing the rendered code of the provided AST `node`. However, if an `output` stream is provided in the `options`, it writes to that stream and returns it.\n\nThe `options` are:\n\n- `indent`: string to use for indentation (defaults to `\"␣␣\"`)\n- `lineEnd`: string to use for line endings (defaults to `\"\\n\"`)\n- `startingIndentLevel`: indent level to start from (defaults to `0`)\n- `comments`: generate comments if `true` (defaults to `false`)\n- `output`: output stream to write the rendered code to (defaults to `null`)\n- `generator`: custom code generator (defaults to `GENERATOR`)\n- `sourceMap`: [source map generator](https://github.com/mozilla/source-map#sourcemapgenerator) (defaults to `null`)\n- `expressionsPrecedence`: custom map of node types and their precedence level (defaults to `EXPRESSIONS_PRECEDENCE`)\n\n### `GENERATOR: object`\n\nBase generator that can be used to [extend Astring](#extending).\n\n### `EXPRESSIONS_PRECEDENCE: object`\n\nMapping of node types and their precedence level to let the generator know when to use parentheses.\n\n### `NEEDS_PARENTHESES: number`\n\nDefault precedence level that always triggers the use of parentheses.\n\n### `baseGenerator: object`\n\n\u003e :warning: Deprecated, use `GENERATOR` instead.\n\n## Benchmark\n\n### Generating code\n\nOperations per second for generating each sample code from a pre-parsed AST:\n\n| code sample (length) | escodegen |   astring |  uglify |   babel | prettier |\n| :------------------- | --------: | --------: | ------: | ------: | -------: |\n| tiny code (11)       | 1,257,527 | 7,185,642 | 129,467 | 156,184 |      333 |\n| everything (8532)    |     1,366 |     8,008 |       0 |     346 |       64 |\n\n### Parsing and generating code\n\nOperations per second for parsing and generating each sample code:\n\n| code sample (length) | acorn + astring | meriyah + astring |  buble | sucrase |\n| :------------------- | --------------: | ----------------: | -----: | ------: |\n| tiny code (11)       |          92,578 |           864,665 | 25,911 | 575,370 |\n| everything (8532)    |             706 |             1,425 |    132 |   1,403 |\n\n## Examples\n\nThe following examples are written in JavaScript 5 with Astring imported _à la CommonJS_.\n\n### Generating code\n\nThis example uses [Acorn](https://github.com/acornjs/acorn), a blazingly fast JavaScript AST producer and therefore the perfect companion of Astring.\n\n```javascript\n// Make sure acorn and astring modules are imported\n\n// Set example code\nvar code = 'let answer = 4 + 7 * 5 + 3;\\n'\n// Parse it into an AST\nvar ast = acorn.parse(code, { ecmaVersion: 6 })\n// Format it into a code string\nvar formattedCode = astring.generate(ast)\n// Check it\nconsole.log(code === formattedCode ? 'It works!' : 'Something went wrong…')\n```\n\n### Generating source maps\n\nThis example uses the source map generator from the [Source Map](https://github.com/mozilla/source-map#sourcemapgenerator) module.\n\n```javascript\n// Make sure acorn, sourceMap and astring modules are imported\n\nvar code = 'function add(a, b) { return a + b; }\\n'\nvar ast = acorn.parse(code, {\n  ecmaVersion: 6,\n  sourceType: 'module',\n  // Locations are needed in order for the source map generator to work\n  locations: true,\n})\n// Create empty source map generator\nvar map = new sourceMap.SourceMapGenerator({\n  // Source file name must be set and will be used for mappings\n  file: 'script.js',\n})\nvar formattedCode = generate(ast, {\n  // Enable source maps\n  sourceMap: map,\n})\n// Display generated source map\nconsole.log(map.toString())\n```\n\n### Using writable streams\n\nThis example for [Node](http://nodejs.org) shows how to use writable streams to get the rendered code.\n\n```javascript\n// Make sure acorn and astring modules are imported\n\n// Set example code\nvar code = 'let answer = 4 + 7 * 5 + 3;\\n'\n// Parse it into an AST\nvar ast = acorn.parse(code, { ecmaVersion: 6 })\n// Format it and write the result to stdout\nvar stream = astring.generate(ast, {\n  output: process.stdout,\n})\n// The returned value is the output stream\nconsole.log('Does stream equal process.stdout?', stream === process.stdout)\n```\n\n### Generating comments\n\nAstring supports comment generation, provided they are stored on the AST nodes. To do so, this example uses [Astravel](https://github.com/davidbonnet/astravel), a fast AST traveller and modifier.\n\n```javascript\n// Make sure acorn, astravel and astring modules are imported\n\n// Set example code\nvar code =\n  [\n    '// Compute the answer to everything',\n    'let answer = 4 + 7 * 5 + 3;',\n    '// Display it',\n    'console.log(answer);',\n  ].join('\\n') + '\\n'\n// Parse it into an AST and retrieve the list of comments\nvar comments = []\nvar ast = acorn.parse(code, {\n  ecmaVersion: 6,\n  locations: true,\n  onComment: comments,\n})\n// Attach comments to AST nodes\nastravel.attachComments(ast, comments)\n// Format it into a code string\nvar formattedCode = astring.generate(ast, {\n  comments: true,\n})\n// Check it\nconsole.log(code === formattedCode ? 'It works!' : 'Something went wrong…')\n```\n\n### Extending\n\nAstring can easily be extended by updating or passing a custom code `generator`. A code `generator` consists of a mapping of node names and functions that take two arguments: `node` and `state`. The `node` points to the node from which to generate the code and the `state` exposes the `write` method that takes generated code strings.\n\nThis example shows how to support the `await` keyword which is part of the [asynchronous functions proposal](https://github.com/tc39/ecmascript-asyncawait). The corresponding `AwaitExpression` node is based on [this suggested definition](https://github.com/estree/estree/blob/master/es2017.md).\n\n```javascript\n// Make sure the astring module is imported and that `Object.assign` is defined\n\n// Create a custom generator that inherits from Astring's base generator\nvar customGenerator = Object.assign({}, astring.GENERATOR, {\n  AwaitExpression: function (node, state) {\n    state.write('await ')\n    var argument = node.argument\n    if (argument != null) {\n      this[argument.type](argument, state)\n    }\n  },\n})\n// Obtain a custom AST somehow (note that this AST is not obtained from a valid code)\nvar ast = {\n  type: 'AwaitExpression',\n  argument: {\n    type: 'CallExpression',\n    callee: {\n      type: 'Identifier',\n      name: 'callable',\n    },\n    arguments: [],\n  },\n}\n// Format it\nvar code = astring.generate(ast, {\n  generator: customGenerator,\n})\n// Check it\nconsole.log(\n  code === 'await callable();\\n' ? 'It works!' : 'Something went wrong…',\n)\n```\n\n## Command line interface\n\nThe `bin/astring` utility can be used to convert a JSON-formatted ESTree compliant AST of a JavaScript code. It accepts the following arguments:\n\n- `-i`, `--indent`: string to use as indentation (defaults to `\"␣␣\"`)\n- `-l`, `--line-end`: string to use for line endings (defaults to `\"\\n\"`)\n- `-s`, `--starting-indent-level`: indent level to start from (defaults to `0`)\n- `-h`, `--help`: print a usage message and exit\n- `-v`, `--version`: print package version and exit\n\nThe utility reads the AST from a provided list of files or from `stdin` if none is supplied and prints the generated code.\n\n### Example\n\nAs in the previous example, these examples use [Acorn](https://github.com/acornjs/acorn) to get the JSON-formatted AST. This command pipes the AST output by Acorn from a `script.js` file to Astring and writes the formatted JavaScript code into a `result.js` file:\n\n```bash\nacorn --ecma6 script.js | astring \u003e result.js\n```\n\nThis command does the same, but reads the AST from an intermediary file:\n\n```bash\nacorn --ecma6 script.js \u003e ast.json\nastring ast.json \u003e result.js\n```\n\nThis command reads JavaScript 6 code from `stdin` and outputs a prettified version:\n\n```bash\ncat | acorn --ecma6 | astring\n```\n","funding_links":[],"categories":["JavaScript","Repository","javascript"],"sub_categories":["AST"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidbonnet%2Fastring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidbonnet%2Fastring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidbonnet%2Fastring/lists"}