├── .nvmrc ├── dist └── .keep ├── .prettierignore ├── src ├── tests │ ├── fixtures │ │ ├── syntax │ │ │ ├── export-class.js │ │ │ ├── number.js │ │ │ ├── export-function.js │ │ │ ├── await.js │ │ │ ├── debugger.js │ │ │ ├── array.js │ │ │ ├── sequence.js │ │ │ ├── literal.js │ │ │ ├── error.js │ │ │ ├── call.js │ │ │ ├── variable.js │ │ │ ├── export.js │ │ │ ├── import.js │ │ │ ├── template.js │ │ │ ├── object.js │ │ │ ├── operators.js │ │ │ ├── loop.js │ │ │ ├── control.js │ │ │ ├── function.js │ │ │ ├── class.js │ │ │ └── precedence.js │ │ ├── other │ │ │ └── a.json │ │ ├── deprecated │ │ │ └── es5.js │ │ ├── comment │ │ │ ├── block.js │ │ │ └── line.js │ │ └── tree │ │ │ └── es6.js │ ├── tools.js │ ├── performance.js │ ├── scripts.js │ ├── benchmark.js │ └── astring.js └── astring.js ├── .github ├── dependencies.yml ├── dependabot.yml └── workflows │ ├── dependencies.yml │ └── tests.yml ├── .gitignore ├── .eslintignore ├── docs ├── index.html ├── ISSUE_TEMPLATE.md ├── demo │ ├── style.css │ ├── index.html │ ├── astring.min.js │ └── astring.min.js.map └── CONTRIBUTING.md ├── deno.json ├── .npmignore ├── babel.config.js ├── astring.sublime-project ├── LICENSE ├── .eslintrc.json ├── astring.d.ts ├── bin └── astring ├── package.json ├── README.md └── CHANGELOG.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /dist/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/tests/fixtures/**/*.js -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/export-class.js: -------------------------------------------------------------------------------- 1 | export default class {} 2 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/number.js: -------------------------------------------------------------------------------- 1 | let a; 2 | a = 1n; 3 | a = 1; 4 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/export-function.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/await.js: -------------------------------------------------------------------------------- 1 | async function f() { 2 | await (() => 1); 3 | } 4 | -------------------------------------------------------------------------------- /src/tests/fixtures/other/a.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": "For testing import-attributes" 3 | } -------------------------------------------------------------------------------- /.github/dependencies.yml: -------------------------------------------------------------------------------- 1 | - match: 2 | dependency_type: all 3 | update_type: 'semver:minor' 4 | -------------------------------------------------------------------------------- /src/tests/fixtures/deprecated/es5.js: -------------------------------------------------------------------------------- 1 | var a = {}; 2 | with (a) { 3 | b = 1; 4 | c = 2; 5 | } 6 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/debugger.js: -------------------------------------------------------------------------------- 1 | debugger; 2 | "this string should be mapped to the second line"; 3 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/array.js: -------------------------------------------------------------------------------- 1 | let a = []; 2 | let b = [42]; 3 | let c = [42, 7]; 4 | let [d, ...e] = [1, 2, 3, 4, 5]; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-workspace 3 | test/_*.js 4 | .nyc_output 5 | coverage 6 | dist 7 | local 8 | node_modules 9 | npm-debug.log 10 | .nova/ -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/sequence.js: -------------------------------------------------------------------------------- 1 | let a = (x => (x, x * 2), 3); 2 | let b = ((x, y) => (x, x * y), 1); 3 | let c = (x => x * x)(2); 4 | let d = (1, 2, 3); 5 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/literal.js: -------------------------------------------------------------------------------- 1 | const a = Infinity; 2 | const b = -Infinity; 3 | const c = +Infinity; 4 | const d = /abc/; 5 | const e = /abc/g; 6 | const f = /abc/gi; 7 | -------------------------------------------------------------------------------- /src/tests/tools.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import normalizeNewline from 'normalize-newline' 3 | 4 | export function readFile(filePath) { 5 | return normalizeNewline(fs.readFileSync(filePath, 'utf8')) 6 | } 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | local/* 3 | vendor/* 4 | dist/* 5 | src/tests/fixtures/deprecated/es5.js 6 | src/tests/fixtures/syntax/import.js 7 | src/tests/fixtures/syntax/export.js 8 | src/tests/fixtures/tree/es6.js 9 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/error.js: -------------------------------------------------------------------------------- 1 | try { 2 | let a = 42; 3 | } catch (error) { 4 | let b = error; 5 | } 6 | try { 7 | let a = 42; 8 | } catch (error) { 9 | let b = error; 10 | } finally { 11 | let c = "done"; 12 | } 13 | throw new Error("this is an error"); 14 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/call.js: -------------------------------------------------------------------------------- 1 | f(); 2 | g(a); 3 | h(a, b); 4 | i(a, b, ...c); 5 | j(...a); 6 | a.k(); 7 | (a + b).l(); 8 | a.m().n(); 9 | new A(); 10 | new A(a); 11 | new a.B(); 12 | new a.b.C(); 13 | new (a().B)(); 14 | new A().b(); 15 | new new A()(); 16 | new (A, B)(); 17 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/variable.js: -------------------------------------------------------------------------------- 1 | var a; 2 | let b = 42; 3 | const c = 21 * 2; 4 | let {e} = d; 5 | var f, g = 42, h = false; 6 | let {i, j: k} = l; 7 | let [m, n] = c; 8 | var {a: [o, {p}]} = d; 9 | let {q = 42} = f; 10 | const {g: r = 42} = i; 11 | const {s, ...t} = r; 12 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Astring 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@davidbonnet/astring", 3 | "version": "1.8.6", 4 | "exports": "./src/astring.js", 5 | "publish": { 6 | "include": [ 7 | "LICENSE", 8 | "README.md", 9 | "src/astring.js", 10 | "astring.d.ts", 11 | "deno.json" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.sublime-project 2 | *.sublime-workspace 3 | .nova 4 | .eslintignore 5 | .gitignore 6 | .npmignore 7 | .nyc_output 8 | .travis.yml 9 | .prettierignore 10 | .nvmrc 11 | .github 12 | CHANGELOG.md 13 | coverage/ 14 | dist/.keep 15 | docs/ 16 | local/ 17 | node_modules/ 18 | package-lock.json 19 | src/ 20 | babel.config.js 21 | *.DS_Store -------------------------------------------------------------------------------- /docs/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Motivation 2 | 3 | _Describe cases that motivate the implementation of the expected behavior._ 4 | 5 | # Expected behavior 6 | 7 | _Describe how the feature should work._ 8 | 9 | # Actual behavior 10 | 11 | _Describe the actual behavior of the feature or remove this section if the feature has not been implemented yet._ 12 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/export.js: -------------------------------------------------------------------------------- 1 | export * from "module"; 2 | export * as m from "module"; 3 | export {name} from "module"; 4 | export {a as b, c as d} from "module"; 5 | let e, g; 6 | export {e as f, g as h}; 7 | export {}; 8 | export default i = 42; 9 | export var j = 42; 10 | export let k = 42; 11 | export function l() {} 12 | export {val} from '../other/a.json' with { type: "json" }; 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | time: "12:00" 8 | open-pull-requests-limit: 10 9 | versioning-strategy: increase 10 | ignore: 11 | - dependency-name: "@babel/parser" 12 | versions: 13 | - 7.12.13 14 | - 7.13.10 15 | - dependency-name: "@babel/generator" 16 | versions: 17 | - 7.12.13 18 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/import.js: -------------------------------------------------------------------------------- 1 | import a from "module"; 2 | import b, * as c from "module"; 3 | import * as d from "module"; 4 | import e, {f as g, h as i, j} from "module"; 5 | import {k as l, m} from "module"; 6 | import {n, o as p} from "module"; 7 | import * as q from "../other/a.json" with { type: "json" }; 8 | import r from "../other/a.json" with { type: "json" }; 9 | import("module"); 10 | const x = import("module"); 11 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/template.js: -------------------------------------------------------------------------------- 1 | let a; 2 | let b = `this is a template`; 3 | let c = `this is a template\ 4 | with multiple 5 | lines`; 6 | let d = f`template with function`; 7 | let e = f`template with ${some} ${variables}`; 8 | let f = f`template with ${some}${variables}${attached}`; 9 | let g = (f())`template with function call before`; 10 | let h = (f().g)`template with more complex function call`; 11 | let i = (() => {})`test`; 12 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/object.js: -------------------------------------------------------------------------------- 1 | let a = {}; 2 | let b = { 3 | "1": "one", 4 | "2": "two", 5 | "3": "three" 6 | }; 7 | let c = { 8 | [42]: "answer", 9 | [7]: "lucky" 10 | }; 11 | let d = { 12 | a: 1, 13 | b: 2, 14 | c: 3 15 | }; 16 | let e = d.a; 17 | let f = d["c"]; 18 | let g = { 19 | m() {}, 20 | ['n'](a) {}, 21 | o(a) { 22 | return a; 23 | } 24 | }; 25 | let h = ({}).toString(); 26 | let i = { 27 | ...d, 28 | a 29 | }; 30 | a?.['b']?.[0]?.(1); 31 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/operators.js: -------------------------------------------------------------------------------- 1 | let a, b, c, d; 2 | a = a || (a = 2); 3 | a ||= 2; 4 | a = a && (a = 2); 5 | a &&= 2; 6 | a = a ?? (a = 2); 7 | a ??= 2; 8 | b = 1 + 2; 9 | b = 1 - 2; 10 | b = 1 / 2; 11 | b = 1 * 2; 12 | c = 2 ** 1; 13 | c = 1 % 2; 14 | d = 1 << 2; 15 | d = 1 >> 2; 16 | d = 1 >>> 2; 17 | d = 1 & 3; 18 | d = 1 ^ 3; 19 | d = 1 | 3; 20 | a == b; 21 | a === b; 22 | a != b; 23 | a !== b; 24 | a > b; 25 | a >= b; 26 | a < b; 27 | a <= b; 28 | ++a; 29 | a++; 30 | +a; 31 | -a; 32 | --a; 33 | a--; 34 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/loop.js: -------------------------------------------------------------------------------- 1 | for (let a in b) {} 2 | for (let [a, b] in c) {} 3 | for (let {a, b} in c) {} 4 | for (let {a: b, c} in d) {} 5 | for (let a of b) {} 6 | for (var [a, b] of c) {} 7 | for (let {a, b} in c) {} 8 | for (let {a: b, c} in d) {} 9 | for (let i = 0, {length} = list; i < length; i++) {} 10 | for (; ; ) {} 11 | for (function () { 12 | const i = 0; 13 | }; ; ) {} 14 | for (() => { 15 | const i = 0; 16 | }; ; ) {} 17 | async function test() { 18 | for await (const x of xs) { 19 | x(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/control.js: -------------------------------------------------------------------------------- 1 | if (a > b) {} else {} 2 | if (c != d) {} 3 | var a = b > c ? d : e; 4 | let b = (c = 1) ? d : e; 5 | switch (a) { 6 | case b: 7 | break; 8 | case "c": 9 | break; 10 | case 42: 11 | break; 12 | case d: 13 | if (a < b) {} 14 | break; 15 | default: 16 | break; 17 | } 18 | while (a > b) { 19 | if (c == d) { 20 | break; 21 | } 22 | } 23 | do { 24 | if (e === f) { 25 | continue; 26 | } 27 | } while (g < h); 28 | label: if (a === b) { 29 | if (b = c) { 30 | break label; 31 | } 32 | } 33 | if (a != b) {} 34 | endingLabel: {} 35 | -------------------------------------------------------------------------------- /.github/workflows/dependencies.yml: -------------------------------------------------------------------------------- 1 | name: Dependencies 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, synchronize, reopened, ready_for_review] 6 | branches: [master] 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | merge: 12 | name: Merge 13 | runs-on: ubuntu-latest 14 | if: ${{ github.actor == 'dependabot[bot]' }} 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: ahmadnassri/action-dependabot-auto-merge@v2 19 | with: 20 | target: minor 21 | github-token: ${{ secrets.ACCESS_TOKEN }} 22 | config: .github/dependencies.yml 23 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node-version: [14, 16] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v2 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | cache: 'npm' 23 | - run: npm ci 24 | - run: npm test 25 | - run: npx codecov --file=./coverage/lcov.info 26 | -------------------------------------------------------------------------------- /src/tests/fixtures/comment/block.js: -------------------------------------------------------------------------------- 1 | /* 2 | Block comment for this script file. 3 | */ 4 | /* 5 | Block comment for function f. 6 | */ 7 | function f() {} 8 | /** 9 | * JSDoc block comment. 10 | * @param {string} a - Some string to test 11 | */ 12 | function g(a) { 13 | return a; 14 | } 15 | /* 16 | Block comment for function g. 17 | */ 18 | function h() { 19 | /* 20 | Block comment inside of function g. 21 | */ 22 | instruction1; 23 | /* 24 | Block comment for instruction 2 with a quote: 25 | > What was that? 26 | */ 27 | instruction2; 28 | /* 29 | Block comment for instruction 3… 30 | …with several indented lines. 31 | */ 32 | instruction3; 33 | /* 34 | Trailing block comment inside of function g. 35 | */ 36 | } 37 | /* 38 | Trailing block comment of this script file. 39 | */ 40 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.cache.never() 3 | switch (process.env.BABEL_MODE) { 4 | case 'minified': 5 | return { 6 | presets: [ 7 | [ 8 | '@babel/preset-env', 9 | { 10 | forceAllTransforms: true, 11 | modules: 'umd', 12 | }, 13 | ], 14 | [ 15 | 'minify', 16 | { 17 | mangle: { 18 | blacklist: { 19 | generate: true, 20 | baseGenerator: true, 21 | }, 22 | }, 23 | }, 24 | ], 25 | ], 26 | } 27 | default: 28 | return { 29 | presets: [ 30 | [ 31 | '@babel/preset-env', 32 | { 33 | forceAllTransforms: true, 34 | }, 35 | ], 36 | ], 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /astring.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".", 5 | "folder_exclude_patterns": ["node_modules", "coverage", ".nyc_output"] 6 | } 7 | ], 8 | "settings": { 9 | "folder_exclude_patterns": [".git", "node_modules", "dist"], 10 | "tab_size": 2, 11 | "js_prettier": { 12 | "auto_format_on_save": true, 13 | "auto_format_on_save_excludes": [ 14 | "*/dist/*", 15 | "*/fixtures/*", 16 | "*/node_modules/*", 17 | "*/.git/*" 18 | ], 19 | "allow_inline_formatting": true, 20 | "custom_file_extensions": ["sublime-project"], 21 | "additional_cli_args": { 22 | "--config": "package.json", 23 | "--config-precedence": "prefer-file", 24 | "--parser": "babel" 25 | } 26 | } 27 | }, 28 | "SublimeLinter": { 29 | "linters": { 30 | "eslint": { 31 | "disable": false 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/function.js: -------------------------------------------------------------------------------- 1 | function f(a, b, c) { 2 | return null; 3 | } 4 | var g = function (a, b, c) { 5 | return null; 6 | }; 7 | function h(a, b = 1, c = 2) { 8 | return null; 9 | } 10 | function i(a = 1, b, c) { 11 | return null; 12 | } 13 | function j(...a) {} 14 | function k() {} 15 | var l = function () {}; 16 | var m = function (a = 1, b, c) {}; 17 | function* o() { 18 | yield 42; 19 | } 20 | function* p() { 21 | yield 42; 22 | yield 4 + 2; 23 | return "answer"; 24 | } 25 | async function a() {} 26 | const b = async function () {}; 27 | const c = { 28 | async f() {} 29 | }; 30 | const d = async () => {}; 31 | async function e() { 32 | await a + await b; 33 | return await f(); 34 | } 35 | let q = function* () {}; 36 | let r = a => a; 37 | let s = (a, b) => a + b; 38 | let t = (a, b = 0) => a + b; 39 | let u = (a, b) => {}; 40 | let v = () => {}; 41 | let w = () => ({}); 42 | let x = () => { 43 | let a = 42; 44 | return a; 45 | }; 46 | let y = () => ({ 47 | a: 1, 48 | b: 2 49 | }); 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, David Bonnet 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/tests/fixtures/comment/line.js: -------------------------------------------------------------------------------- 1 | function f() {} 2 | // Line comment for function g: 3 | function g() { 4 | // Line comment for instruction 1: 5 | instruction1; 6 | // Line comment for instruction 2: 7 | instruction2; 8 | instruction3; 9 | // Line comment for instruction 4: 10 | instruction4; 11 | instruction5; 12 | switch (value) { 13 | // Line comment for case 1: 14 | case 1: 15 | break; 16 | // Line comment for case 2: 17 | case 2: 18 | // Line comment for break: 19 | break; 20 | // Line comment for default: 21 | default: 22 | break; 23 | } 24 | // Comment above object 25 | var point = { 26 | // More line comments 27 | // Line comment for property x: 28 | x: 0, 29 | // Line comment for property y: 30 | y: 1 31 | // Trailing line comment of point object 32 | }; 33 | // Comment after object 34 | // Comments before empty object 35 | var object = {}; 36 | instruction6; 37 | // Several line comments 38 | // …for… 39 | // …instruction 7: 40 | instruction7; 41 | // Trailing line comment 42 | // Another comment 43 | } 44 | // Last line comment 45 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/class.js: -------------------------------------------------------------------------------- 1 | class A { 2 | constructor() {} 3 | } 4 | class B extends A {} 5 | class C extends A { 6 | method() {} 7 | get property() { 8 | return this._property; 9 | } 10 | set property(value) { 11 | this._property = value; 12 | } 13 | } 14 | class D extends class A {} {} 15 | class E extends class { 16 | constructor() {} 17 | } {} 18 | class F extends class { 19 | constructor() {} 20 | } { 21 | constructor() {} 22 | } 23 | class G { 24 | [Symbol.iterator]() {} 25 | ["method"]() {} 26 | } 27 | class H { 28 | static classMethod() {} 29 | method() {} 30 | } 31 | class I { 32 | static get property() {} 33 | static set property(value) {} 34 | } 35 | class J extends A { 36 | constructor() { 37 | super(); 38 | } 39 | } 40 | class K extends (() => {}) {} 41 | class L extends (1 + 1) {} 42 | class M extends (-1) {} 43 | class N extends (c++) {} 44 | function* a() { 45 | class A extends (yield) {} 46 | } 47 | async function b() { 48 | class A extends (await a()) {} 49 | } 50 | const e = 'test'; 51 | class O { 52 | #a = 42; 53 | #b() {} 54 | static #c = 'C'; 55 | #d; 56 | static { 57 | const a = 3; 58 | } 59 | static [e] = 123; 60 | } 61 | -------------------------------------------------------------------------------- /docs/demo/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica, sans-serif; 3 | } 4 | 5 | #console, 6 | #output { 7 | font-family: Menlo, "Bitstream Vera Sans Mono", Courier, monospace; 8 | font-size: 12px; 9 | -webkit-border-radius: 5px; 10 | -moz-border-radius: 5px; 11 | -o-border-radius: 5px; 12 | border-radius: 5px; 13 | border: 2px solid #c6c6c6; 14 | width: 90%; 15 | margin: 10px auto 10px auto; 16 | padding: 10px; 17 | } 18 | 19 | #console { 20 | background-color: #ffffe8; 21 | resize: vertical; 22 | outline: none; 23 | display: block; 24 | } 25 | 26 | .invalid { 27 | border-color: #f60016 !important; 28 | } 29 | 30 | #output { 31 | background-color: #eee; 32 | overflow: auto; 33 | } 34 | 35 | h1, 36 | p { 37 | text-align: center; 38 | } 39 | 40 | p { 41 | color: #696969; 42 | width: 90%; 43 | margin: 10px auto 10px auto; 44 | } 45 | 46 | p.settings { 47 | font-size: 0.8em; 48 | text-align: left; 49 | -webkit-touch-callout: none; 50 | -webkit-user-select: none; 51 | -khtml-user-select: none; 52 | -moz-user-select: none; 53 | -ms-user-select: none; 54 | user-select: none; 55 | } 56 | 57 | .settings label { 58 | padding-right: 2em; 59 | } 60 | 61 | a { 62 | text-decoration: none; 63 | color: #155fce; 64 | } 65 | 66 | a:hover { 67 | text-decoration: underline; 68 | } 69 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["import"], 3 | "extends": ["eslint:recommended", "plugin:import/errors", "prettier"], 4 | "env": { 5 | "es6": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 13, 9 | "sourceType": "module" 10 | }, 11 | "globals": { 12 | "console": true, 13 | "global": true, 14 | "module": true, 15 | "process": true, 16 | "require": true, 17 | "window": true, 18 | "__dirname": true 19 | }, 20 | "overrides": [ 21 | { 22 | "files": ["src/tests/fixtures/**/*.js"], 23 | "rules": { 24 | "constructor-super": 0, 25 | "getter-return": 0, 26 | "no-cond-assign": 0, 27 | "no-constant-condition": 0, 28 | "no-control-regex": 0, 29 | "no-debugger": 0, 30 | "no-dupe-class-members": 0, 31 | "no-dupe-keys": 0, 32 | "no-duplicate-case": 0, 33 | "no-empty": 0, 34 | "no-inner-declarations": 0, 35 | "no-irregular-whitespace": 0, 36 | "no-redeclare": 0, 37 | "no-sparse-arrays": 0, 38 | "no-undef": 0, 39 | "no-unreachable": 0, 40 | "no-unsafe-negation": 0, 41 | "no-unused-labels": 0, 42 | "no-unused-vars": 0, 43 | "no-useless-escape": 0, 44 | "no-var": 0, 45 | "no-loss-of-precision": 0 46 | } 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src/tests/fixtures/syntax/precedence.js: -------------------------------------------------------------------------------- 1 | var a, b, c, d, e, f, g, x, y, z; 2 | a = 1 + 2 * 3 / 5; 3 | b = (1 + 2) * 3 / 5; 4 | c = (1 + 2) * (3 - 5); 5 | d = x | y ^ z; 6 | e = (x | y) ^ z; 7 | f = "a" + (1 + 2) + "b"; 8 | g = "a" + (1 - 2) + "b"; 9 | a = true || false && null; 10 | b = c == d || e != f; 11 | b = (c || d) ?? e; 12 | b = c || (d ?? e); 13 | b = c && (d || e); 14 | b = c && (d ?? e); 15 | b = (c && d) ?? e; 16 | c = x instanceof y || x instanceof z; 17 | d = x == y && y != z; 18 | a = !false; 19 | b = !x instanceof Number; 20 | c = !(x instanceof Number); 21 | d = typeof a === 'boolean'; 22 | e = !typeof a === 'boolean'; 23 | f = !(typeof a === 'boolean'); 24 | f = typeof (() => {}); 25 | a = (1.1).toString(); 26 | b = new A().toString(); 27 | c = new x.A().toString(); 28 | d = new x.y().z(); 29 | var r = (/ab+c/i).exec('abc'); 30 | a = b ** 2 * 3; 31 | c = (d ** 2) ** 3; 32 | e = f ** 2 ** 3; 33 | e = (+2) ** 3; 34 | e = 2 ** +3; 35 | f = a + (b = 3); 36 | g = 1 && (() => {}); 37 | g = (() => {}) && 1; 38 | g = (1, + +2); 39 | g = (1, + +(2 + 3)); 40 | a = - --i; 41 | b = - - --i; 42 | c = + + ++j; 43 | d = !!a; 44 | e = !+-+!a; 45 | f = -+-a++; 46 | g = b + -+-a++; 47 | (async function* () { 48 | await a + b; 49 | await a + await b; 50 | await (a = b); 51 | (await f()).a; 52 | await f().a; 53 | yield 1; 54 | yield 1 + 2; 55 | (yield 1) + (yield 2); 56 | yield a = b; 57 | const c = yield 3; 58 | }); 59 | (function* () { 60 | !(yield 1); 61 | }); 62 | !(() => {}); 63 | (() => {}) ? a : b; 64 | ({}) ? a : b; 65 | (({}) ? a : b) ? c : d; 66 | (function () {}) ? a : b; 67 | (class {}) ? a : b; 68 | -------------------------------------------------------------------------------- /src/tests/performance.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | import test from 'ava' 4 | 5 | import { benchmark } from './benchmark' 6 | import { readFile } from './tools' 7 | 8 | const FIXTURES_FOLDER = path.join(__dirname, 'fixtures') 9 | 10 | test('Performance tiny code', (assert) => { 11 | const result = benchmark('var a = 2;', 'tiny code') 12 | assert.true( 13 | result['astring'].speed > result['escodegen'].speed, 14 | 'astring is faster than escodegen', 15 | ) 16 | assert.true( 17 | result['astring'].speed > 10 * result['babel'].speed, 18 | 'astring is at least 10x faster than babel', 19 | ) 20 | assert.true( 21 | result['astring'].speed > 10 * result['prettier'].speed, 22 | 'astring is at least 10x faster than prettier', 23 | ) 24 | assert.true( 25 | result['acorn + astring'].speed > result['buble'].speed, 26 | 'astring is faster than buble', 27 | ) 28 | }) 29 | 30 | test('Performance with everything', (assert) => { 31 | const result = benchmark( 32 | readFile(path.join(FIXTURES_FOLDER, 'tree', 'es6.js')), 33 | 'everything', 34 | ) 35 | assert.true( 36 | result['astring'].speed > result['escodegen'].speed, 37 | 'astring is faster than escodegen', 38 | ) 39 | assert.true( 40 | result['astring'].speed > 10 * result['babel'].speed, 41 | 'astring is at least 10x faster than babel', 42 | ) 43 | assert.true( 44 | result['astring'].speed > 10 * result['prettier'].speed, 45 | 'astring is at least 10x faster than prettier', 46 | ) 47 | assert.true( 48 | result['acorn + astring'].speed > result['buble'].speed, 49 | 'astring is faster than buble', 50 | ) 51 | }) 52 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Astring 2 | 3 | Suggestions and changes are welcome and can be made through issue tickets and pull requests. 4 | 5 | ## Code 6 | 7 | Formatted code is written out through `state.write(code)` calls. The `code` can end with a `state.lineEnd`, but no use of `state.lineEnd` must be made within. In that case, multiple `state.write()` calls should be made. 8 | 9 | ## Tests 10 | 11 | Code fixtures are used to assert that the generated code matches the expected content. These fixtures are located in `src/tests/fixtures/syntax`. Testing new syntax extensions simply consists of updating the files within that folder or by adding new files. 12 | 13 | ## Scripts 14 | 15 | - `npm run build`: Produces a JavaScript 5-compliant modules at `dist/astring.js`. 16 | - `npm run build:minified`: Produces a JavaScript 5-compliant modules at `dist/astring.min.js` along with a source map at `dist/astring.min.js.map`. 17 | - `npm start`: Generates `dist/astring.js` and `dist/astring.js.map` at each change detected on `src/astring.js`. 18 | - `npm test`: Runs tests. 19 | - `npm run dev`: Runs tests and watches for changes. 20 | - `npm run test:coverage`: Runs tests with coverage. 21 | - `npm run test:scripts`: Runs tests over a large array of script files. 22 | - `npm run test:performance`: Runs performance tests to ensure thresholds are met. 23 | - `npm run benchmark`: Runs benchmarks against other code generators. Requires to run `npm install escodegen@1.8 uglify-js@2 babel-generator@6 buble@0.15` first. 24 | 25 | ## Roadmap 26 | 27 | Planned features and releases are outlined on the [milestones page](https://github.com/davidbonnet/astring/milestones). 28 | -------------------------------------------------------------------------------- /src/tests/scripts.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import fs from 'fs' 3 | import path from 'path' 4 | import normalizeNewline from 'normalize-newline' 5 | import { Parser } from 'acorn' 6 | import { importAttributes } from 'acorn-import-attributes' 7 | import * as astravel from 'astravel' 8 | import glob from 'glob' 9 | 10 | import { generate } from '../astring' 11 | 12 | const pattern = path.join(__dirname, '../../node_modules/@babel/**/*.js') 13 | const options = { 14 | ecmaVersion: 8, 15 | sourceType: 'module', 16 | allowHashBang: true, 17 | } 18 | 19 | const stripLocation = astravel.makeTraveler({ 20 | go: function (node, state) { 21 | delete node.start 22 | delete node.end 23 | this[node.type](node, state) 24 | }, 25 | // TODO: Remove once Astravel is updated 26 | Property(node, state) { 27 | this.go(node.key, state) 28 | if (node.value != null) { 29 | this.go(node.value, state) 30 | } 31 | }, 32 | }) 33 | 34 | const files = glob.sync(pattern, { 35 | nodir: true, 36 | }) 37 | 38 | test('Script tests', (assert) => { 39 | files.forEach((fileName) => { 40 | try { 41 | const code = normalizeNewline(fs.readFileSync(fileName, 'utf8')) 42 | let ast 43 | try { 44 | ast = Parser.extend(importAttributes).parse(code, options) 45 | } catch (error) { 46 | return 47 | } 48 | stripLocation.go(ast) 49 | const formattedAst = Parser.extend(importAttributes).parse( 50 | generate(ast), 51 | options, 52 | ) 53 | stripLocation.go(formattedAst) 54 | assert.deepEqual(formattedAst, ast, fileName) 55 | } catch (error) { 56 | assert.fail(error) 57 | } 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /astring.d.ts: -------------------------------------------------------------------------------- 1 | import type { Node as EstreeNode } from 'estree' 2 | import type { Mapping, SourceMapGenerator } from 'source-map' 3 | import type { Writable } from 'stream' 4 | 5 | /** 6 | * State object passed to generator functions. 7 | */ 8 | export interface State { 9 | output: string 10 | write(code: string, node?: EstreeNode): void 11 | writeComments: boolean 12 | indent: string 13 | lineEnd: string 14 | indentLevel: number 15 | line?: number 16 | column?: number 17 | lineEndSize?: number 18 | mapping?: Mapping 19 | } 20 | 21 | /** 22 | * Code generator for each node type. 23 | */ 24 | export type Generator = { 25 | [T in EstreeNode['type']]: ( 26 | node: EstreeNode & { type: T }, 27 | state: State, 28 | ) => void 29 | } 30 | 31 | /** 32 | * Code generator options. 33 | */ 34 | export interface Options { 35 | /** 36 | * If present, source mappings will be written to the generator. 37 | */ 38 | sourceMap?: SourceMapGenerator 39 | /** 40 | * String to use for indentation, defaults to `"␣␣"`. 41 | */ 42 | indent?: string 43 | /** 44 | * String to use for line endings, defaults to `"\n"`. 45 | */ 46 | lineEnd?: string 47 | /** 48 | * Indent level to start from, defaults to `0`. 49 | */ 50 | startingIndentLevel?: number 51 | /** 52 | * Generate comments if `true`, defaults to `false`. 53 | */ 54 | comments?: boolean 55 | /** 56 | * Output stream to write the render code to, defaults to `null`. 57 | */ 58 | output?: Output 59 | /** 60 | * Custom code generator logic. 61 | */ 62 | generator?: Generator 63 | } 64 | 65 | /** 66 | * Core Estree Node type to accommodate derived node types from parsers. 67 | */ 68 | interface Node { 69 | type: string 70 | } 71 | 72 | /** 73 | * Returns a string representing the rendered code of the provided AST `node`. 74 | * However, if an `output` stream is provided in the `options`, it writes to that stream and returns it. 75 | */ 76 | export function generate(node: Node, options?: Options): string 77 | export function generate(node: Node, options?: Options): Writable 78 | 79 | /** 80 | * Base code generator. 81 | */ 82 | export const GENERATOR: Generator 83 | 84 | /** 85 | * Base code generator. 86 | * 87 | * @deprecated Use {@link GENERATOR} instead. 88 | */ 89 | export const baseGenerator: Generator 90 | -------------------------------------------------------------------------------- /bin/astring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const generate = require('../dist/astring').generate 4 | const version = require('../package').version 5 | const fs = require('fs') 6 | const path = require('path') 7 | 8 | const argv = process.argv.slice(2) 9 | const options = { 10 | indent: ' ', 11 | lindeEnd: '\n', 12 | startingIndentLevel: 0, 13 | } 14 | const files = [] 15 | 16 | function printHelp(status) { 17 | // eslint-disable-next-line no-console 18 | const print = status === 0 ? console.log : console.error 19 | const binName = path.basename(process.argv[1]) 20 | print('Usage: ' + binName + ' [-h, --help] [-v, --version]') 21 | print( 22 | ' ' + 23 | binName + 24 | ' [-i, --indent INDENT] [-l, --line-end LINE_END] [-s, --starting-indent-level LEVEL] files...', 25 | ) 26 | process.exit(status) 27 | } 28 | 29 | function printVersion() { 30 | // eslint-disable-next-line no-console 31 | console.log(version) 32 | process.exit(0) 33 | } 34 | 35 | for (let i = 0, length = argv.length; i < length; i++) { 36 | let arg = argv[i] 37 | if (arg[0] === '-') { 38 | switch (arg) { 39 | case '-i': 40 | case '--indent': 41 | options.indent = argv[++i] 42 | break 43 | case '-l': 44 | case '--line-end': 45 | options.lineEnd = argv[++i] 46 | break 47 | case '-s': 48 | case '--starting-indent-level': 49 | options.startingIndentLevel = parseInt(argv[++i]) 50 | break 51 | case '-h': 52 | case '--help': 53 | printHelp(0) 54 | break 55 | case '-v': 56 | case '--version': 57 | printVersion() 58 | break 59 | default: 60 | console.error('Option "' + arg + '" not supported.') 61 | printHelp(1) 62 | break 63 | } 64 | } else { 65 | files.push(arg) 66 | } 67 | } 68 | 69 | options.output = process.stdout 70 | 71 | if (files.length === 0) { 72 | let data = '' 73 | process.stdin.setEncoding('utf8') 74 | process.stdin.resume() 75 | process.stdin 76 | .on('data', function (chunk) { 77 | data += chunk 78 | }) 79 | .on('end', function () { 80 | try { 81 | generate(JSON.parse(data), options) 82 | } catch (error) { 83 | console.error('Error: ' + error.message) 84 | process.exit(1) 85 | } 86 | }) 87 | } else { 88 | let hasError = false 89 | for (let i = 0, length = files.length; i < length; i++) { 90 | try { 91 | let file = files[i] 92 | generate(JSON.parse(fs.readFileSync(file, 'utf8')), options) 93 | } catch (error) { 94 | console.error('Error: ' + error.message) 95 | if (hasError !== true) { 96 | hasError = true 97 | } 98 | } 99 | } 100 | if (hasError) { 101 | process.exit(1) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astring", 3 | "version": "1.9.0", 4 | "description": "JavaScript code generator from an ESTree-compliant AST.", 5 | "main": "./dist/astring.js", 6 | "module": "./dist/astring.mjs", 7 | "types": "./astring.d.ts", 8 | "exports": { 9 | "types": "./astring.d.ts", 10 | "import": "./dist/astring.mjs", 11 | "require": "./dist/astring.js", 12 | "browser": "./dist/astring.min.js" 13 | }, 14 | "bin": { 15 | "astring": "bin/astring" 16 | }, 17 | "scripts": { 18 | "build": "babel src/astring.js --out-file dist/astring.js --source-maps --no-comments && cp src/astring.js dist/astring.mjs", 19 | "build:watch": "babel src/astring.js --out-file dist/astring.js --source-maps --no-comments --watch", 20 | "build:minified": "cross-env BABEL_MODE=minified babel src/astring.js --out-file dist/astring.min.js --source-maps --no-comments", 21 | "build:demo": "npm run build:minified && cp dist/astring.min.* docs/demo/", 22 | "prepare": "npm run build && npm run build:minified", 23 | "test": "npm run eslint && npm run prettier:check && npm run build:minified && npm run test:coverage", 24 | "dev": "ava --watch src/tests/astring.js", 25 | "test:coverage": "c8 --reporter=html --reporter=text --reporter=lcov --include='src/*.js' --exclude='src/tests/**/*.js' ava src/tests/astring.js", 26 | "test:scripts": "npm run test:scripts:build && ava src/tests/_scripts.js", 27 | "test:performance": "ava src/tests/performance.js", 28 | "benchmark": "node --require esm ./src/tests/benchmark.js", 29 | "eslint": "eslint src", 30 | "prettier": "prettier --write \"{src,scripts}/**/*.js\" \"bin/astring\"", 31 | "prettier:check": "prettier --list-different \"{src,scripts}/**/*.js\" \"bin/astring\"", 32 | "prepush": "npm test", 33 | "release": "standard-version", 34 | "deploy": "git push --follow-tags origin main && npm publish" 35 | }, 36 | "keywords": [ 37 | "ast", 38 | "codegen", 39 | "code generator", 40 | "estree", 41 | "astravel" 42 | ], 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/davidbonnet/astring.git" 46 | }, 47 | "author": "David Bonnet ", 48 | "license": "MIT", 49 | "devDependencies": { 50 | "@babel/cli": "^7.14.3", 51 | "@babel/core": "^7.14.3", 52 | "@babel/generator": "^7.14.3", 53 | "@babel/parser": "^7.16.4", 54 | "@babel/preset-env": "^7.14.4", 55 | "acorn": "^8.6.0", 56 | "acorn-import-attributes": "^1.9.5", 57 | "astravel": "^0.5.0", 58 | "ava": "^3.15.0", 59 | "babel-preset-minify": "^0.5.1", 60 | "benchmark": "^2.1.4", 61 | "buble": "^0.20.0", 62 | "c8": "^7.10.0", 63 | "cross-env": "^7.0.3", 64 | "escodegen": "^2.0.0", 65 | "eslint": "^8.3.0", 66 | "eslint-config-prettier": "^8.3.0", 67 | "eslint-plugin-import": "^2.25.3", 68 | "esm": "^3.2.25", 69 | "glob": "^7.1.7", 70 | "husky": "^6.0.0", 71 | "lodash": "^4.17.21", 72 | "meriyah": "^4.1.5", 73 | "normalize-newline": "^3.0.0", 74 | "prettier": "^2.4.1", 75 | "standard-version": "^9.3.0", 76 | "sucrase": "^3.18.1", 77 | "uglify-js": "^3.13.8" 78 | }, 79 | "prettier": { 80 | "printWidth": 80, 81 | "tabWidth": 2, 82 | "useTabs": false, 83 | "semi": false, 84 | "singleQuote": true, 85 | "trailingComma": "all", 86 | "bracketSpacing": true 87 | }, 88 | "ava": { 89 | "files": [ 90 | "src/**/tests/astring.js", 91 | "src/**/tests/performance.js" 92 | ], 93 | "require": [ 94 | "esm" 95 | ] 96 | }, 97 | "esm": "auto" 98 | } 99 | -------------------------------------------------------------------------------- /src/tests/benchmark.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | import Benchmark from 'benchmark' 4 | import { join, keys, fill, map } from 'lodash' 5 | 6 | import { parse as acorn } from 'acorn' 7 | import { parseScript as meriyah } from 'meriyah' 8 | import uglify from 'uglify-js' 9 | import { generate as escodegen } from 'escodegen' 10 | import { generate as astring } from '../astring' 11 | import { parse as babelParser } from '@babel/parser' 12 | import babelGenerator from '@babel/generator' 13 | import { format as prettier } from 'prettier' 14 | import { transform as buble } from 'buble' 15 | import { transform as sucrase } from 'sucrase' 16 | 17 | import { readFile } from './tools' 18 | 19 | const SCRIPT = process.argv[1].indexOf('benchmark.js') !== -1 20 | 21 | export function benchmark(code) { 22 | const acornOptions = { 23 | ecmaVersion: 12, 24 | sourceType: 'module', 25 | } 26 | const ast = acorn(code, acornOptions) 27 | let uglifyAst = null 28 | try { 29 | uglifyAst = uglify.parse(code) 30 | } catch (error) { 31 | // Ignore 32 | } 33 | const uglifyOptions = { 34 | beautify: true, 35 | } 36 | const babelAst = babelParser(code, { 37 | sourceType: 'module', 38 | }) 39 | const bubleOptions = { 40 | transforms: { 41 | getterSetter: false, 42 | arrow: false, 43 | classes: false, 44 | computedProperty: false, 45 | conciseMethodProperty: false, 46 | defaultParameter: false, 47 | destructuring: false, 48 | forOf: false, 49 | generator: false, 50 | letConst: false, 51 | moduleExport: false, 52 | moduleImport: false, 53 | numericLiteral: false, 54 | parameterDestructuring: false, 55 | spreadRest: false, 56 | stickyRegExp: false, 57 | templateString: false, 58 | unicodeRegExp: false, 59 | exponentiation: false, 60 | reservedProperties: false, 61 | trailingFunctionCommas: false, 62 | asyncAwait: false, 63 | objectRestSpread: false, 64 | }, 65 | } 66 | const babelOptions = {} 67 | const meriyahOptions = { 68 | module: true, 69 | specDeviation: true, 70 | } 71 | const prettierOptions = { parser: () => babelAst } 72 | const sucraseOptions = { transforms: [] } 73 | let results = {} 74 | new Benchmark.Suite() 75 | .add('escodegen', () => { 76 | escodegen(ast) 77 | }) 78 | .add('astring', () => { 79 | astring(ast) 80 | }) 81 | .add('uglify', () => { 82 | uglifyAst.print_to_string(uglifyOptions) 83 | }) 84 | .add('babel', () => { 85 | babelGenerator(babelAst, babelOptions, code).code 86 | }) 87 | .add('prettier', () => { 88 | prettier(code, prettierOptions) 89 | }) 90 | .add('acorn + astring', () => { 91 | astring(acorn(code, acornOptions)) 92 | }) 93 | .add('meriyah + astring', () => { 94 | astring(meriyah(code, meriyahOptions)) 95 | }) 96 | .add('buble', () => { 97 | buble(code, bubleOptions).code 98 | }) 99 | .add('sucrase', () => { 100 | sucrase(code, sucraseOptions).code 101 | }) 102 | .on('cycle', (event) => { 103 | if (SCRIPT) { 104 | console.log(`${event.target}`) 105 | } 106 | const { target: bench } = event 107 | results[bench.name] = { 108 | speed: bench.hz || 0, 109 | stats: bench.stats.rme, 110 | size: bench.stats.sample.length, 111 | } 112 | }) 113 | .run() 114 | return results 115 | } 116 | 117 | function resultsToMarkdown(results) { 118 | const categories = keys(results[0].results) 119 | const { format } = global.Intl.NumberFormat('en', { 120 | maximumFractionDigits: 0, 121 | }) 122 | let output = `| code sample (length) | ${join(categories, ' | ')} |\n` 123 | output += `|:---|${join(fill(Array(categories.length), '---:'), '|')}|\n` 124 | const { length } = results 125 | for (let i = 0; i < length; i++) { 126 | const result = results[i] 127 | output += `| ${result.name} (${result.length}) | ${join( 128 | map(categories, (key) => format(result.results[key].speed)), 129 | ' | ', 130 | )} |\n` 131 | } 132 | return output 133 | } 134 | 135 | if (SCRIPT) { 136 | const results = [] 137 | results.push({ 138 | name: 'tiny code', 139 | length: 'var a = 42;'.length, 140 | results: benchmark('var a = 42;'), 141 | }) 142 | const code = readFile(path.join(__dirname, 'fixtures', 'tree', 'es6.js')) 143 | results.push({ 144 | name: 'everything', 145 | length: code.length, 146 | results: benchmark(code), 147 | }) 148 | console.log(resultsToMarkdown(results)) 149 | } 150 | -------------------------------------------------------------------------------- /docs/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JavaScript Prettifier 6 | 7 | 8 | 9 | 10 |

JavaScript Prettifier

11 |

12 | Parses the code with 13 | Acorn and prints it with 14 | Astring. 15 |

16 | 22 |

23 | 24 | 35 | 36 | 37 |

38 |

 39 |     
130 |   
131 | 
132 | 


--------------------------------------------------------------------------------
/src/tests/astring.js:
--------------------------------------------------------------------------------
  1 | import fs from 'fs'
  2 | import test from 'ava'
  3 | import path from 'path'
  4 | import { Parser } from 'acorn'
  5 | import { importAttributesOrAssertions } from 'acorn-import-attributes'
  6 | import * as astravel from 'astravel'
  7 | import { pick } from 'lodash'
  8 | 
  9 | import { generate } from '../astring'
 10 | import { readFile } from './tools'
 11 | 
 12 | const FIXTURES_FOLDER = path.join(__dirname, 'fixtures')
 13 | 
 14 | const ecmaVersion = 13
 15 | 
 16 | const parser = Parser.extend(importAttributesOrAssertions)
 17 | 
 18 | const stripLocation = astravel.makeTraveler({
 19 |   go(node, state) {
 20 |     delete node.start
 21 |     delete node.end
 22 |     delete node.raw
 23 |     if (node.directive) {
 24 |       delete node.directive
 25 |     }
 26 |     this[node.type](node, state)
 27 |   },
 28 |   Property(node, state) {
 29 |     this.go(node.key, state)
 30 |     // Always walk through value, regardless of `node.shorthand` flag
 31 |     this.go(node.value, state)
 32 |   },
 33 |   // astravel does not support import attributes yet
 34 |   ImportDeclaration(node, state) {
 35 |     const { specifiers } = node,
 36 |       { length } = specifiers
 37 |     for (let i = 0; i < length; i++) {
 38 |       this.go(specifiers[i], state)
 39 |     }
 40 |     const { attributes } = node
 41 |     if (attributes != null)
 42 |       for (let i = 0; i < attributes.length; i++) this.go(attributes[i], state)
 43 | 
 44 |     this.go(node.source, state)
 45 |   },
 46 |   ImportAttribute(node, state) {
 47 |     this.go(node.key, state)
 48 |     this.go(node.value, state)
 49 |   },
 50 | })
 51 | 
 52 | test('Syntax check', (assert) => {
 53 |   const dirname = path.join(FIXTURES_FOLDER, 'syntax')
 54 |   const files = fs.readdirSync(dirname).sort()
 55 |   const options = {
 56 |     ecmaVersion,
 57 |     sourceType: 'module',
 58 |   }
 59 |   files.forEach((filename) => {
 60 |     const code = readFile(path.join(dirname, filename))
 61 |     const ast = parser.parse(code, options)
 62 |     assert.is(
 63 |       generate(ast),
 64 |       code,
 65 |       filename.substring(0, filename.length - 3),
 66 |       'Generates code with the expected format',
 67 |     )
 68 |   })
 69 | })
 70 | 
 71 | test('Tree comparison', (assert) => {
 72 |   const dirname = path.join(FIXTURES_FOLDER, 'tree')
 73 |   const files = fs.readdirSync(dirname).sort()
 74 |   const options = {
 75 |     ecmaVersion,
 76 |     sourceType: 'module',
 77 |   }
 78 |   files.forEach((filename) => {
 79 |     const code = readFile(path.join(dirname, filename))
 80 |     const ast = parser.parse(code, options)
 81 |     stripLocation.go(ast)
 82 |     const formattedAst = parser.parse(generate(ast), options)
 83 |     stripLocation.go(formattedAst)
 84 |     assert.deepEqual(
 85 |       formattedAst,
 86 |       ast,
 87 |       filename.substring(0, filename.length - 3),
 88 |       'Generates code with the same meaning',
 89 |     )
 90 |   })
 91 | })
 92 | 
 93 | test('Deprecated syntax check', (assert) => {
 94 |   const dirname = path.join(FIXTURES_FOLDER, 'deprecated')
 95 |   const files = fs.readdirSync(dirname).sort()
 96 |   files.forEach((filename) => {
 97 |     const code = readFile(path.join(dirname, filename))
 98 |     const version = parseInt(filename.substring(2, filename.length - 3))
 99 |     const ast = parser.parse(code, { ecmaVersion: version })
100 |     assert.is(generate(ast), code, 'es' + version)
101 |   })
102 | })
103 | 
104 | test('Output stream', (assert) => {
105 |   const code = 'const a = 42;\n'
106 |   const output = {
107 |     buffer: '',
108 |     write(code) {
109 |       this.buffer += code
110 |     },
111 |   }
112 |   const ast = parser.parse(code, {
113 |     ecmaVersion,
114 |   })
115 |   const result = generate(ast, {
116 |     output,
117 |   })
118 |   assert.is(result, output)
119 |   assert.is(result.buffer, code)
120 | })
121 | 
122 | test('Comment generation', (assert) => {
123 |   const dirname = path.join(FIXTURES_FOLDER, 'comment')
124 |   const files = fs.readdirSync(dirname).sort()
125 |   const options = {
126 |     comments: true,
127 |   }
128 |   files.forEach((filename) => {
129 |     const code = readFile(path.join(dirname, filename))
130 |     const comments = []
131 |     const ast = parser.parse(code, {
132 |       ecmaVersion,
133 |       locations: true,
134 |       onComment: comments,
135 |     })
136 |     astravel.attachComments(ast, comments)
137 |     assert.is(
138 |       generate(ast, options),
139 |       code,
140 |       filename.substring(0, filename.length - 3),
141 |     )
142 |   })
143 | })
144 | 
145 | test('Source map generation', (assert) => {
146 |   const dirname = path.join(FIXTURES_FOLDER, 'syntax')
147 |   const files = fs.readdirSync(dirname).sort()
148 |   const options = {
149 |     ecmaVersion,
150 |     sourceType: 'module',
151 |     locations: true,
152 |   }
153 |   files.forEach((filename) => {
154 |     const code = readFile(path.join(dirname, filename))
155 |     const sourceMap = {
156 |       mappings: [],
157 |       _file: filename,
158 |       addMapping({ original, generated, name, source }) {
159 |         assert.deepEqual(
160 |           pick(generated, ['line', 'column']),
161 |           pick(original, ['line', 'column']),
162 |           `${source}:${name}`,
163 |         )
164 |         assert.is(source, this._file)
165 |         this.mappings.push({
166 |           original,
167 |           generated,
168 |           name,
169 |           source,
170 |         })
171 |       },
172 |     }
173 |     const ast = parser.parse(code, options)
174 |     generate(ast, {
175 |       sourceMap,
176 |     })
177 |     assert.true(
178 |       sourceMap.mappings.length > 0,
179 |       `Expect ${path.basename(filename)} to have mappings`,
180 |     )
181 |   })
182 | })
183 | 
184 | test('Source map generation with comments', (assert) => {
185 |   const dirname = path.join(FIXTURES_FOLDER, 'comment')
186 |   const files = fs.readdirSync(dirname).sort()
187 |   files.forEach((filename) => {
188 |     const code = readFile(path.join(dirname, filename))
189 |     const sourceMap = {
190 |       mappings: [],
191 |       _file: filename,
192 |       addMapping({ original, generated, name, source }) {
193 |         assert.deepEqual(
194 |           pick(generated, ['line', 'column']),
195 |           pick(original, ['line', 'column']),
196 |           `${source}:${name}`,
197 |         )
198 |         assert.is(source, this._file)
199 |         this.mappings.push({
200 |           original,
201 |           generated,
202 |           name,
203 |           source,
204 |         })
205 |       },
206 |     }
207 |     const comments = []
208 |     const ast = parser.parse(code, {
209 |       ecmaVersion,
210 |       comments: true,
211 |       locations: true,
212 |       onComment: comments,
213 |     })
214 |     astravel.attachComments(ast, comments)
215 |     generate(ast, {
216 |       sourceMap,
217 |       comments: true,
218 |     })
219 |   })
220 | })
221 | 


--------------------------------------------------------------------------------
/src/tests/fixtures/tree/es6.js:
--------------------------------------------------------------------------------
  1 | /*
  2 | Copyright (c) 2014, Michael Ficarra. All rights reserved.
  3 | 
  4 | Redistribution and use in source and binary forms, with or without
  5 | modification, are permitted provided that the following conditions are met:
  6 | 
  7 |   * Redistributions of source code must retain the above copyright notice, this
  8 |     list of conditions and the following disclaimer.
  9 | 
 10 |   * Redistributions in binary form must reproduce the above copyright notice,
 11 |     this list of conditions and the following disclaimer in the documentation
 12 |     and/or other materials provided with the distribution.
 13 | 
 14 |   * Neither the name of the project nor the names of its contributors may be
 15 |     used to endorse or promote products derived from this software without
 16 |     specific prior written permission.
 17 | 
 18 | This software is provided by the copyright holders and contributors "as is" and
 19 | any express or implied warranties, including, but not limited to, the implied
 20 | warranties of merchantability and fitness for a particular purpose are
 21 | disclaimed. In no event shall the copyright holder be liable for any direct,
 22 | indirect, incidental, special, exemplary, or consequential damages (including,
 23 | but not limited to, procurement of substitute goods or services; loss of use,
 24 | data, or profits; or business interruption) however caused and on any theory of
 25 | liability, whether in contract, strict liability, or tort (including negligence
 26 | or otherwise) arising in any way out of the use of this software, even if
 27 | advised of the possibility of such damage.
 28 | */
 29 | 
 30 | /*
 31 | This file contains all grammatical productions in ECMA-262 edition 5.1
 32 | It does not contain `with` statements and octal literals.
 33 | */
 34 | 
 35 | /* Comment ** * **/
 36 | 
 37 | import i0 from "module";
 38 | import * as i1 from "module";
 39 | import {} from "module";
 40 | import { i2, a as i3, } from "module";
 41 | import i4, * as i5 from "module";
 42 | import i6, {} from "module";
 43 | import i7, { i8, var as i9 } from "module";
 44 | import "module";
 45 | import * as q from "./a.json" with { type: "json" };
 46 | import r from "./a.json" with { type: "json" };
 47 | 
 48 | export * from "module";
 49 | export {} from "module";
 50 | export { i0, i1 as a, i2 as var, } from "module";
 51 | export {};
 52 | export { i3, i4 as in };
 53 | export var e5, e6 = 0;
 54 | export let e7, e8 = 0;
 55 | export const e9 = 0, e10 = 0;
 56 | export function e11(){}
 57 | export function* e12(){}
 58 | export class e13 {}
 59 | export class e14 extends e15 {}
 60 | export default function e16(){}
 61 | 
 62 | 
 63 | // whitespace
 64 | tab:for(;;)break  tab;
 65 | verticalTab:for(;;)breakverticalTab;
 66 | formFeed:for(;;)breakformFeed;
 67 | space:for(;;)break space;
 68 | nbsp:for(;;)break nbsp;
 69 | bom:for(;;)breakbom;
 70 | 
 71 | // line terminators
 72 | lineFeed:0
 73 | 0;
 74 | carriageReturn:0
 75 | 0;
 76 | carriageReturnLineFeed:0
 77 | 0;
 78 | lineSeparator:0
0;
 79 | paragraphSeparator:0
0;
 80 | 
 81 | // identifier names
 82 | var $, _, \u0078, \u{2F9F9}, x$, x_, x\u0030, x\u{e01d5}, xa, x0, x0a,
 83 |   x0123456789, qwertyuiopasdfghjklzxcvbnm, QWERTYUIOPASDFGHJKLZXCVBNM;
 84 | // a representative sample of ID_Start and ID_Continue
 85 | var 䩶, x󠇕, œ一, ǻ둘, ɤ〩, φ, fiⅷ, ユニコード, x‌‍;
 86 | // var yield; let letx; let[x\u0078] = 0; const constx = 0;
 87 | { let x; let y = 0; const z = 0; }
 88 | // var let; var await;
 89 | 
 90 | null; true; false;
 91 | 
 92 | 0; 1234567890; 1234567;
 93 | 0.; 0.00; 10.00; .0; .00
 94 | 0e0; 0E0; 0.e0; 0.00e+0; .00e-0;
 95 | 0x0; 0X0; 0x0123456789abcdefABCDEF;
 96 | 0b0; 0B0; 0b01; 0b10; 0b10101010;
 97 | 0o0; 0O0; 0o01234567;
 98 | 2e307;
 99 | 
100 | ""; "'"; "\'\"\\\b\f\n\r\t\v\0";
101 | "\x01\x23\x45\x67\x89\xAB\xCD\xEF\xab\xcd\xef";
102 | "\u0123\u4567\u89AB\uCDEF\u00ab\ucdef";
103 | "\uD834\uDF06\u2603\u03C6 \u{0000001F4a9}\u{1D306}\u{2603}\u{3c6} 𝌆☃φ"; "\
104 | ";
105 | 
106 | ''; '"'; '\'\"\\\b\f\n\r\t\v\0';
107 | '\x01\x23\x45\x67\x89\xAB\xCD\xEF\xab\xcd\xef';
108 | '\u0123\u4567\u89AB\uCDEF\u00ab\ucdef';
109 | '\uD834\uDF06\u2603\u03C6 \u{0000001F4a9} \u{1D306}\u{2603}\u{3c6} 𝌆☃φ'; '\
110 | ';
111 | 
112 | /x/; /|/; /|||/;
113 | /^$\b\B/; /(?=(?!(?:(.))))/;
114 | /a.\f\n\r\t\v\0\[\-\/\\\x00\u0000\uD834\uDF06/; /\u{00000001d306}/u; /\d\D\s\S\w\W/;
115 | /\ca\cb\cc\cd\ce\cf\cg\ch\ci\cj\ck\cl\cm\cn\co\cp\cq\cr\cs\ct\cu\cv\cw\cx\cy\cz/;
116 | /\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cP\cQ\cR\cS\cT\cU\cV\cW\cX\cY\cZ/;
117 | /[a-z-]/; /[^\b\-^]/; /[/\]\\]/;
118 | /./i; /./g; /./m; /./igm;
119 | /.*/; /.*?/; /.+/; /.+?/; /.?/; /.??/;
120 | /.{0}/; /.{0,}/; /.{0,0}/;
121 | 
122 | `a`; `${0}`; `0${0,1}2`; `0${`1${2}3`}4`;
123 | `\``; `a\${b`; `\0\n\x0A\u000A\u{A}`;
124 | 
125 | this;
126 | 
127 | x;
128 | 
129 | []; [,]; [0]; [0,]; [,0]; [0,0]; [0,0,]; [0,,0]; [,,];
130 | 
131 | ({}); ({x}); ({x:0}); ({x:0,y:0}); ({x:0,}); ({'x':0,"y":0,in:0});
132 | ({
133 |   0: 0, 0.: 0, 0.0: 0, .0: 0, 0e0: 0, 0x0: 0, [0]: 0,
134 |   get x(){}, set x(a){}, get 'y'(){}, set "y"(a){},
135 |   get 0(){}, set 0(a){}, get var(){}, set var(a){},
136 |   get [0](){}, set [0](a){}, [1](){},
137 |   a(){}, 'b'(){}, "c"(){}, 0(){}, .1(){}, 1.(){}, 1e1(){},
138 |   var(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){},
139 |   set in([a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k]){},
140 |   *d(){}, *'e'(){}, *"f"(){}, *2(){}, *.2(){}, *3.(){}, *2e2(){}, *in(){},
141 | });
142 | ({ __proto__: null, get __proto__(){}, set __proto__(a){}, });
143 | ({ "__proto__": null, __proto__(){}, });
144 | 
145 | 0..a; 0 .a; (0).a;
146 | 
147 | 0[0];
148 | 
149 | // this function makes the NewExpression and CallExpression tests not throw at runtime
150 | x = function f(){ return f; }; x[0] = x; x.a = x;
151 | 
152 | new x(); new new x()();
153 | new x[0](); new x.a(); new x[0].a(); new x.a[0]();
154 | new x; new new x; new new x();
155 | new new x().a; new new x()[0];
156 | 
157 | x(); x()(); x(x); x(x, x);
158 | x.a().a(); x[0]()[0](); x().a[0]();
159 | x(...[0,1,], ...[], ...function* f(){ return yield 2; });
160 | x`a`; x`0${1}2`;
161 | 
162 | x++; x--;
163 | 
164 | delete void typeof+-~!x; ++x; --x;
165 | 
166 | 0*0; 0/0; 0%0;
167 | 
168 | 0+0; 0-0;
169 | 
170 | 0<<0; 0>>0; 0>>>0;
171 | 
172 | 0<0; 0>0; 0<=0; 0>=0;
173 | 0 instanceof function(){};
174 | 0 in{};
175 | 
176 | 0==0; 0!=0; 0===0; 0!==0;
177 | 
178 | 0&0; 0^0; 0|0; 0&&0; 0||0;
179 | 
180 | 0?0:0; 0?0?0:0:0; 0||0?x=0:x=0;
181 | 
182 | x=0; x*=0; x/=0; x%=0; x+=0; x-=0;
183 | x<<=0; x>>=0; x>>>=0; x&=0; x^=0; x|=0;
184 | 
185 | 0,0; 0,0,0; x=0,x=0;
186 | 
187 | 
188 | {} {;} {0} {0;} {0;0} {0;0;}
189 | 
190 | var x; var x,y; var x,y,z;
191 | var x=0; var x=0,y; var x,y=0; var x=0,y=0;
192 | 
193 | ;
194 | 
195 | if(0); if(0);else;
196 | 
197 | do;while(0) 0;
198 | do;while(0);
199 | do;while(0) 0
200 | while(0);
201 | for(;;)break; for(0;0;0); for((0 in[]);0;);
202 | for(var a;;)break; for(var a,b;0;0);
203 | for(var a=0;;)break; for(var a=(0 in[]);0;);
204 | for(x in{}); for(var x in{});
205 | for(x of[]); for(var x of[]);
206 | 
207 | for(;0;)continue; x:for(;0;)continue x;
208 | 
209 | for(;;)break; x:for(;;)break x;
210 | switch(0){case 0:break;}
211 | 
212 | function f1(){ return; }
213 | function f2(){ return 0; }
214 | 
215 | switch(0){} switch(0){case 0:} switch(0){case 0:case 0:}
216 | switch(0){default:} switch(0){case 0:default:case 0:}
217 | switch(0){case 0:;} switch(0){case 0:;;}
218 | switch(0){default:;} switch(0){default:;;}
219 | 
220 | x:; x:y:;
221 | 
222 | try { throw 0; }catch(x){}
223 | 
224 | try{}catch(x){}
225 | try{}finally{}
226 | try{}catch(x){}finally{}
227 | 
228 | debugger;
229 | 
230 | function f3(){}
231 | function f4(x){}
232 | function f5(x,y){}
233 | function f6(){ function f(){} }
234 | { function f(){} };
235 | //for (;0;) label: function f(){} 0
236 | //do label: function f(){} while(0)
237 | 
238 | function f7(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){}
239 | function f8(){ "use strict" }
240 | function f9(){ 'use strict' }
241 | function fA(){ "other directive" }
242 | function fB(){ 'other directive' }
243 | function fC(){ ("string") }
244 | function fD(){ ('string') }
245 | function fE(){
246 |   'string'
247 |   +0
248 | }
249 | 
250 | function*g(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){
251 |   return a = yield* b = yield c = yield yield;
252 | }
253 | (function * g(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){
254 |   return a = yield* b = yield c = yield yield;
255 | })
256 | 
257 | (function(){});
258 | (function(x){});
259 | (function(x,y){});
260 | (function(){ function f(){} });
261 | (function f(){});
262 | (function f(x){});
263 | (function f(x,y){});
264 | (function f(){ function f(){} });
265 | 
266 | () => 0;
267 | () => {;}
268 | x => x
269 | x => x = 0
270 | x => y => x
271 | x => {x}
272 | x => ({x});
273 | (x) => x;
274 | (x) => {return x};
275 | (x) => ({x});
276 | ({x}) => ({x});
277 | (a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k) => {;};
278 | 
279 | [a] = [...[0]];
280 | ({a} = {});
281 | try{}catch([e]){}
282 | try{}catch({e}){}
283 | 
284 | class A {}
285 | class B extends new A {
286 |   constructor(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k) {
287 |     super(new.target);
288 |     super()`template`;
289 |     () => super(this);
290 |   }
291 |   m(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k) {
292 |     super.m();
293 |     super.m`template`;
294 |     () => super.m(this);
295 |   }
296 | 
297 |   ;
298 | 
299 |   static a(){} static 'b'(){} static 0(){} static [0](){}
300 |   static *c(){ yield; } static *"d"() { yield; } static *1(){ yield; } static *[1](){ yield; }
301 |   static var(){} static *in(){}
302 | 
303 |   static get e(){} static get 'f'(){} static get 2(){} static get [2](){}
304 |   static set g(a){} static set "h"(a){} static set 3(a){} static set [3](a){}
305 |   static get if(){} static set if(a){}
306 | 
307 |   a(){} 'b'(){} 0(){} [0](){}
308 |   *c(){ yield; } *"d"(){ yield; } *1(){ yield; } *[1](){ yield; }
309 |   var(){} *in(){ yield; }
310 | 
311 |   get e(){} get 'f'(){} get 2(){} get [2](){}
312 |   set g(a){} set "h"(a){} set 3(a){} set [3](a){}
313 |   get if() {} set if(f) {}
314 | }
315 | class C extends B { "constructor"(){ super(); } }
316 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # Astring
  2 | 
  3 | [![NPM Version](https://img.shields.io/npm/v/astring.svg)](https://www.npmjs.org/package/astring)
  4 | [![Coverage](https://codecov.io/gh/davidbonnet/astring/branch/master/graph/badge.svg)](https://codecov.io/gh/davidbonnet/astring)
  5 | 
  6 | 🌳 Tiny and fast JavaScript code generator from an [ESTree](https://github.com/estree/estree)-compliant AST.
  7 | 
  8 | ### Key features
  9 | 
 10 | - Generates JavaScript code up to [version 15 (2024)](https://tc39.github.io/ecma262/) and [stage 3 proposals](https://github.com/tc39/proposals#stage-3).
 11 | - 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).
 12 | - Extendable with custom AST node handlers.
 13 | - 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×).
 14 | - Supports source map generation with [Source Map](https://github.com/mozilla/source-map#sourcemapgenerator).
 15 | - Supports comment generation with [Astravel](https://github.com/davidbonnet/astravel).
 16 | - No dependencies and small footprint (≈ 16 KB minified, ≈ 4 KB gziped).
 17 | - Runs on [🦕 Deno](https://deno.land/x/astring).
 18 | 
 19 | ## Installation
 20 | 
 21 | > :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).
 22 | 
 23 | Install with the [Node Package Manager](https://www.npmjs.com/package/astring):
 24 | 
 25 | ```bash
 26 | npm install astring
 27 | ```
 28 | 
 29 | Or install with [JSR](https://jsr.io/@davidbonnet/astring):
 30 | 
 31 | ```bash
 32 | deno add @davidbonnet/astring
 33 | ```
 34 | 
 35 | Alternatively, checkout this repository and install the development dependencies to build the module file:
 36 | 
 37 | ```bash
 38 | git clone https://github.com/davidbonnet/astring.git
 39 | cd astring
 40 | npm install
 41 | ```
 42 | 
 43 | ## Import
 44 | 
 45 | Import it from [Deno's third party module repository](https://deno.land/x/astring/src/astring.js):
 46 | 
 47 | ```js
 48 | const { generate } = await import('https://deno.land/x/astring/src/astring.js')
 49 | ```
 50 | 
 51 | With JavaScript 6 modules:
 52 | 
 53 | ```js
 54 | import { generate } from 'astring'
 55 | ```
 56 | 
 57 | With CommonJS:
 58 | 
 59 | ```js
 60 | const { generate } = require('astring')
 61 | ```
 62 | 
 63 | A browser-ready minified bundle containing Astring is available at `dist/astring.min.js`. The module exposes a global variable `astring`:
 64 | 
 65 | ```html
 66 | 
 67 | 
 70 | ```
 71 | 
 72 | ## API
 73 | 
 74 | The `astring` module exposes the following properties:
 75 | 
 76 | ### `generate(node: object, options: object): string | object`
 77 | 
 78 | Returns 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.
 79 | 
 80 | The `options` are:
 81 | 
 82 | - `indent`: string to use for indentation (defaults to `"␣␣"`)
 83 | - `lineEnd`: string to use for line endings (defaults to `"\n"`)
 84 | - `startingIndentLevel`: indent level to start from (defaults to `0`)
 85 | - `comments`: generate comments if `true` (defaults to `false`)
 86 | - `output`: output stream to write the rendered code to (defaults to `null`)
 87 | - `generator`: custom code generator (defaults to `GENERATOR`)
 88 | - `sourceMap`: [source map generator](https://github.com/mozilla/source-map#sourcemapgenerator) (defaults to `null`)
 89 | - `expressionsPrecedence`: custom map of node types and their precedence level (defaults to `EXPRESSIONS_PRECEDENCE`)
 90 | 
 91 | ### `GENERATOR: object`
 92 | 
 93 | Base generator that can be used to [extend Astring](#extending).
 94 | 
 95 | ### `EXPRESSIONS_PRECEDENCE: object`
 96 | 
 97 | Mapping of node types and their precedence level to let the generator know when to use parentheses.
 98 | 
 99 | ### `NEEDS_PARENTHESES: number`
100 | 
101 | Default precedence level that always triggers the use of parentheses.
102 | 
103 | ### `baseGenerator: object`
104 | 
105 | > :warning: Deprecated, use `GENERATOR` instead.
106 | 
107 | ## Benchmark
108 | 
109 | ### Generating code
110 | 
111 | Operations per second for generating each sample code from a pre-parsed AST:
112 | 
113 | | code sample (length) | escodegen |   astring |  uglify |   babel | prettier |
114 | | :------------------- | --------: | --------: | ------: | ------: | -------: |
115 | | tiny code (11)       | 1,257,527 | 7,185,642 | 129,467 | 156,184 |      333 |
116 | | everything (8532)    |     1,366 |     8,008 |       0 |     346 |       64 |
117 | 
118 | ### Parsing and generating code
119 | 
120 | Operations per second for parsing and generating each sample code:
121 | 
122 | | code sample (length) | acorn + astring | meriyah + astring |  buble | sucrase |
123 | | :------------------- | --------------: | ----------------: | -----: | ------: |
124 | | tiny code (11)       |          92,578 |           864,665 | 25,911 | 575,370 |
125 | | everything (8532)    |             706 |             1,425 |    132 |   1,403 |
126 | 
127 | ## Examples
128 | 
129 | The following examples are written in JavaScript 5 with Astring imported _à la CommonJS_.
130 | 
131 | ### Generating code
132 | 
133 | This example uses [Acorn](https://github.com/acornjs/acorn), a blazingly fast JavaScript AST producer and therefore the perfect companion of Astring.
134 | 
135 | ```javascript
136 | // Make sure acorn and astring modules are imported
137 | 
138 | // Set example code
139 | var code = 'let answer = 4 + 7 * 5 + 3;\n'
140 | // Parse it into an AST
141 | var ast = acorn.parse(code, { ecmaVersion: 6 })
142 | // Format it into a code string
143 | var formattedCode = astring.generate(ast)
144 | // Check it
145 | console.log(code === formattedCode ? 'It works!' : 'Something went wrong…')
146 | ```
147 | 
148 | ### Generating source maps
149 | 
150 | This example uses the source map generator from the [Source Map](https://github.com/mozilla/source-map#sourcemapgenerator) module.
151 | 
152 | ```javascript
153 | // Make sure acorn, sourceMap and astring modules are imported
154 | 
155 | var code = 'function add(a, b) { return a + b; }\n'
156 | var ast = acorn.parse(code, {
157 |   ecmaVersion: 6,
158 |   sourceType: 'module',
159 |   // Locations are needed in order for the source map generator to work
160 |   locations: true,
161 | })
162 | // Create empty source map generator
163 | var map = new sourceMap.SourceMapGenerator({
164 |   // Source file name must be set and will be used for mappings
165 |   file: 'script.js',
166 | })
167 | var formattedCode = generate(ast, {
168 |   // Enable source maps
169 |   sourceMap: map,
170 | })
171 | // Display generated source map
172 | console.log(map.toString())
173 | ```
174 | 
175 | ### Using writable streams
176 | 
177 | This example for [Node](http://nodejs.org) shows how to use writable streams to get the rendered code.
178 | 
179 | ```javascript
180 | // Make sure acorn and astring modules are imported
181 | 
182 | // Set example code
183 | var code = 'let answer = 4 + 7 * 5 + 3;\n'
184 | // Parse it into an AST
185 | var ast = acorn.parse(code, { ecmaVersion: 6 })
186 | // Format it and write the result to stdout
187 | var stream = astring.generate(ast, {
188 |   output: process.stdout,
189 | })
190 | // The returned value is the output stream
191 | console.log('Does stream equal process.stdout?', stream === process.stdout)
192 | ```
193 | 
194 | ### Generating comments
195 | 
196 | Astring 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.
197 | 
198 | ```javascript
199 | // Make sure acorn, astravel and astring modules are imported
200 | 
201 | // Set example code
202 | var code =
203 |   [
204 |     '// Compute the answer to everything',
205 |     'let answer = 4 + 7 * 5 + 3;',
206 |     '// Display it',
207 |     'console.log(answer);',
208 |   ].join('\n') + '\n'
209 | // Parse it into an AST and retrieve the list of comments
210 | var comments = []
211 | var ast = acorn.parse(code, {
212 |   ecmaVersion: 6,
213 |   locations: true,
214 |   onComment: comments,
215 | })
216 | // Attach comments to AST nodes
217 | astravel.attachComments(ast, comments)
218 | // Format it into a code string
219 | var formattedCode = astring.generate(ast, {
220 |   comments: true,
221 | })
222 | // Check it
223 | console.log(code === formattedCode ? 'It works!' : 'Something went wrong…')
224 | ```
225 | 
226 | ### Extending
227 | 
228 | Astring 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.
229 | 
230 | This 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).
231 | 
232 | ```javascript
233 | // Make sure the astring module is imported and that `Object.assign` is defined
234 | 
235 | // Create a custom generator that inherits from Astring's base generator
236 | var customGenerator = Object.assign({}, astring.GENERATOR, {
237 |   AwaitExpression: function (node, state) {
238 |     state.write('await ')
239 |     var argument = node.argument
240 |     if (argument != null) {
241 |       this[argument.type](argument, state)
242 |     }
243 |   },
244 | })
245 | // Obtain a custom AST somehow (note that this AST is not obtained from a valid code)
246 | var ast = {
247 |   type: 'AwaitExpression',
248 |   argument: {
249 |     type: 'CallExpression',
250 |     callee: {
251 |       type: 'Identifier',
252 |       name: 'callable',
253 |     },
254 |     arguments: [],
255 |   },
256 | }
257 | // Format it
258 | var code = astring.generate(ast, {
259 |   generator: customGenerator,
260 | })
261 | // Check it
262 | console.log(
263 |   code === 'await callable();\n' ? 'It works!' : 'Something went wrong…',
264 | )
265 | ```
266 | 
267 | ## Command line interface
268 | 
269 | The `bin/astring` utility can be used to convert a JSON-formatted ESTree compliant AST of a JavaScript code. It accepts the following arguments:
270 | 
271 | - `-i`, `--indent`: string to use as indentation (defaults to `"␣␣"`)
272 | - `-l`, `--line-end`: string to use for line endings (defaults to `"\n"`)
273 | - `-s`, `--starting-indent-level`: indent level to start from (defaults to `0`)
274 | - `-h`, `--help`: print a usage message and exit
275 | - `-v`, `--version`: print package version and exit
276 | 
277 | The utility reads the AST from a provided list of files or from `stdin` if none is supplied and prints the generated code.
278 | 
279 | ### Example
280 | 
281 | As 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:
282 | 
283 | ```bash
284 | acorn --ecma6 script.js | astring > result.js
285 | ```
286 | 
287 | This command does the same, but reads the AST from an intermediary file:
288 | 
289 | ```bash
290 | acorn --ecma6 script.js > ast.json
291 | astring ast.json > result.js
292 | ```
293 | 
294 | This command reads JavaScript 6 code from `stdin` and outputs a prettified version:
295 | 
296 | ```bash
297 | cat | acorn --ecma6 | astring
298 | ```
299 | 


--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
  1 | # Changelog
  2 | 
  3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
  4 | 
  5 | ## [1.9.0](https://github.com/davidbonnet/astring/compare/v1.8.6...v1.9.0) (2024-08-25)
  6 | 
  7 | 
  8 | ### Features
  9 | 
 10 | * add import-attributes support ([#712](https://github.com/davidbonnet/astring/issues/712)) ([d22c19e](https://github.com/davidbonnet/astring/commit/d22c19ee636e671a8214e062c1165cf56511b40f))
 11 | 
 12 | ### [1.8.6](https://github.com/davidbonnet/astring/compare/v1.8.5...v1.8.6) (2023-05-30)
 13 | 
 14 | 
 15 | ### Bug Fixes
 16 | 
 17 | * **nullish:** missing parenthesis ([be1aefb](https://github.com/davidbonnet/astring/commit/be1aefb7396c62b8504d15fc21891e4e9317f492)), closes [#695](https://github.com/davidbonnet/astring/issues/695)
 18 | 
 19 | ### [1.8.5](https://github.com/davidbonnet/astring/compare/v1.8.4...v1.8.5) (2023-05-19)
 20 | 
 21 | 
 22 | ### Bug Fixes
 23 | 
 24 | * **package:** add type conditional export ([36c0029](https://github.com/davidbonnet/astring/commit/36c00290ab8573a56dec118600721a0b87363a8b))
 25 | * incorrect nullish coalescing operator precedence ([#694](https://github.com/davidbonnet/astring/issues/694)) ([ad9ce87](https://github.com/davidbonnet/astring/commit/ad9ce8724453bdd497290b464787dde0a86d42ec))
 26 | 
 27 | ### [1.8.4](https://github.com/davidbonnet/astring/compare/v1.8.3...v1.8.4) (2022-12-21)
 28 | 
 29 | 
 30 | ### Bug Fixes
 31 | 
 32 | * static computed property ([#672](https://github.com/davidbonnet/astring/issues/672)) ([1630853](https://github.com/davidbonnet/astring/commit/16308537294bf0af26f318dc2f4a535814c3cae4))
 33 | 
 34 | ### [1.8.3](https://github.com/davidbonnet/astring/compare/v1.8.2...v1.8.3) (2022-04-28)
 35 | 
 36 | 
 37 | ### Bug Fixes
 38 | 
 39 | * add missing definitions ([9bb7bcf](https://github.com/davidbonnet/astring/commit/9bb7bcf7ab946bae3aab48b4d4b5edc72b52c208)), closes [#604](https://github.com/davidbonnet/astring/issues/604)
 40 | 
 41 | ### [1.8.2](https://github.com/davidbonnet/astring/compare/v1.8.1...v1.8.2) (2022-04-28)
 42 | 
 43 | 
 44 | ### Bug Fixes
 45 | 
 46 | * Does not handle undefined private properties ([e6b8ee6](https://github.com/davidbonnet/astring/commit/e6b8ee645d0e9fa3cc6ff4bb30d2a15e2289a88b)), closes [#609](https://github.com/davidbonnet/astring/issues/609)
 47 | 
 48 | ### [1.8.1](https://github.com/davidbonnet/astring/compare/v1.8.0...v1.8.1) (2021-11-21)
 49 | 
 50 | ## [1.8.0](https://github.com/davidbonnet/astring/compare/v1.7.6...v1.8.0) (2021-11-21)
 51 | 
 52 | 
 53 | ### Features
 54 | 
 55 | * support ES2022 ([#593](https://github.com/davidbonnet/astring/issues/593)) ([5a327d1](https://github.com/davidbonnet/astring/commit/5a327d1425cdd620377fb52b987880f8af461b62))
 56 | 
 57 | ### [1.7.6](https://github.com/davidbonnet/astring/compare/v1.7.5...v1.7.6) (2021-11-21)
 58 | 
 59 | 
 60 | ### Bug Fixes
 61 | 
 62 | * wrong precedence of nullish operator ([#590](https://github.com/davidbonnet/astring/issues/590)) ([10fac23](https://github.com/davidbonnet/astring/commit/10fac23a010feedb26d3baaf0e74e2311504e846))
 63 | 
 64 | ### [1.7.5](https://github.com/davidbonnet/astring/compare/v1.7.4...v1.7.5) (2021-06-02)
 65 | 
 66 | ### [1.7.4](https://github.com/davidbonnet/astring/compare/v1.7.3...v1.7.4) (2021-04-07)
 67 | 
 68 | 
 69 | ### Bug Fixes
 70 | 
 71 | * **package:** correctly declare module variant ([45203ca](https://github.com/davidbonnet/astring/commit/45203ca5bdd0307cfa3ed9a838d59718de84c6b5)), closes [#505](https://github.com/davidbonnet/astring/issues/505)
 72 | 
 73 | ### [1.7.3](https://github.com/davidbonnet/astring/compare/v1.7.2...v1.7.3) (2021-04-05)
 74 | 
 75 | 
 76 | ### Bug Fixes
 77 | 
 78 | * **package:** add "exports" field ([e82e873](https://github.com/davidbonnet/astring/commit/e82e87312f51c2cfa1a3c1104091a30352023bc5))
 79 | 
 80 | ### [1.7.2](https://github.com/davidbonnet/astring/compare/v1.7.1...v1.7.2) (2021-04-05)
 81 | 
 82 | 
 83 | ### Bug Fixes
 84 | 
 85 | * class, ternary, and arrow function miss parentheses ([#504](https://github.com/davidbonnet/astring/issues/504)) ([5037b94](https://github.com/davidbonnet/astring/commit/5037b94b3a447be7d42ae9edeb1e50ef2b2b776c))
 86 | 
 87 | ### [1.7.1](https://github.com/davidbonnet/astring/compare/v1.7.0...v1.7.1) (2021-04-05)
 88 | 
 89 | 
 90 | ### Bug Fixes
 91 | 
 92 | * **sourcemaps:** missing sourcemaps on debugger statement ([#503](https://github.com/davidbonnet/astring/issues/503)) ([9822a2a](https://github.com/davidbonnet/astring/commit/9822a2a4432ff957ef18c5959f3c71d10f0e361d))
 93 | 
 94 | ## [1.7.0](https://github.com/davidbonnet/astring/compare/v1.6.2...v1.7.0) (2021-02-06)
 95 | 
 96 | 
 97 | ### Features
 98 | 
 99 | * add typescript definitions ([#346](https://github.com/davidbonnet/astring/issues/346)) ([d2e197a](https://github.com/davidbonnet/astring/commit/d2e197a6b82efeeffc2d7a6fa2f16295c54c8dea))
100 | 
101 | ### [1.6.2](https://github.com/davidbonnet/astring/compare/v1.6.1...v1.6.2) (2021-02-03)
102 | 
103 | 
104 | ### Bug Fixes
105 | 
106 | * lower yield operator precedence ([d3af2fc](https://github.com/davidbonnet/astring/commit/d3af2fcd8096401b5618a7e479bfb5b25e129eed))
107 | 
108 | ### [1.6.1](https://github.com/davidbonnet/astring/compare/v1.6.0...v1.6.1) (2021-02-03)
109 | 
110 | 
111 | ### Bug Fixes
112 | 
113 | * adjust await and yield operator precendences ([d6166a2](https://github.com/davidbonnet/astring/commit/d6166a256f8e6f1071440b7469b786c18ddf252f)), closes [#435](https://github.com/davidbonnet/astring/issues/435)
114 | 
115 | ## [1.6.0](https://github.com/davidbonnet/astring/compare/v1.5.1...v1.6.0) (2021-01-04)
116 | 
117 | 
118 | ### Features
119 | 
120 | * support custom expression precedence ([#427](https://github.com/davidbonnet/astring/issues/427)) ([76ce709](https://github.com/davidbonnet/astring/commit/76ce7099c4ba391ef130ea6010bcce6ae7392cf4))
121 | 
122 | 
123 | ### Bug Fixes
124 | 
125 | * unary and update expression precedence ([0b273a6](https://github.com/davidbonnet/astring/commit/0b273a6cfe7c7672de4cf1bd00f423358d0729f4)), closes [#426](https://github.com/davidbonnet/astring/issues/426)
126 | 
127 | ### [1.5.1](https://github.com/davidbonnet/astring/compare/v1.5.0...v1.5.1) (2021-01-03)
128 | 
129 | 
130 | ### Bug Fixes
131 | 
132 | * **source-maps:** map nameless nodes ([102e569](https://github.com/davidbonnet/astring/commit/102e5696482d42f5dcccdb2ce088f7361c7dee94))
133 | 
134 | ## [1.5.0](https://github.com/davidbonnet/astring/compare/v1.4.3...v1.5.0) (2021-01-03)
135 | 
136 | 
137 | ### Features
138 | 
139 | * add bigint support ([d061997](https://github.com/davidbonnet/astring/commit/d061997b03095bbd864889dd04b6442fae6363ce))
140 | * add identifier support to export all ([a646dfa](https://github.com/davidbonnet/astring/commit/a646dfa9a6d093111f934b306d37ad61cf32fd9b))
141 | * add optional chaining support ([8c3ef44](https://github.com/davidbonnet/astring/commit/8c3ef44ae6d273562f6e03cb890726d2cc02f9b2)), closes [#424](https://github.com/davidbonnet/astring/issues/424)
142 | * support import expression ([#345](https://github.com/davidbonnet/astring/issues/345)) ([56a1574](https://github.com/davidbonnet/astring/commit/56a1574774533764644107a61bf0acc0d1c7d209))
143 | 
144 | 
145 | ### Bug Fixes
146 | 
147 | * **demo:** disable spellcheck on input ([b95ef6a](https://github.com/davidbonnet/astring/commit/b95ef6a4a179b031beba27387dd1bba935b2ce72))
148 | * incorrect awaited arrow function render ([11ec06c](https://github.com/davidbonnet/astring/commit/11ec06cd092cabc1a82ccd8b74c8219fcf98dcb7))
149 | * missing space for repeating unary operator ([#315](https://github.com/davidbonnet/astring/issues/315)) ([48e8a2e](https://github.com/davidbonnet/astring/commit/48e8a2e157858df4e1765cc2db9148b5b708216d))
150 | * sourcemaps for multiline strings are incorrect ([f246aff](https://github.com/davidbonnet/astring/commit/f246affc88b57455bc9eaa7f306fc9d2b6fd645f)), closes [#247](https://github.com/davidbonnet/astring/issues/247)
151 | 
152 | ### [1.4.3](https://github.com/davidbonnet/astring/compare/v1.4.2...v1.4.3) (2019-10-13)
153 | 
154 | 
155 | ### Bug Fixes
156 | 
157 | * render TemplateElement nodes ([8e5f77b](https://github.com/davidbonnet/astring/commit/8e5f77b)), closes [#129](https://github.com/davidbonnet/astring/issues/129)
158 | 
159 | ### [1.4.2](https://github.com/davidbonnet/astring/compare/v1.4.1...v1.4.2) (2019-09-15)
160 | 
161 | 
162 | ### Build System
163 | 
164 | * **deps-dev:** bump @babel/cli from 7.5.5 to 7.6.0 ([#103](https://github.com/davidbonnet/astring/issues/103)) ([e4681cc](https://github.com/davidbonnet/astring/commit/e4681cc))
165 | * **deps-dev:** bump @babel/core from 7.5.5 to 7.6.0 ([#105](https://github.com/davidbonnet/astring/issues/105)) ([08af974](https://github.com/davidbonnet/astring/commit/08af974))
166 | * **deps-dev:** bump @babel/generator from 7.5.5 to 7.6.0 ([#104](https://github.com/davidbonnet/astring/issues/104)) ([d4e29bd](https://github.com/davidbonnet/astring/commit/d4e29bd))
167 | * **deps-dev:** bump @babel/parser from 7.5.5 to 7.6.0 ([#110](https://github.com/davidbonnet/astring/issues/110)) ([df0414b](https://github.com/davidbonnet/astring/commit/df0414b))
168 | * **deps-dev:** bump @babel/preset-env from 7.5.5 to 7.6.0 ([#106](https://github.com/davidbonnet/astring/issues/106)) ([7616978](https://github.com/davidbonnet/astring/commit/7616978))
169 | * **deps-dev:** bump acorn from 6.2.1 to 6.3.0 ([#86](https://github.com/davidbonnet/astring/issues/86)) ([585e4c6](https://github.com/davidbonnet/astring/commit/585e4c6))
170 | * **deps-dev:** bump ava from 2.2.0 to 2.3.0 ([#89](https://github.com/davidbonnet/astring/issues/89)) ([21c90fa](https://github.com/davidbonnet/astring/commit/21c90fa))
171 | * **deps-dev:** bump babel-preset-minify from 0.5.0 to 0.5.1 ([#88](https://github.com/davidbonnet/astring/issues/88)) ([a9c02a2](https://github.com/davidbonnet/astring/commit/a9c02a2))
172 | * **deps-dev:** bump cross-env from 5.2.0 to 5.2.1 ([#99](https://github.com/davidbonnet/astring/issues/99)) ([d24faef](https://github.com/davidbonnet/astring/commit/d24faef))
173 | * **deps-dev:** bump escodegen from 1.11.1 to 1.12.0 ([#84](https://github.com/davidbonnet/astring/issues/84)) ([09d0a59](https://github.com/davidbonnet/astring/commit/09d0a59))
174 | * **deps-dev:** bump eslint from 6.1.0 to 6.2.0 ([#91](https://github.com/davidbonnet/astring/issues/91)) ([63f193d](https://github.com/davidbonnet/astring/commit/63f193d))
175 | * **deps-dev:** bump eslint from 6.2.0 to 6.2.1 ([#93](https://github.com/davidbonnet/astring/issues/93)) ([f36bd83](https://github.com/davidbonnet/astring/commit/f36bd83))
176 | * **deps-dev:** bump eslint from 6.2.1 to 6.2.2 ([#95](https://github.com/davidbonnet/astring/issues/95)) ([7a0c860](https://github.com/davidbonnet/astring/commit/7a0c860))
177 | * **deps-dev:** bump eslint from 6.2.2 to 6.3.0 ([#97](https://github.com/davidbonnet/astring/issues/97)) ([8ba7db9](https://github.com/davidbonnet/astring/commit/8ba7db9))
178 | * **deps-dev:** bump eslint from 6.3.0 to 6.4.0 ([#111](https://github.com/davidbonnet/astring/issues/111)) ([eefe681](https://github.com/davidbonnet/astring/commit/eefe681))
179 | * **deps-dev:** bump eslint-config-prettier from 6.0.0 to 6.1.0 ([#92](https://github.com/davidbonnet/astring/issues/92)) ([82d33dc](https://github.com/davidbonnet/astring/commit/82d33dc))
180 | * **deps-dev:** bump eslint-config-prettier from 6.1.0 to 6.2.0 ([#101](https://github.com/davidbonnet/astring/issues/101)) ([b4198a4](https://github.com/davidbonnet/astring/commit/b4198a4))
181 | * **deps-dev:** bump eslint-config-prettier from 6.2.0 to 6.3.0 ([#108](https://github.com/davidbonnet/astring/issues/108)) ([f63fd0c](https://github.com/davidbonnet/astring/commit/f63fd0c))
182 | * **deps-dev:** bump husky from 3.0.1 to 3.0.2 ([#77](https://github.com/davidbonnet/astring/issues/77)) ([dbb65dc](https://github.com/davidbonnet/astring/commit/dbb65dc))
183 | * **deps-dev:** bump husky from 3.0.2 to 3.0.3 ([#82](https://github.com/davidbonnet/astring/issues/82)) ([f11579c](https://github.com/davidbonnet/astring/commit/f11579c))
184 | * **deps-dev:** bump husky from 3.0.3 to 3.0.4 ([a686998](https://github.com/davidbonnet/astring/commit/a686998))
185 | * **deps-dev:** bump husky from 3.0.4 to 3.0.5 ([#100](https://github.com/davidbonnet/astring/issues/100)) ([2bff815](https://github.com/davidbonnet/astring/commit/2bff815))
186 | * **deps-dev:** bump meriyah from 1.3.5 to 1.6.0 ([#79](https://github.com/davidbonnet/astring/issues/79)) ([2cad1d4](https://github.com/davidbonnet/astring/commit/2cad1d4))
187 | * **deps-dev:** bump meriyah from 1.6.0 to 1.6.2 ([#81](https://github.com/davidbonnet/astring/issues/81)) ([7ce3afd](https://github.com/davidbonnet/astring/commit/7ce3afd))
188 | * **deps-dev:** bump meriyah from 1.6.10 to 1.6.13 ([#94](https://github.com/davidbonnet/astring/issues/94)) ([49f2899](https://github.com/davidbonnet/astring/commit/49f2899))
189 | * **deps-dev:** bump meriyah from 1.6.13 to 1.6.15 ([#96](https://github.com/davidbonnet/astring/issues/96)) ([9a0ce8f](https://github.com/davidbonnet/astring/commit/9a0ce8f))
190 | * **deps-dev:** bump meriyah from 1.6.15 to 1.6.16 ([#98](https://github.com/davidbonnet/astring/issues/98)) ([4085bf9](https://github.com/davidbonnet/astring/commit/4085bf9))
191 | * **deps-dev:** bump meriyah from 1.6.16 to 1.6.17 ([#102](https://github.com/davidbonnet/astring/issues/102)) ([e56c7c6](https://github.com/davidbonnet/astring/commit/e56c7c6))
192 | * **deps-dev:** bump meriyah from 1.6.17 to 1.6.18 ([#107](https://github.com/davidbonnet/astring/issues/107)) ([2c4fc18](https://github.com/davidbonnet/astring/commit/2c4fc18))
193 | * **deps-dev:** bump meriyah from 1.6.18 to 1.7.0 ([#109](https://github.com/davidbonnet/astring/issues/109)) ([ba3c487](https://github.com/davidbonnet/astring/commit/ba3c487))
194 | * **deps-dev:** bump meriyah from 1.6.2 to 1.6.8 ([#85](https://github.com/davidbonnet/astring/issues/85)) ([0c91697](https://github.com/davidbonnet/astring/commit/0c91697))
195 | * **deps-dev:** bump meriyah from 1.6.8 to 1.6.10 ([#87](https://github.com/davidbonnet/astring/issues/87)) ([036c19d](https://github.com/davidbonnet/astring/commit/036c19d))
196 | 
197 | 
198 | 
199 | ### [1.4.1](https://github.com/davidbonnet/astring/compare/v1.4.0...v1.4.1) (2019-07-20)
200 | 
201 | 
202 | ### Bug Fixes
203 | 
204 | * **#74:** correct exponentiation precedence ([b267927](https://github.com/davidbonnet/astring/commit/b267927)), closes [#74](https://github.com/davidbonnet/astring/issues/74) [#74](https://github.com/davidbonnet/astring/issues/74)
205 | 
206 | 
207 | 
208 | 
209 | # [1.4.0](https://github.com/davidbonnet/astring/compare/v1.3.1...v1.4.0) (2019-03-30)
210 | 
211 | 
212 | ### Bug Fixes
213 | 
214 | * remove Node 6 support ([800c07f](https://github.com/davidbonnet/astring/commit/800c07f))
215 | 
216 | 
217 | ### Features
218 | 
219 | * support async loops and rest properties ([294021c](https://github.com/davidbonnet/astring/commit/294021c)), closes [#64](https://github.com/davidbonnet/astring/issues/64)
220 | 
221 | 
222 | 
223 | 
224 | ## [1.3.1](https://github.com/davidbonnet/astring/compare/v1.3.0...v1.3.1) (2018-06-23)
225 | 


--------------------------------------------------------------------------------
/docs/demo/astring.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){if("function"==typeof define&&define.amd)define(["exports"],b);else if("undefined"!=typeof exports)b(exports);else{var c={exports:{}};b(c.exports),a.astring=c.exports}})("undefined"==typeof globalThis?"undefined"==typeof self?this:self:globalThis,function(a){"use strict";var b=String.prototype;function c(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function d(a,b){for(var c,d=0;d":9,"<=":9,">=":9,in:9,instanceof:9,"<<":10,">>":10,">>>":10,"+":11,"-":11,"*":12,"%":12,"/":12,"**":13},p=17;a.NEEDS_PARENTHESES=p;var q={ArrayExpression:20,TaggedTemplateExpression:20,ThisExpression:20,Identifier:20,PrivateIdentifier:20,Literal:18,TemplateLiteral:20,Super:20,SequenceExpression:20,MemberExpression:19,ChainExpression:19,CallExpression:19,NewExpression:19,ArrowFunctionExpression:p,ClassExpression:p,FunctionExpression:p,ObjectExpression:p,UpdateExpression:16,UnaryExpression:15,AwaitExpression:15,BinaryExpression:14,LogicalExpression:13,ConditionalExpression:4,AssignmentExpression:3,YieldExpression:2,RestElement:1};a.EXPRESSIONS_PRECEDENCE=q;var r,s,t,u,v,w,x={Program:function Program(a,b){var c=b.indent.repeat(b.indentLevel),d=b.lineEnd,e=b.writeComments;e&&null!=a.comments&&k(b,a.comments,c,d);for(var f,g=a.body,h=g.length,j=0;j "),"O"===a.body.type[0]?(b.write("("),this.ObjectExpression(a.body,b),b.write(")")):this[a.body.type](a.body,b)},ThisExpression:function ThisExpression(a,b){b.write("this",a)},Super:function Super(a,b){b.write("super",a)},RestElement:t=function(a,b){b.write("..."),this[a.argument.type](a.argument,b)},SpreadElement:t,YieldExpression:function YieldExpression(a,b){b.write(a.delegate?"yield*":"yield"),a.argument&&(b.write(" "),this[a.argument.type](a.argument,b))},AwaitExpression:function AwaitExpression(a,b){b.write("await ",a),h(b,a.argument,a)},TemplateLiteral:function TemplateLiteral(a,b){var c=a.quasis,d=a.expressions;b.write("`");for(var e=d.length,f=0;f': 9,
  42 |   '<=': 9,
  43 |   '>=': 9,
  44 |   in: 9,
  45 |   instanceof: 9,
  46 |   '<<': 10,
  47 |   '>>': 10,
  48 |   '>>>': 10,
  49 |   '+': 11,
  50 |   '-': 11,
  51 |   '*': 12,
  52 |   '%': 12,
  53 |   '/': 12,
  54 |   '**': 13,
  55 | }
  56 | 
  57 | // Enables parenthesis regardless of precedence
  58 | export const NEEDS_PARENTHESES = 17
  59 | 
  60 | export const EXPRESSIONS_PRECEDENCE = {
  61 |   // Definitions
  62 |   ArrayExpression: 20,
  63 |   TaggedTemplateExpression: 20,
  64 |   ThisExpression: 20,
  65 |   Identifier: 20,
  66 |   PrivateIdentifier: 20,
  67 |   Literal: 18,
  68 |   TemplateLiteral: 20,
  69 |   Super: 20,
  70 |   SequenceExpression: 20,
  71 |   // Operations
  72 |   MemberExpression: 19,
  73 |   ChainExpression: 19,
  74 |   CallExpression: 19,
  75 |   NewExpression: 19,
  76 |   // Other definitions
  77 |   ArrowFunctionExpression: NEEDS_PARENTHESES,
  78 |   ClassExpression: NEEDS_PARENTHESES,
  79 |   FunctionExpression: NEEDS_PARENTHESES,
  80 |   ObjectExpression: NEEDS_PARENTHESES,
  81 |   // Other operations
  82 |   UpdateExpression: 16,
  83 |   UnaryExpression: 15,
  84 |   AwaitExpression: 15,
  85 |   BinaryExpression: 14,
  86 |   LogicalExpression: 13,
  87 |   ConditionalExpression: 4,
  88 |   AssignmentExpression: 3,
  89 |   YieldExpression: 2,
  90 |   RestElement: 1,
  91 | }
  92 | 
  93 | function formatSequence(state, nodes) {
  94 |   /*
  95 |   Writes into `state` a sequence of `nodes`.
  96 |   */
  97 |   const { generator } = state
  98 |   state.write('(')
  99 |   if (nodes != null && nodes.length > 0) {
 100 |     generator[nodes[0].type](nodes[0], state)
 101 |     const { length } = nodes
 102 |     for (let i = 1; i < length; i++) {
 103 |       const param = nodes[i]
 104 |       state.write(', ')
 105 |       generator[param.type](param, state)
 106 |     }
 107 |   }
 108 |   state.write(')')
 109 | }
 110 | 
 111 | function expressionNeedsParenthesis(state, node, parentNode, isRightHand) {
 112 |   const nodePrecedence = state.expressionsPrecedence[node.type]
 113 |   if (nodePrecedence === NEEDS_PARENTHESES) {
 114 |     return true
 115 |   }
 116 |   const parentNodePrecedence = state.expressionsPrecedence[parentNode.type]
 117 |   if (nodePrecedence !== parentNodePrecedence) {
 118 |     // Different node types
 119 |     return (
 120 |       (!isRightHand &&
 121 |         nodePrecedence === 15 &&
 122 |         parentNodePrecedence === 14 &&
 123 |         parentNode.operator === '**') ||
 124 |       nodePrecedence < parentNodePrecedence
 125 |     )
 126 |   }
 127 |   if (nodePrecedence !== 13 && nodePrecedence !== 14) {
 128 |     // Not a `LogicalExpression` or `BinaryExpression`
 129 |     return false
 130 |   }
 131 |   if (node.operator === '**' && parentNode.operator === '**') {
 132 |     // Exponentiation operator has right-to-left associativity
 133 |     return !isRightHand
 134 |   }
 135 |   if (
 136 |     nodePrecedence === 13 &&
 137 |     parentNodePrecedence === 13 &&
 138 |     (node.operator === '??' || parentNode.operator === '??')
 139 |   ) {
 140 |     // Nullish coalescing and boolean operators cannot be combined
 141 |     return true
 142 |   }
 143 |   if (isRightHand) {
 144 |     // Parenthesis are used if both operators have the same precedence
 145 |     return (
 146 |       OPERATOR_PRECEDENCE[node.operator] <=
 147 |       OPERATOR_PRECEDENCE[parentNode.operator]
 148 |     )
 149 |   }
 150 |   return (
 151 |     OPERATOR_PRECEDENCE[node.operator] <
 152 |     OPERATOR_PRECEDENCE[parentNode.operator]
 153 |   )
 154 | }
 155 | 
 156 | function formatExpression(state, node, parentNode, isRightHand) {
 157 |   /*
 158 |   Writes into `state` the provided `node`, adding parenthesis around if the provided `parentNode` needs it. If `node` is a right-hand argument, the provided `isRightHand` parameter should be `true`.
 159 |   */
 160 |   const { generator } = state
 161 |   if (expressionNeedsParenthesis(state, node, parentNode, isRightHand)) {
 162 |     state.write('(')
 163 |     generator[node.type](node, state)
 164 |     state.write(')')
 165 |   } else {
 166 |     generator[node.type](node, state)
 167 |   }
 168 | }
 169 | 
 170 | function reindent(state, text, indent, lineEnd) {
 171 |   /*
 172 |   Writes into `state` the `text` string reindented with the provided `indent`.
 173 |   */
 174 |   const lines = text.split('\n')
 175 |   const end = lines.length - 1
 176 |   state.write(lines[0].trim())
 177 |   if (end > 0) {
 178 |     state.write(lineEnd)
 179 |     for (let i = 1; i < end; i++) {
 180 |       state.write(indent + lines[i].trim() + lineEnd)
 181 |     }
 182 |     state.write(indent + lines[end].trim())
 183 |   }
 184 | }
 185 | 
 186 | function formatComments(state, comments, indent, lineEnd) {
 187 |   /*
 188 |   Writes into `state` the provided list of `comments`, with the given `indent` and `lineEnd` strings.
 189 |   Line comments will end with `"\n"` regardless of the value of `lineEnd`.
 190 |   Expects to start on a new unindented line.
 191 |   */
 192 |   const { length } = comments
 193 |   for (let i = 0; i < length; i++) {
 194 |     const comment = comments[i]
 195 |     state.write(indent)
 196 |     if (comment.type[0] === 'L') {
 197 |       // Line comment
 198 |       state.write('// ' + comment.value.trim() + '\n', comment)
 199 |     } else {
 200 |       // Block comment
 201 |       state.write('/*')
 202 |       reindent(state, comment.value, indent, lineEnd)
 203 |       state.write('*/' + lineEnd)
 204 |     }
 205 |   }
 206 | }
 207 | 
 208 | function hasCallExpression(node) {
 209 |   /*
 210 |   Returns `true` if the provided `node` contains a call expression and `false` otherwise.
 211 |   */
 212 |   let currentNode = node
 213 |   while (currentNode != null) {
 214 |     const { type } = currentNode
 215 |     if (type[0] === 'C' && type[1] === 'a') {
 216 |       // Is CallExpression
 217 |       return true
 218 |     } else if (type[0] === 'M' && type[1] === 'e' && type[2] === 'm') {
 219 |       // Is MemberExpression
 220 |       currentNode = currentNode.object
 221 |     } else {
 222 |       return false
 223 |     }
 224 |   }
 225 | }
 226 | 
 227 | function formatVariableDeclaration(state, node) {
 228 |   /*
 229 |   Writes into `state` a variable declaration.
 230 |   */
 231 |   const { generator } = state
 232 |   const { declarations } = node
 233 |   state.write(node.kind + ' ')
 234 |   const { length } = declarations
 235 |   if (length > 0) {
 236 |     generator.VariableDeclarator(declarations[0], state)
 237 |     for (let i = 1; i < length; i++) {
 238 |       state.write(', ')
 239 |       generator.VariableDeclarator(declarations[i], state)
 240 |     }
 241 |   }
 242 | }
 243 | 
 244 | let ForInStatement,
 245 |   FunctionDeclaration,
 246 |   RestElement,
 247 |   BinaryExpression,
 248 |   ArrayExpression,
 249 |   BlockStatement
 250 | 
 251 | export const GENERATOR = {
 252 |   /*
 253 |   Default generator.
 254 |   */
 255 |   Program(node, state) {
 256 |     const indent = state.indent.repeat(state.indentLevel)
 257 |     const { lineEnd, writeComments } = state
 258 |     if (writeComments && node.comments != null) {
 259 |       formatComments(state, node.comments, indent, lineEnd)
 260 |     }
 261 |     const statements = node.body
 262 |     const { length } = statements
 263 |     for (let i = 0; i < length; i++) {
 264 |       const statement = statements[i]
 265 |       if (writeComments && statement.comments != null) {
 266 |         formatComments(state, statement.comments, indent, lineEnd)
 267 |       }
 268 |       state.write(indent)
 269 |       this[statement.type](statement, state)
 270 |       state.write(lineEnd)
 271 |     }
 272 |     if (writeComments && node.trailingComments != null) {
 273 |       formatComments(state, node.trailingComments, indent, lineEnd)
 274 |     }
 275 |   },
 276 |   BlockStatement: (BlockStatement = function (node, state) {
 277 |     const indent = state.indent.repeat(state.indentLevel++)
 278 |     const { lineEnd, writeComments } = state
 279 |     const statementIndent = indent + state.indent
 280 |     state.write('{')
 281 |     const statements = node.body
 282 |     if (statements != null && statements.length > 0) {
 283 |       state.write(lineEnd)
 284 |       if (writeComments && node.comments != null) {
 285 |         formatComments(state, node.comments, statementIndent, lineEnd)
 286 |       }
 287 |       const { length } = statements
 288 |       for (let i = 0; i < length; i++) {
 289 |         const statement = statements[i]
 290 |         if (writeComments && statement.comments != null) {
 291 |           formatComments(state, statement.comments, statementIndent, lineEnd)
 292 |         }
 293 |         state.write(statementIndent)
 294 |         this[statement.type](statement, state)
 295 |         state.write(lineEnd)
 296 |       }
 297 |       state.write(indent)
 298 |     } else {
 299 |       if (writeComments && node.comments != null) {
 300 |         state.write(lineEnd)
 301 |         formatComments(state, node.comments, statementIndent, lineEnd)
 302 |         state.write(indent)
 303 |       }
 304 |     }
 305 |     if (writeComments && node.trailingComments != null) {
 306 |       formatComments(state, node.trailingComments, statementIndent, lineEnd)
 307 |     }
 308 |     state.write('}')
 309 |     state.indentLevel--
 310 |   }),
 311 |   ClassBody: BlockStatement,
 312 |   StaticBlock(node, state) {
 313 |     state.write('static ')
 314 |     this.BlockStatement(node, state)
 315 |   },
 316 |   EmptyStatement(node, state) {
 317 |     state.write(';')
 318 |   },
 319 |   ExpressionStatement(node, state) {
 320 |     const precedence = state.expressionsPrecedence[node.expression.type]
 321 |     if (
 322 |       precedence === NEEDS_PARENTHESES ||
 323 |       (precedence === 3 && node.expression.left.type[0] === 'O')
 324 |     ) {
 325 |       // Should always have parentheses or is an AssignmentExpression to an ObjectPattern
 326 |       state.write('(')
 327 |       this[node.expression.type](node.expression, state)
 328 |       state.write(')')
 329 |     } else {
 330 |       this[node.expression.type](node.expression, state)
 331 |     }
 332 |     state.write(';')
 333 |   },
 334 |   IfStatement(node, state) {
 335 |     state.write('if (')
 336 |     this[node.test.type](node.test, state)
 337 |     state.write(') ')
 338 |     this[node.consequent.type](node.consequent, state)
 339 |     if (node.alternate != null) {
 340 |       state.write(' else ')
 341 |       this[node.alternate.type](node.alternate, state)
 342 |     }
 343 |   },
 344 |   LabeledStatement(node, state) {
 345 |     this[node.label.type](node.label, state)
 346 |     state.write(': ')
 347 |     this[node.body.type](node.body, state)
 348 |   },
 349 |   BreakStatement(node, state) {
 350 |     state.write('break')
 351 |     if (node.label != null) {
 352 |       state.write(' ')
 353 |       this[node.label.type](node.label, state)
 354 |     }
 355 |     state.write(';')
 356 |   },
 357 |   ContinueStatement(node, state) {
 358 |     state.write('continue')
 359 |     if (node.label != null) {
 360 |       state.write(' ')
 361 |       this[node.label.type](node.label, state)
 362 |     }
 363 |     state.write(';')
 364 |   },
 365 |   WithStatement(node, state) {
 366 |     state.write('with (')
 367 |     this[node.object.type](node.object, state)
 368 |     state.write(') ')
 369 |     this[node.body.type](node.body, state)
 370 |   },
 371 |   SwitchStatement(node, state) {
 372 |     const indent = state.indent.repeat(state.indentLevel++)
 373 |     const { lineEnd, writeComments } = state
 374 |     state.indentLevel++
 375 |     const caseIndent = indent + state.indent
 376 |     const statementIndent = caseIndent + state.indent
 377 |     state.write('switch (')
 378 |     this[node.discriminant.type](node.discriminant, state)
 379 |     state.write(') {' + lineEnd)
 380 |     const { cases: occurences } = node
 381 |     const { length: occurencesCount } = occurences
 382 |     for (let i = 0; i < occurencesCount; i++) {
 383 |       const occurence = occurences[i]
 384 |       if (writeComments && occurence.comments != null) {
 385 |         formatComments(state, occurence.comments, caseIndent, lineEnd)
 386 |       }
 387 |       if (occurence.test) {
 388 |         state.write(caseIndent + 'case ')
 389 |         this[occurence.test.type](occurence.test, state)
 390 |         state.write(':' + lineEnd)
 391 |       } else {
 392 |         state.write(caseIndent + 'default:' + lineEnd)
 393 |       }
 394 |       const { consequent } = occurence
 395 |       const { length: consequentCount } = consequent
 396 |       for (let i = 0; i < consequentCount; i++) {
 397 |         const statement = consequent[i]
 398 |         if (writeComments && statement.comments != null) {
 399 |           formatComments(state, statement.comments, statementIndent, lineEnd)
 400 |         }
 401 |         state.write(statementIndent)
 402 |         this[statement.type](statement, state)
 403 |         state.write(lineEnd)
 404 |       }
 405 |     }
 406 |     state.indentLevel -= 2
 407 |     state.write(indent + '}')
 408 |   },
 409 |   ReturnStatement(node, state) {
 410 |     state.write('return')
 411 |     if (node.argument) {
 412 |       state.write(' ')
 413 |       this[node.argument.type](node.argument, state)
 414 |     }
 415 |     state.write(';')
 416 |   },
 417 |   ThrowStatement(node, state) {
 418 |     state.write('throw ')
 419 |     this[node.argument.type](node.argument, state)
 420 |     state.write(';')
 421 |   },
 422 |   TryStatement(node, state) {
 423 |     state.write('try ')
 424 |     this[node.block.type](node.block, state)
 425 |     if (node.handler) {
 426 |       const { handler } = node
 427 |       if (handler.param == null) {
 428 |         state.write(' catch ')
 429 |       } else {
 430 |         state.write(' catch (')
 431 |         this[handler.param.type](handler.param, state)
 432 |         state.write(') ')
 433 |       }
 434 |       this[handler.body.type](handler.body, state)
 435 |     }
 436 |     if (node.finalizer) {
 437 |       state.write(' finally ')
 438 |       this[node.finalizer.type](node.finalizer, state)
 439 |     }
 440 |   },
 441 |   WhileStatement(node, state) {
 442 |     state.write('while (')
 443 |     this[node.test.type](node.test, state)
 444 |     state.write(') ')
 445 |     this[node.body.type](node.body, state)
 446 |   },
 447 |   DoWhileStatement(node, state) {
 448 |     state.write('do ')
 449 |     this[node.body.type](node.body, state)
 450 |     state.write(' while (')
 451 |     this[node.test.type](node.test, state)
 452 |     state.write(');')
 453 |   },
 454 |   ForStatement(node, state) {
 455 |     state.write('for (')
 456 |     if (node.init != null) {
 457 |       const { init } = node
 458 |       if (init.type[0] === 'V') {
 459 |         formatVariableDeclaration(state, init)
 460 |       } else {
 461 |         this[init.type](init, state)
 462 |       }
 463 |     }
 464 |     state.write('; ')
 465 |     if (node.test) {
 466 |       this[node.test.type](node.test, state)
 467 |     }
 468 |     state.write('; ')
 469 |     if (node.update) {
 470 |       this[node.update.type](node.update, state)
 471 |     }
 472 |     state.write(') ')
 473 |     this[node.body.type](node.body, state)
 474 |   },
 475 |   ForInStatement: (ForInStatement = function (node, state) {
 476 |     state.write(`for ${node.await ? 'await ' : ''}(`)
 477 |     const { left } = node
 478 |     if (left.type[0] === 'V') {
 479 |       formatVariableDeclaration(state, left)
 480 |     } else {
 481 |       this[left.type](left, state)
 482 |     }
 483 |     // Identifying whether node.type is `ForInStatement` or `ForOfStatement`
 484 |     state.write(node.type[3] === 'I' ? ' in ' : ' of ')
 485 |     this[node.right.type](node.right, state)
 486 |     state.write(') ')
 487 |     this[node.body.type](node.body, state)
 488 |   }),
 489 |   ForOfStatement: ForInStatement,
 490 |   DebuggerStatement(node, state) {
 491 |     state.write('debugger;', node)
 492 |   },
 493 |   FunctionDeclaration: (FunctionDeclaration = function (node, state) {
 494 |     state.write(
 495 |       (node.async ? 'async ' : '') +
 496 |         (node.generator ? 'function* ' : 'function ') +
 497 |         (node.id ? node.id.name : ''),
 498 |       node,
 499 |     )
 500 |     formatSequence(state, node.params)
 501 |     state.write(' ')
 502 |     this[node.body.type](node.body, state)
 503 |   }),
 504 |   FunctionExpression: FunctionDeclaration,
 505 |   VariableDeclaration(node, state) {
 506 |     formatVariableDeclaration(state, node)
 507 |     state.write(';')
 508 |   },
 509 |   VariableDeclarator(node, state) {
 510 |     this[node.id.type](node.id, state)
 511 |     if (node.init != null) {
 512 |       state.write(' = ')
 513 |       this[node.init.type](node.init, state)
 514 |     }
 515 |   },
 516 |   ClassDeclaration(node, state) {
 517 |     state.write('class ' + (node.id ? `${node.id.name} ` : ''), node)
 518 |     if (node.superClass) {
 519 |       state.write('extends ')
 520 |       const { superClass } = node
 521 |       const { type } = superClass
 522 |       const precedence = state.expressionsPrecedence[type]
 523 |       if (
 524 |         (type[0] !== 'C' || type[1] !== 'l' || type[5] !== 'E') &&
 525 |         (precedence === NEEDS_PARENTHESES ||
 526 |           precedence < state.expressionsPrecedence.ClassExpression)
 527 |       ) {
 528 |         // Not a ClassExpression that needs parentheses
 529 |         state.write('(')
 530 |         this[node.superClass.type](superClass, state)
 531 |         state.write(')')
 532 |       } else {
 533 |         this[superClass.type](superClass, state)
 534 |       }
 535 |       state.write(' ')
 536 |     }
 537 |     this.ClassBody(node.body, state)
 538 |   },
 539 |   ImportDeclaration(node, state) {
 540 |     state.write('import ')
 541 |     const { specifiers, attributes } = node
 542 |     const { length } = specifiers
 543 |     // TODO: Once babili is fixed, put this after condition
 544 |     // https://github.com/babel/babili/issues/430
 545 |     let i = 0
 546 |     if (length > 0) {
 547 |       for (; i < length; ) {
 548 |         if (i > 0) {
 549 |           state.write(', ')
 550 |         }
 551 |         const specifier = specifiers[i]
 552 |         const type = specifier.type[6]
 553 |         if (type === 'D') {
 554 |           // ImportDefaultSpecifier
 555 |           state.write(specifier.local.name, specifier)
 556 |           i++
 557 |         } else if (type === 'N') {
 558 |           // ImportNamespaceSpecifier
 559 |           state.write('* as ' + specifier.local.name, specifier)
 560 |           i++
 561 |         } else {
 562 |           // ImportSpecifier
 563 |           break
 564 |         }
 565 |       }
 566 |       if (i < length) {
 567 |         state.write('{')
 568 |         for (;;) {
 569 |           const specifier = specifiers[i]
 570 |           const { name } = specifier.imported
 571 |           state.write(name, specifier)
 572 |           if (name !== specifier.local.name) {
 573 |             state.write(' as ' + specifier.local.name)
 574 |           }
 575 |           if (++i < length) {
 576 |             state.write(', ')
 577 |           } else {
 578 |             break
 579 |           }
 580 |         }
 581 |         state.write('}')
 582 |       }
 583 |       state.write(' from ')
 584 |     }
 585 |     this.Literal(node.source, state)
 586 | 
 587 |     if (attributes && attributes.length > 0) {
 588 |       state.write(' with { ')
 589 |       for (let i = 0; i < attributes.length; i++) {
 590 |         this.ImportAttribute(attributes[i], state)
 591 |         if (i < attributes.length - 1) state.write(', ')
 592 |       }
 593 | 
 594 |       state.write(' }')
 595 |     }
 596 |     state.write(';')
 597 |   },
 598 |   ImportAttribute(node, state) {
 599 |     this.Identifier(node.key, state)
 600 |     state.write(': ')
 601 |     this.Literal(node.value, state)
 602 |   },
 603 |   ImportExpression(node, state) {
 604 |     state.write('import(')
 605 |     this[node.source.type](node.source, state)
 606 |     state.write(')')
 607 |   },
 608 |   ExportDefaultDeclaration(node, state) {
 609 |     state.write('export default ')
 610 |     this[node.declaration.type](node.declaration, state)
 611 |     if (
 612 |       state.expressionsPrecedence[node.declaration.type] != null &&
 613 |       node.declaration.type[0] !== 'F'
 614 |     ) {
 615 |       // All expression nodes except `FunctionExpression`
 616 |       state.write(';')
 617 |     }
 618 |   },
 619 |   ExportNamedDeclaration(node, state) {
 620 |     state.write('export ')
 621 |     if (node.declaration) {
 622 |       this[node.declaration.type](node.declaration, state)
 623 |     } else {
 624 |       state.write('{')
 625 |       const { specifiers } = node,
 626 |         { length } = specifiers
 627 |       if (length > 0) {
 628 |         for (let i = 0; ; ) {
 629 |           const specifier = specifiers[i]
 630 |           const { name } = specifier.local
 631 |           state.write(name, specifier)
 632 |           if (name !== specifier.exported.name) {
 633 |             state.write(' as ' + specifier.exported.name)
 634 |           }
 635 |           if (++i < length) {
 636 |             state.write(', ')
 637 |           } else {
 638 |             break
 639 |           }
 640 |         }
 641 |       }
 642 |       state.write('}')
 643 |       if (node.source) {
 644 |         state.write(' from ')
 645 |         this.Literal(node.source, state)
 646 |       }
 647 | 
 648 |       if (node.attributes && node.attributes.length > 0) {
 649 |         state.write(' with { ')
 650 |         for (let i = 0; i < node.attributes.length; i++) {
 651 |           this.ImportAttribute(node.attributes[i], state)
 652 |           if (i < node.attributes.length - 1) state.write(', ')
 653 |         }
 654 | 
 655 |         state.write(' }')
 656 |       }
 657 | 
 658 |       state.write(';')
 659 |     }
 660 |   },
 661 |   ExportAllDeclaration(node, state) {
 662 |     if (node.exported != null) {
 663 |       state.write('export * as ' + node.exported.name + ' from ')
 664 |     } else {
 665 |       state.write('export * from ')
 666 |     }
 667 |     this.Literal(node.source, state)
 668 | 
 669 |     if (node.attributes && node.attributes.length > 0) {
 670 |       state.write(' with { ')
 671 |       for (let i = 0; i < node.attributes.length; i++) {
 672 |         this.ImportAttribute(node.attributes[i], state)
 673 |         if (i < node.attributes.length - 1) state.write(', ')
 674 |       }
 675 | 
 676 |       state.write(' }')
 677 |     }
 678 | 
 679 |     state.write(';')
 680 |   },
 681 |   MethodDefinition(node, state) {
 682 |     if (node.static) {
 683 |       state.write('static ')
 684 |     }
 685 |     const kind = node.kind[0]
 686 |     if (kind === 'g' || kind === 's') {
 687 |       // Getter or setter
 688 |       state.write(node.kind + ' ')
 689 |     }
 690 |     if (node.value.async) {
 691 |       state.write('async ')
 692 |     }
 693 |     if (node.value.generator) {
 694 |       state.write('*')
 695 |     }
 696 |     if (node.computed) {
 697 |       state.write('[')
 698 |       this[node.key.type](node.key, state)
 699 |       state.write(']')
 700 |     } else {
 701 |       this[node.key.type](node.key, state)
 702 |     }
 703 |     formatSequence(state, node.value.params)
 704 |     state.write(' ')
 705 |     this[node.value.body.type](node.value.body, state)
 706 |   },
 707 |   ClassExpression(node, state) {
 708 |     this.ClassDeclaration(node, state)
 709 |   },
 710 |   ArrowFunctionExpression(node, state) {
 711 |     state.write(node.async ? 'async ' : '', node)
 712 |     const { params } = node
 713 |     if (params != null) {
 714 |       // Omit parenthesis if only one named parameter
 715 |       if (params.length === 1 && params[0].type[0] === 'I') {
 716 |         // If params[0].type[0] starts with 'I', it can't be `ImportDeclaration` nor `IfStatement` and thus is `Identifier`
 717 |         state.write(params[0].name, params[0])
 718 |       } else {
 719 |         formatSequence(state, node.params)
 720 |       }
 721 |     }
 722 |     state.write(' => ')
 723 |     if (node.body.type[0] === 'O') {
 724 |       // Body is an object expression
 725 |       state.write('(')
 726 |       this.ObjectExpression(node.body, state)
 727 |       state.write(')')
 728 |     } else {
 729 |       this[node.body.type](node.body, state)
 730 |     }
 731 |   },
 732 |   ThisExpression(node, state) {
 733 |     state.write('this', node)
 734 |   },
 735 |   Super(node, state) {
 736 |     state.write('super', node)
 737 |   },
 738 |   RestElement: (RestElement = function (node, state) {
 739 |     state.write('...')
 740 |     this[node.argument.type](node.argument, state)
 741 |   }),
 742 |   SpreadElement: RestElement,
 743 |   YieldExpression(node, state) {
 744 |     state.write(node.delegate ? 'yield*' : 'yield')
 745 |     if (node.argument) {
 746 |       state.write(' ')
 747 |       this[node.argument.type](node.argument, state)
 748 |     }
 749 |   },
 750 |   AwaitExpression(node, state) {
 751 |     state.write('await ', node)
 752 |     formatExpression(state, node.argument, node)
 753 |   },
 754 |   TemplateLiteral(node, state) {
 755 |     const { quasis, expressions } = node
 756 |     state.write('`')
 757 |     const { length } = expressions
 758 |     for (let i = 0; i < length; i++) {
 759 |       const expression = expressions[i]
 760 |       const quasi = quasis[i]
 761 |       state.write(quasi.value.raw, quasi)
 762 |       state.write('${')
 763 |       this[expression.type](expression, state)
 764 |       state.write('}')
 765 |     }
 766 |     const quasi = quasis[quasis.length - 1]
 767 |     state.write(quasi.value.raw, quasi)
 768 |     state.write('`')
 769 |   },
 770 |   TemplateElement(node, state) {
 771 |     state.write(node.value.raw, node)
 772 |   },
 773 |   TaggedTemplateExpression(node, state) {
 774 |     formatExpression(state, node.tag, node)
 775 |     this[node.quasi.type](node.quasi, state)
 776 |   },
 777 |   ArrayExpression: (ArrayExpression = function (node, state) {
 778 |     state.write('[')
 779 |     if (node.elements.length > 0) {
 780 |       const { elements } = node,
 781 |         { length } = elements
 782 |       for (let i = 0; ; ) {
 783 |         const element = elements[i]
 784 |         if (element != null) {
 785 |           this[element.type](element, state)
 786 |         }
 787 |         if (++i < length) {
 788 |           state.write(', ')
 789 |         } else {
 790 |           if (element == null) {
 791 |             state.write(', ')
 792 |           }
 793 |           break
 794 |         }
 795 |       }
 796 |     }
 797 |     state.write(']')
 798 |   }),
 799 |   ArrayPattern: ArrayExpression,
 800 |   ObjectExpression(node, state) {
 801 |     const indent = state.indent.repeat(state.indentLevel++)
 802 |     const { lineEnd, writeComments } = state
 803 |     const propertyIndent = indent + state.indent
 804 |     state.write('{')
 805 |     if (node.properties.length > 0) {
 806 |       state.write(lineEnd)
 807 |       if (writeComments && node.comments != null) {
 808 |         formatComments(state, node.comments, propertyIndent, lineEnd)
 809 |       }
 810 |       const comma = ',' + lineEnd
 811 |       const { properties } = node,
 812 |         { length } = properties
 813 |       for (let i = 0; ; ) {
 814 |         const property = properties[i]
 815 |         if (writeComments && property.comments != null) {
 816 |           formatComments(state, property.comments, propertyIndent, lineEnd)
 817 |         }
 818 |         state.write(propertyIndent)
 819 |         this[property.type](property, state)
 820 |         if (++i < length) {
 821 |           state.write(comma)
 822 |         } else {
 823 |           break
 824 |         }
 825 |       }
 826 |       state.write(lineEnd)
 827 |       if (writeComments && node.trailingComments != null) {
 828 |         formatComments(state, node.trailingComments, propertyIndent, lineEnd)
 829 |       }
 830 |       state.write(indent + '}')
 831 |     } else if (writeComments) {
 832 |       if (node.comments != null) {
 833 |         state.write(lineEnd)
 834 |         formatComments(state, node.comments, propertyIndent, lineEnd)
 835 |         if (node.trailingComments != null) {
 836 |           formatComments(state, node.trailingComments, propertyIndent, lineEnd)
 837 |         }
 838 |         state.write(indent + '}')
 839 |       } else if (node.trailingComments != null) {
 840 |         state.write(lineEnd)
 841 |         formatComments(state, node.trailingComments, propertyIndent, lineEnd)
 842 |         state.write(indent + '}')
 843 |       } else {
 844 |         state.write('}')
 845 |       }
 846 |     } else {
 847 |       state.write('}')
 848 |     }
 849 |     state.indentLevel--
 850 |   },
 851 |   Property(node, state) {
 852 |     if (node.method || node.kind[0] !== 'i') {
 853 |       // Either a method or of kind `set` or `get` (not `init`)
 854 |       this.MethodDefinition(node, state)
 855 |     } else {
 856 |       if (!node.shorthand) {
 857 |         if (node.computed) {
 858 |           state.write('[')
 859 |           this[node.key.type](node.key, state)
 860 |           state.write(']')
 861 |         } else {
 862 |           this[node.key.type](node.key, state)
 863 |         }
 864 |         state.write(': ')
 865 |       }
 866 |       this[node.value.type](node.value, state)
 867 |     }
 868 |   },
 869 |   PropertyDefinition(node, state) {
 870 |     if (node.static) {
 871 |       state.write('static ')
 872 |     }
 873 |     if (node.computed) {
 874 |       state.write('[')
 875 |     }
 876 |     this[node.key.type](node.key, state)
 877 |     if (node.computed) {
 878 |       state.write(']')
 879 |     }
 880 |     if (node.value == null) {
 881 |       if (node.key.type[0] !== 'F') {
 882 |         state.write(';')
 883 |       }
 884 |       return
 885 |     }
 886 |     state.write(' = ')
 887 |     this[node.value.type](node.value, state)
 888 |     state.write(';')
 889 |   },
 890 |   ObjectPattern(node, state) {
 891 |     state.write('{')
 892 |     if (node.properties.length > 0) {
 893 |       const { properties } = node,
 894 |         { length } = properties
 895 |       for (let i = 0; ; ) {
 896 |         this[properties[i].type](properties[i], state)
 897 |         if (++i < length) {
 898 |           state.write(', ')
 899 |         } else {
 900 |           break
 901 |         }
 902 |       }
 903 |     }
 904 |     state.write('}')
 905 |   },
 906 |   SequenceExpression(node, state) {
 907 |     formatSequence(state, node.expressions)
 908 |   },
 909 |   UnaryExpression(node, state) {
 910 |     if (node.prefix) {
 911 |       const {
 912 |         operator,
 913 |         argument,
 914 |         argument: { type },
 915 |       } = node
 916 |       state.write(operator)
 917 |       const needsParentheses = expressionNeedsParenthesis(state, argument, node)
 918 |       if (
 919 |         !needsParentheses &&
 920 |         (operator.length > 1 ||
 921 |           (type[0] === 'U' &&
 922 |             (type[1] === 'n' || type[1] === 'p') &&
 923 |             argument.prefix &&
 924 |             argument.operator[0] === operator &&
 925 |             (operator === '+' || operator === '-')))
 926 |       ) {
 927 |         // Large operator or argument is UnaryExpression or UpdateExpression node
 928 |         state.write(' ')
 929 |       }
 930 |       if (needsParentheses) {
 931 |         state.write(operator.length > 1 ? ' (' : '(')
 932 |         this[type](argument, state)
 933 |         state.write(')')
 934 |       } else {
 935 |         this[type](argument, state)
 936 |       }
 937 |     } else {
 938 |       // FIXME: This case never occurs
 939 |       this[node.argument.type](node.argument, state)
 940 |       state.write(node.operator)
 941 |     }
 942 |   },
 943 |   UpdateExpression(node, state) {
 944 |     // Always applied to identifiers or members, no parenthesis check needed
 945 |     if (node.prefix) {
 946 |       state.write(node.operator)
 947 |       this[node.argument.type](node.argument, state)
 948 |     } else {
 949 |       this[node.argument.type](node.argument, state)
 950 |       state.write(node.operator)
 951 |     }
 952 |   },
 953 |   AssignmentExpression(node, state) {
 954 |     this[node.left.type](node.left, state)
 955 |     state.write(' ' + node.operator + ' ')
 956 |     this[node.right.type](node.right, state)
 957 |   },
 958 |   AssignmentPattern(node, state) {
 959 |     this[node.left.type](node.left, state)
 960 |     state.write(' = ')
 961 |     this[node.right.type](node.right, state)
 962 |   },
 963 |   BinaryExpression: (BinaryExpression = function (node, state) {
 964 |     const isIn = node.operator === 'in'
 965 |     if (isIn) {
 966 |       // Avoids confusion in `for` loops initializers
 967 |       state.write('(')
 968 |     }
 969 |     formatExpression(state, node.left, node, false)
 970 |     state.write(' ' + node.operator + ' ')
 971 |     formatExpression(state, node.right, node, true)
 972 |     if (isIn) {
 973 |       state.write(')')
 974 |     }
 975 |   }),
 976 |   LogicalExpression: BinaryExpression,
 977 |   ConditionalExpression(node, state) {
 978 |     const { test } = node
 979 |     const precedence = state.expressionsPrecedence[test.type]
 980 |     if (
 981 |       precedence === NEEDS_PARENTHESES ||
 982 |       precedence <= state.expressionsPrecedence.ConditionalExpression
 983 |     ) {
 984 |       state.write('(')
 985 |       this[test.type](test, state)
 986 |       state.write(')')
 987 |     } else {
 988 |       this[test.type](test, state)
 989 |     }
 990 |     state.write(' ? ')
 991 |     this[node.consequent.type](node.consequent, state)
 992 |     state.write(' : ')
 993 |     this[node.alternate.type](node.alternate, state)
 994 |   },
 995 |   NewExpression(node, state) {
 996 |     state.write('new ')
 997 |     const precedence = state.expressionsPrecedence[node.callee.type]
 998 |     if (
 999 |       precedence === NEEDS_PARENTHESES ||
1000 |       precedence < state.expressionsPrecedence.CallExpression ||
1001 |       hasCallExpression(node.callee)
1002 |     ) {
1003 |       state.write('(')
1004 |       this[node.callee.type](node.callee, state)
1005 |       state.write(')')
1006 |     } else {
1007 |       this[node.callee.type](node.callee, state)
1008 |     }
1009 |     formatSequence(state, node['arguments'])
1010 |   },
1011 |   CallExpression(node, state) {
1012 |     const precedence = state.expressionsPrecedence[node.callee.type]
1013 |     if (
1014 |       precedence === NEEDS_PARENTHESES ||
1015 |       precedence < state.expressionsPrecedence.CallExpression
1016 |     ) {
1017 |       state.write('(')
1018 |       this[node.callee.type](node.callee, state)
1019 |       state.write(')')
1020 |     } else {
1021 |       this[node.callee.type](node.callee, state)
1022 |     }
1023 |     if (node.optional) {
1024 |       state.write('?.')
1025 |     }
1026 |     formatSequence(state, node['arguments'])
1027 |   },
1028 |   ChainExpression(node, state) {
1029 |     this[node.expression.type](node.expression, state)
1030 |   },
1031 |   MemberExpression(node, state) {
1032 |     const precedence = state.expressionsPrecedence[node.object.type]
1033 |     if (
1034 |       precedence === NEEDS_PARENTHESES ||
1035 |       precedence < state.expressionsPrecedence.MemberExpression
1036 |     ) {
1037 |       state.write('(')
1038 |       this[node.object.type](node.object, state)
1039 |       state.write(')')
1040 |     } else {
1041 |       this[node.object.type](node.object, state)
1042 |     }
1043 |     if (node.computed) {
1044 |       if (node.optional) {
1045 |         state.write('?.')
1046 |       }
1047 |       state.write('[')
1048 |       this[node.property.type](node.property, state)
1049 |       state.write(']')
1050 |     } else {
1051 |       if (node.optional) {
1052 |         state.write('?.')
1053 |       } else {
1054 |         state.write('.')
1055 |       }
1056 |       this[node.property.type](node.property, state)
1057 |     }
1058 |   },
1059 |   MetaProperty(node, state) {
1060 |     state.write(node.meta.name + '.' + node.property.name, node)
1061 |   },
1062 |   Identifier(node, state) {
1063 |     state.write(node.name, node)
1064 |   },
1065 |   PrivateIdentifier(node, state) {
1066 |     state.write(`#${node.name}`, node)
1067 |   },
1068 |   Literal(node, state) {
1069 |     if (node.raw != null) {
1070 |       // Non-standard property
1071 |       state.write(node.raw, node)
1072 |     } else if (node.regex != null) {
1073 |       this.RegExpLiteral(node, state)
1074 |     } else if (node.bigint != null) {
1075 |       state.write(node.bigint + 'n', node)
1076 |     } else {
1077 |       state.write(stringify(node.value), node)
1078 |     }
1079 |   },
1080 |   RegExpLiteral(node, state) {
1081 |     const { regex } = node
1082 |     state.write(`/${regex.pattern}/${regex.flags}`, node)
1083 |   },
1084 | }
1085 | 
1086 | const EMPTY_OBJECT = {}
1087 | 
1088 | /*
1089 | DEPRECATED: Alternate export of `GENERATOR`.
1090 | */
1091 | export const baseGenerator = GENERATOR
1092 | 
1093 | class State {
1094 |   constructor(options) {
1095 |     const setup = options == null ? EMPTY_OBJECT : options
1096 |     this.output = ''
1097 |     // Functional options
1098 |     if (setup.output != null) {
1099 |       this.output = setup.output
1100 |       this.write = this.writeToStream
1101 |     } else {
1102 |       this.output = ''
1103 |     }
1104 |     this.generator = setup.generator != null ? setup.generator : GENERATOR
1105 |     this.expressionsPrecedence =
1106 |       setup.expressionsPrecedence != null
1107 |         ? setup.expressionsPrecedence
1108 |         : EXPRESSIONS_PRECEDENCE
1109 |     // Formating setup
1110 |     this.indent = setup.indent != null ? setup.indent : '  '
1111 |     this.lineEnd = setup.lineEnd != null ? setup.lineEnd : '\n'
1112 |     this.indentLevel =
1113 |       setup.startingIndentLevel != null ? setup.startingIndentLevel : 0
1114 |     this.writeComments = setup.comments ? setup.comments : false
1115 |     // Source map
1116 |     if (setup.sourceMap != null) {
1117 |       this.write =
1118 |         setup.output == null ? this.writeAndMap : this.writeToStreamAndMap
1119 |       this.sourceMap = setup.sourceMap
1120 |       this.line = 1
1121 |       this.column = 0
1122 |       this.lineEndSize = this.lineEnd.split('\n').length - 1
1123 |       this.mapping = {
1124 |         original: null,
1125 |         // Uses the entire state to avoid generating ephemeral objects
1126 |         generated: this,
1127 |         name: undefined,
1128 |         source: setup.sourceMap.file || setup.sourceMap._file,
1129 |       }
1130 |     }
1131 |   }
1132 | 
1133 |   write(code) {
1134 |     this.output += code
1135 |   }
1136 | 
1137 |   writeToStream(code) {
1138 |     this.output.write(code)
1139 |   }
1140 | 
1141 |   writeAndMap(code, node) {
1142 |     this.output += code
1143 |     this.map(code, node)
1144 |   }
1145 | 
1146 |   writeToStreamAndMap(code, node) {
1147 |     this.output.write(code)
1148 |     this.map(code, node)
1149 |   }
1150 | 
1151 |   map(code, node) {
1152 |     if (node != null) {
1153 |       const { type } = node
1154 |       if (type[0] === 'L' && type[2] === 'n') {
1155 |         // LineComment
1156 |         this.column = 0
1157 |         this.line++
1158 |         return
1159 |       }
1160 |       if (node.loc != null) {
1161 |         const { mapping } = this
1162 |         mapping.original = node.loc.start
1163 |         mapping.name = node.name
1164 |         this.sourceMap.addMapping(mapping)
1165 |       }
1166 |       if (
1167 |         (type[0] === 'T' && type[8] === 'E') ||
1168 |         (type[0] === 'L' && type[1] === 'i' && typeof node.value === 'string')
1169 |       ) {
1170 |         // TemplateElement or Literal string node
1171 |         const { length } = code
1172 |         let { column, line } = this
1173 |         for (let i = 0; i < length; i++) {
1174 |           if (code[i] === '\n') {
1175 |             column = 0
1176 |             line++
1177 |           } else {
1178 |             column++
1179 |           }
1180 |         }
1181 |         this.column = column
1182 |         this.line = line
1183 |         return
1184 |       }
1185 |     }
1186 |     const { length } = code
1187 |     const { lineEnd } = this
1188 |     if (length > 0) {
1189 |       if (
1190 |         this.lineEndSize > 0 &&
1191 |         (lineEnd.length === 1
1192 |           ? code[length - 1] === lineEnd
1193 |           : code.endsWith(lineEnd))
1194 |       ) {
1195 |         this.line += this.lineEndSize
1196 |         this.column = 0
1197 |       } else {
1198 |         this.column += length
1199 |       }
1200 |     }
1201 |   }
1202 | 
1203 |   toString() {
1204 |     return this.output
1205 |   }
1206 | }
1207 | 
1208 | export function generate(node, options) {
1209 |   /*
1210 |   Returns a string representing the rendered code of the provided AST `node`.
1211 |   The `options` are:
1212 | 
1213 |   - `indent`: string to use for indentation (defaults to `␣␣`)
1214 |   - `lineEnd`: string to use for line endings (defaults to `\n`)
1215 |   - `startingIndentLevel`: indent level to start from (defaults to `0`)
1216 |   - `comments`: generate comments if `true` (defaults to `false`)
1217 |   - `output`: output stream to write the rendered code to (defaults to `null`)
1218 |   - `generator`: custom code generator (defaults to `GENERATOR`)
1219 |   - `expressionsPrecedence`: custom map of node types and their precedence level (defaults to `EXPRESSIONS_PRECEDENCE`)
1220 |   */
1221 |   const state = new State(options)
1222 |   // Travel through the AST node and generate the code
1223 |   state.generator[node.type](node, state)
1224 |   return state.output
1225 | }
1226 | 


--------------------------------------------------------------------------------
/docs/demo/astring.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../src/astring.js"],"names":[],"mappings":"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","file":"astring.min.js","sourcesContent":["// Astring is a tiny and fast JavaScript code generator from an ESTree-compliant AST.\n//\n// Astring was written by David Bonnet and released under an MIT license.\n//\n// The Git repository for Astring is available at:\n// https://github.com/davidbonnet/astring.git\n//\n// Please use the GitHub bug tracker to report issues:\n// https://github.com/davidbonnet/astring/issues\n\nconst { stringify } = JSON\n\n/* c8 ignore if */\nif (!String.prototype.repeat) {\n  /* c8 ignore next */\n  throw new Error(\n    'String.prototype.repeat is undefined, see https://github.com/davidbonnet/astring#installation',\n  )\n}\n\n/* c8 ignore if */\nif (!String.prototype.endsWith) {\n  /* c8 ignore next */\n  throw new Error(\n    'String.prototype.endsWith is undefined, see https://github.com/davidbonnet/astring#installation',\n  )\n}\n\nconst OPERATOR_PRECEDENCE = {\n  '||': 2,\n  '??': 3,\n  '&&': 4,\n  '|': 5,\n  '^': 6,\n  '&': 7,\n  '==': 8,\n  '!=': 8,\n  '===': 8,\n  '!==': 8,\n  '<': 9,\n  '>': 9,\n  '<=': 9,\n  '>=': 9,\n  in: 9,\n  instanceof: 9,\n  '<<': 10,\n  '>>': 10,\n  '>>>': 10,\n  '+': 11,\n  '-': 11,\n  '*': 12,\n  '%': 12,\n  '/': 12,\n  '**': 13,\n}\n\n// Enables parenthesis regardless of precedence\nexport const NEEDS_PARENTHESES = 17\n\nexport const EXPRESSIONS_PRECEDENCE = {\n  // Definitions\n  ArrayExpression: 20,\n  TaggedTemplateExpression: 20,\n  ThisExpression: 20,\n  Identifier: 20,\n  PrivateIdentifier: 20,\n  Literal: 18,\n  TemplateLiteral: 20,\n  Super: 20,\n  SequenceExpression: 20,\n  // Operations\n  MemberExpression: 19,\n  ChainExpression: 19,\n  CallExpression: 19,\n  NewExpression: 19,\n  // Other definitions\n  ArrowFunctionExpression: NEEDS_PARENTHESES,\n  ClassExpression: NEEDS_PARENTHESES,\n  FunctionExpression: NEEDS_PARENTHESES,\n  ObjectExpression: NEEDS_PARENTHESES,\n  // Other operations\n  UpdateExpression: 16,\n  UnaryExpression: 15,\n  AwaitExpression: 15,\n  BinaryExpression: 14,\n  LogicalExpression: 13,\n  ConditionalExpression: 4,\n  AssignmentExpression: 3,\n  YieldExpression: 2,\n  RestElement: 1,\n}\n\nfunction formatSequence(state, nodes) {\n  /*\n  Writes into `state` a sequence of `nodes`.\n  */\n  const { generator } = state\n  state.write('(')\n  if (nodes != null && nodes.length > 0) {\n    generator[nodes[0].type](nodes[0], state)\n    const { length } = nodes\n    for (let i = 1; i < length; i++) {\n      const param = nodes[i]\n      state.write(', ')\n      generator[param.type](param, state)\n    }\n  }\n  state.write(')')\n}\n\nfunction expressionNeedsParenthesis(state, node, parentNode, isRightHand) {\n  const nodePrecedence = state.expressionsPrecedence[node.type]\n  if (nodePrecedence === NEEDS_PARENTHESES) {\n    return true\n  }\n  const parentNodePrecedence = state.expressionsPrecedence[parentNode.type]\n  if (nodePrecedence !== parentNodePrecedence) {\n    // Different node types\n    return (\n      (!isRightHand &&\n        nodePrecedence === 15 &&\n        parentNodePrecedence === 14 &&\n        parentNode.operator === '**') ||\n      nodePrecedence < parentNodePrecedence\n    )\n  }\n  if (nodePrecedence !== 13 && nodePrecedence !== 14) {\n    // Not a `LogicalExpression` or `BinaryExpression`\n    return false\n  }\n  if (node.operator === '**' && parentNode.operator === '**') {\n    // Exponentiation operator has right-to-left associativity\n    return !isRightHand\n  }\n  if (\n    nodePrecedence === 13 &&\n    parentNodePrecedence === 13 &&\n    (node.operator === '??' || parentNode.operator === '??')\n  ) {\n    // Nullish coalescing and boolean operators cannot be combined\n    return true\n  }\n  if (isRightHand) {\n    // Parenthesis are used if both operators have the same precedence\n    return (\n      OPERATOR_PRECEDENCE[node.operator] <=\n      OPERATOR_PRECEDENCE[parentNode.operator]\n    )\n  }\n  return (\n    OPERATOR_PRECEDENCE[node.operator] <\n    OPERATOR_PRECEDENCE[parentNode.operator]\n  )\n}\n\nfunction formatExpression(state, node, parentNode, isRightHand) {\n  /*\n  Writes into `state` the provided `node`, adding parenthesis around if the provided `parentNode` needs it. If `node` is a right-hand argument, the provided `isRightHand` parameter should be `true`.\n  */\n  const { generator } = state\n  if (expressionNeedsParenthesis(state, node, parentNode, isRightHand)) {\n    state.write('(')\n    generator[node.type](node, state)\n    state.write(')')\n  } else {\n    generator[node.type](node, state)\n  }\n}\n\nfunction reindent(state, text, indent, lineEnd) {\n  /*\n  Writes into `state` the `text` string reindented with the provided `indent`.\n  */\n  const lines = text.split('\\n')\n  const end = lines.length - 1\n  state.write(lines[0].trim())\n  if (end > 0) {\n    state.write(lineEnd)\n    for (let i = 1; i < end; i++) {\n      state.write(indent + lines[i].trim() + lineEnd)\n    }\n    state.write(indent + lines[end].trim())\n  }\n}\n\nfunction formatComments(state, comments, indent, lineEnd) {\n  /*\n  Writes into `state` the provided list of `comments`, with the given `indent` and `lineEnd` strings.\n  Line comments will end with `\"\\n\"` regardless of the value of `lineEnd`.\n  Expects to start on a new unindented line.\n  */\n  const { length } = comments\n  for (let i = 0; i < length; i++) {\n    const comment = comments[i]\n    state.write(indent)\n    if (comment.type[0] === 'L') {\n      // Line comment\n      state.write('// ' + comment.value.trim() + '\\n', comment)\n    } else {\n      // Block comment\n      state.write('/*')\n      reindent(state, comment.value, indent, lineEnd)\n      state.write('*/' + lineEnd)\n    }\n  }\n}\n\nfunction hasCallExpression(node) {\n  /*\n  Returns `true` if the provided `node` contains a call expression and `false` otherwise.\n  */\n  let currentNode = node\n  while (currentNode != null) {\n    const { type } = currentNode\n    if (type[0] === 'C' && type[1] === 'a') {\n      // Is CallExpression\n      return true\n    } else if (type[0] === 'M' && type[1] === 'e' && type[2] === 'm') {\n      // Is MemberExpression\n      currentNode = currentNode.object\n    } else {\n      return false\n    }\n  }\n}\n\nfunction formatVariableDeclaration(state, node) {\n  /*\n  Writes into `state` a variable declaration.\n  */\n  const { generator } = state\n  const { declarations } = node\n  state.write(node.kind + ' ')\n  const { length } = declarations\n  if (length > 0) {\n    generator.VariableDeclarator(declarations[0], state)\n    for (let i = 1; i < length; i++) {\n      state.write(', ')\n      generator.VariableDeclarator(declarations[i], state)\n    }\n  }\n}\n\nlet ForInStatement,\n  FunctionDeclaration,\n  RestElement,\n  BinaryExpression,\n  ArrayExpression,\n  BlockStatement\n\nexport const GENERATOR = {\n  /*\n  Default generator.\n  */\n  Program(node, state) {\n    const indent = state.indent.repeat(state.indentLevel)\n    const { lineEnd, writeComments } = state\n    if (writeComments && node.comments != null) {\n      formatComments(state, node.comments, indent, lineEnd)\n    }\n    const statements = node.body\n    const { length } = statements\n    for (let i = 0; i < length; i++) {\n      const statement = statements[i]\n      if (writeComments && statement.comments != null) {\n        formatComments(state, statement.comments, indent, lineEnd)\n      }\n      state.write(indent)\n      this[statement.type](statement, state)\n      state.write(lineEnd)\n    }\n    if (writeComments && node.trailingComments != null) {\n      formatComments(state, node.trailingComments, indent, lineEnd)\n    }\n  },\n  BlockStatement: (BlockStatement = function (node, state) {\n    const indent = state.indent.repeat(state.indentLevel++)\n    const { lineEnd, writeComments } = state\n    const statementIndent = indent + state.indent\n    state.write('{')\n    const statements = node.body\n    if (statements != null && statements.length > 0) {\n      state.write(lineEnd)\n      if (writeComments && node.comments != null) {\n        formatComments(state, node.comments, statementIndent, lineEnd)\n      }\n      const { length } = statements\n      for (let i = 0; i < length; i++) {\n        const statement = statements[i]\n        if (writeComments && statement.comments != null) {\n          formatComments(state, statement.comments, statementIndent, lineEnd)\n        }\n        state.write(statementIndent)\n        this[statement.type](statement, state)\n        state.write(lineEnd)\n      }\n      state.write(indent)\n    } else {\n      if (writeComments && node.comments != null) {\n        state.write(lineEnd)\n        formatComments(state, node.comments, statementIndent, lineEnd)\n        state.write(indent)\n      }\n    }\n    if (writeComments && node.trailingComments != null) {\n      formatComments(state, node.trailingComments, statementIndent, lineEnd)\n    }\n    state.write('}')\n    state.indentLevel--\n  }),\n  ClassBody: BlockStatement,\n  StaticBlock(node, state) {\n    state.write('static ')\n    this.BlockStatement(node, state)\n  },\n  EmptyStatement(node, state) {\n    state.write(';')\n  },\n  ExpressionStatement(node, state) {\n    const precedence = state.expressionsPrecedence[node.expression.type]\n    if (\n      precedence === NEEDS_PARENTHESES ||\n      (precedence === 3 && node.expression.left.type[0] === 'O')\n    ) {\n      // Should always have parentheses or is an AssignmentExpression to an ObjectPattern\n      state.write('(')\n      this[node.expression.type](node.expression, state)\n      state.write(')')\n    } else {\n      this[node.expression.type](node.expression, state)\n    }\n    state.write(';')\n  },\n  IfStatement(node, state) {\n    state.write('if (')\n    this[node.test.type](node.test, state)\n    state.write(') ')\n    this[node.consequent.type](node.consequent, state)\n    if (node.alternate != null) {\n      state.write(' else ')\n      this[node.alternate.type](node.alternate, state)\n    }\n  },\n  LabeledStatement(node, state) {\n    this[node.label.type](node.label, state)\n    state.write(': ')\n    this[node.body.type](node.body, state)\n  },\n  BreakStatement(node, state) {\n    state.write('break')\n    if (node.label != null) {\n      state.write(' ')\n      this[node.label.type](node.label, state)\n    }\n    state.write(';')\n  },\n  ContinueStatement(node, state) {\n    state.write('continue')\n    if (node.label != null) {\n      state.write(' ')\n      this[node.label.type](node.label, state)\n    }\n    state.write(';')\n  },\n  WithStatement(node, state) {\n    state.write('with (')\n    this[node.object.type](node.object, state)\n    state.write(') ')\n    this[node.body.type](node.body, state)\n  },\n  SwitchStatement(node, state) {\n    const indent = state.indent.repeat(state.indentLevel++)\n    const { lineEnd, writeComments } = state\n    state.indentLevel++\n    const caseIndent = indent + state.indent\n    const statementIndent = caseIndent + state.indent\n    state.write('switch (')\n    this[node.discriminant.type](node.discriminant, state)\n    state.write(') {' + lineEnd)\n    const { cases: occurences } = node\n    const { length: occurencesCount } = occurences\n    for (let i = 0; i < occurencesCount; i++) {\n      const occurence = occurences[i]\n      if (writeComments && occurence.comments != null) {\n        formatComments(state, occurence.comments, caseIndent, lineEnd)\n      }\n      if (occurence.test) {\n        state.write(caseIndent + 'case ')\n        this[occurence.test.type](occurence.test, state)\n        state.write(':' + lineEnd)\n      } else {\n        state.write(caseIndent + 'default:' + lineEnd)\n      }\n      const { consequent } = occurence\n      const { length: consequentCount } = consequent\n      for (let i = 0; i < consequentCount; i++) {\n        const statement = consequent[i]\n        if (writeComments && statement.comments != null) {\n          formatComments(state, statement.comments, statementIndent, lineEnd)\n        }\n        state.write(statementIndent)\n        this[statement.type](statement, state)\n        state.write(lineEnd)\n      }\n    }\n    state.indentLevel -= 2\n    state.write(indent + '}')\n  },\n  ReturnStatement(node, state) {\n    state.write('return')\n    if (node.argument) {\n      state.write(' ')\n      this[node.argument.type](node.argument, state)\n    }\n    state.write(';')\n  },\n  ThrowStatement(node, state) {\n    state.write('throw ')\n    this[node.argument.type](node.argument, state)\n    state.write(';')\n  },\n  TryStatement(node, state) {\n    state.write('try ')\n    this[node.block.type](node.block, state)\n    if (node.handler) {\n      const { handler } = node\n      if (handler.param == null) {\n        state.write(' catch ')\n      } else {\n        state.write(' catch (')\n        this[handler.param.type](handler.param, state)\n        state.write(') ')\n      }\n      this[handler.body.type](handler.body, state)\n    }\n    if (node.finalizer) {\n      state.write(' finally ')\n      this[node.finalizer.type](node.finalizer, state)\n    }\n  },\n  WhileStatement(node, state) {\n    state.write('while (')\n    this[node.test.type](node.test, state)\n    state.write(') ')\n    this[node.body.type](node.body, state)\n  },\n  DoWhileStatement(node, state) {\n    state.write('do ')\n    this[node.body.type](node.body, state)\n    state.write(' while (')\n    this[node.test.type](node.test, state)\n    state.write(');')\n  },\n  ForStatement(node, state) {\n    state.write('for (')\n    if (node.init != null) {\n      const { init } = node\n      if (init.type[0] === 'V') {\n        formatVariableDeclaration(state, init)\n      } else {\n        this[init.type](init, state)\n      }\n    }\n    state.write('; ')\n    if (node.test) {\n      this[node.test.type](node.test, state)\n    }\n    state.write('; ')\n    if (node.update) {\n      this[node.update.type](node.update, state)\n    }\n    state.write(') ')\n    this[node.body.type](node.body, state)\n  },\n  ForInStatement: (ForInStatement = function (node, state) {\n    state.write(`for ${node.await ? 'await ' : ''}(`)\n    const { left } = node\n    if (left.type[0] === 'V') {\n      formatVariableDeclaration(state, left)\n    } else {\n      this[left.type](left, state)\n    }\n    // Identifying whether node.type is `ForInStatement` or `ForOfStatement`\n    state.write(node.type[3] === 'I' ? ' in ' : ' of ')\n    this[node.right.type](node.right, state)\n    state.write(') ')\n    this[node.body.type](node.body, state)\n  }),\n  ForOfStatement: ForInStatement,\n  DebuggerStatement(node, state) {\n    state.write('debugger;', node)\n  },\n  FunctionDeclaration: (FunctionDeclaration = function (node, state) {\n    state.write(\n      (node.async ? 'async ' : '') +\n        (node.generator ? 'function* ' : 'function ') +\n        (node.id ? node.id.name : ''),\n      node,\n    )\n    formatSequence(state, node.params)\n    state.write(' ')\n    this[node.body.type](node.body, state)\n  }),\n  FunctionExpression: FunctionDeclaration,\n  VariableDeclaration(node, state) {\n    formatVariableDeclaration(state, node)\n    state.write(';')\n  },\n  VariableDeclarator(node, state) {\n    this[node.id.type](node.id, state)\n    if (node.init != null) {\n      state.write(' = ')\n      this[node.init.type](node.init, state)\n    }\n  },\n  ClassDeclaration(node, state) {\n    state.write('class ' + (node.id ? `${node.id.name} ` : ''), node)\n    if (node.superClass) {\n      state.write('extends ')\n      const { superClass } = node\n      const { type } = superClass\n      const precedence = state.expressionsPrecedence[type]\n      if (\n        (type[0] !== 'C' || type[1] !== 'l' || type[5] !== 'E') &&\n        (precedence === NEEDS_PARENTHESES ||\n          precedence < state.expressionsPrecedence.ClassExpression)\n      ) {\n        // Not a ClassExpression that needs parentheses\n        state.write('(')\n        this[node.superClass.type](superClass, state)\n        state.write(')')\n      } else {\n        this[superClass.type](superClass, state)\n      }\n      state.write(' ')\n    }\n    this.ClassBody(node.body, state)\n  },\n  ImportDeclaration(node, state) {\n    state.write('import ')\n    const { specifiers } = node\n    const { length } = specifiers\n    // TODO: Once babili is fixed, put this after condition\n    // https://github.com/babel/babili/issues/430\n    let i = 0\n    if (length > 0) {\n      for (; i < length; ) {\n        if (i > 0) {\n          state.write(', ')\n        }\n        const specifier = specifiers[i]\n        const type = specifier.type[6]\n        if (type === 'D') {\n          // ImportDefaultSpecifier\n          state.write(specifier.local.name, specifier)\n          i++\n        } else if (type === 'N') {\n          // ImportNamespaceSpecifier\n          state.write('* as ' + specifier.local.name, specifier)\n          i++\n        } else {\n          // ImportSpecifier\n          break\n        }\n      }\n      if (i < length) {\n        state.write('{')\n        for (;;) {\n          const specifier = specifiers[i]\n          const { name } = specifier.imported\n          state.write(name, specifier)\n          if (name !== specifier.local.name) {\n            state.write(' as ' + specifier.local.name)\n          }\n          if (++i < length) {\n            state.write(', ')\n          } else {\n            break\n          }\n        }\n        state.write('}')\n      }\n      state.write(' from ')\n    }\n    this.Literal(node.source, state)\n    state.write(';')\n  },\n  ImportExpression(node, state) {\n    state.write('import(')\n    this[node.source.type](node.source, state)\n    state.write(')')\n  },\n  ExportDefaultDeclaration(node, state) {\n    state.write('export default ')\n    this[node.declaration.type](node.declaration, state)\n    if (\n      state.expressionsPrecedence[node.declaration.type] != null &&\n      node.declaration.type[0] !== 'F'\n    ) {\n      // All expression nodes except `FunctionExpression`\n      state.write(';')\n    }\n  },\n  ExportNamedDeclaration(node, state) {\n    state.write('export ')\n    if (node.declaration) {\n      this[node.declaration.type](node.declaration, state)\n    } else {\n      state.write('{')\n      const { specifiers } = node,\n        { length } = specifiers\n      if (length > 0) {\n        for (let i = 0; ; ) {\n          const specifier = specifiers[i]\n          const { name } = specifier.local\n          state.write(name, specifier)\n          if (name !== specifier.exported.name) {\n            state.write(' as ' + specifier.exported.name)\n          }\n          if (++i < length) {\n            state.write(', ')\n          } else {\n            break\n          }\n        }\n      }\n      state.write('}')\n      if (node.source) {\n        state.write(' from ')\n        this.Literal(node.source, state)\n      }\n      state.write(';')\n    }\n  },\n  ExportAllDeclaration(node, state) {\n    if (node.exported != null) {\n      state.write('export * as ' + node.exported.name + ' from ')\n    } else {\n      state.write('export * from ')\n    }\n    this.Literal(node.source, state)\n    state.write(';')\n  },\n  MethodDefinition(node, state) {\n    if (node.static) {\n      state.write('static ')\n    }\n    const kind = node.kind[0]\n    if (kind === 'g' || kind === 's') {\n      // Getter or setter\n      state.write(node.kind + ' ')\n    }\n    if (node.value.async) {\n      state.write('async ')\n    }\n    if (node.value.generator) {\n      state.write('*')\n    }\n    if (node.computed) {\n      state.write('[')\n      this[node.key.type](node.key, state)\n      state.write(']')\n    } else {\n      this[node.key.type](node.key, state)\n    }\n    formatSequence(state, node.value.params)\n    state.write(' ')\n    this[node.value.body.type](node.value.body, state)\n  },\n  ClassExpression(node, state) {\n    this.ClassDeclaration(node, state)\n  },\n  ArrowFunctionExpression(node, state) {\n    state.write(node.async ? 'async ' : '', node)\n    const { params } = node\n    if (params != null) {\n      // Omit parenthesis if only one named parameter\n      if (params.length === 1 && params[0].type[0] === 'I') {\n        // If params[0].type[0] starts with 'I', it can't be `ImportDeclaration` nor `IfStatement` and thus is `Identifier`\n        state.write(params[0].name, params[0])\n      } else {\n        formatSequence(state, node.params)\n      }\n    }\n    state.write(' => ')\n    if (node.body.type[0] === 'O') {\n      // Body is an object expression\n      state.write('(')\n      this.ObjectExpression(node.body, state)\n      state.write(')')\n    } else {\n      this[node.body.type](node.body, state)\n    }\n  },\n  ThisExpression(node, state) {\n    state.write('this', node)\n  },\n  Super(node, state) {\n    state.write('super', node)\n  },\n  RestElement: (RestElement = function (node, state) {\n    state.write('...')\n    this[node.argument.type](node.argument, state)\n  }),\n  SpreadElement: RestElement,\n  YieldExpression(node, state) {\n    state.write(node.delegate ? 'yield*' : 'yield')\n    if (node.argument) {\n      state.write(' ')\n      this[node.argument.type](node.argument, state)\n    }\n  },\n  AwaitExpression(node, state) {\n    state.write('await ', node)\n    formatExpression(state, node.argument, node)\n  },\n  TemplateLiteral(node, state) {\n    const { quasis, expressions } = node\n    state.write('`')\n    const { length } = expressions\n    for (let i = 0; i < length; i++) {\n      const expression = expressions[i]\n      const quasi = quasis[i]\n      state.write(quasi.value.raw, quasi)\n      state.write('${')\n      this[expression.type](expression, state)\n      state.write('}')\n    }\n    const quasi = quasis[quasis.length - 1]\n    state.write(quasi.value.raw, quasi)\n    state.write('`')\n  },\n  TemplateElement(node, state) {\n    state.write(node.value.raw, node)\n  },\n  TaggedTemplateExpression(node, state) {\n    formatExpression(state, node.tag, node)\n    this[node.quasi.type](node.quasi, state)\n  },\n  ArrayExpression: (ArrayExpression = function (node, state) {\n    state.write('[')\n    if (node.elements.length > 0) {\n      const { elements } = node,\n        { length } = elements\n      for (let i = 0; ; ) {\n        const element = elements[i]\n        if (element != null) {\n          this[element.type](element, state)\n        }\n        if (++i < length) {\n          state.write(', ')\n        } else {\n          if (element == null) {\n            state.write(', ')\n          }\n          break\n        }\n      }\n    }\n    state.write(']')\n  }),\n  ArrayPattern: ArrayExpression,\n  ObjectExpression(node, state) {\n    const indent = state.indent.repeat(state.indentLevel++)\n    const { lineEnd, writeComments } = state\n    const propertyIndent = indent + state.indent\n    state.write('{')\n    if (node.properties.length > 0) {\n      state.write(lineEnd)\n      if (writeComments && node.comments != null) {\n        formatComments(state, node.comments, propertyIndent, lineEnd)\n      }\n      const comma = ',' + lineEnd\n      const { properties } = node,\n        { length } = properties\n      for (let i = 0; ; ) {\n        const property = properties[i]\n        if (writeComments && property.comments != null) {\n          formatComments(state, property.comments, propertyIndent, lineEnd)\n        }\n        state.write(propertyIndent)\n        this[property.type](property, state)\n        if (++i < length) {\n          state.write(comma)\n        } else {\n          break\n        }\n      }\n      state.write(lineEnd)\n      if (writeComments && node.trailingComments != null) {\n        formatComments(state, node.trailingComments, propertyIndent, lineEnd)\n      }\n      state.write(indent + '}')\n    } else if (writeComments) {\n      if (node.comments != null) {\n        state.write(lineEnd)\n        formatComments(state, node.comments, propertyIndent, lineEnd)\n        if (node.trailingComments != null) {\n          formatComments(state, node.trailingComments, propertyIndent, lineEnd)\n        }\n        state.write(indent + '}')\n      } else if (node.trailingComments != null) {\n        state.write(lineEnd)\n        formatComments(state, node.trailingComments, propertyIndent, lineEnd)\n        state.write(indent + '}')\n      } else {\n        state.write('}')\n      }\n    } else {\n      state.write('}')\n    }\n    state.indentLevel--\n  },\n  Property(node, state) {\n    if (node.method || node.kind[0] !== 'i') {\n      // Either a method or of kind `set` or `get` (not `init`)\n      this.MethodDefinition(node, state)\n    } else {\n      if (!node.shorthand) {\n        if (node.computed) {\n          state.write('[')\n          this[node.key.type](node.key, state)\n          state.write(']')\n        } else {\n          this[node.key.type](node.key, state)\n        }\n        state.write(': ')\n      }\n      this[node.value.type](node.value, state)\n    }\n  },\n  PropertyDefinition(node, state) {\n    if (node.static) {\n      state.write('static ')\n    }\n    if (node.computed) {\n      state.write('[')\n    }\n    this[node.key.type](node.key, state)\n    if (node.computed) {\n      state.write(']')\n    }\n    if (node.value == null) {\n      if (node.key.type[0] !== 'F') {\n        state.write(';')\n      }\n      return\n    }\n    state.write(' = ')\n    this[node.value.type](node.value, state)\n    state.write(';')\n  },\n  ObjectPattern(node, state) {\n    state.write('{')\n    if (node.properties.length > 0) {\n      const { properties } = node,\n        { length } = properties\n      for (let i = 0; ; ) {\n        this[properties[i].type](properties[i], state)\n        if (++i < length) {\n          state.write(', ')\n        } else {\n          break\n        }\n      }\n    }\n    state.write('}')\n  },\n  SequenceExpression(node, state) {\n    formatSequence(state, node.expressions)\n  },\n  UnaryExpression(node, state) {\n    if (node.prefix) {\n      const {\n        operator,\n        argument,\n        argument: { type },\n      } = node\n      state.write(operator)\n      const needsParentheses = expressionNeedsParenthesis(state, argument, node)\n      if (\n        !needsParentheses &&\n        (operator.length > 1 ||\n          (type[0] === 'U' &&\n            (type[1] === 'n' || type[1] === 'p') &&\n            argument.prefix &&\n            argument.operator[0] === operator &&\n            (operator === '+' || operator === '-')))\n      ) {\n        // Large operator or argument is UnaryExpression or UpdateExpression node\n        state.write(' ')\n      }\n      if (needsParentheses) {\n        state.write(operator.length > 1 ? ' (' : '(')\n        this[type](argument, state)\n        state.write(')')\n      } else {\n        this[type](argument, state)\n      }\n    } else {\n      // FIXME: This case never occurs\n      this[node.argument.type](node.argument, state)\n      state.write(node.operator)\n    }\n  },\n  UpdateExpression(node, state) {\n    // Always applied to identifiers or members, no parenthesis check needed\n    if (node.prefix) {\n      state.write(node.operator)\n      this[node.argument.type](node.argument, state)\n    } else {\n      this[node.argument.type](node.argument, state)\n      state.write(node.operator)\n    }\n  },\n  AssignmentExpression(node, state) {\n    this[node.left.type](node.left, state)\n    state.write(' ' + node.operator + ' ')\n    this[node.right.type](node.right, state)\n  },\n  AssignmentPattern(node, state) {\n    this[node.left.type](node.left, state)\n    state.write(' = ')\n    this[node.right.type](node.right, state)\n  },\n  BinaryExpression: (BinaryExpression = function (node, state) {\n    const isIn = node.operator === 'in'\n    if (isIn) {\n      // Avoids confusion in `for` loops initializers\n      state.write('(')\n    }\n    formatExpression(state, node.left, node, false)\n    state.write(' ' + node.operator + ' ')\n    formatExpression(state, node.right, node, true)\n    if (isIn) {\n      state.write(')')\n    }\n  }),\n  LogicalExpression: BinaryExpression,\n  ConditionalExpression(node, state) {\n    const { test } = node\n    const precedence = state.expressionsPrecedence[test.type]\n    if (\n      precedence === NEEDS_PARENTHESES ||\n      precedence <= state.expressionsPrecedence.ConditionalExpression\n    ) {\n      state.write('(')\n      this[test.type](test, state)\n      state.write(')')\n    } else {\n      this[test.type](test, state)\n    }\n    state.write(' ? ')\n    this[node.consequent.type](node.consequent, state)\n    state.write(' : ')\n    this[node.alternate.type](node.alternate, state)\n  },\n  NewExpression(node, state) {\n    state.write('new ')\n    const precedence = state.expressionsPrecedence[node.callee.type]\n    if (\n      precedence === NEEDS_PARENTHESES ||\n      precedence < state.expressionsPrecedence.CallExpression ||\n      hasCallExpression(node.callee)\n    ) {\n      state.write('(')\n      this[node.callee.type](node.callee, state)\n      state.write(')')\n    } else {\n      this[node.callee.type](node.callee, state)\n    }\n    formatSequence(state, node['arguments'])\n  },\n  CallExpression(node, state) {\n    const precedence = state.expressionsPrecedence[node.callee.type]\n    if (\n      precedence === NEEDS_PARENTHESES ||\n      precedence < state.expressionsPrecedence.CallExpression\n    ) {\n      state.write('(')\n      this[node.callee.type](node.callee, state)\n      state.write(')')\n    } else {\n      this[node.callee.type](node.callee, state)\n    }\n    if (node.optional) {\n      state.write('?.')\n    }\n    formatSequence(state, node['arguments'])\n  },\n  ChainExpression(node, state) {\n    this[node.expression.type](node.expression, state)\n  },\n  MemberExpression(node, state) {\n    const precedence = state.expressionsPrecedence[node.object.type]\n    if (\n      precedence === NEEDS_PARENTHESES ||\n      precedence < state.expressionsPrecedence.MemberExpression\n    ) {\n      state.write('(')\n      this[node.object.type](node.object, state)\n      state.write(')')\n    } else {\n      this[node.object.type](node.object, state)\n    }\n    if (node.computed) {\n      if (node.optional) {\n        state.write('?.')\n      }\n      state.write('[')\n      this[node.property.type](node.property, state)\n      state.write(']')\n    } else {\n      if (node.optional) {\n        state.write('?.')\n      } else {\n        state.write('.')\n      }\n      this[node.property.type](node.property, state)\n    }\n  },\n  MetaProperty(node, state) {\n    state.write(node.meta.name + '.' + node.property.name, node)\n  },\n  Identifier(node, state) {\n    state.write(node.name, node)\n  },\n  PrivateIdentifier(node, state) {\n    state.write(`#${node.name}`, node)\n  },\n  Literal(node, state) {\n    if (node.raw != null) {\n      // Non-standard property\n      state.write(node.raw, node)\n    } else if (node.regex != null) {\n      this.RegExpLiteral(node, state)\n    } else if (node.bigint != null) {\n      state.write(node.bigint + 'n', node)\n    } else {\n      state.write(stringify(node.value), node)\n    }\n  },\n  RegExpLiteral(node, state) {\n    const { regex } = node\n    state.write(`/${regex.pattern}/${regex.flags}`, node)\n  },\n}\n\nconst EMPTY_OBJECT = {}\n\n/*\nDEPRECATED: Alternate export of `GENERATOR`.\n*/\nexport const baseGenerator = GENERATOR\n\nclass State {\n  constructor(options) {\n    const setup = options == null ? EMPTY_OBJECT : options\n    this.output = ''\n    // Functional options\n    if (setup.output != null) {\n      this.output = setup.output\n      this.write = this.writeToStream\n    } else {\n      this.output = ''\n    }\n    this.generator = setup.generator != null ? setup.generator : GENERATOR\n    this.expressionsPrecedence =\n      setup.expressionsPrecedence != null\n        ? setup.expressionsPrecedence\n        : EXPRESSIONS_PRECEDENCE\n    // Formating setup\n    this.indent = setup.indent != null ? setup.indent : '  '\n    this.lineEnd = setup.lineEnd != null ? setup.lineEnd : '\\n'\n    this.indentLevel =\n      setup.startingIndentLevel != null ? setup.startingIndentLevel : 0\n    this.writeComments = setup.comments ? setup.comments : false\n    // Source map\n    if (setup.sourceMap != null) {\n      this.write =\n        setup.output == null ? this.writeAndMap : this.writeToStreamAndMap\n      this.sourceMap = setup.sourceMap\n      this.line = 1\n      this.column = 0\n      this.lineEndSize = this.lineEnd.split('\\n').length - 1\n      this.mapping = {\n        original: null,\n        // Uses the entire state to avoid generating ephemeral objects\n        generated: this,\n        name: undefined,\n        source: setup.sourceMap.file || setup.sourceMap._file,\n      }\n    }\n  }\n\n  write(code) {\n    this.output += code\n  }\n\n  writeToStream(code) {\n    this.output.write(code)\n  }\n\n  writeAndMap(code, node) {\n    this.output += code\n    this.map(code, node)\n  }\n\n  writeToStreamAndMap(code, node) {\n    this.output.write(code)\n    this.map(code, node)\n  }\n\n  map(code, node) {\n    if (node != null) {\n      const { type } = node\n      if (type[0] === 'L' && type[2] === 'n') {\n        // LineComment\n        this.column = 0\n        this.line++\n        return\n      }\n      if (node.loc != null) {\n        const { mapping } = this\n        mapping.original = node.loc.start\n        mapping.name = node.name\n        this.sourceMap.addMapping(mapping)\n      }\n      if (\n        (type[0] === 'T' && type[8] === 'E') ||\n        (type[0] === 'L' && type[1] === 'i' && typeof node.value === 'string')\n      ) {\n        // TemplateElement or Literal string node\n        const { length } = code\n        let { column, line } = this\n        for (let i = 0; i < length; i++) {\n          if (code[i] === '\\n') {\n            column = 0\n            line++\n          } else {\n            column++\n          }\n        }\n        this.column = column\n        this.line = line\n        return\n      }\n    }\n    const { length } = code\n    const { lineEnd } = this\n    if (length > 0) {\n      if (\n        this.lineEndSize > 0 &&\n        (lineEnd.length === 1\n          ? code[length - 1] === lineEnd\n          : code.endsWith(lineEnd))\n      ) {\n        this.line += this.lineEndSize\n        this.column = 0\n      } else {\n        this.column += length\n      }\n    }\n  }\n\n  toString() {\n    return this.output\n  }\n}\n\nexport function generate(node, options) {\n  /*\n  Returns a string representing the rendered code of the provided AST `node`.\n  The `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  - `expressionsPrecedence`: custom map of node types and their precedence level (defaults to `EXPRESSIONS_PRECEDENCE`)\n  */\n  const state = new State(options)\n  // Travel through the AST node and generate the code\n  state.generator[node.type](node, state)\n  return state.output\n}\n"]}


--------------------------------------------------------------------------------