| 1 | # Acorn
|
|---|
| 2 |
|
|---|
| 3 | A tiny, fast JavaScript parser written in JavaScript.
|
|---|
| 4 |
|
|---|
| 5 | ## Community
|
|---|
| 6 |
|
|---|
| 7 | Acorn is open source software released under an
|
|---|
| 8 | [MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE).
|
|---|
| 9 |
|
|---|
| 10 | You are welcome to
|
|---|
| 11 | [report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
|---|
| 12 | requests on [github](https://github.com/acornjs/acorn).
|
|---|
| 13 |
|
|---|
| 14 | ## Installation
|
|---|
| 15 |
|
|---|
| 16 | The easiest way to install acorn is from [`npm`](https://www.npmjs.com/):
|
|---|
| 17 |
|
|---|
| 18 | ```sh
|
|---|
| 19 | npm install acorn
|
|---|
| 20 | ```
|
|---|
| 21 |
|
|---|
| 22 | Alternately, you can download the source and build acorn yourself:
|
|---|
| 23 |
|
|---|
| 24 | ```sh
|
|---|
| 25 | git clone https://github.com/acornjs/acorn.git
|
|---|
| 26 | cd acorn
|
|---|
| 27 | npm install
|
|---|
| 28 | ```
|
|---|
| 29 | ## Importing acorn
|
|---|
| 30 |
|
|---|
| 31 | ESM as well as CommonJS is supported for all 3: `acorn`, `acorn-walk` and `acorn-loose`.
|
|---|
| 32 |
|
|---|
| 33 | ESM example for `acorn`:
|
|---|
| 34 |
|
|---|
| 35 | ```js
|
|---|
| 36 | import * as acorn from "acorn"
|
|---|
| 37 | ```
|
|---|
| 38 |
|
|---|
| 39 | CommonJS example for `acorn`:
|
|---|
| 40 |
|
|---|
| 41 | ```js
|
|---|
| 42 | let acorn = require("acorn")
|
|---|
| 43 | ```
|
|---|
| 44 |
|
|---|
| 45 | ESM is preferred, as it allows better editor auto-completions by offering TypeScript support.
|
|---|
| 46 | For this reason, following examples will use ESM imports.
|
|---|
| 47 |
|
|---|
| 48 | ## Interface
|
|---|
| 49 |
|
|---|
| 50 | **parse**`(input, options)` is the main interface to the library. The
|
|---|
| 51 | `input` parameter is a string, `options` must be an object setting
|
|---|
| 52 | some of the options listed below. The return value will be an abstract
|
|---|
| 53 | syntax tree object as specified by the [ESTree
|
|---|
| 54 | spec](https://github.com/estree/estree).
|
|---|
| 55 |
|
|---|
| 56 | ```javascript
|
|---|
| 57 | import * as acorn from "acorn"
|
|---|
| 58 | console.log(acorn.parse("1 + 1", {ecmaVersion: 2020}))
|
|---|
| 59 | ```
|
|---|
| 60 |
|
|---|
| 61 | When encountering a syntax error, the parser will raise a
|
|---|
| 62 | `SyntaxError` object with a meaningful message. The error object will
|
|---|
| 63 | have a `pos` property that indicates the string offset at which the
|
|---|
| 64 | error occurred, and a `loc` object that contains a `{line, column}`
|
|---|
| 65 | object referring to that same position.
|
|---|
| 66 |
|
|---|
| 67 | Options are provided by in a second argument, which should be an
|
|---|
| 68 | object containing any of these fields (only `ecmaVersion` is
|
|---|
| 69 | required):
|
|---|
| 70 |
|
|---|
| 71 | - **ecmaVersion**: Indicates the ECMAScript version to parse. Can be a
|
|---|
| 72 | number, either in year (`2022`) or plain version number (`6`) form,
|
|---|
| 73 | or `"latest"` (the latest the library supports). This influences
|
|---|
| 74 | support for strict mode, the set of reserved words, and support for
|
|---|
| 75 | new syntax features.
|
|---|
| 76 |
|
|---|
| 77 | **NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
|---|
| 78 | implemented by Acorn. Other proposed new features must be
|
|---|
| 79 | implemented through plugins.
|
|---|
| 80 |
|
|---|
| 81 | - **sourceType**: Indicate the mode the code should be parsed in. Can be
|
|---|
| 82 | either `"script"`, `"module"` or `"commonjs"`. This influences global strict mode
|
|---|
| 83 | and parsing of `import` and `export` declarations.
|
|---|
| 84 |
|
|---|
| 85 | **NOTE**: If set to `"module"`, then static `import` / `export` syntax
|
|---|
| 86 | will be valid, even if `ecmaVersion` is less than 6. If set to `"commonjs"`,
|
|---|
| 87 | it is the same as `"script"` except that the top-level scope behaves like a function.
|
|---|
| 88 |
|
|---|
| 89 | - **onInsertedSemicolon**: If given a callback, that callback will be
|
|---|
| 90 | called whenever a missing semicolon is inserted by the parser. The
|
|---|
| 91 | callback will be given the character offset of the point where the
|
|---|
| 92 | semicolon is inserted as argument, and if `locations` is on, also a
|
|---|
| 93 | `{line, column}` object representing this position.
|
|---|
| 94 |
|
|---|
| 95 | - **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing
|
|---|
| 96 | commas.
|
|---|
| 97 |
|
|---|
| 98 | - **allowReserved**: If `false`, using a reserved word will generate
|
|---|
| 99 | an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher
|
|---|
| 100 | versions. When given the value `"never"`, reserved words and
|
|---|
| 101 | keywords can also not be used as property names (as in Internet
|
|---|
| 102 | Explorer's old parser).
|
|---|
| 103 |
|
|---|
| 104 | - **allowReturnOutsideFunction**: By default, a return statement at
|
|---|
| 105 | the top level raises an error. Set this to `true` to accept such
|
|---|
| 106 | code.
|
|---|
| 107 |
|
|---|
| 108 | - **allowImportExportEverywhere**: By default, `import` and `export`
|
|---|
| 109 | declarations can only appear at a program's top level. Setting this
|
|---|
| 110 | option to `true` allows them anywhere where a statement is allowed,
|
|---|
| 111 | and also allows `import.meta` expressions to appear in scripts
|
|---|
| 112 | (when `sourceType` is not `"module"`).
|
|---|
| 113 |
|
|---|
| 114 | - **allowAwaitOutsideFunction**: If `false`, `await` expressions can
|
|---|
| 115 | only appear inside `async` functions. Defaults to `true` in modules
|
|---|
| 116 | for `ecmaVersion` 2022 and later, `false` for lower versions.
|
|---|
| 117 | Setting this option to `true` allows to have top-level `await`
|
|---|
| 118 | expressions. They are still not allowed in non-`async` functions,
|
|---|
| 119 | though. Setting this option to `true` is not allowed when `sourceType: "commonjs"`.
|
|---|
| 120 |
|
|---|
| 121 | - **allowSuperOutsideMethod**: By default, `super` outside a method
|
|---|
| 122 | raises an error. Set this to `true` to accept such code.
|
|---|
| 123 |
|
|---|
| 124 | - **allowHashBang**: When this is enabled, if the code starts with the
|
|---|
| 125 | characters `#!` (as in a shellscript), the first line will be
|
|---|
| 126 | treated as a comment. Defaults to true when `ecmaVersion` >= 2023.
|
|---|
| 127 |
|
|---|
| 128 | - **checkPrivateFields**: By default, the parser will verify that
|
|---|
| 129 | private properties are only used in places where they are valid and
|
|---|
| 130 | have been declared. Set this to false to turn such checks off.
|
|---|
| 131 |
|
|---|
| 132 | - **locations**: When `true`, each node has a `loc` object attached
|
|---|
| 133 | with `start` and `end` subobjects, each of which contains the
|
|---|
| 134 | one-based line and zero-based column numbers in `{line, column}`
|
|---|
| 135 | form. Default is `false`.
|
|---|
| 136 |
|
|---|
| 137 | - **onToken**: If a function is passed for this option, each found
|
|---|
| 138 | token will be passed in same format as tokens returned from
|
|---|
| 139 | `tokenizer().getToken()`.
|
|---|
| 140 |
|
|---|
| 141 | If array is passed, each found token is pushed to it.
|
|---|
| 142 |
|
|---|
| 143 | Note that you are not allowed to call the parser from the
|
|---|
| 144 | callback—that will corrupt its internal state.
|
|---|
| 145 |
|
|---|
| 146 | - **onComment**: If a function is passed for this option, whenever a
|
|---|
| 147 | comment is encountered the function will be called with the
|
|---|
| 148 | following parameters:
|
|---|
| 149 |
|
|---|
| 150 | - `block`: `true` if the comment is a block comment, false if it
|
|---|
| 151 | is a line comment.
|
|---|
| 152 | - `text`: The content of the comment.
|
|---|
| 153 | - `start`: Character offset of the start of the comment.
|
|---|
| 154 | - `end`: Character offset of the end of the comment.
|
|---|
| 155 |
|
|---|
| 156 | When the `locations` options is on, the `{line, column}` locations
|
|---|
| 157 | of the comment’s start and end are passed as two additional
|
|---|
| 158 | parameters.
|
|---|
| 159 |
|
|---|
| 160 | If array is passed for this option, each found comment is pushed
|
|---|
| 161 | to it as object in Esprima format:
|
|---|
| 162 |
|
|---|
| 163 | ```javascript
|
|---|
| 164 | {
|
|---|
| 165 | "type": "Line" | "Block",
|
|---|
| 166 | "value": "comment text",
|
|---|
| 167 | "start": Number,
|
|---|
| 168 | "end": Number,
|
|---|
| 169 | // If `locations` option is on:
|
|---|
| 170 | "loc": {
|
|---|
| 171 | "start": {line: Number, column: Number}
|
|---|
| 172 | "end": {line: Number, column: Number}
|
|---|
| 173 | },
|
|---|
| 174 | // If `ranges` option is on:
|
|---|
| 175 | "range": [Number, Number]
|
|---|
| 176 | }
|
|---|
| 177 | ```
|
|---|
| 178 |
|
|---|
| 179 | Note that you are not allowed to call the parser from the
|
|---|
| 180 | callback—that will corrupt its internal state.
|
|---|
| 181 |
|
|---|
| 182 | - **ranges**: Nodes have their start and end characters offsets
|
|---|
| 183 | recorded in `start` and `end` properties (directly on the node,
|
|---|
| 184 | rather than the `loc` object, which holds line/column data. To also
|
|---|
| 185 | add a
|
|---|
| 186 | [semi-standardized](https://bugzilla.mozilla.org/show_bug.cgi?id=745678)
|
|---|
| 187 | `range` property holding a `[start, end]` array with the same
|
|---|
| 188 | numbers, set the `ranges` option to `true`.
|
|---|
| 189 |
|
|---|
| 190 | - **program**: It is possible to parse multiple files into a single
|
|---|
| 191 | AST by passing the tree produced by parsing the first file as the
|
|---|
| 192 | `program` option in subsequent parses. This will add the toplevel
|
|---|
| 193 | forms of the parsed file to the "Program" (top) node of an existing
|
|---|
| 194 | parse tree.
|
|---|
| 195 |
|
|---|
| 196 | - **sourceFile**: When the `locations` option is `true`, you can pass
|
|---|
| 197 | this option to add a `source` attribute in every node’s `loc`
|
|---|
| 198 | object. Note that the contents of this option are not examined or
|
|---|
| 199 | processed in any way; you are free to use whatever format you
|
|---|
| 200 | choose.
|
|---|
| 201 |
|
|---|
| 202 | - **directSourceFile**: Like `sourceFile`, but a `sourceFile` property
|
|---|
| 203 | will be added (regardless of the `location` option) directly to the
|
|---|
| 204 | nodes, rather than the `loc` object.
|
|---|
| 205 |
|
|---|
| 206 | - **preserveParens**: If this option is `true`, parenthesized expressions
|
|---|
| 207 | are represented by (non-standard) `ParenthesizedExpression` nodes
|
|---|
| 208 | that have a single `expression` property containing the expression
|
|---|
| 209 | inside parentheses.
|
|---|
| 210 |
|
|---|
| 211 | **parseExpressionAt**`(input, offset, options)` will parse a single
|
|---|
| 212 | expression in a string, and return its AST. It will not complain if
|
|---|
| 213 | there is more of the string left after the expression.
|
|---|
| 214 |
|
|---|
| 215 | **tokenizer**`(input, options)` returns an object with a `getToken`
|
|---|
| 216 | method that can be called repeatedly to get the next token, a `{start,
|
|---|
| 217 | end, type, value}` object (with added `loc` property when the
|
|---|
| 218 | `locations` option is enabled and `range` property when the `ranges`
|
|---|
| 219 | option is enabled). When the token's type is `tokTypes.eof`, you
|
|---|
| 220 | should stop calling the method, since it will keep returning that same
|
|---|
| 221 | token forever.
|
|---|
| 222 |
|
|---|
| 223 | Note that tokenizing JavaScript without parsing it is, in modern
|
|---|
| 224 | versions of the language, not really possible due to the way syntax is
|
|---|
| 225 | overloaded in ways that can only be disambiguated by the parse
|
|---|
| 226 | context. This package applies a bunch of heuristics to try and do a
|
|---|
| 227 | reasonable job, but you are advised to use `parse` with the `onToken`
|
|---|
| 228 | option instead of this.
|
|---|
| 229 |
|
|---|
| 230 | In ES6 environment, returned result can be used as any other
|
|---|
| 231 | protocol-compliant iterable:
|
|---|
| 232 |
|
|---|
| 233 | ```javascript
|
|---|
| 234 | for (let token of acorn.tokenizer(str)) {
|
|---|
| 235 | // iterate over the tokens
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | // transform code to array of tokens:
|
|---|
| 239 | var tokens = [...acorn.tokenizer(str)]
|
|---|
| 240 | ```
|
|---|
| 241 |
|
|---|
| 242 | **tokTypes** holds an object mapping names to the token type objects
|
|---|
| 243 | that end up in the `type` properties of tokens.
|
|---|
| 244 |
|
|---|
| 245 | **getLineInfo**`(input, offset)` can be used to get a `{line,
|
|---|
| 246 | column}` object for a given program string and offset.
|
|---|
| 247 |
|
|---|
| 248 | ### The `Parser` class
|
|---|
| 249 |
|
|---|
| 250 | Instances of the **`Parser`** class contain all the state and logic
|
|---|
| 251 | that drives a parse. It has static methods `parse`,
|
|---|
| 252 | `parseExpressionAt`, and `tokenizer` that match the top-level
|
|---|
| 253 | functions by the same name.
|
|---|
| 254 |
|
|---|
| 255 | When extending the parser with plugins, you need to call these methods
|
|---|
| 256 | on the extended version of the class. To extend a parser with plugins,
|
|---|
| 257 | you can use its static `extend` method.
|
|---|
| 258 |
|
|---|
| 259 | ```javascript
|
|---|
| 260 | var acorn = require("acorn")
|
|---|
| 261 | var jsx = require("acorn-jsx")
|
|---|
| 262 | var JSXParser = acorn.Parser.extend(jsx())
|
|---|
| 263 | JSXParser.parse("foo(<bar/>)", {ecmaVersion: 2020})
|
|---|
| 264 | ```
|
|---|
| 265 |
|
|---|
| 266 | The `extend` method takes any number of plugin values, and returns a
|
|---|
| 267 | new `Parser` class that includes the extra parser logic provided by
|
|---|
| 268 | the plugins.
|
|---|
| 269 |
|
|---|
| 270 | ## Command line interface
|
|---|
| 271 |
|
|---|
| 272 | The `bin/acorn` utility can be used to parse a file from the command
|
|---|
| 273 | line. It accepts as arguments its input file and the following
|
|---|
| 274 | options:
|
|---|
| 275 |
|
|---|
| 276 | - `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version
|
|---|
| 277 | to parse. Default is version 9.
|
|---|
| 278 |
|
|---|
| 279 | - `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise.
|
|---|
| 280 |
|
|---|
| 281 | - `--locations`: Attaches a "loc" object to each node with "start" and
|
|---|
| 282 | "end" subobjects, each of which contains the one-based line and
|
|---|
| 283 | zero-based column numbers in `{line, column}` form.
|
|---|
| 284 |
|
|---|
| 285 | - `--allow-hash-bang`: If the code starts with the characters #! (as
|
|---|
| 286 | in a shellscript), the first line will be treated as a comment.
|
|---|
| 287 |
|
|---|
| 288 | - `--allow-await-outside-function`: Allows top-level `await` expressions.
|
|---|
| 289 | See the `allowAwaitOutsideFunction` option for more information.
|
|---|
| 290 |
|
|---|
| 291 | - `--compact`: No whitespace is used in the AST output.
|
|---|
| 292 |
|
|---|
| 293 | - `--silent`: Do not output the AST, just return the exit status.
|
|---|
| 294 |
|
|---|
| 295 | - `--help`: Print the usage information and quit.
|
|---|
| 296 |
|
|---|
| 297 | The utility spits out the syntax tree as JSON data.
|
|---|
| 298 |
|
|---|
| 299 | ## Existing plugins
|
|---|
| 300 |
|
|---|
| 301 | - [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
|---|