UNPKG

20.1 kBMarkdownView Raw
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
8A tiny, fast JavaScript parser, written completely in JavaScript.
9
10## Community
11
12Acorn is open source software released under an
13[MIT license](https://github.com/acornjs/acorn/blob/master/LICENSE).
14
15You are welcome to
16[report bugs](https://github.com/acornjs/acorn/issues) or create pull
17requests on [github](https://github.com/acornjs/acorn). For questions
18and discussion, please use the
19[Tern discussion forum](https://discuss.ternjs.net).
20
21## Installation
22
23The easiest way to install acorn is with [`npm`][npm].
24
25[npm]: https://www.npmjs.com/
26
27```sh
28npm install acorn
29```
30
31Alternately, you can download the source and build acorn yourself:
32
33```sh
34git clone https://github.com/acornjs/acorn.git
35cd acorn
36npm install
37npm run build
38```
39
40## Components
41
42When run in a CommonJS (node.js) or AMD environment, exported values
43appear in the interfaces exposed by the individual files, as usual.
44When loaded in the browser (Acorn works in any JS-enabled browser more
45recent than IE5) without any kind of module management, a single
46global object `acorn` will be defined, and all the exported properties
47will be added to that.
48
49### Main parser
50
51This 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.
55The `input` parameter is a string, `options` can be undefined or an
56object setting some of the options listed below. The return value will
57be an abstract syntax tree object as specified by the
58[ESTree spec][estree].
59
60When encountering a syntax error, the parser will raise a
61`SyntaxError` object with a meaningful message. The error object will
62have a `pos` property that indicates the character offset at which the
63error occurred, and a `loc` object that contains a `{line, column}`
64object 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
190expression in a string, and return its AST. It will not complain if
191there is more of the string left after the expression.
192
193**getLineInfo**`(input, offset)` can be used to get a `{line,
194column}` object for a given program string and character offset.
195
196**tokenizer**`(input, options)` returns an object with a `getToken`
197method that can be called repeatedly to get the next token, a `{start,
198end, type, value}` object (with added `loc` property when the
199`locations` option is enabled and `range` property when the `ranges`
200option is enabled). When the token's type is `tokTypes.eof`, you
201should stop calling the method, since it will keep returning that same
202token forever.
203
204In ES6 environment, returned result can be used as any other
205protocol-compliant iterable:
206
207```javascript
208for (let token of acorn.tokenizer(str)) {
209 // iterate over the tokens
210}
211
212// transform code to array of tokens:
213var tokens = [...acorn.tokenizer(str)];
214```
215
216**tokTypes** holds an object mapping names to the token type objects
217that end up in the `type` properties of tokens.
218
219#### Note on using with [Escodegen][escodegen]
220
221Escodegen supports generating comments from AST, attached in
222Esprima-specific format. In order to simulate same format in
223Acorn, consider following example:
224
225```javascript
226var comments = [], tokens = [];
227
228var 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
238escodegen.attachComments(ast, comments, tokens);
239
240// generate code
241console.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
249This file implements an error-tolerant parser. It exposes a single
250function. 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
253returns the same syntax tree as the `parse` function in `acorn.js`,
254but never raises an error, and will do its best to parse syntactically
255invalid code in as meaningful a way as it can. It'll insert identifier
256nodes with name `"✖"` as placeholders in places where it can't make
257sense of the input. Depends on `acorn.js`, because it uses the same
258tokenizer.
259
260### dist/walk.js ###
261
262Implements 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
266a tree. `node` should be the AST node to walk, and `visitors` an
267object with properties whose names correspond to node types in the
268[ESTree spec][estree]. The properties should contain functions
269that will be called with the node object and, if applicable the state
270at that point. The last two arguments are optional. `base` is a walker
271algorithm, and `state` is a start state. The default walker will
272simply visit all statements and expressions and not produce a
273meaningful state. (An example of a use of state is to track scope at
274each point in the tree.)
275
276```js
277const acorn = require("acorn")
278const walk = require("acorn/dist/walk")
279
280walk.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
288a tree, building up an array of ancestor nodes (including the current node)
289and passing the array to the callbacks as a third parameter.
290
291```js
292const acorn = require("acorn")
293const walk = require("acorn/dist/walk")
294
295walk.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'
304walk, where the walker functions are responsible for continuing the
305walk on the child nodes of their target node. `state` is the start
306state, and `functions` should contain an object that maps node types
307to walker functions. Such functions are called with `(node, state, c)`
308arguments, and can cause the walk to continue on a sub-node by calling
309the `c` argument on it with `(node, state)` arguments. The optional
310`base` argument provides the fallback walker functions for node types
311that aren't handled in the `functions` object. If not given, the
312default walkers will be used.
313
314**make**`(functions, base)` builds a new walker object by using the
315walker functions in `functions` and filling in the missing ones by
316taking defaults from `base`.
317
318**full**`(node, callback, base, state)` does a 'full'
319walk over a tree, calling the callback with the arguments (node, state, type)
320for each node
321
322**fullAncestor**`(node, callback, base, state)` does a 'full' walk over
323a tree, building up an array of ancestor nodes (including the current node)
324and passing the array to the callbacks as a third parameter.
325
326```js
327const acorn = require("acorn")
328const walk = require("acorn/dist/walk")
329
330walk.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
336locate a node in a tree at the given start and/or end offsets, which
337satisfies the predicate `test`. `start` and `end` can be either `null`
338(as wildcard) or a number. `test` may be a string (indicating a node
339type) or a function that takes `(nodeType, node)` arguments and
340returns a boolean indicating whether this node is interesting. `base`
341and `state` are optional, and can be used to specify a custom walker.
342Nodes are tested from inner to outer, so if two nodes match the
343boundaries, 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)
347the 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
355The `bin/acorn` utility can be used to parse a file from the command
356line. It accepts as arguments its input file and the following
357options:
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
376The utility spits out the syntax tree as JSON data.
377
378## Build system
379
380Acorn is written in ECMAScript 6, as a set of small modules, in the
381project's `src` directory, and compiled down to bigger ECMAScript 3
382files in `dist` using [Browserify](http://browserify.org) and
383[Babel](http://babeljs.io/). If you are already using Babel, you can
384consider including the modules directly.
385
386The command-line test runner (`npm test`) uses the ES6 modules. The
387browser-based test page (`test/index.html`) uses the compiled modules.
388The `bin/build-acorn.js` script builds the latter from the former.
389
390If you are working on Acorn, you'll probably want to try the code out
391directly, without an intermediate build step. In your scripts, you can
392register the Babel require shim like this:
393
394 require("babel-core/register")
395
396That will allow you to directly `require` the ES6 modules.
397
398## Plugins
399
400Acorn is designed support allow plugins which, within reasonable
401bounds, redefine the way the parser works. Plugins can add new token
402types and new tokenizer contexts (if necessary), and extend methods in
403the parser object. This is not a clean, elegant API—using it requires
404an understanding of Acorn's internals, and plugins are likely to break
405whenever those internals are significantly changed. But still, it is
406_possible_, in this way, to create parsers for JavaScript dialects
407without forking all of Acorn. And in principle it is even possible to
408combine such plugins, so that if you have, for example, a plugin for
409parsing types and a plugin for parsing JSX-style XML literals, you
410could load them both and parse code with both JSX tags and types.
411
412A 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
415to configuration values (or just `true` for plugins that don't take
416options). After the parser object has been created, the initialization
417functions for the chosen plugins are called with `(parser,
418configValue)` arguments. They are expected to use the `parser.extend`
419method to extend parser methods. For example, the `readToken` method
420could be extended like this:
421
422```javascript
423parser.extend("readToken", function(nextMethod) {
424 return function(code) {
425 console.log("Reading a token!")
426 return nextMethod.call(this, code)
427 }
428})
429```
430
431The `nextMethod` argument passed to `extend`'s second argument is the
432previous value of this method, and should usually be called through to
433whenever the extended method does not handle the call itself.
434
435Similarly, the loose parser allows plugins to register themselves via
436`acorn.pluginsLoose`. The extension mechanism is the same as for the
437normal parser:
438
439```javascript
440looseParser.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)