1 | # Acorn
|
2 |
|
3 | [![Build Status](https://travis-ci.org/acornjs/acorn.svg?branch=master)](https://travis-ci.org/acornjs/acorn)
|
4 | [![NPM version](https://img.shields.io/npm/v/acorn.svg)](https://www.npmjs.com/package/acorn)
|
5 | [![CDNJS](https://img.shields.io/cdnjs/v/acorn.svg)](https://cdnjs.com/libraries/acorn)
|
6 | [Author funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?force)](https://marijnhaverbeke.nl/fund/)
|
7 |
|
8 | A tiny, fast JavaScript parser, written completely in JavaScript.
|
9 |
|
10 | ## Community
|
11 |
|
12 | Acorn is open source software released under an
|
13 | [MIT license](https://github.com/acornjs/acorn/blob/master/LICENSE).
|
14 |
|
15 | You are welcome to
|
16 | [report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
17 | requests on [github](https://github.com/acornjs/acorn). For questions
|
18 | and discussion, please use the
|
19 | [Tern discussion forum](https://discuss.ternjs.net).
|
20 |
|
21 | ## Installation
|
22 |
|
23 | The easiest way to install acorn is with [`npm`][npm].
|
24 |
|
25 | [npm]: https://www.npmjs.com/
|
26 |
|
27 | ```sh
|
28 | npm install acorn
|
29 | ```
|
30 |
|
31 | Alternately, you can download the source and build acorn yourself:
|
32 |
|
33 | ```sh
|
34 | git clone https://github.com/acornjs/acorn.git
|
35 | cd acorn
|
36 | npm install
|
37 | npm run build
|
38 | ```
|
39 |
|
40 | ## Components
|
41 |
|
42 | When run in a CommonJS (node.js) or AMD environment, exported values
|
43 | appear in the interfaces exposed by the individual files, as usual.
|
44 | When loaded in the browser (Acorn works in any JS-enabled browser more
|
45 | recent than IE5) without any kind of module management, a single
|
46 | global object `acorn` will be defined, and all the exported properties
|
47 | will be added to that.
|
48 |
|
49 | ### Main parser
|
50 |
|
51 | This is implemented in `dist/acorn.js`, and is what you get when you
|
52 | `require("acorn")` in node.js.
|
53 |
|
54 | **parse**`(input, options)` is used to parse a JavaScript program.
|
55 | The `input` parameter is a string, `options` can be undefined or an
|
56 | object setting some of the options listed below. The return value will
|
57 | be an abstract syntax tree object as specified by the
|
58 | [ESTree spec][estree].
|
59 |
|
60 | When encountering a syntax error, the parser will raise a
|
61 | `SyntaxError` object with a meaningful message. The error object will
|
62 | have a `pos` property that indicates the character offset at which the
|
63 | error occurred, and a `loc` object that contains a `{line, column}`
|
64 | object referring to that same position.
|
65 |
|
66 | [estree]: https://github.com/estree/estree
|
67 |
|
68 | - **ecmaVersion**: Indicates the ECMAScript version to parse. Must be
|
69 | either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018) or 10 (2019, partial
|
70 | support). This influences support for strict mode, the set of
|
71 | reserved words, and support for new syntax features. Default is 7.
|
72 |
|
73 | **NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
74 | implemented by Acorn.
|
75 |
|
76 | - **sourceType**: Indicate the mode the code should be parsed in. Can be
|
77 | either `"script"` or `"module"`. This influences global strict mode
|
78 | and parsing of `import` and `export` declarations.
|
79 |
|
80 | - **onInsertedSemicolon**: If given a callback, that callback will be
|
81 | called whenever a missing semicolon is inserted by the parser. The
|
82 | callback will be given the character offset of the point where the
|
83 | semicolon is inserted as argument, and if `locations` is on, also a
|
84 | `{line, column}` object representing this position.
|
85 |
|
86 | - **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing
|
87 | commas.
|
88 |
|
89 | - **allowReserved**: If `false`, using a reserved word will generate
|
90 | an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher
|
91 | versions. When given the value `"never"`, reserved words and
|
92 | keywords can also not be used as property names (as in Internet
|
93 | Explorer's old parser).
|
94 |
|
95 | - **allowReturnOutsideFunction**: By default, a return statement at
|
96 | the top level raises an error. Set this to `true` to accept such
|
97 | code.
|
98 |
|
99 | - **allowImportExportEverywhere**: By default, `import` and `export`
|
100 | declarations can only appear at a program's top level. Setting this
|
101 | option to `true` allows them anywhere where a statement is allowed.
|
102 |
|
103 | - **allowAwaitOutsideFunction**: By default, `await` expressions can only appear inside `async` functions. Setting this option to `true` allows to have top-level `await` expressions. They are still not allowed in non-`async` functions, though.
|
104 |
|
105 | - **allowHashBang**: When this is enabled (off by default), if the
|
106 | code starts with the characters `#!` (as in a shellscript), the
|
107 | first line will be treated as a comment.
|
108 |
|
109 | - **locations**: When `true`, each node has a `loc` object attached
|
110 | with `start` and `end` subobjects, each of which contains the
|
111 | one-based line and zero-based column numbers in `{line, column}`
|
112 | form. Default is `false`.
|
113 |
|
114 | - **onToken**: If a function is passed for this option, each found
|
115 | token will be passed in same format as tokens returned from
|
116 | `tokenizer().getToken()`.
|
117 |
|
118 | If array is passed, each found token is pushed to it.
|
119 |
|
120 | Note that you are not allowed to call the parser from the
|
121 | callback—that will corrupt its internal state.
|
122 |
|
123 | - **onComment**: If a function is passed for this option, whenever a
|
124 | comment is encountered the function will be called with the
|
125 | following parameters:
|
126 |
|
127 | - `block`: `true` if the comment is a block comment, false if it
|
128 | is a line comment.
|
129 | - `text`: The content of the comment.
|
130 | - `start`: Character offset of the start of the comment.
|
131 | - `end`: Character offset of the end of the comment.
|
132 |
|
133 | When the `locations` options is on, the `{line, column}` locations
|
134 | of the comment’s start and end are passed as two additional
|
135 | parameters.
|
136 |
|
137 | If array is passed for this option, each found comment is pushed
|
138 | to it as object in Esprima format:
|
139 |
|
140 | ```javascript
|
141 | {
|
142 | "type": "Line" | "Block",
|
143 | "value": "comment text",
|
144 | "start": Number,
|
145 | "end": Number,
|
146 | // If `locations` option is on:
|
147 | "loc": {
|
148 | "start": {line: Number, column: Number}
|
149 | "end": {line: Number, column: Number}
|
150 | },
|
151 | // If `ranges` option is on:
|
152 | "range": [Number, Number]
|
153 | }
|
154 | ```
|
155 |
|
156 | Note that you are not allowed to call the parser from the
|
157 | callback—that will corrupt its internal state.
|
158 |
|
159 | - **ranges**: Nodes have their start and end characters offsets
|
160 | recorded in `start` and `end` properties (directly on the node,
|
161 | rather than the `loc` object, which holds line/column data. To also
|
162 | add a [semi-standardized][range] `range` property holding a
|
163 | `[start, end]` array with the same numbers, set the `ranges` option
|
164 | to `true`.
|
165 |
|
166 | - **program**: It is possible to parse multiple files into a single
|
167 | AST by passing the tree produced by parsing the first file as the
|
168 | `program` option in subsequent parses. This will add the toplevel
|
169 | forms of the parsed file to the "Program" (top) node of an existing
|
170 | parse tree.
|
171 |
|
172 | - **sourceFile**: When the `locations` option is `true`, you can pass
|
173 | this option to add a `source` attribute in every node’s `loc`
|
174 | object. Note that the contents of this option are not examined or
|
175 | processed in any way; you are free to use whatever format you
|
176 | choose.
|
177 |
|
178 | - **directSourceFile**: Like `sourceFile`, but a `sourceFile` property
|
179 | will be added (regardless of the `location` option) directly to the
|
180 | nodes, rather than the `loc` object.
|
181 |
|
182 | - **preserveParens**: If this option is `true`, parenthesized expressions
|
183 | are represented by (non-standard) `ParenthesizedExpression` nodes
|
184 | that have a single `expression` property containing the expression
|
185 | inside parentheses.
|
186 |
|
187 | [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
|
188 |
|
189 | **parseExpressionAt**`(input, offset, options)` will parse a single
|
190 | expression in a string, and return its AST. It will not complain if
|
191 | there is more of the string left after the expression.
|
192 |
|
193 | **getLineInfo**`(input, offset)` can be used to get a `{line,
|
194 | column}` object for a given program string and character offset.
|
195 |
|
196 | **tokenizer**`(input, options)` returns an object with a `getToken`
|
197 | method that can be called repeatedly to get the next token, a `{start,
|
198 | end, type, value}` object (with added `loc` property when the
|
199 | `locations` option is enabled and `range` property when the `ranges`
|
200 | option is enabled). When the token's type is `tokTypes.eof`, you
|
201 | should stop calling the method, since it will keep returning that same
|
202 | token forever.
|
203 |
|
204 | In ES6 environment, returned result can be used as any other
|
205 | protocol-compliant iterable:
|
206 |
|
207 | ```javascript
|
208 | for (let token of acorn.tokenizer(str)) {
|
209 | // iterate over the tokens
|
210 | }
|
211 |
|
212 | // transform code to array of tokens:
|
213 | var tokens = [...acorn.tokenizer(str)];
|
214 | ```
|
215 |
|
216 | **tokTypes** holds an object mapping names to the token type objects
|
217 | that end up in the `type` properties of tokens.
|
218 |
|
219 | #### Note on using with [Escodegen][escodegen]
|
220 |
|
221 | Escodegen supports generating comments from AST, attached in
|
222 | Esprima-specific format. In order to simulate same format in
|
223 | Acorn, consider following example:
|
224 |
|
225 | ```javascript
|
226 | var comments = [], tokens = [];
|
227 |
|
228 | var ast = acorn.parse('var x = 42; // answer', {
|
229 | // collect ranges for each node
|
230 | ranges: true,
|
231 | // collect comments in Esprima's format
|
232 | onComment: comments,
|
233 | // collect token ranges
|
234 | onToken: tokens
|
235 | });
|
236 |
|
237 | // attach comments using collected information
|
238 | escodegen.attachComments(ast, comments, tokens);
|
239 |
|
240 | // generate code
|
241 | console.log(escodegen.generate(ast, {comment: true}));
|
242 | // > 'var x = 42; // answer'
|
243 | ```
|
244 |
|
245 | [escodegen]: https://github.com/estools/escodegen
|
246 |
|
247 | ### dist/acorn_loose.js ###
|
248 |
|
249 | This file implements an error-tolerant parser. It exposes a single
|
250 | function. The loose parser is accessible in node.js via `require("acorn/dist/acorn_loose")`.
|
251 |
|
252 | **parse_dammit**`(input, options)` takes the same arguments and
|
253 | returns the same syntax tree as the `parse` function in `acorn.js`,
|
254 | but never raises an error, and will do its best to parse syntactically
|
255 | invalid code in as meaningful a way as it can. It'll insert identifier
|
256 | nodes with name `"✖"` as placeholders in places where it can't make
|
257 | sense of the input. Depends on `acorn.js`, because it uses the same
|
258 | tokenizer.
|
259 |
|
260 | ### dist/walk.js ###
|
261 |
|
262 | Implements an abstract syntax tree walker. Will store its interface in
|
263 | `acorn.walk` when loaded without a module system.
|
264 |
|
265 | **simple**`(node, visitors, base, state)` does a 'simple' walk over
|
266 | a tree. `node` should be the AST node to walk, and `visitors` an
|
267 | object with properties whose names correspond to node types in the
|
268 | [ESTree spec][estree]. The properties should contain functions
|
269 | that will be called with the node object and, if applicable the state
|
270 | at that point. The last two arguments are optional. `base` is a walker
|
271 | algorithm, and `state` is a start state. The default walker will
|
272 | simply visit all statements and expressions and not produce a
|
273 | meaningful state. (An example of a use of state is to track scope at
|
274 | each point in the tree.)
|
275 |
|
276 | ```js
|
277 | const acorn = require("acorn")
|
278 | const walk = require("acorn/dist/walk")
|
279 |
|
280 | walk.simple(acorn.parse("let x = 10"), {
|
281 | Literal(node) {
|
282 | console.log(`Found a literal: ${node.value}`)
|
283 | }
|
284 | })
|
285 | ```
|
286 |
|
287 | **ancestor**`(node, visitors, base, state)` does a 'simple' walk over
|
288 | a tree, building up an array of ancestor nodes (including the current node)
|
289 | and passing the array to the callbacks as a third parameter.
|
290 |
|
291 | ```js
|
292 | const acorn = require("acorn")
|
293 | const walk = require("acorn/dist/walk")
|
294 |
|
295 | walk.ancestor(acorn.parse("foo('hi')"), {
|
296 | Literal(_, ancestors) {
|
297 | console.log("This literal's ancestors are:",
|
298 | ancestors.map(n => n.type))
|
299 | }
|
300 | })
|
301 | ```
|
302 |
|
303 | **recursive**`(node, state, functions, base)` does a 'recursive'
|
304 | walk, where the walker functions are responsible for continuing the
|
305 | walk on the child nodes of their target node. `state` is the start
|
306 | state, and `functions` should contain an object that maps node types
|
307 | to walker functions. Such functions are called with `(node, state, c)`
|
308 | arguments, and can cause the walk to continue on a sub-node by calling
|
309 | the `c` argument on it with `(node, state)` arguments. The optional
|
310 | `base` argument provides the fallback walker functions for node types
|
311 | that aren't handled in the `functions` object. If not given, the
|
312 | default walkers will be used.
|
313 |
|
314 | **make**`(functions, base)` builds a new walker object by using the
|
315 | walker functions in `functions` and filling in the missing ones by
|
316 | taking defaults from `base`.
|
317 |
|
318 | **full**`(node, callback, base, state)` does a 'full'
|
319 | walk over a tree, calling the callback with the arguments (node, state, type)
|
320 | for each node
|
321 |
|
322 | **fullAncestor**`(node, callback, base, state)` does a 'full' walk over
|
323 | a tree, building up an array of ancestor nodes (including the current node)
|
324 | and passing the array to the callbacks as a third parameter.
|
325 |
|
326 | ```js
|
327 | const acorn = require("acorn")
|
328 | const walk = require("acorn/dist/walk")
|
329 |
|
330 | walk.full(acorn.parse("1 + 1"), node => {
|
331 | console.log(`There's a ${node.type} node at ${node.ch}`)
|
332 | })
|
333 | ```
|
334 |
|
335 | **findNodeAt**`(node, start, end, test, base, state)` tries to
|
336 | locate a node in a tree at the given start and/or end offsets, which
|
337 | satisfies the predicate `test`. `start` and `end` can be either `null`
|
338 | (as wildcard) or a number. `test` may be a string (indicating a node
|
339 | type) or a function that takes `(nodeType, node)` arguments and
|
340 | returns a boolean indicating whether this node is interesting. `base`
|
341 | and `state` are optional, and can be used to specify a custom walker.
|
342 | Nodes are tested from inner to outer, so if two nodes match the
|
343 | boundaries, the inner one will be preferred.
|
344 |
|
345 | **findNodeAround**`(node, pos, test, base, state)` is a lot like
|
346 | `findNodeAt`, but will match any node that exists 'around' (spanning)
|
347 | the given position.
|
348 |
|
349 | **findNodeAfter**`(node, pos, test, base, state)` is similar to
|
350 | `findNodeAround`, but will match all nodes *after* the given position
|
351 | (testing outer nodes before inner nodes).
|
352 |
|
353 | ## Command line interface
|
354 |
|
355 | The `bin/acorn` utility can be used to parse a file from the command
|
356 | line. It accepts as arguments its input file and the following
|
357 | options:
|
358 |
|
359 | - `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version
|
360 | to parse. Default is version 7.
|
361 |
|
362 | - `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise.
|
363 |
|
364 | - `--locations`: Attaches a "loc" object to each node with "start" and
|
365 | "end" subobjects, each of which contains the one-based line and
|
366 | zero-based column numbers in `{line, column}` form.
|
367 |
|
368 | - `--allow-hash-bang`: If the code starts with the characters #! (as in a shellscript), the first line will be treated as a comment.
|
369 |
|
370 | - `--compact`: No whitespace is used in the AST output.
|
371 |
|
372 | - `--silent`: Do not output the AST, just return the exit status.
|
373 |
|
374 | - `--help`: Print the usage information and quit.
|
375 |
|
376 | The utility spits out the syntax tree as JSON data.
|
377 |
|
378 | ## Build system
|
379 |
|
380 | Acorn is written in ECMAScript 6, as a set of small modules, in the
|
381 | project's `src` directory, and compiled down to bigger ECMAScript 3
|
382 | files in `dist` using [Browserify](http://browserify.org) and
|
383 | [Babel](http://babeljs.io/). If you are already using Babel, you can
|
384 | consider including the modules directly.
|
385 |
|
386 | The command-line test runner (`npm test`) uses the ES6 modules. The
|
387 | browser-based test page (`test/index.html`) uses the compiled modules.
|
388 | The `bin/build-acorn.js` script builds the latter from the former.
|
389 |
|
390 | If you are working on Acorn, you'll probably want to try the code out
|
391 | directly, without an intermediate build step. In your scripts, you can
|
392 | register the Babel require shim like this:
|
393 |
|
394 | require("babel-core/register")
|
395 |
|
396 | That will allow you to directly `require` the ES6 modules.
|
397 |
|
398 | ## Plugins
|
399 |
|
400 | Acorn is designed support allow plugins which, within reasonable
|
401 | bounds, redefine the way the parser works. Plugins can add new token
|
402 | types and new tokenizer contexts (if necessary), and extend methods in
|
403 | the parser object. This is not a clean, elegant API—using it requires
|
404 | an understanding of Acorn's internals, and plugins are likely to break
|
405 | whenever those internals are significantly changed. But still, it is
|
406 | _possible_, in this way, to create parsers for JavaScript dialects
|
407 | without forking all of Acorn. And in principle it is even possible to
|
408 | combine such plugins, so that if you have, for example, a plugin for
|
409 | parsing types and a plugin for parsing JSX-style XML literals, you
|
410 | could load them both and parse code with both JSX tags and types.
|
411 |
|
412 | A plugin should register itself by adding a property to
|
413 | `acorn.plugins`, which holds a function. Calling `acorn.parse`, a
|
414 | `plugins` option can be passed, holding an object mapping plugin names
|
415 | to configuration values (or just `true` for plugins that don't take
|
416 | options). After the parser object has been created, the initialization
|
417 | functions for the chosen plugins are called with `(parser,
|
418 | configValue)` arguments. They are expected to use the `parser.extend`
|
419 | method to extend parser methods. For example, the `readToken` method
|
420 | could be extended like this:
|
421 |
|
422 | ```javascript
|
423 | parser.extend("readToken", function(nextMethod) {
|
424 | return function(code) {
|
425 | console.log("Reading a token!")
|
426 | return nextMethod.call(this, code)
|
427 | }
|
428 | })
|
429 | ```
|
430 |
|
431 | The `nextMethod` argument passed to `extend`'s second argument is the
|
432 | previous value of this method, and should usually be called through to
|
433 | whenever the extended method does not handle the call itself.
|
434 |
|
435 | Similarly, the loose parser allows plugins to register themselves via
|
436 | `acorn.pluginsLoose`. The extension mechanism is the same as for the
|
437 | normal parser:
|
438 |
|
439 | ```javascript
|
440 | looseParser.extend("readToken", function(nextMethod) {
|
441 | return function() {
|
442 | console.log("Reading a token in the loose parser!")
|
443 | return nextMethod.call(this)
|
444 | }
|
445 | })
|
446 | ```
|
447 |
|
448 | ### Existing plugins
|
449 |
|
450 | - [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
451 | - [`acorn-objj`](https://github.com/cappuccino/acorn-objj): [Objective-J](http://www.cappuccino-project.org/learn/objective-j.html) language parser built as Acorn plugin
|
452 |
|
453 | Plugins for ECMAScript proposals:
|
454 |
|
455 | - [`acorn-stage3`](https://github.com/acornjs/acorn-stage3): Parse most stage 3 proposals, bundling:
|
456 | - [`acorn-async-iteration`](https://github.com/acornjs/acorn-async-iteration): Parse [async iteration proposal](https://github.com/tc39/proposal-async-iteration)
|
457 | - [`acorn-bigint`](https://github.com/acornjs/acorn-bigint): Parse [BigInt proposal](https://github.com/tc39/proposal-bigint)
|
458 | - [`acorn-class-fields`](https://github.com/acornjs/acorn-class-fields): Parse [class fields proposal](https://github.com/tc39/proposal-class-fields)
|
459 | - [`acorn-dynamic-import`](https://github.com/kesne/acorn-dynamic-import): Parse [import() proposal](https://github.com/tc39/proposal-dynamic-import)
|
460 | - [`acorn-import-meta`](https://github.com/acornjs/acorn-import-meta): Parse [import.meta proposal](https://github.com/tc39/proposal-import-meta)
|
461 | - [`acorn-numeric-separator`](https://github.com/acornjs/acorn-numeric-separator): Parse [numeric separator proposal](https://github.com/tc39/proposal-numeric-separator)
|
462 | - [`acorn-optional-catch-binding`](https://github.com/acornjs/acorn-optional-catch-binding): Parse [optional catch binding proposal](https://github.com/tc39/proposal-optional-catch-binding)
|
463 | - [`acorn-private-methods`](https://github.com/acornjs/acorn-private-methods): parse [private methods, getters and setters proposal](https://github.com/tc39/proposal-private-methods)
|
464 | - [`acorn5-object-spread`](https://github.com/adrianheine/acorn5-object-spread): Parse [Object Rest/Spread Properties proposal](https://github.com/tc39/proposal-object-rest-spread)
|
465 | - [`acorn-object-rest-spread`](https://github.com/victor-homyakov/acorn-object-rest-spread): Parse [Object Rest/Spread Properties proposal](https://github.com/tc39/proposal-object-rest-spread)
|
466 | - [`acorn-es7`](https://github.com/angelozerr/acorn-es7): Parse [decorator syntax proposal](https://github.com/wycats/javascript-decorators)
|
467 | - [`acorn-static-class-property-initializer`](https://github.com/victor-homyakov/acorn-static-class-property-initializer): Partial support for static class properties from [ES Class Fields & Static Properties Proposal](https://github.com/tc39/proposal-class-public-fields) to support static property initializers in [React components written as ES6+ classes](https://babeljs.io/blog/2015/06/07/react-on-es6-plus)
|