├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .mailmap ├── .npmignore ├── .npmrc ├── .tern-project ├── AUTHORS ├── README.md ├── acorn-loose ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── node_modules │ └── acorn ├── package.json ├── rollup.config.js └── src │ ├── .eslintrc │ ├── expression.js │ ├── index.js │ ├── package.json │ ├── parseutil.js │ ├── state.js │ ├── statement.js │ └── tokenize.js ├── acorn-walk ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dist │ └── walk.d.ts ├── package.json ├── rollup.config.js └── src │ ├── .eslintrc │ ├── index.js │ └── package.json ├── acorn ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin │ └── acorn ├── dist │ ├── acorn.d.ts │ └── acorn.mjs.d.ts ├── package.json ├── rollup.config.bin.js ├── rollup.config.js └── src │ ├── .eslintrc │ ├── bin │ ├── .eslintrc │ └── acorn.js │ ├── expression.js │ ├── identifier.js │ ├── index.js │ ├── location.js │ ├── locutil.js │ ├── lval.js │ ├── node.js │ ├── options.js │ ├── package.json │ ├── parseutil.js │ ├── regexp.js │ ├── scope.js │ ├── scopeflags.js │ ├── state.js │ ├── statement.js │ ├── tokencontext.js │ ├── tokenize.js │ ├── tokentype.js │ ├── unicode-property-data.js │ ├── util.js │ └── whitespace.js ├── bin ├── generate-identifier-regex.js ├── run_test262.js ├── test262.whitelist └── update_authors.sh ├── logo.svg ├── package.json └── test ├── bench ├── common.js ├── fixtures │ ├── angular.js │ ├── backbone.js │ ├── ember.js │ ├── jquery.js │ ├── react-dom.js │ └── react.js ├── index.html ├── index.js ├── package.json └── worker.js ├── driver.js ├── lint.js ├── run.js ├── tests-async-iteration.js ├── tests-asyncawait.js ├── tests-await-top-level.js ├── tests-bigint.js ├── tests-class-features-2022.js ├── tests-directive.js ├── tests-dynamic-import.js ├── tests-es7.js ├── tests-export-all-as-ns-from-source.js ├── tests-harmony.js ├── tests-import-meta.js ├── tests-json-superset.js ├── tests-logical-assignment-operators.js ├── tests-nullish-coalescing.js ├── tests-numeric-separators.js ├── tests-optional-catch-binding.js ├── tests-optional-chaining.js ├── tests-regexp-2018.js ├── tests-regexp-2020.js ├── tests-regexp-2022.js ├── tests-regexp.js ├── tests-rest-spread-properties.js ├── tests-template-literal-revision.js ├── tests-trailing-commas-in-func.js └── tests.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | insert_final_newline = true 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: [push] 3 | jobs: 4 | build-and-test: 5 | runs-on: ubuntu-latest 6 | name: Build and test 7 | steps: 8 | - uses: actions/checkout@v2 9 | - uses: bahmutov/npm-install@v1 10 | with: 11 | useLockFile: false 12 | - run: npm test 13 | - run: npm run test:test262 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/node_modules 3 | !/acorn-loose/node_modules 4 | /.tern-port 5 | /local 6 | /bin/_acorn.js 7 | /acorn/dist/* 8 | /acorn-loose/dist 9 | /acorn-walk/dist 10 | /yarn.lock 11 | !/acorn/dist/acorn.d.ts 12 | !/acorn/dist/acorn.mjs.d.ts -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Adrian Heine 2 | Alistair Braidwood 3 | Forbes Lindesay 4 | Rich Harris 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.tern-port 2 | /test 3 | /local 4 | /rollup 5 | /bin/generate-identifier-regex.js 6 | /bin/update_authors.sh 7 | .editorconfig 8 | .gitattributes 9 | .tern-project 10 | .travis.yml 11 | /src 12 | yarn-error.log 13 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = false -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "node": true, 4 | "es_modules": true 5 | } 6 | } -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | List of Acorn contributors. Updated before every release. 2 | 3 | Adam Walsh 4 | Adrian Heine 5 | Adrian Rakovsky 6 | Alistair Braidwood 7 | Amila Welihinda 8 | Andres Suarez 9 | Angelo 10 | Aparajita Fishman 11 | Arian Stolwijk 12 | Artem Govorov 13 | Benedikt Meurer 14 | Ben Page 15 | Boopesh Mahendran 16 | Bradley Heinz 17 | Brandon Mills 18 | Brian Donovan 19 | Charles Hughes 20 | Charmander 21 | Chris McKnight 22 | Conrad Irwin 23 | Cyril Auburtin 24 | Daniel Tschinder 25 | David Bonnet 26 | dnalborczyk 27 | Domenico Matteo 28 | ehmicky 29 | Eugene Obrezkov 30 | Fabien LOISON 31 | Felix Maier 32 | Forbes Lindesay 33 | Gilad Peleg 34 | HonkingGoose 35 | Huáng Jùnliàng 36 | impinball 37 | Ingvar Stepanyan 38 | Jackson Ray Hamilton 39 | Jesse McCarthy 40 | Jiaxing Wang 41 | Joe Krump 42 | Joel Kemp 43 | Johannes Herr 44 | John-David Dalton 45 | Jordan Gensler 46 | Jordan Harband 47 | Jordan Klassen 48 | Julian Wyzykowski 49 | Jürg Lehni 50 | Kai Cataldo 51 | keeyipchan 52 | Keheliya Gallaba 53 | Kevin Irish 54 | Kevin Kwok 55 | krator 56 | kyranet 57 | laosb 58 | luckyzeng 59 | Marek 60 | Marijn Haverbeke 61 | Martin Carlberg 62 | Mat Garcia 63 | Mathias Bynens 64 | Mathieu 'p01' Henri 65 | Matthew Bastien 66 | Max Schaefer 67 | Max Zerzouri 68 | Mihai Bazon 69 | Mike Rennie 70 | naoh 71 | Nauja 72 | Nicholas C. Zakas 73 | Nick Fitzgerald 74 | Olivier Thomann 75 | Oskar Schöldström 76 | Paul Harper 77 | peakchen90 78 | Peter Rust 79 | piotr 80 | PlNG 81 | Praveen N 82 | Prayag Verma 83 | ReadmeCritic 84 | r-e-d 85 | Renée Kooi 86 | Richard Gibson 87 | Rich Harris 88 | Robert Palmer 89 | Rouven Weßling 90 | Sebastian McKenzie 91 | Shahar Soel 92 | Sheel Bedi 93 | Simen Bekkhus 94 | susiwen 95 | susiwen8 96 | Teddy Katz 97 | Timothy Gu 98 | Timo Tijhof 99 | Tim van der Lippe 100 | Tony Ross 101 | Toru Nagashima 102 | tuesmiddt 103 | Victor Homyakov 104 | Vladislav Tupikin 105 | Wexpo Lyu 106 | yosuke ota 107 | Žiga Zupančič 108 | zsjforcn 109 | 星灵 110 | 龙腾道 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Acorn 2 | 3 | [![Build Status](https://github.com/acornjs/acorn/workflows/ci/badge.svg)](https://github.com/acornjs/acorn/actions) 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 | 7 | A tiny, fast JavaScript parser, written completely in JavaScript. 8 | 9 | ## Community 10 | 11 | Acorn is open source software released under an 12 | [MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE). 13 | 14 | You are welcome to 15 | [report bugs](https://github.com/acornjs/acorn/issues) or create pull 16 | requests on [github](https://github.com/acornjs/acorn). For questions 17 | and discussion, please use the 18 | [Tern discussion forum](https://discuss.ternjs.net). 19 | 20 | ## Packages 21 | 22 | This repository holds three packages: 23 | 24 | - [acorn](https://github.com/acornjs/acorn/blob/master/acorn/): The 25 | main parser 26 | - [acorn-loose](https://github.com/acornjs/acorn/blob/master/acorn-loose/): The 27 | error-tolerant parser 28 | - [acorn-walk](https://github.com/acornjs/acorn/blob/master/acorn-walk/): The 29 | syntax tree walker 30 | 31 | To build the content of the repository, run `npm install`. 32 | 33 | ```sh 34 | git clone https://github.com/acornjs/acorn.git 35 | cd acorn 36 | npm install 37 | ``` 38 | 39 | ## Plugin developments 40 | 41 | Acorn is designed to support plugins which can, within reasonable 42 | bounds, redefine the way the parser works. Plugins can add new token 43 | types and new tokenizer contexts (if necessary), and extend methods in 44 | the parser object. This is not a clean, elegant API—using it requires 45 | an understanding of Acorn's internals, and plugins are likely to break 46 | whenever those internals are significantly changed. But still, it is 47 | _possible_, in this way, to create parsers for JavaScript dialects 48 | without forking all of Acorn. And in principle it is even possible to 49 | combine such plugins, so that if you have, for example, a plugin for 50 | parsing types and a plugin for parsing JSX-style XML literals, you 51 | could load them both and parse code with both JSX tags and types. 52 | 53 | A plugin is a function from a parser class to an extended parser 54 | class. Plugins can be used by simply applying them to the `Parser` 55 | class (or a version of that already extended by another plugin). But 56 | because that gets a little awkward, syntactically, when you are using 57 | multiple plugins, the static method `Parser.extend` can be called with 58 | any number of plugin values as arguments to create a `Parser` class 59 | extended by all those plugins. You'll usually want to create such an 60 | extended class only once, and then repeatedly call `parse` on it, to 61 | avoid needlessly confusing the JavaScript engine's optimizer. 62 | 63 | ```javascript 64 | const {Parser} = require("acorn") 65 | 66 | const MyParser = Parser.extend( 67 | require("acorn-jsx")(), 68 | require("acorn-bigint") 69 | ) 70 | console.log(MyParser.parse("// Some bigint + JSX code")) 71 | ``` 72 | 73 | Plugins override methods in their new parser class to implement 74 | additional functionality. It is recommended for a plugin package to 75 | export its plugin function as its default value or, if it takes 76 | configuration parameters, to export a constructor function that 77 | creates the plugin function. 78 | 79 | This is what a trivial plugin, which adds a bit of code to the 80 | `readToken` method, might look like: 81 | 82 | ```javascript 83 | module.exports = function noisyReadToken(Parser) { 84 | return class extends Parser { 85 | readToken(code) { 86 | console.log("Reading a token!") 87 | super.readToken(code) 88 | } 89 | } 90 | } 91 | ``` 92 | -------------------------------------------------------------------------------- /acorn-loose/.npmignore: -------------------------------------------------------------------------------- 1 | .tern-* 2 | /rollup.config.* 3 | /src 4 | -------------------------------------------------------------------------------- /acorn-loose/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.1.0 (2021-04-24) 2 | 3 | ### New features 4 | 5 | Add support for ES2022 class fields and private methods. 6 | 7 | ## 8.0.2 (2021-01-25) 8 | 9 | ### Bug fixes 10 | 11 | Adjust package.json to work with Node 12.16.0 and 13.0-13.6. 12 | 13 | ## 8.0.1 (2020-10-11) 14 | 15 | ### Bug fixes 16 | 17 | Allow `for await` at the top level. 18 | 19 | ## 8.0.0 (2020-08-12) 20 | 21 | ### New features 22 | 23 | The package can now be loaded directly as an ECMAScript module in node 13+. 24 | 25 | ### Breaking changes 26 | 27 | The `ecmaVersion` option is now required. For the moment, omitting it will still work with a warning, but that will change in a future release. 28 | 29 | ## 7.1.0 (2020-06-11) 30 | 31 | ### Bug fixes 32 | 33 | Fix various issues in regexp validation. 34 | 35 | ### New features 36 | 37 | Add support for `import.meta`. 38 | 39 | Add support for optional chaining (`?.`) and nullish coalescing (`??`). 40 | 41 | Support `export * as ns from "source"`. 42 | 43 | ## 7.0.0 (2019-08-12) 44 | 45 | ### Breaking changes 46 | 47 | Changes the node format for dynamic imports to use the `ImportExpression` node type, as defined in [ESTree](https://github.com/estree/estree/blob/master/es2020.md#importexpression). 48 | 49 | ## 6.1.0 (2019-07-04) 50 | 51 | ### New features 52 | 53 | Support bigint syntax. 54 | 55 | Support dynamic import. 56 | 57 | ## 6.0.0 (2018-09-14) 58 | 59 | ### Breaking changes 60 | 61 | This module has been moved into its own package, `acorn-loose`. 62 | 63 | Plugins work differently, and will have to be rewritten to work with this version. 64 | 65 | The `parse_dammit` function is now simply called `parse`. 66 | 67 | ## 5.1.0 (2017-07-05) 68 | 69 | ### Bug fixes 70 | 71 | Make the ES module version of the loose parser actually work. 72 | 73 | ## 4.0.4 (2016-12-19) 74 | 75 | ### Bug fixes 76 | 77 | Fix issue with loading acorn_loose.js with an AMD loader. 78 | 79 | ## 3.2.0 (2016-06-07) 80 | 81 | ### Bug fixes 82 | 83 | Don't crash when the loose parser is called without options object. 84 | 85 | ## 3.1.0 (2016-04-18) 86 | 87 | ### Bug fixes 88 | 89 | Fix issue where the loose parser created invalid TemplateElement nodes for unclosed template literals. 90 | 91 | ## 2.7.0 (2016-01-04) 92 | 93 | ### Fixes 94 | 95 | Make sure the loose parser always attaches a `local` property to `ImportNamespaceSpecifier` nodes. 96 | 97 | ## 2.6.4 (2015-11-12) 98 | 99 | ### Fixes 100 | 101 | Fix crash in loose parser when parsing invalid object pattern. 102 | 103 | ### New features 104 | 105 | Support plugins in the loose parser. 106 | 107 | ## 2.5.0 (2015-10-27) 108 | 109 | ### Fixes 110 | 111 | In the loose parser, don't allow non-string-literals as import sources. 112 | -------------------------------------------------------------------------------- /acorn-loose/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2012-2020 by various contributors (see AUTHORS) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /acorn-loose/README.md: -------------------------------------------------------------------------------- 1 | # Acorn loose parser 2 | 3 | An error-tolerant JavaScript parser written in JavaScript. 4 | 5 | This parser will parse _any_ text into an 6 | [ESTree](https://github.com/estree/estree) syntax tree that is a 7 | reasonable approximation of what it might mean as a JavaScript 8 | program. 9 | 10 | It will, to recover from missing brackets, treat whitespace as 11 | significant, which has the downside that it might mis-parse a valid 12 | but weirdly indented file. It is recommended to always try a parse 13 | with the regular `acorn` parser first, and only fall back to this 14 | parser when that one finds syntax errors. 15 | 16 | ## Community 17 | 18 | Acorn is open source software released under an 19 | [MIT license](https://github.com/acornjs/acorn/blob/master/acorn-loose/LICENSE). 20 | 21 | You are welcome to [report 22 | bugs](https://github.com/acornjs/acorn/issues) or create pull requests 23 | on [github](https://github.com/acornjs/acorn). For questions and 24 | discussion, please use the [Tern discussion 25 | forum](https://discuss.ternjs.net). 26 | 27 | ## Installation 28 | 29 | The easiest way to install acorn-loose is from [`npm`](https://www.npmjs.com/): 30 | 31 | ```sh 32 | npm install acorn-loose 33 | ``` 34 | 35 | Alternately, you can download the source and build acorn yourself: 36 | 37 | ```sh 38 | git clone https://github.com/acornjs/acorn.git 39 | cd acorn 40 | npm install 41 | ``` 42 | 43 | ## Interface 44 | 45 | **parse**`(input, options)` takes an input string and a set of options 46 | (the same options as 47 | [acorn](https://github.com/acornjs/acorn/blob/master/acorn/README.md) 48 | takes), and returns a syntax tree, even if the code isn't 49 | syntactically valid. It'll insert identifier nodes with name `"✖"` as 50 | placeholders in places where it can't make sense of the input. Depends 51 | on the `acorn` package, because it uses the same tokenizer. 52 | 53 | ```javascript 54 | var acornLoose = require("acorn-loose"); 55 | console.log(acornLoose.parse("1 / * 4 )[2]", {ecmaVersion: 2020})); 56 | ``` 57 | 58 | Like the regular parser, the loose parser supports plugins. You can 59 | take the **`LooseParser`** class exported by the module, and call its 60 | static `extend` method with one or more plugins to get a customized 61 | parser class. The class has a static `parse` method that acts like the 62 | top-level `parse` method. 63 | 64 | **isDummy**`(node)` takes a `Node` and returns `true` if it is a dummy node 65 | inserted by the parser. The function performs a simple equality check on the 66 | node's name. 67 | -------------------------------------------------------------------------------- /acorn-loose/node_modules/acorn: -------------------------------------------------------------------------------- 1 | ../../acorn -------------------------------------------------------------------------------- /acorn-loose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acorn-loose", 3 | "description": "Error-tolerant ECMAScript parser", 4 | "homepage": "https://github.com/acornjs/acorn", 5 | "main": "dist/acorn-loose.js", 6 | "module": "dist/acorn-loose.mjs", 7 | "exports": { 8 | ".": [ 9 | { 10 | "import": "./dist/acorn-loose.mjs", 11 | "require": "./dist/acorn-loose.js", 12 | "default": "./dist/acorn-loose.js" 13 | }, 14 | "./dist/acorn-loose.js" 15 | ], 16 | "./package.json": "./package.json" 17 | }, 18 | "version": "8.1.0", 19 | "engines": {"node": ">=0.4.0"}, 20 | "dependencies": { 21 | "acorn": "^8.2.0" 22 | }, 23 | "maintainers": [ 24 | { 25 | "name": "Marijn Haverbeke", 26 | "email": "marijnh@gmail.com", 27 | "web": "https://marijnhaverbeke.nl" 28 | }, 29 | { 30 | "name": "Ingvar Stepanyan", 31 | "email": "me@rreverser.com", 32 | "web": "https://rreverser.com/" 33 | }, 34 | { 35 | "name": "Adrian Heine", 36 | "web": "http://adrianheine.de" 37 | } 38 | ], 39 | "repository": { 40 | "type": "git", 41 | "url": "https://github.com/acornjs/acorn.git" 42 | }, 43 | "scripts": { 44 | "prepare": "cd ..; npm run build:loose" 45 | }, 46 | "license": "MIT" 47 | } 48 | -------------------------------------------------------------------------------- /acorn-loose/rollup.config.js: -------------------------------------------------------------------------------- 1 | import buble from "rollup-plugin-buble" 2 | 3 | export default { 4 | input: "./acorn-loose/src/index.js", 5 | output: [ 6 | { 7 | file: "acorn-loose/dist/acorn-loose.js", 8 | format: "umd", 9 | name: "acorn.loose", 10 | external: ["acorn"], 11 | globals: {acorn: "acorn"} 12 | }, 13 | { 14 | file: "acorn-loose/dist/acorn-loose.mjs", 15 | format: "es", 16 | external: ["acorn"], 17 | globals: {acorn: "acorn"} 18 | } 19 | ], 20 | plugins: [ 21 | buble({transforms: {dangerousForOf: true}}) 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /acorn-loose/src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "standard", 5 | "plugin:import/errors", 6 | "plugin:import/warnings" 7 | ], 8 | "rules": { 9 | "curly": "off", 10 | "eqeqeq": ["error", "always", { "null": "ignore" }], 11 | "indent": ["error", 2, { "SwitchCase": 0, "VariableDeclarator": 2, "CallExpression": { "arguments": "off" } }], 12 | "new-parens": "off", 13 | "no-case-declarations": "off", 14 | "no-cond-assign": "off", 15 | "no-fallthrough": "off", 16 | "no-labels": "off", 17 | "no-mixed-operators": "off", 18 | "no-return-assign": "off", 19 | "no-unused-labels": "error", 20 | "no-var": "error", 21 | "object-curly-spacing": ["error", "never"], 22 | "one-var": "off", 23 | "quotes": ["error", "double"], 24 | "semi-spacing": "off", 25 | "space-before-function-paren": ["error", "never"] 26 | }, 27 | "globals": { 28 | "Packages": false 29 | }, 30 | "plugins": [ 31 | "import" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /acorn-loose/src/index.js: -------------------------------------------------------------------------------- 1 | // Acorn: Loose parser 2 | // 3 | // This module provides an alternative parser that exposes that same 4 | // interface as the main module's `parse` function, but will try to 5 | // parse anything as JavaScript, repairing syntax error the best it 6 | // can. There are circumstances in which it will raise an error and 7 | // give up, but they are very rare. The resulting AST will be a mostly 8 | // valid JavaScript AST (as per the [Mozilla parser API][api], except 9 | // that: 10 | // 11 | // - Return outside functions is allowed 12 | // 13 | // - Label consistency (no conflicts, break only to existing labels) 14 | // is not enforced. 15 | // 16 | // - Bogus Identifier nodes with a name of `"✖"` are inserted whenever 17 | // the parser got too confused to return anything meaningful. 18 | // 19 | // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API 20 | // 21 | // The expected use for this is to *first* try `acorn.parse`, and only 22 | // if that fails switch to the loose parser. The loose parser might 23 | // parse badly indented code incorrectly, so **don't** use it as your 24 | // default parser. 25 | // 26 | // Quite a lot of acorn.js is duplicated here. The alternative was to 27 | // add a *lot* of extra cruft to that file, making it less readable 28 | // and slower. Copying and editing the code allowed me to make 29 | // invasive changes and simplifications without creating a complicated 30 | // tangle. 31 | 32 | import {defaultOptions} from "acorn" 33 | import {LooseParser} from "./state.js" 34 | import "./tokenize.js" 35 | import "./statement.js" 36 | import "./expression.js" 37 | 38 | export {LooseParser} from "./state.js" 39 | export {isDummy} from "./parseutil.js" 40 | 41 | defaultOptions.tabSize = 4 42 | 43 | export function parse(input, options) { 44 | return LooseParser.parse(input, options) 45 | } 46 | -------------------------------------------------------------------------------- /acorn-loose/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /acorn-loose/src/parseutil.js: -------------------------------------------------------------------------------- 1 | export const dummyValue = "✖" 2 | 3 | export function isDummy(node) { return node.name === dummyValue } 4 | -------------------------------------------------------------------------------- /acorn-loose/src/state.js: -------------------------------------------------------------------------------- 1 | import {Parser, SourceLocation, tokTypes as tt, Node, lineBreak, isNewLine} from "acorn" 2 | import {dummyValue} from "./parseutil.js" 3 | 4 | function noop() {} 5 | 6 | export class LooseParser { 7 | constructor(input, options = {}) { 8 | this.toks = this.constructor.BaseParser.tokenizer(input, options) 9 | this.options = this.toks.options 10 | this.input = this.toks.input 11 | this.tok = this.last = {type: tt.eof, start: 0, end: 0} 12 | this.tok.validateRegExpFlags = noop 13 | this.tok.validateRegExpPattern = noop 14 | if (this.options.locations) { 15 | let here = this.toks.curPosition() 16 | this.tok.loc = new SourceLocation(this.toks, here, here) 17 | } 18 | this.ahead = [] // Tokens ahead 19 | this.context = [] // Indentation contexted 20 | this.curIndent = 0 21 | this.curLineStart = 0 22 | this.nextLineStart = this.lineEnd(this.curLineStart) + 1 23 | this.inAsync = false 24 | this.inGenerator = false 25 | this.inFunction = false 26 | } 27 | 28 | startNode() { 29 | return new Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) 30 | } 31 | 32 | storeCurrentPos() { 33 | return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start 34 | } 35 | 36 | startNodeAt(pos) { 37 | if (this.options.locations) { 38 | return new Node(this.toks, pos[0], pos[1]) 39 | } else { 40 | return new Node(this.toks, pos) 41 | } 42 | } 43 | 44 | finishNode(node, type) { 45 | node.type = type 46 | node.end = this.last.end 47 | if (this.options.locations) 48 | node.loc.end = this.last.loc.end 49 | if (this.options.ranges) 50 | node.range[1] = this.last.end 51 | return node 52 | } 53 | 54 | dummyNode(type) { 55 | let dummy = this.startNode() 56 | dummy.type = type 57 | dummy.end = dummy.start 58 | if (this.options.locations) 59 | dummy.loc.end = dummy.loc.start 60 | if (this.options.ranges) 61 | dummy.range[1] = dummy.start 62 | this.last = {type: tt.name, start: dummy.start, end: dummy.start, loc: dummy.loc} 63 | return dummy 64 | } 65 | 66 | dummyIdent() { 67 | let dummy = this.dummyNode("Identifier") 68 | dummy.name = dummyValue 69 | return dummy 70 | } 71 | 72 | dummyString() { 73 | let dummy = this.dummyNode("Literal") 74 | dummy.value = dummy.raw = dummyValue 75 | return dummy 76 | } 77 | 78 | eat(type) { 79 | if (this.tok.type === type) { 80 | this.next() 81 | return true 82 | } else { 83 | return false 84 | } 85 | } 86 | 87 | isContextual(name) { 88 | return this.tok.type === tt.name && this.tok.value === name 89 | } 90 | 91 | eatContextual(name) { 92 | return this.tok.value === name && this.eat(tt.name) 93 | } 94 | 95 | canInsertSemicolon() { 96 | return this.tok.type === tt.eof || this.tok.type === tt.braceR || 97 | lineBreak.test(this.input.slice(this.last.end, this.tok.start)) 98 | } 99 | 100 | semicolon() { 101 | return this.eat(tt.semi) 102 | } 103 | 104 | expect(type) { 105 | if (this.eat(type)) return true 106 | for (let i = 1; i <= 2; i++) { 107 | if (this.lookAhead(i).type === type) { 108 | for (let j = 0; j < i; j++) this.next() 109 | return true 110 | } 111 | } 112 | } 113 | 114 | pushCx() { 115 | this.context.push(this.curIndent) 116 | } 117 | 118 | popCx() { 119 | this.curIndent = this.context.pop() 120 | } 121 | 122 | lineEnd(pos) { 123 | while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos 124 | return pos 125 | } 126 | 127 | indentationAfter(pos) { 128 | for (let count = 0;; ++pos) { 129 | let ch = this.input.charCodeAt(pos) 130 | if (ch === 32) ++count 131 | else if (ch === 9) count += this.options.tabSize 132 | else return count 133 | } 134 | } 135 | 136 | closes(closeTok, indent, line, blockHeuristic) { 137 | if (this.tok.type === closeTok || this.tok.type === tt.eof) return true 138 | return line !== this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && 139 | (!blockHeuristic || this.nextLineStart >= this.input.length || 140 | this.indentationAfter(this.nextLineStart) < indent) 141 | } 142 | 143 | tokenStartsLine() { 144 | for (let p = this.tok.start - 1; p >= this.curLineStart; --p) { 145 | let ch = this.input.charCodeAt(p) 146 | if (ch !== 9 && ch !== 32) return false 147 | } 148 | return true 149 | } 150 | 151 | extend(name, f) { 152 | this[name] = f(this[name]) 153 | } 154 | 155 | parse() { 156 | this.next() 157 | return this.parseTopLevel() 158 | } 159 | 160 | static extend(...plugins) { 161 | let cls = this 162 | for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls) 163 | return cls 164 | } 165 | 166 | static parse(input, options) { 167 | return new this(input, options).parse() 168 | } 169 | } 170 | 171 | // Allows plugins to extend the base parser / tokenizer used 172 | LooseParser.BaseParser = Parser 173 | -------------------------------------------------------------------------------- /acorn-loose/src/tokenize.js: -------------------------------------------------------------------------------- 1 | import {tokTypes as tt, Token, isNewLine, SourceLocation, getLineInfo, lineBreakG} from "acorn" 2 | import {LooseParser} from "./state.js" 3 | import {dummyValue} from "./parseutil.js" 4 | 5 | const lp = LooseParser.prototype 6 | 7 | function isSpace(ch) { 8 | return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewLine(ch) 9 | } 10 | 11 | lp.next = function() { 12 | this.last = this.tok 13 | if (this.ahead.length) 14 | this.tok = this.ahead.shift() 15 | else 16 | this.tok = this.readToken() 17 | 18 | if (this.tok.start >= this.nextLineStart) { 19 | while (this.tok.start >= this.nextLineStart) { 20 | this.curLineStart = this.nextLineStart 21 | this.nextLineStart = this.lineEnd(this.curLineStart) + 1 22 | } 23 | this.curIndent = this.indentationAfter(this.curLineStart) 24 | } 25 | } 26 | 27 | lp.readToken = function() { 28 | for (;;) { 29 | try { 30 | this.toks.next() 31 | if (this.toks.type === tt.dot && 32 | this.input.substr(this.toks.end, 1) === "." && 33 | this.options.ecmaVersion >= 6) { 34 | this.toks.end++ 35 | this.toks.type = tt.ellipsis 36 | } 37 | return new Token(this.toks) 38 | } catch (e) { 39 | if (!(e instanceof SyntaxError)) throw e 40 | 41 | // Try to skip some text, based on the error message, and then continue 42 | let msg = e.message, pos = e.raisedAt, replace = true 43 | if (/unterminated/i.test(msg)) { 44 | pos = this.lineEnd(e.pos + 1) 45 | if (/string/.test(msg)) { 46 | replace = {start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos)} 47 | } else if (/regular expr/i.test(msg)) { 48 | let re = this.input.slice(e.pos, pos) 49 | try { re = new RegExp(re) } catch (e) { /* ignore compilation error due to new syntax */ } 50 | replace = {start: e.pos, end: pos, type: tt.regexp, value: re} 51 | } else if (/template/.test(msg)) { 52 | replace = { 53 | start: e.pos, 54 | end: pos, 55 | type: tt.template, 56 | value: this.input.slice(e.pos, pos) 57 | } 58 | } else { 59 | replace = false 60 | } 61 | } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number|expected number in radix/i.test(msg)) { 62 | while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos 63 | } else if (/character escape|expected hexadecimal/i.test(msg)) { 64 | while (pos < this.input.length) { 65 | let ch = this.input.charCodeAt(pos++) 66 | if (ch === 34 || ch === 39 || isNewLine(ch)) break 67 | } 68 | } else if (/unexpected character/i.test(msg)) { 69 | pos++ 70 | replace = false 71 | } else if (/regular expression/i.test(msg)) { 72 | replace = true 73 | } else { 74 | throw e 75 | } 76 | this.resetTo(pos) 77 | if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: dummyValue} 78 | if (replace) { 79 | if (this.options.locations) 80 | replace.loc = new SourceLocation( 81 | this.toks, 82 | getLineInfo(this.input, replace.start), 83 | getLineInfo(this.input, replace.end)) 84 | return replace 85 | } 86 | } 87 | } 88 | } 89 | 90 | lp.resetTo = function(pos) { 91 | this.toks.pos = pos 92 | let ch = this.input.charAt(pos - 1) 93 | this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) || 94 | /[enwfd]/.test(ch) && 95 | /\b(case|else|return|throw|new|in|(instance|type)?of|delete|void)$/.test(this.input.slice(pos - 10, pos)) 96 | 97 | if (this.options.locations) { 98 | this.toks.curLine = 1 99 | this.toks.lineStart = lineBreakG.lastIndex = 0 100 | let match 101 | while ((match = lineBreakG.exec(this.input)) && match.index < pos) { 102 | ++this.toks.curLine 103 | this.toks.lineStart = match.index + match[0].length 104 | } 105 | } 106 | } 107 | 108 | lp.lookAhead = function(n) { 109 | while (n > this.ahead.length) 110 | this.ahead.push(this.readToken()) 111 | return this.ahead[n - 1] 112 | } 113 | -------------------------------------------------------------------------------- /acorn-walk/.npmignore: -------------------------------------------------------------------------------- 1 | .tern-* 2 | /rollup.config.* 3 | /src 4 | -------------------------------------------------------------------------------- /acorn-walk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.1.0 (2021-04-24) 2 | 3 | ### New features 4 | 5 | Support node types for class fields and private methods. 6 | 7 | ## 8.0.2 (2021-01-25) 8 | 9 | ### Bug fixes 10 | 11 | Adjust package.json to work with Node 12.16.0 and 13.0-13.6. 12 | 13 | ## 8.0.0 (2021-01-05) 14 | 15 | ### Bug fixes 16 | 17 | Fix a bug where `full` and `fullAncestor` would skip nodes with overridden types. 18 | 19 | ## 8.0.0 (2020-08-12) 20 | 21 | ### New features 22 | 23 | The package can now be loaded directly as an ECMAScript module in node 13+. 24 | 25 | ## 7.2.0 (2020-06-17) 26 | 27 | ### New features 28 | 29 | Support optional chaining and nullish coalescing. 30 | 31 | Support `import.meta`. 32 | 33 | Add support for `export * as ns from "source"`. 34 | 35 | ## 7.1.1 (2020-02-13) 36 | 37 | ### Bug fixes 38 | 39 | Clean up the type definitions to actually work well with the main parser. 40 | 41 | ## 7.1.0 (2020-02-11) 42 | 43 | ### New features 44 | 45 | Add a TypeScript definition file for the library. 46 | 47 | ## 7.0.0 (2017-08-12) 48 | 49 | ### New features 50 | 51 | Support walking `ImportExpression` nodes. 52 | 53 | ## 6.2.0 (2017-07-04) 54 | 55 | ### New features 56 | 57 | Add support for `Import` nodes. 58 | 59 | ## 6.1.0 (2018-09-28) 60 | 61 | ### New features 62 | 63 | The walker now walks `TemplateElement` nodes. 64 | 65 | ## 6.0.1 (2018-09-14) 66 | 67 | ### Bug fixes 68 | 69 | Fix bad "main" field in package.json. 70 | 71 | ## 6.0.0 (2018-09-14) 72 | 73 | ### Breaking changes 74 | 75 | This is now a separate package, `acorn-walk`, rather than part of the main `acorn` package. 76 | 77 | The `ScopeBody` and `ScopeExpression` meta-node-types are no longer supported. 78 | 79 | ## 5.7.1 (2018-06-15) 80 | 81 | ### Bug fixes 82 | 83 | Make sure the walker and bin files are rebuilt on release (the previous release didn't get the up-to-date versions). 84 | 85 | ## 5.7.0 (2018-06-15) 86 | 87 | ### Bug fixes 88 | 89 | Fix crash in walker when walking a binding-less catch node. 90 | 91 | ## 5.6.2 (2018-06-05) 92 | 93 | ### Bug fixes 94 | 95 | In the walker, go back to allowing the `baseVisitor` argument to be null to default to the default base everywhere. 96 | 97 | ## 5.6.1 (2018-06-01) 98 | 99 | ### Bug fixes 100 | 101 | Fix regression when passing `null` as fourth argument to `walk.recursive`. 102 | 103 | ## 5.6.0 (2018-05-31) 104 | 105 | ### Bug fixes 106 | 107 | Fix a bug in the walker that caused a crash when walking an object pattern spread. 108 | 109 | ## 5.5.1 (2018-03-06) 110 | 111 | ### Bug fixes 112 | 113 | Fix regression in walker causing property values in object patterns to be walked as expressions. 114 | 115 | ## 5.5.0 (2018-02-27) 116 | 117 | ### Bug fixes 118 | 119 | Support object spread in the AST walker. 120 | 121 | ## 5.4.1 (2018-02-02) 122 | 123 | ### Bug fixes 124 | 125 | 5.4.0 somehow accidentally included an old version of walk.js. 126 | 127 | ## 5.2.0 (2017-10-30) 128 | 129 | ### Bug fixes 130 | 131 | The `full` and `fullAncestor` walkers no longer visit nodes multiple times. 132 | 133 | ## 5.1.0 (2017-07-05) 134 | 135 | ### New features 136 | 137 | New walker functions `full` and `fullAncestor`. 138 | 139 | ## 3.2.0 (2016-06-07) 140 | 141 | ### New features 142 | 143 | Make it possible to use `visit.ancestor` with a walk state. 144 | 145 | ## 3.1.0 (2016-04-18) 146 | 147 | ### New features 148 | 149 | The walker now allows defining handlers for `CatchClause` nodes. 150 | 151 | ## 2.5.2 (2015-10-27) 152 | 153 | ### Fixes 154 | 155 | Fix bug where the walker walked an exported `let` statement as an expression. 156 | -------------------------------------------------------------------------------- /acorn-walk/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2012-2020 by various contributors (see AUTHORS) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /acorn-walk/README.md: -------------------------------------------------------------------------------- 1 | # Acorn AST walker 2 | 3 | An abstract syntax tree walker for the 4 | [ESTree](https://github.com/estree/estree) format. 5 | 6 | ## Community 7 | 8 | Acorn is open source software released under an 9 | [MIT license](https://github.com/acornjs/acorn/blob/master/acorn-walk/LICENSE). 10 | 11 | You are welcome to 12 | [report bugs](https://github.com/acornjs/acorn/issues) or create pull 13 | requests on [github](https://github.com/acornjs/acorn). For questions 14 | and discussion, please use the 15 | [Tern discussion forum](https://discuss.ternjs.net). 16 | 17 | ## Installation 18 | 19 | The easiest way to install acorn is from [`npm`](https://www.npmjs.com/): 20 | 21 | ```sh 22 | npm install acorn-walk 23 | ``` 24 | 25 | Alternately, you can download the source and build acorn yourself: 26 | 27 | ```sh 28 | git clone https://github.com/acornjs/acorn.git 29 | cd acorn 30 | npm install 31 | ``` 32 | 33 | ## Interface 34 | 35 | An algorithm for recursing through a syntax tree is stored as an 36 | object, with a property for each tree node type holding a function 37 | that will recurse through such a node. There are several ways to run 38 | such a walker. 39 | 40 | **simple**`(node, visitors, base, state)` does a 'simple' walk over a 41 | tree. `node` should be the AST node to walk, and `visitors` an object 42 | with properties whose names correspond to node types in the [ESTree 43 | spec](https://github.com/estree/estree). The properties should contain 44 | functions that will be called with the node object and, if applicable 45 | the state at that point. The last two arguments are optional. `base` 46 | is a walker algorithm, and `state` is a start state. The default 47 | walker will simply visit all statements and expressions and not 48 | produce a meaningful state. (An example of a use of state is to track 49 | scope at each point in the tree.) 50 | 51 | ```js 52 | const acorn = require("acorn") 53 | const walk = require("acorn-walk") 54 | 55 | walk.simple(acorn.parse("let x = 10"), { 56 | Literal(node) { 57 | console.log(`Found a literal: ${node.value}`) 58 | } 59 | }) 60 | ``` 61 | 62 | **ancestor**`(node, visitors, base, state)` does a 'simple' walk over 63 | a tree, building up an array of ancestor nodes (including the current node) 64 | and passing the array to the callbacks as a third parameter. 65 | 66 | ```js 67 | const acorn = require("acorn") 68 | const walk = require("acorn-walk") 69 | 70 | walk.ancestor(acorn.parse("foo('hi')"), { 71 | Literal(_, ancestors) { 72 | console.log("This literal's ancestors are:", ancestors.map(n => n.type)) 73 | } 74 | }) 75 | ``` 76 | 77 | **recursive**`(node, state, functions, base)` does a 'recursive' 78 | walk, where the walker functions are responsible for continuing the 79 | walk on the child nodes of their target node. `state` is the start 80 | state, and `functions` should contain an object that maps node types 81 | to walker functions. Such functions are called with `(node, state, c)` 82 | arguments, and can cause the walk to continue on a sub-node by calling 83 | the `c` argument on it with `(node, state)` arguments. The optional 84 | `base` argument provides the fallback walker functions for node types 85 | that aren't handled in the `functions` object. If not given, the 86 | default walkers will be used. 87 | 88 | **make**`(functions, base)` builds a new walker object by using the 89 | walker functions in `functions` and filling in the missing ones by 90 | taking defaults from `base`. 91 | 92 | **full**`(node, callback, base, state)` does a 'full' walk over a 93 | tree, calling the callback with the arguments (node, state, type) for 94 | each node 95 | 96 | **fullAncestor**`(node, callback, base, state)` does a 'full' walk 97 | over a tree, building up an array of ancestor nodes (including the 98 | current node) and passing the array to the callbacks as a third 99 | parameter. 100 | 101 | ```js 102 | const acorn = require("acorn") 103 | const walk = require("acorn-walk") 104 | 105 | walk.full(acorn.parse("1 + 1"), node => { 106 | console.log(`There's a ${node.type} node at ${node.ch}`) 107 | }) 108 | ``` 109 | 110 | **findNodeAt**`(node, start, end, test, base, state)` tries to locate 111 | a node in a tree at the given start and/or end offsets, which 112 | satisfies the predicate `test`. `start` and `end` can be either `null` 113 | (as wildcard) or a number. `test` may be a string (indicating a node 114 | type) or a function that takes `(nodeType, node)` arguments and 115 | returns a boolean indicating whether this node is interesting. `base` 116 | and `state` are optional, and can be used to specify a custom walker. 117 | Nodes are tested from inner to outer, so if two nodes match the 118 | boundaries, the inner one will be preferred. 119 | 120 | **findNodeAround**`(node, pos, test, base, state)` is a lot like 121 | `findNodeAt`, but will match any node that exists 'around' (spanning) 122 | the given position. 123 | 124 | **findNodeAfter**`(node, pos, test, base, state)` is similar to 125 | `findNodeAround`, but will match all nodes *after* the given position 126 | (testing outer nodes before inner nodes). 127 | -------------------------------------------------------------------------------- /acorn-walk/dist/walk.d.ts: -------------------------------------------------------------------------------- 1 | import {Node} from 'acorn'; 2 | 3 | declare module "acorn-walk" { 4 | type FullWalkerCallback = ( 5 | node: Node, 6 | state: TState, 7 | type: string 8 | ) => void; 9 | 10 | type FullAncestorWalkerCallback = ( 11 | node: Node, 12 | state: TState | Node[], 13 | ancestors: Node[], 14 | type: string 15 | ) => void; 16 | type WalkerCallback = (node: Node, state: TState) => void; 17 | 18 | type SimpleWalkerFn = ( 19 | node: Node, 20 | state: TState 21 | ) => void; 22 | 23 | type AncestorWalkerFn = ( 24 | node: Node, 25 | state: TState| Node[], 26 | ancestors: Node[] 27 | ) => void; 28 | 29 | type RecursiveWalkerFn = ( 30 | node: Node, 31 | state: TState, 32 | callback: WalkerCallback 33 | ) => void; 34 | 35 | type SimpleVisitors = { 36 | [type: string]: SimpleWalkerFn 37 | }; 38 | 39 | type AncestorVisitors = { 40 | [type: string]: AncestorWalkerFn 41 | }; 42 | 43 | type RecursiveVisitors = { 44 | [type: string]: RecursiveWalkerFn 45 | }; 46 | 47 | type FindPredicate = (type: string, node: Node) => boolean; 48 | 49 | interface Found { 50 | node: Node, 51 | state: TState 52 | } 53 | 54 | export function simple( 55 | node: Node, 56 | visitors: SimpleVisitors, 57 | base?: RecursiveVisitors, 58 | state?: TState 59 | ): void; 60 | 61 | export function ancestor( 62 | node: Node, 63 | visitors: AncestorVisitors, 64 | base?: RecursiveVisitors, 65 | state?: TState 66 | ): void; 67 | 68 | export function recursive( 69 | node: Node, 70 | state: TState, 71 | functions: RecursiveVisitors, 72 | base?: RecursiveVisitors 73 | ): void; 74 | 75 | export function full( 76 | node: Node, 77 | callback: FullWalkerCallback, 78 | base?: RecursiveVisitors, 79 | state?: TState 80 | ): void; 81 | 82 | export function fullAncestor( 83 | node: Node, 84 | callback: FullAncestorWalkerCallback, 85 | base?: RecursiveVisitors, 86 | state?: TState 87 | ): void; 88 | 89 | export function make( 90 | functions: RecursiveVisitors, 91 | base?: RecursiveVisitors 92 | ): RecursiveVisitors; 93 | 94 | export function findNodeAt( 95 | node: Node, 96 | start: number | undefined, 97 | end?: number | undefined, 98 | type?: FindPredicate | string, 99 | base?: RecursiveVisitors, 100 | state?: TState 101 | ): Found | undefined; 102 | 103 | export function findNodeAround( 104 | node: Node, 105 | start: number | undefined, 106 | type?: FindPredicate | string, 107 | base?: RecursiveVisitors, 108 | state?: TState 109 | ): Found | undefined; 110 | 111 | export const findNodeAfter: typeof findNodeAround; 112 | 113 | export const base: RecursiveVisitors; 114 | } 115 | -------------------------------------------------------------------------------- /acorn-walk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acorn-walk", 3 | "description": "ECMAScript (ESTree) AST walker", 4 | "homepage": "https://github.com/acornjs/acorn", 5 | "main": "dist/walk.js", 6 | "types": "dist/walk.d.ts", 7 | "module": "dist/walk.mjs", 8 | "exports": { 9 | ".": [ 10 | { 11 | "import": "./dist/walk.mjs", 12 | "require": "./dist/walk.js", 13 | "default": "./dist/walk.js" 14 | }, 15 | "./dist/walk.js" 16 | ], 17 | "./package.json": "./package.json" 18 | }, 19 | "version": "8.1.0", 20 | "engines": {"node": ">=0.4.0"}, 21 | "maintainers": [ 22 | { 23 | "name": "Marijn Haverbeke", 24 | "email": "marijnh@gmail.com", 25 | "web": "https://marijnhaverbeke.nl" 26 | }, 27 | { 28 | "name": "Ingvar Stepanyan", 29 | "email": "me@rreverser.com", 30 | "web": "https://rreverser.com/" 31 | }, 32 | { 33 | "name": "Adrian Heine", 34 | "web": "http://adrianheine.de" 35 | } 36 | ], 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/acornjs/acorn.git" 40 | }, 41 | "scripts": { 42 | "prepare": "cd ..; npm run build:walk" 43 | }, 44 | "license": "MIT" 45 | } 46 | -------------------------------------------------------------------------------- /acorn-walk/rollup.config.js: -------------------------------------------------------------------------------- 1 | import buble from "rollup-plugin-buble" 2 | 3 | export default { 4 | input: "acorn-walk/src/index.js", 5 | output: [ 6 | { 7 | file: "acorn-walk/dist/walk.js", 8 | format: "umd", 9 | name: "acorn.walk" 10 | }, 11 | { 12 | file: "acorn-walk/dist/walk.mjs", 13 | format: "es" 14 | } 15 | ], 16 | plugins: [ 17 | buble({transforms: {dangerousForOf: true}}) 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /acorn-walk/src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "standard", 5 | "plugin:import/errors", 6 | "plugin:import/warnings" 7 | ], 8 | "rules": { 9 | "curly": "off", 10 | "eqeqeq": ["error", "always", { "null": "ignore" }], 11 | "indent": ["error", 2, { "SwitchCase": 0, "VariableDeclarator": 2, "CallExpression": { "arguments": "off" } }], 12 | "new-parens": "off", 13 | "no-case-declarations": "off", 14 | "no-cond-assign": "off", 15 | "no-fallthrough": "off", 16 | "no-labels": "off", 17 | "no-mixed-operators": "off", 18 | "no-return-assign": "off", 19 | "no-unused-labels": "error", 20 | "no-var": "error", 21 | "object-curly-spacing": ["error", "never"], 22 | "one-var": "off", 23 | "quotes": ["error", "double"], 24 | "semi-spacing": "off", 25 | "space-before-function-paren": ["error", "never"] 26 | }, 27 | "globals": { 28 | "Packages": false 29 | }, 30 | "plugins": [ 31 | "import" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /acorn-walk/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /acorn/.npmignore: -------------------------------------------------------------------------------- 1 | .tern-* 2 | /rollup.config.* 3 | /src 4 | -------------------------------------------------------------------------------- /acorn/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2012-2020 by various contributors (see AUTHORS) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /acorn/README.md: -------------------------------------------------------------------------------- 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). For questions 13 | and discussion, please use the 14 | [Tern discussion forum](https://discuss.ternjs.net). 15 | 16 | ## Installation 17 | 18 | The easiest way to install acorn is from [`npm`](https://www.npmjs.com/): 19 | 20 | ```sh 21 | npm install acorn 22 | ``` 23 | 24 | Alternately, you can download the source and build acorn yourself: 25 | 26 | ```sh 27 | git clone https://github.com/acornjs/acorn.git 28 | cd acorn 29 | npm install 30 | ``` 31 | 32 | ## Interface 33 | 34 | **parse**`(input, options)` is the main interface to the library. The 35 | `input` parameter is a string, `options` must be an object setting 36 | some of the options listed below. The return value will be an abstract 37 | syntax tree object as specified by the [ESTree 38 | spec](https://github.com/estree/estree). 39 | 40 | ```javascript 41 | let acorn = require("acorn"); 42 | console.log(acorn.parse("1 + 1", {ecmaVersion: 2020})); 43 | ``` 44 | 45 | When encountering a syntax error, the parser will raise a 46 | `SyntaxError` object with a meaningful message. The error object will 47 | have a `pos` property that indicates the string offset at which the 48 | error occurred, and a `loc` object that contains a `{line, column}` 49 | object referring to that same position. 50 | 51 | Options are provided by in a second argument, which should be an 52 | object containing any of these fields (only `ecmaVersion` is 53 | required): 54 | 55 | - **ecmaVersion**: Indicates the ECMAScript version to parse. Must be 56 | either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 (2019), 57 | 11 (2020), 12 (2021, partial support), 13 (2022, partial support) 58 | or `"latest"` (the latest the library supports). This influences 59 | support for strict mode, the set of reserved words, and support 60 | for new syntax features. 61 | 62 | **NOTE**: Only 'stage 4' (finalized) ECMAScript features are being 63 | implemented by Acorn. Other proposed new features must be 64 | implemented through plugins. 65 | 66 | - **sourceType**: Indicate the mode the code should be parsed in. Can be 67 | either `"script"` or `"module"`. This influences global strict mode 68 | and parsing of `import` and `export` declarations. 69 | 70 | **NOTE**: If set to `"module"`, then static `import` / `export` syntax 71 | will be valid, even if `ecmaVersion` is less than 6. 72 | 73 | - **onInsertedSemicolon**: If given a callback, that callback will be 74 | called whenever a missing semicolon is inserted by the parser. The 75 | callback will be given the character offset of the point where the 76 | semicolon is inserted as argument, and if `locations` is on, also a 77 | `{line, column}` object representing this position. 78 | 79 | - **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing 80 | commas. 81 | 82 | - **allowReserved**: If `false`, using a reserved word will generate 83 | an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher 84 | versions. When given the value `"never"`, reserved words and 85 | keywords can also not be used as property names (as in Internet 86 | Explorer's old parser). 87 | 88 | - **allowReturnOutsideFunction**: By default, a return statement at 89 | the top level raises an error. Set this to `true` to accept such 90 | code. 91 | 92 | - **allowImportExportEverywhere**: By default, `import` and `export` 93 | declarations can only appear at a program's top level. Setting this 94 | option to `true` allows them anywhere where a statement is allowed, 95 | and also allows `import.meta` expressions to appear in scripts 96 | (when `sourceType` is not `"module"`). 97 | 98 | - **allowAwaitOutsideFunction**: If `false`, `await` expressions can 99 | only appear inside `async` functions. Defaults to `true` for 100 | `ecmaVersion` 2022 and later, `false` for lower versions. Setting this option to 101 | `true` allows to have top-level `await` expressions. They are 102 | still not allowed in non-`async` functions, though. 103 | 104 | - **allowSuperOutsideMethod**: By default, `super` outside a method 105 | raises an error. Set this to `true` to accept such code. 106 | 107 | - **allowHashBang**: When this is enabled (off by default), if the 108 | code starts with the characters `#!` (as in a shellscript), the 109 | first line will be treated as a comment. 110 | 111 | - **locations**: When `true`, each node has a `loc` object attached 112 | with `start` and `end` subobjects, each of which contains the 113 | one-based line and zero-based column numbers in `{line, column}` 114 | form. Default is `false`. 115 | 116 | - **onToken**: If a function is passed for this option, each found 117 | token will be passed in same format as tokens returned from 118 | `tokenizer().getToken()`. 119 | 120 | If array is passed, each found token is pushed to it. 121 | 122 | Note that you are not allowed to call the parser from the 123 | callback—that will corrupt its internal state. 124 | 125 | - **onComment**: If a function is passed for this option, whenever a 126 | comment is encountered the function will be called with the 127 | following parameters: 128 | 129 | - `block`: `true` if the comment is a block comment, false if it 130 | is a line comment. 131 | - `text`: The content of the comment. 132 | - `start`: Character offset of the start of the comment. 133 | - `end`: Character offset of the end of the comment. 134 | 135 | When the `locations` options is on, the `{line, column}` locations 136 | of the comment’s start and end are passed as two additional 137 | parameters. 138 | 139 | If array is passed for this option, each found comment is pushed 140 | to it as object in Esprima format: 141 | 142 | ```javascript 143 | { 144 | "type": "Line" | "Block", 145 | "value": "comment text", 146 | "start": Number, 147 | "end": Number, 148 | // If `locations` option is on: 149 | "loc": { 150 | "start": {line: Number, column: Number} 151 | "end": {line: Number, column: Number} 152 | }, 153 | // If `ranges` option is on: 154 | "range": [Number, Number] 155 | } 156 | ``` 157 | 158 | Note that you are not allowed to call the parser from the 159 | callback—that will corrupt its internal state. 160 | 161 | - **ranges**: Nodes have their start and end characters offsets 162 | recorded in `start` and `end` properties (directly on the node, 163 | rather than the `loc` object, which holds line/column data. To also 164 | add a 165 | [semi-standardized](https://bugzilla.mozilla.org/show_bug.cgi?id=745678) 166 | `range` property holding a `[start, end]` array with the same 167 | numbers, set the `ranges` option to `true`. 168 | 169 | - **program**: It is possible to parse multiple files into a single 170 | AST by passing the tree produced by parsing the first file as the 171 | `program` option in subsequent parses. This will add the toplevel 172 | forms of the parsed file to the "Program" (top) node of an existing 173 | parse tree. 174 | 175 | - **sourceFile**: When the `locations` option is `true`, you can pass 176 | this option to add a `source` attribute in every node’s `loc` 177 | object. Note that the contents of this option are not examined or 178 | processed in any way; you are free to use whatever format you 179 | choose. 180 | 181 | - **directSourceFile**: Like `sourceFile`, but a `sourceFile` property 182 | will be added (regardless of the `location` option) directly to the 183 | nodes, rather than the `loc` object. 184 | 185 | - **preserveParens**: If this option is `true`, parenthesized expressions 186 | are represented by (non-standard) `ParenthesizedExpression` nodes 187 | that have a single `expression` property containing the expression 188 | inside parentheses. 189 | 190 | **parseExpressionAt**`(input, offset, options)` will parse a single 191 | expression in a string, and return its AST. It will not complain if 192 | there is more of the string left after the expression. 193 | 194 | **tokenizer**`(input, options)` returns an object with a `getToken` 195 | method that can be called repeatedly to get the next token, a `{start, 196 | end, type, value}` object (with added `loc` property when the 197 | `locations` option is enabled and `range` property when the `ranges` 198 | option is enabled). When the token's type is `tokTypes.eof`, you 199 | should stop calling the method, since it will keep returning that same 200 | token forever. 201 | 202 | In ES6 environment, returned result can be used as any other 203 | protocol-compliant iterable: 204 | 205 | ```javascript 206 | for (let token of acorn.tokenizer(str)) { 207 | // iterate over the tokens 208 | } 209 | 210 | // transform code to array of tokens: 211 | var tokens = [...acorn.tokenizer(str)]; 212 | ``` 213 | 214 | **tokTypes** holds an object mapping names to the token type objects 215 | that end up in the `type` properties of tokens. 216 | 217 | **getLineInfo**`(input, offset)` can be used to get a `{line, 218 | column}` object for a given program string and offset. 219 | 220 | ### The `Parser` class 221 | 222 | Instances of the **`Parser`** class contain all the state and logic 223 | that drives a parse. It has static methods `parse`, 224 | `parseExpressionAt`, and `tokenizer` that match the top-level 225 | functions by the same name. 226 | 227 | When extending the parser with plugins, you need to call these methods 228 | on the extended version of the class. To extend a parser with plugins, 229 | you can use its static `extend` method. 230 | 231 | ```javascript 232 | var acorn = require("acorn"); 233 | var jsx = require("acorn-jsx"); 234 | var JSXParser = acorn.Parser.extend(jsx()); 235 | JSXParser.parse("foo()", {ecmaVersion: 2020}); 236 | ``` 237 | 238 | The `extend` method takes any number of plugin values, and returns a 239 | new `Parser` class that includes the extra parser logic provided by 240 | the plugins. 241 | 242 | ## Command line interface 243 | 244 | The `bin/acorn` utility can be used to parse a file from the command 245 | line. It accepts as arguments its input file and the following 246 | options: 247 | 248 | - `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version 249 | to parse. Default is version 9. 250 | 251 | - `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise. 252 | 253 | - `--locations`: Attaches a "loc" object to each node with "start" and 254 | "end" subobjects, each of which contains the one-based line and 255 | zero-based column numbers in `{line, column}` form. 256 | 257 | - `--allow-hash-bang`: If the code starts with the characters #! (as 258 | in a shellscript), the first line will be treated as a comment. 259 | 260 | - `--allow-await-outside-function`: Allows top-level `await` expressions. 261 | See the `allowAwaitOutsideFunction` option for more information. 262 | 263 | - `--compact`: No whitespace is used in the AST output. 264 | 265 | - `--silent`: Do not output the AST, just return the exit status. 266 | 267 | - `--help`: Print the usage information and quit. 268 | 269 | The utility spits out the syntax tree as JSON data. 270 | 271 | ## Existing plugins 272 | 273 | - [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx) 274 | 275 | Plugins for ECMAScript proposals: 276 | 277 | - [`acorn-stage3`](https://github.com/acornjs/acorn-stage3): Parse most stage 3 proposals, bundling: 278 | - [`acorn-class-fields`](https://github.com/acornjs/acorn-class-fields): Parse [class fields proposal](https://github.com/tc39/proposal-class-fields) 279 | - [`acorn-import-meta`](https://github.com/acornjs/acorn-import-meta): Parse [import.meta proposal](https://github.com/tc39/proposal-import-meta) 280 | - [`acorn-private-methods`](https://github.com/acornjs/acorn-private-methods): parse [private methods, getters and setters proposal](https://github.com/tc39/proposal-private-methods)n 281 | -------------------------------------------------------------------------------- /acorn/bin/acorn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | require('../dist/bin.js'); 5 | -------------------------------------------------------------------------------- /acorn/dist/acorn.d.ts: -------------------------------------------------------------------------------- 1 | export as namespace acorn 2 | export = acorn 3 | 4 | declare namespace acorn { 5 | function parse(input: string, options: Options): Node 6 | 7 | function parseExpressionAt(input: string, pos: number, options: Options): Node 8 | 9 | function tokenizer(input: string, options: Options): { 10 | getToken(): Token 11 | [Symbol.iterator](): Iterator 12 | } 13 | 14 | interface Options { 15 | ecmaVersion: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 'latest' 16 | sourceType?: 'script' | 'module' 17 | onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void 18 | onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void 19 | allowReserved?: boolean | 'never' 20 | allowReturnOutsideFunction?: boolean 21 | allowImportExportEverywhere?: boolean 22 | allowAwaitOutsideFunction?: boolean 23 | allowSuperOutsideMethod?: boolean 24 | allowHashBang?: boolean 25 | locations?: boolean 26 | onToken?: ((token: Token) => any) | Token[] 27 | onComment?: (( 28 | isBlock: boolean, text: string, start: number, end: number, startLoc?: Position, 29 | endLoc?: Position 30 | ) => void) | Comment[] 31 | ranges?: boolean 32 | program?: Node 33 | sourceFile?: string 34 | directSourceFile?: string 35 | preserveParens?: boolean 36 | } 37 | 38 | class Parser { 39 | constructor(options: Options, input: string, startPos?: number) 40 | parse(this: Parser): Node 41 | static parse(this: typeof Parser, input: string, options: Options): Node 42 | static parseExpressionAt(this: typeof Parser, input: string, pos: number, options: Options): Node 43 | static tokenizer(this: typeof Parser, input: string, options: Options): { 44 | getToken(): Token 45 | [Symbol.iterator](): Iterator 46 | } 47 | static extend(this: typeof Parser, ...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser 48 | } 49 | 50 | interface Position { line: number; column: number; offset: number } 51 | 52 | const defaultOptions: Options 53 | 54 | function getLineInfo(input: string, offset: number): Position 55 | 56 | class SourceLocation { 57 | start: Position 58 | end: Position 59 | source?: string | null 60 | constructor(p: Parser, start: Position, end: Position) 61 | } 62 | 63 | class Node { 64 | type: string 65 | start: number 66 | end: number 67 | loc?: SourceLocation 68 | sourceFile?: string 69 | range?: [number, number] 70 | constructor(parser: Parser, pos: number, loc?: SourceLocation) 71 | } 72 | 73 | class TokenType { 74 | label: string 75 | keyword: string 76 | beforeExpr: boolean 77 | startsExpr: boolean 78 | isLoop: boolean 79 | isAssign: boolean 80 | prefix: boolean 81 | postfix: boolean 82 | binop: number 83 | updateContext?: (prevType: TokenType) => void 84 | constructor(label: string, conf?: any) 85 | } 86 | 87 | const tokTypes: { 88 | num: TokenType 89 | regexp: TokenType 90 | string: TokenType 91 | name: TokenType 92 | privateId: TokenType 93 | eof: TokenType 94 | bracketL: TokenType 95 | bracketR: TokenType 96 | braceL: TokenType 97 | braceR: TokenType 98 | parenL: TokenType 99 | parenR: TokenType 100 | comma: TokenType 101 | semi: TokenType 102 | colon: TokenType 103 | dot: TokenType 104 | question: TokenType 105 | arrow: TokenType 106 | template: TokenType 107 | ellipsis: TokenType 108 | backQuote: TokenType 109 | dollarBraceL: TokenType 110 | eq: TokenType 111 | assign: TokenType 112 | incDec: TokenType 113 | prefix: TokenType 114 | logicalOR: TokenType 115 | logicalAND: TokenType 116 | bitwiseOR: TokenType 117 | bitwiseXOR: TokenType 118 | bitwiseAND: TokenType 119 | equality: TokenType 120 | relational: TokenType 121 | bitShift: TokenType 122 | plusMin: TokenType 123 | modulo: TokenType 124 | star: TokenType 125 | slash: TokenType 126 | starstar: TokenType 127 | _break: TokenType 128 | _case: TokenType 129 | _catch: TokenType 130 | _continue: TokenType 131 | _debugger: TokenType 132 | _default: TokenType 133 | _do: TokenType 134 | _else: TokenType 135 | _finally: TokenType 136 | _for: TokenType 137 | _function: TokenType 138 | _if: TokenType 139 | _return: TokenType 140 | _switch: TokenType 141 | _throw: TokenType 142 | _try: TokenType 143 | _var: TokenType 144 | _const: TokenType 145 | _while: TokenType 146 | _with: TokenType 147 | _new: TokenType 148 | _this: TokenType 149 | _super: TokenType 150 | _class: TokenType 151 | _extends: TokenType 152 | _export: TokenType 153 | _import: TokenType 154 | _null: TokenType 155 | _true: TokenType 156 | _false: TokenType 157 | _in: TokenType 158 | _instanceof: TokenType 159 | _typeof: TokenType 160 | _void: TokenType 161 | _delete: TokenType 162 | } 163 | 164 | class TokContext { 165 | constructor(token: string, isExpr: boolean, preserveSpace: boolean, override?: (p: Parser) => void) 166 | } 167 | 168 | const tokContexts: { 169 | b_stat: TokContext 170 | b_expr: TokContext 171 | b_tmpl: TokContext 172 | p_stat: TokContext 173 | p_expr: TokContext 174 | q_tmpl: TokContext 175 | f_expr: TokContext 176 | } 177 | 178 | function isIdentifierStart(code: number, astral?: boolean): boolean 179 | 180 | function isIdentifierChar(code: number, astral?: boolean): boolean 181 | 182 | interface AbstractToken { 183 | } 184 | 185 | interface Comment extends AbstractToken { 186 | type: string 187 | value: string 188 | start: number 189 | end: number 190 | loc?: SourceLocation 191 | range?: [number, number] 192 | } 193 | 194 | class Token { 195 | type: TokenType 196 | value: any 197 | start: number 198 | end: number 199 | loc?: SourceLocation 200 | range?: [number, number] 201 | constructor(p: Parser) 202 | } 203 | 204 | function isNewLine(code: number): boolean 205 | 206 | const lineBreak: RegExp 207 | 208 | const lineBreakG: RegExp 209 | 210 | const version: string 211 | } 212 | -------------------------------------------------------------------------------- /acorn/dist/acorn.mjs.d.ts: -------------------------------------------------------------------------------- 1 | import * as acorn from "./acorn"; 2 | export = acorn; -------------------------------------------------------------------------------- /acorn/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acorn", 3 | "description": "ECMAScript parser", 4 | "homepage": "https://github.com/acornjs/acorn", 5 | "main": "dist/acorn.js", 6 | "types": "dist/acorn.d.ts", 7 | "module": "dist/acorn.mjs", 8 | "exports": { 9 | ".": [ 10 | { 11 | "import": "./dist/acorn.mjs", 12 | "require": "./dist/acorn.js", 13 | "default": "./dist/acorn.js" 14 | }, 15 | "./dist/acorn.js" 16 | ], 17 | "./package.json": "./package.json" 18 | }, 19 | "version": "8.4.0", 20 | "engines": {"node": ">=0.4.0"}, 21 | "maintainers": [ 22 | { 23 | "name": "Marijn Haverbeke", 24 | "email": "marijnh@gmail.com", 25 | "web": "https://marijnhaverbeke.nl" 26 | }, 27 | { 28 | "name": "Ingvar Stepanyan", 29 | "email": "me@rreverser.com", 30 | "web": "https://rreverser.com/" 31 | }, 32 | { 33 | "name": "Adrian Heine", 34 | "web": "http://adrianheine.de" 35 | } 36 | ], 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/acornjs/acorn.git" 40 | }, 41 | "license": "MIT", 42 | "scripts": { 43 | "prepare": "cd ..; npm run build:main && npm run build:bin" 44 | }, 45 | "bin": {"acorn": "./bin/acorn"} 46 | } 47 | -------------------------------------------------------------------------------- /acorn/rollup.config.bin.js: -------------------------------------------------------------------------------- 1 | import buble from "rollup-plugin-buble" 2 | 3 | export default { 4 | input: "acorn/src/bin/acorn.js", 5 | output: { 6 | file: "acorn/dist/bin.js", 7 | format: "cjs", 8 | paths: {acorn: "./acorn.js"}, 9 | external: ["fs", "path", "acorn"] 10 | }, 11 | plugins: [buble()] 12 | } 13 | -------------------------------------------------------------------------------- /acorn/rollup.config.js: -------------------------------------------------------------------------------- 1 | import buble from "rollup-plugin-buble" 2 | 3 | export default { 4 | input: "acorn/src/index.js", 5 | output: [ 6 | { 7 | file: "acorn/dist/acorn.js", 8 | format: "umd", 9 | name: "acorn" 10 | }, 11 | { 12 | file: "acorn/dist/acorn.mjs", 13 | format: "es" 14 | } 15 | ], 16 | plugins: [ 17 | buble({transforms: {dangerousForOf: true}}) 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /acorn/src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "standard", 5 | "plugin:import/errors", 6 | "plugin:import/warnings" 7 | ], 8 | "rules": { 9 | "curly": "off", 10 | "eqeqeq": ["error", "always", { "null": "ignore" }], 11 | "indent": ["error", 2, { "SwitchCase": 0, "VariableDeclarator": 2, "CallExpression": { "arguments": "off" } }], 12 | "new-parens": "off", 13 | "no-case-declarations": "off", 14 | "no-cond-assign": "off", 15 | "no-console": ["error", { allow: ["warn", "error"] }], 16 | "no-fallthrough": "off", 17 | "no-labels": "off", 18 | "no-mixed-operators": "off", 19 | "no-return-assign": "off", 20 | "no-unused-labels": "error", 21 | "no-var": "error", 22 | "object-curly-spacing": ["error", "never"], 23 | "one-var": "off", 24 | "quotes": ["error", "double"], 25 | "semi-spacing": "off", 26 | "space-before-function-paren": ["error", "never"] 27 | }, 28 | "globals": { 29 | "Packages": false, 30 | "BigInt": false 31 | }, 32 | "plugins": [ 33 | "import" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /acorn/src/bin/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.eslintrc", 3 | "rules": { 4 | "no-console": "off" 5 | } 6 | } -------------------------------------------------------------------------------- /acorn/src/bin/acorn.js: -------------------------------------------------------------------------------- 1 | import {basename} from "path" 2 | import {readFileSync as readFile} from "fs" 3 | import * as acorn from "acorn" 4 | 5 | let infile, forceFile, silent = false, compact = false, tokenize = false 6 | const options = {} 7 | 8 | function help(status) { 9 | const print = (status === 0) ? console.log : console.error 10 | print("usage: " + basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|...|--ecma2015|--ecma2016|--ecma2017|--ecma2018|...]") 11 | print(" [--tokenize] [--locations] [---allow-hash-bang] [--allow-await-outside-function] [--compact] [--silent] [--module] [--help] [--] [infile]") 12 | process.exit(status) 13 | } 14 | 15 | for (let i = 2; i < process.argv.length; ++i) { 16 | const arg = process.argv[i] 17 | if ((arg === "-" || arg[0] !== "-") && !infile) infile = arg 18 | else if (arg === "--" && !infile && i + 2 === process.argv.length) forceFile = infile = process.argv[++i] 19 | else if (arg === "--locations") options.locations = true 20 | else if (arg === "--allow-hash-bang") options.allowHashBang = true 21 | else if (arg === "--allow-await-outside-function") options.allowAwaitOutsideFunction = true 22 | else if (arg === "--silent") silent = true 23 | else if (arg === "--compact") compact = true 24 | else if (arg === "--help") help(0) 25 | else if (arg === "--tokenize") tokenize = true 26 | else if (arg === "--module") options.sourceType = "module" 27 | else { 28 | let match = arg.match(/^--ecma(\d+)$/) 29 | if (match) 30 | options.ecmaVersion = +match[1] 31 | else 32 | help(1) 33 | } 34 | } 35 | 36 | function run(code) { 37 | let result 38 | try { 39 | if (!tokenize) { 40 | result = acorn.parse(code, options) 41 | } else { 42 | result = [] 43 | let tokenizer = acorn.tokenizer(code, options), token 44 | do { 45 | token = tokenizer.getToken() 46 | result.push(token) 47 | } while (token.type !== acorn.tokTypes.eof) 48 | } 49 | } catch (e) { 50 | console.error(infile && infile !== "-" ? e.message.replace(/\(\d+:\d+\)$/, m => m.slice(0, 1) + infile + " " + m.slice(1)) : e.message) 51 | process.exit(1) 52 | } 53 | if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)) 54 | } 55 | 56 | if (forceFile || infile && infile !== "-") { 57 | run(readFile(infile, "utf8")) 58 | } else { 59 | let code = "" 60 | process.stdin.resume() 61 | process.stdin.on("data", chunk => code += chunk) 62 | process.stdin.on("end", () => run(code)) 63 | } 64 | -------------------------------------------------------------------------------- /acorn/src/identifier.js: -------------------------------------------------------------------------------- 1 | // Reserved word lists for various dialects of the language 2 | 3 | export const reservedWords = { 4 | 3: "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile", 5 | 5: "class enum extends super const export import", 6 | 6: "enum", 7 | strict: "implements interface let package private protected public static yield", 8 | strictBind: "eval arguments" 9 | } 10 | 11 | // And the keywords 12 | 13 | const ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this" 14 | 15 | export const keywords = { 16 | 5: ecma5AndLessKeywords, 17 | "5module": ecma5AndLessKeywords + " export import", 18 | 6: ecma5AndLessKeywords + " const class extends export import super" 19 | } 20 | 21 | export const keywordRelationalOperator = /^in(stanceof)?$/ 22 | 23 | // ## Character categories 24 | 25 | // Big ugly regular expressions that match characters in the 26 | // whitespace, identifier, and identifier-start categories. These 27 | // are only applied when a character is found to actually have a 28 | // code point above 128. 29 | // Generated by `bin/generate-identifier-regex.js`. 30 | let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08c7\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\u9ffc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7bf\ua7c2-\ua7ca\ua7f5-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" 31 | let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d3-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf\u1ac0\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" 32 | 33 | const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") 34 | const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") 35 | 36 | nonASCIIidentifierStartChars = nonASCIIidentifierChars = null 37 | 38 | // These are a run-length and offset encoded representation of the 39 | // >0xffff code points that are a valid part of identifiers. The 40 | // offset starts at 0x10000, and each pair of numbers represents an 41 | // offset to the next range, and then a size of the range. They were 42 | // generated by bin/generate-identifier-regex.js 43 | 44 | // eslint-disable-next-line comma-spacing 45 | const astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,349,41,7,1,79,28,11,0,9,21,107,20,28,22,13,52,76,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,230,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,190,0,80,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,43,8,8952,286,50,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,2357,44,11,6,17,0,370,43,1301,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42717,35,4148,12,221,3,5761,15,7472,3104,541,1507,4938] 46 | 47 | // eslint-disable-next-line comma-spacing 48 | const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,370,1,154,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1014,0,2,54,8,3,82,0,12,1,19628,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,419,13,1495,6,110,6,6,9,4759,9,787719,239] 49 | 50 | // This has a complexity linear to the value of the code. The 51 | // assumption is that looking up astral identifier characters is 52 | // rare. 53 | function isInAstralSet(code, set) { 54 | let pos = 0x10000 55 | for (let i = 0; i < set.length; i += 2) { 56 | pos += set[i] 57 | if (pos > code) return false 58 | pos += set[i + 1] 59 | if (pos >= code) return true 60 | } 61 | } 62 | 63 | // Test whether a given character code starts an identifier. 64 | 65 | export function isIdentifierStart(code, astral) { 66 | if (code < 65) return code === 36 67 | if (code < 91) return true 68 | if (code < 97) return code === 95 69 | if (code < 123) return true 70 | if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) 71 | if (astral === false) return false 72 | return isInAstralSet(code, astralIdentifierStartCodes) 73 | } 74 | 75 | // Test whether a given character is part of an identifier. 76 | 77 | export function isIdentifierChar(code, astral) { 78 | if (code < 48) return code === 36 79 | if (code < 58) return true 80 | if (code < 65) return false 81 | if (code < 91) return true 82 | if (code < 97) return code === 95 83 | if (code < 123) return true 84 | if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) 85 | if (astral === false) return false 86 | return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) 87 | } 88 | -------------------------------------------------------------------------------- /acorn/src/index.js: -------------------------------------------------------------------------------- 1 | // Acorn is a tiny, fast JavaScript parser written in JavaScript. 2 | // 3 | // Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and 4 | // various contributors and released under an MIT license. 5 | // 6 | // Git repositories for Acorn are available at 7 | // 8 | // http://marijnhaverbeke.nl/git/acorn 9 | // https://github.com/acornjs/acorn.git 10 | // 11 | // Please use the [github bug tracker][ghbt] to report issues. 12 | // 13 | // [ghbt]: https://github.com/acornjs/acorn/issues 14 | // 15 | // [walk]: util/walk.js 16 | 17 | import {Parser} from "./state.js" 18 | import "./parseutil.js" 19 | import "./statement.js" 20 | import "./lval.js" 21 | import "./expression.js" 22 | import "./location.js" 23 | import "./scope.js" 24 | 25 | import {defaultOptions} from "./options.js" 26 | import {Position, SourceLocation, getLineInfo} from "./locutil.js" 27 | import {Node} from "./node.js" 28 | import {TokenType, types as tokTypes, keywords as keywordTypes} from "./tokentype.js" 29 | import {TokContext, types as tokContexts} from "./tokencontext.js" 30 | import {isIdentifierChar, isIdentifierStart} from "./identifier.js" 31 | import {Token} from "./tokenize.js" 32 | import {isNewLine, lineBreak, lineBreakG, nonASCIIwhitespace} from "./whitespace.js" 33 | 34 | export const version = "8.4.0" 35 | export { 36 | Parser, 37 | defaultOptions, 38 | Position, 39 | SourceLocation, 40 | getLineInfo, 41 | Node, 42 | TokenType, 43 | tokTypes, 44 | keywordTypes, 45 | TokContext, 46 | tokContexts, 47 | isIdentifierChar, 48 | isIdentifierStart, 49 | Token, 50 | isNewLine, 51 | lineBreak, 52 | lineBreakG, 53 | nonASCIIwhitespace 54 | } 55 | 56 | Parser.acorn = { 57 | Parser, 58 | version, 59 | defaultOptions, 60 | Position, 61 | SourceLocation, 62 | getLineInfo, 63 | Node, 64 | TokenType, 65 | tokTypes, 66 | keywordTypes, 67 | TokContext, 68 | tokContexts, 69 | isIdentifierChar, 70 | isIdentifierStart, 71 | Token, 72 | isNewLine, 73 | lineBreak, 74 | lineBreakG, 75 | nonASCIIwhitespace 76 | } 77 | 78 | // The main exported interface (under `self.acorn` when in the 79 | // browser) is a `parse` function that takes a code string and 80 | // returns an abstract syntax tree as specified by [Mozilla parser 81 | // API][api]. 82 | // 83 | // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API 84 | 85 | export function parse(input, options) { 86 | return Parser.parse(input, options) 87 | } 88 | 89 | // This function tries to parse a single expression at a given 90 | // offset in a string. Useful for parsing mixed-language formats 91 | // that embed JavaScript expressions. 92 | 93 | export function parseExpressionAt(input, pos, options) { 94 | return Parser.parseExpressionAt(input, pos, options) 95 | } 96 | 97 | // Acorn is organized as a tokenizer and a recursive-descent parser. 98 | // The `tokenizer` export provides an interface to the tokenizer. 99 | 100 | export function tokenizer(input, options) { 101 | return Parser.tokenizer(input, options) 102 | } 103 | -------------------------------------------------------------------------------- /acorn/src/location.js: -------------------------------------------------------------------------------- 1 | import {Parser} from "./state.js" 2 | import {Position, getLineInfo} from "./locutil.js" 3 | 4 | const pp = Parser.prototype 5 | 6 | // This function is used to raise exceptions on parse errors. It 7 | // takes an offset integer (into the current `input`) to indicate 8 | // the location of the error, attaches the position to the end 9 | // of the error message, and then raises a `SyntaxError` with that 10 | // message. 11 | 12 | pp.raise = function(pos, message) { 13 | let loc = getLineInfo(this.input, pos) 14 | message += " (" + loc.line + ":" + loc.column + ")" 15 | let err = new SyntaxError(message) 16 | err.pos = pos; err.loc = loc; err.raisedAt = this.pos 17 | throw err 18 | } 19 | 20 | pp.raiseRecoverable = pp.raise 21 | 22 | pp.curPosition = function() { 23 | if (this.options.locations) { 24 | return new Position(this.curLine, this.pos - this.lineStart) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /acorn/src/locutil.js: -------------------------------------------------------------------------------- 1 | import {lineBreakG} from "./whitespace.js" 2 | 3 | // These are used when `options.locations` is on, for the 4 | // `startLoc` and `endLoc` properties. 5 | 6 | export class Position { 7 | constructor(line, col) { 8 | this.line = line 9 | this.column = col 10 | } 11 | 12 | offset(n) { 13 | return new Position(this.line, this.column + n) 14 | } 15 | } 16 | 17 | export class SourceLocation { 18 | constructor(p, start, end) { 19 | this.start = start 20 | this.end = end 21 | if (p.sourceFile !== null) this.source = p.sourceFile 22 | } 23 | } 24 | 25 | // The `getLineInfo` function is mostly useful when the 26 | // `locations` option is off (for performance reasons) and you 27 | // want to find the line/column position for a given character 28 | // offset. `input` should be the code string that the offset refers 29 | // into. 30 | 31 | export function getLineInfo(input, offset) { 32 | for (let line = 1, cur = 0;;) { 33 | lineBreakG.lastIndex = cur 34 | let match = lineBreakG.exec(input) 35 | if (match && match.index < offset) { 36 | ++line 37 | cur = match.index + match[0].length 38 | } else { 39 | return new Position(line, offset - cur) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /acorn/src/lval.js: -------------------------------------------------------------------------------- 1 | import {types as tt} from "./tokentype.js" 2 | import {Parser} from "./state.js" 3 | import {has} from "./util.js" 4 | import {BIND_NONE, BIND_OUTSIDE, BIND_LEXICAL} from "./scopeflags.js" 5 | 6 | const pp = Parser.prototype 7 | 8 | // Convert existing expression atom to assignable pattern 9 | // if possible. 10 | 11 | pp.toAssignable = function(node, isBinding, refDestructuringErrors) { 12 | if (this.options.ecmaVersion >= 6 && node) { 13 | switch (node.type) { 14 | case "Identifier": 15 | if (this.inAsync && node.name === "await") 16 | this.raise(node.start, "Cannot use 'await' as identifier inside an async function") 17 | break 18 | 19 | case "ObjectPattern": 20 | case "ArrayPattern": 21 | case "AssignmentPattern": 22 | case "RestElement": 23 | break 24 | 25 | case "ObjectExpression": 26 | node.type = "ObjectPattern" 27 | if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true) 28 | for (let prop of node.properties) { 29 | this.toAssignable(prop, isBinding) 30 | // Early error: 31 | // AssignmentRestProperty[Yield, Await] : 32 | // `...` DestructuringAssignmentTarget[Yield, Await] 33 | // 34 | // It is a Syntax Error if |DestructuringAssignmentTarget| is an |ArrayLiteral| or an |ObjectLiteral|. 35 | if ( 36 | prop.type === "RestElement" && 37 | (prop.argument.type === "ArrayPattern" || prop.argument.type === "ObjectPattern") 38 | ) { 39 | this.raise(prop.argument.start, "Unexpected token") 40 | } 41 | } 42 | break 43 | 44 | case "Property": 45 | // AssignmentProperty has type === "Property" 46 | if (node.kind !== "init") this.raise(node.key.start, "Object pattern can't contain getter or setter") 47 | this.toAssignable(node.value, isBinding) 48 | break 49 | 50 | case "ArrayExpression": 51 | node.type = "ArrayPattern" 52 | if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true) 53 | this.toAssignableList(node.elements, isBinding) 54 | break 55 | 56 | case "SpreadElement": 57 | node.type = "RestElement" 58 | this.toAssignable(node.argument, isBinding) 59 | if (node.argument.type === "AssignmentPattern") 60 | this.raise(node.argument.start, "Rest elements cannot have a default value") 61 | break 62 | 63 | case "AssignmentExpression": 64 | if (node.operator !== "=") this.raise(node.left.end, "Only '=' operator can be used for specifying default value.") 65 | node.type = "AssignmentPattern" 66 | delete node.operator 67 | this.toAssignable(node.left, isBinding) 68 | break 69 | 70 | case "ParenthesizedExpression": 71 | this.toAssignable(node.expression, isBinding, refDestructuringErrors) 72 | break 73 | 74 | case "ChainExpression": 75 | this.raiseRecoverable(node.start, "Optional chaining cannot appear in left-hand side") 76 | break 77 | 78 | case "MemberExpression": 79 | if (!isBinding) break 80 | 81 | default: 82 | this.raise(node.start, "Assigning to rvalue") 83 | } 84 | } else if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true) 85 | return node 86 | } 87 | 88 | // Convert list of expression atoms to binding list. 89 | 90 | pp.toAssignableList = function(exprList, isBinding) { 91 | let end = exprList.length 92 | for (let i = 0; i < end; i++) { 93 | let elt = exprList[i] 94 | if (elt) this.toAssignable(elt, isBinding) 95 | } 96 | if (end) { 97 | let last = exprList[end - 1] 98 | if (this.options.ecmaVersion === 6 && isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier") 99 | this.unexpected(last.argument.start) 100 | } 101 | return exprList 102 | } 103 | 104 | // Parses spread element. 105 | 106 | pp.parseSpread = function(refDestructuringErrors) { 107 | let node = this.startNode() 108 | this.next() 109 | node.argument = this.parseMaybeAssign(false, refDestructuringErrors) 110 | return this.finishNode(node, "SpreadElement") 111 | } 112 | 113 | pp.parseRestBinding = function() { 114 | let node = this.startNode() 115 | this.next() 116 | 117 | // RestElement inside of a function parameter must be an identifier 118 | if (this.options.ecmaVersion === 6 && this.type !== tt.name) 119 | this.unexpected() 120 | 121 | node.argument = this.parseBindingAtom() 122 | 123 | return this.finishNode(node, "RestElement") 124 | } 125 | 126 | // Parses lvalue (assignable) atom. 127 | 128 | pp.parseBindingAtom = function() { 129 | if (this.options.ecmaVersion >= 6) { 130 | switch (this.type) { 131 | case tt.bracketL: 132 | let node = this.startNode() 133 | this.next() 134 | node.elements = this.parseBindingList(tt.bracketR, true, true) 135 | return this.finishNode(node, "ArrayPattern") 136 | 137 | case tt.braceL: 138 | return this.parseObj(true) 139 | } 140 | } 141 | return this.parseIdent() 142 | } 143 | 144 | pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) { 145 | let elts = [], first = true 146 | while (!this.eat(close)) { 147 | if (first) first = false 148 | else this.expect(tt.comma) 149 | if (allowEmpty && this.type === tt.comma) { 150 | elts.push(null) 151 | } else if (allowTrailingComma && this.afterTrailingComma(close)) { 152 | break 153 | } else if (this.type === tt.ellipsis) { 154 | let rest = this.parseRestBinding() 155 | this.parseBindingListItem(rest) 156 | elts.push(rest) 157 | if (this.type === tt.comma) this.raise(this.start, "Comma is not permitted after the rest element") 158 | this.expect(close) 159 | break 160 | } else { 161 | let elem = this.parseMaybeDefault(this.start, this.startLoc) 162 | this.parseBindingListItem(elem) 163 | elts.push(elem) 164 | } 165 | } 166 | return elts 167 | } 168 | 169 | pp.parseBindingListItem = function(param) { 170 | return param 171 | } 172 | 173 | // Parses assignment pattern around given atom if possible. 174 | 175 | pp.parseMaybeDefault = function(startPos, startLoc, left) { 176 | left = left || this.parseBindingAtom() 177 | if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left 178 | let node = this.startNodeAt(startPos, startLoc) 179 | node.left = left 180 | node.right = this.parseMaybeAssign() 181 | return this.finishNode(node, "AssignmentPattern") 182 | } 183 | 184 | // The following three functions all verify that a node is an lvalue — 185 | // something that can be bound, or assigned to. In order to do so, they perform 186 | // a variety of checks: 187 | // 188 | // - Check that none of the bound/assigned-to identifiers are reserved words. 189 | // - Record name declarations for bindings in the appropriate scope. 190 | // - Check duplicate argument names, if checkClashes is set. 191 | // 192 | // If a complex binding pattern is encountered (e.g., object and array 193 | // destructuring), the entire pattern is recursively checked. 194 | // 195 | // There are three versions of checkLVal*() appropriate for different 196 | // circumstances: 197 | // 198 | // - checkLValSimple() shall be used if the syntactic construct supports 199 | // nothing other than identifiers and member expressions. Parenthesized 200 | // expressions are also correctly handled. This is generally appropriate for 201 | // constructs for which the spec says 202 | // 203 | // > It is a Syntax Error if AssignmentTargetType of [the production] is not 204 | // > simple. 205 | // 206 | // It is also appropriate for checking if an identifier is valid and not 207 | // defined elsewhere, like import declarations or function/class identifiers. 208 | // 209 | // Examples where this is used include: 210 | // a += …; 211 | // import a from '…'; 212 | // where a is the node to be checked. 213 | // 214 | // - checkLValPattern() shall be used if the syntactic construct supports 215 | // anything checkLValSimple() supports, as well as object and array 216 | // destructuring patterns. This is generally appropriate for constructs for 217 | // which the spec says 218 | // 219 | // > It is a Syntax Error if [the production] is neither an ObjectLiteral nor 220 | // > an ArrayLiteral and AssignmentTargetType of [the production] is not 221 | // > simple. 222 | // 223 | // Examples where this is used include: 224 | // (a = …); 225 | // const a = …; 226 | // try { … } catch (a) { … } 227 | // where a is the node to be checked. 228 | // 229 | // - checkLValInnerPattern() shall be used if the syntactic construct supports 230 | // anything checkLValPattern() supports, as well as default assignment 231 | // patterns, rest elements, and other constructs that may appear within an 232 | // object or array destructuring pattern. 233 | // 234 | // As a special case, function parameters also use checkLValInnerPattern(), 235 | // as they also support defaults and rest constructs. 236 | // 237 | // These functions deliberately support both assignment and binding constructs, 238 | // as the logic for both is exceedingly similar. If the node is the target of 239 | // an assignment, then bindingType should be set to BIND_NONE. Otherwise, it 240 | // should be set to the appropriate BIND_* constant, like BIND_VAR or 241 | // BIND_LEXICAL. 242 | // 243 | // If the function is called with a non-BIND_NONE bindingType, then 244 | // additionally a checkClashes object may be specified to allow checking for 245 | // duplicate argument names. checkClashes is ignored if the provided construct 246 | // is an assignment (i.e., bindingType is BIND_NONE). 247 | 248 | pp.checkLValSimple = function(expr, bindingType = BIND_NONE, checkClashes) { 249 | const isBind = bindingType !== BIND_NONE 250 | 251 | switch (expr.type) { 252 | case "Identifier": 253 | if (this.strict && this.reservedWordsStrictBind.test(expr.name)) 254 | this.raiseRecoverable(expr.start, (isBind ? "Binding " : "Assigning to ") + expr.name + " in strict mode") 255 | if (isBind) { 256 | if (bindingType === BIND_LEXICAL && expr.name === "let") 257 | this.raiseRecoverable(expr.start, "let is disallowed as a lexically bound name") 258 | if (checkClashes) { 259 | if (has(checkClashes, expr.name)) 260 | this.raiseRecoverable(expr.start, "Argument name clash") 261 | checkClashes[expr.name] = true 262 | } 263 | if (bindingType !== BIND_OUTSIDE) this.declareName(expr.name, bindingType, expr.start) 264 | } 265 | break 266 | 267 | case "ChainExpression": 268 | this.raiseRecoverable(expr.start, "Optional chaining cannot appear in left-hand side") 269 | break 270 | 271 | case "MemberExpression": 272 | if (isBind) this.raiseRecoverable(expr.start, "Binding member expression") 273 | break 274 | 275 | case "ParenthesizedExpression": 276 | if (isBind) this.raiseRecoverable(expr.start, "Binding parenthesized expression") 277 | return this.checkLValSimple(expr.expression, bindingType, checkClashes) 278 | 279 | default: 280 | this.raise(expr.start, (isBind ? "Binding" : "Assigning to") + " rvalue") 281 | } 282 | } 283 | 284 | pp.checkLValPattern = function(expr, bindingType = BIND_NONE, checkClashes) { 285 | switch (expr.type) { 286 | case "ObjectPattern": 287 | for (let prop of expr.properties) { 288 | this.checkLValInnerPattern(prop, bindingType, checkClashes) 289 | } 290 | break 291 | 292 | case "ArrayPattern": 293 | for (let elem of expr.elements) { 294 | if (elem) this.checkLValInnerPattern(elem, bindingType, checkClashes) 295 | } 296 | break 297 | 298 | default: 299 | this.checkLValSimple(expr, bindingType, checkClashes) 300 | } 301 | } 302 | 303 | pp.checkLValInnerPattern = function(expr, bindingType = BIND_NONE, checkClashes) { 304 | switch (expr.type) { 305 | case "Property": 306 | // AssignmentProperty has type === "Property" 307 | this.checkLValInnerPattern(expr.value, bindingType, checkClashes) 308 | break 309 | 310 | case "AssignmentPattern": 311 | this.checkLValPattern(expr.left, bindingType, checkClashes) 312 | break 313 | 314 | case "RestElement": 315 | this.checkLValPattern(expr.argument, bindingType, checkClashes) 316 | break 317 | 318 | default: 319 | this.checkLValPattern(expr, bindingType, checkClashes) 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /acorn/src/node.js: -------------------------------------------------------------------------------- 1 | import {Parser} from "./state.js" 2 | import {SourceLocation} from "./locutil.js" 3 | 4 | export class Node { 5 | constructor(parser, pos, loc) { 6 | this.type = "" 7 | this.start = pos 8 | this.end = 0 9 | if (parser.options.locations) 10 | this.loc = new SourceLocation(parser, loc) 11 | if (parser.options.directSourceFile) 12 | this.sourceFile = parser.options.directSourceFile 13 | if (parser.options.ranges) 14 | this.range = [pos, 0] 15 | } 16 | } 17 | 18 | // Start an AST node, attaching a start offset. 19 | 20 | const pp = Parser.prototype 21 | 22 | pp.startNode = function() { 23 | return new Node(this, this.start, this.startLoc) 24 | } 25 | 26 | pp.startNodeAt = function(pos, loc) { 27 | return new Node(this, pos, loc) 28 | } 29 | 30 | // Finish an AST node, adding `type` and `end` properties. 31 | 32 | function finishNodeAt(node, type, pos, loc) { 33 | node.type = type 34 | node.end = pos 35 | if (this.options.locations) 36 | node.loc.end = loc 37 | if (this.options.ranges) 38 | node.range[1] = pos 39 | return node 40 | } 41 | 42 | pp.finishNode = function(node, type) { 43 | return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) 44 | } 45 | 46 | // Finish node at given position 47 | 48 | pp.finishNodeAt = function(node, type, pos, loc) { 49 | return finishNodeAt.call(this, node, type, pos, loc) 50 | } 51 | 52 | pp.copyNode = function(node) { 53 | let newNode = new Node(this, node.start, this.startLoc) 54 | for (let prop in node) newNode[prop] = node[prop] 55 | return newNode 56 | } 57 | -------------------------------------------------------------------------------- /acorn/src/options.js: -------------------------------------------------------------------------------- 1 | import {has, isArray} from "./util.js" 2 | import {SourceLocation} from "./locutil.js" 3 | 4 | // A second argument must be given to configure the parser process. 5 | // These options are recognized (only `ecmaVersion` is required): 6 | 7 | export const defaultOptions = { 8 | // `ecmaVersion` indicates the ECMAScript version to parse. Must be 9 | // either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 10 | // (2019), 11 (2020), 12 (2021), 13 (2022), or `"latest"` (the 11 | // latest version the library supports). This influences support 12 | // for strict mode, the set of reserved words, and support for 13 | // new syntax features. 14 | ecmaVersion: null, 15 | // `sourceType` indicates the mode the code should be parsed in. 16 | // Can be either `"script"` or `"module"`. This influences global 17 | // strict mode and parsing of `import` and `export` declarations. 18 | sourceType: "script", 19 | // `onInsertedSemicolon` can be a callback that will be called 20 | // when a semicolon is automatically inserted. It will be passed 21 | // the position of the comma as an offset, and if `locations` is 22 | // enabled, it is given the location as a `{line, column}` object 23 | // as second argument. 24 | onInsertedSemicolon: null, 25 | // `onTrailingComma` is similar to `onInsertedSemicolon`, but for 26 | // trailing commas. 27 | onTrailingComma: null, 28 | // By default, reserved words are only enforced if ecmaVersion >= 5. 29 | // Set `allowReserved` to a boolean value to explicitly turn this on 30 | // an off. When this option has the value "never", reserved words 31 | // and keywords can also not be used as property names. 32 | allowReserved: null, 33 | // When enabled, a return at the top level is not considered an 34 | // error. 35 | allowReturnOutsideFunction: false, 36 | // When enabled, import/export statements are not constrained to 37 | // appearing at the top of the program, and an import.meta expression 38 | // in a script isn't considered an error. 39 | allowImportExportEverywhere: false, 40 | // By default, await identifiers are allowed to appear at the top-level scope only if ecmaVersion >= 2022. 41 | // When enabled, await identifiers are allowed to appear at the top-level scope, 42 | // but they are still not allowed in non-async functions. 43 | allowAwaitOutsideFunction: null, 44 | // When enabled, super identifiers are not constrained to 45 | // appearing in methods and do not raise an error when they appear elsewhere. 46 | allowSuperOutsideMethod: null, 47 | // When enabled, hashbang directive in the beginning of file 48 | // is allowed and treated as a line comment. 49 | allowHashBang: false, 50 | // When `locations` is on, `loc` properties holding objects with 51 | // `start` and `end` properties in `{line, column}` form (with 52 | // line being 1-based and column 0-based) will be attached to the 53 | // nodes. 54 | locations: false, 55 | // A function can be passed as `onToken` option, which will 56 | // cause Acorn to call that function with object in the same 57 | // format as tokens returned from `tokenizer().getToken()`. Note 58 | // that you are not allowed to call the parser from the 59 | // callback—that will corrupt its internal state. 60 | onToken: null, 61 | // A function can be passed as `onComment` option, which will 62 | // cause Acorn to call that function with `(block, text, start, 63 | // end)` parameters whenever a comment is skipped. `block` is a 64 | // boolean indicating whether this is a block (`/* */`) comment, 65 | // `text` is the content of the comment, and `start` and `end` are 66 | // character offsets that denote the start and end of the comment. 67 | // When the `locations` option is on, two more parameters are 68 | // passed, the full `{line, column}` locations of the start and 69 | // end of the comments. Note that you are not allowed to call the 70 | // parser from the callback—that will corrupt its internal state. 71 | onComment: null, 72 | // Nodes have their start and end characters offsets recorded in 73 | // `start` and `end` properties (directly on the node, rather than 74 | // the `loc` object, which holds line/column data. To also add a 75 | // [semi-standardized][range] `range` property holding a `[start, 76 | // end]` array with the same numbers, set the `ranges` option to 77 | // `true`. 78 | // 79 | // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 80 | ranges: false, 81 | // It is possible to parse multiple files into a single AST by 82 | // passing the tree produced by parsing the first file as 83 | // `program` option in subsequent parses. This will add the 84 | // toplevel forms of the parsed file to the `Program` (top) node 85 | // of an existing parse tree. 86 | program: null, 87 | // When `locations` is on, you can pass this to record the source 88 | // file in every node's `loc` object. 89 | sourceFile: null, 90 | // This value, if given, is stored in every node, whether 91 | // `locations` is on or off. 92 | directSourceFile: null, 93 | // When enabled, parenthesized expressions are represented by 94 | // (non-standard) ParenthesizedExpression nodes 95 | preserveParens: false 96 | } 97 | 98 | // Interpret and default an options object 99 | 100 | let warnedAboutEcmaVersion = false 101 | 102 | export function getOptions(opts) { 103 | let options = {} 104 | 105 | for (let opt in defaultOptions) 106 | options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt] 107 | 108 | if (options.ecmaVersion === "latest") { 109 | options.ecmaVersion = 1e8 110 | } else if (options.ecmaVersion == null) { 111 | if (!warnedAboutEcmaVersion && typeof console === "object" && console.warn) { 112 | warnedAboutEcmaVersion = true 113 | console.warn("Since Acorn 8.0.0, options.ecmaVersion is required.\nDefaulting to 2020, but this will stop working in the future.") 114 | } 115 | options.ecmaVersion = 11 116 | } else if (options.ecmaVersion >= 2015) { 117 | options.ecmaVersion -= 2009 118 | } 119 | 120 | if (options.allowReserved == null) 121 | options.allowReserved = options.ecmaVersion < 5 122 | 123 | if (isArray(options.onToken)) { 124 | let tokens = options.onToken 125 | options.onToken = (token) => tokens.push(token) 126 | } 127 | if (isArray(options.onComment)) 128 | options.onComment = pushComment(options, options.onComment) 129 | 130 | return options 131 | } 132 | 133 | function pushComment(options, array) { 134 | return function(block, text, start, end, startLoc, endLoc) { 135 | let comment = { 136 | type: block ? "Block" : "Line", 137 | value: text, 138 | start: start, 139 | end: end 140 | } 141 | if (options.locations) 142 | comment.loc = new SourceLocation(this, startLoc, endLoc) 143 | if (options.ranges) 144 | comment.range = [start, end] 145 | array.push(comment) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /acorn/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /acorn/src/parseutil.js: -------------------------------------------------------------------------------- 1 | import {types as tt} from "./tokentype.js" 2 | import {Parser} from "./state.js" 3 | import {lineBreak, skipWhiteSpace} from "./whitespace.js" 4 | 5 | const pp = Parser.prototype 6 | 7 | // ## Parser utilities 8 | 9 | const literal = /^(?:'((?:\\.|[^'\\])*?)'|"((?:\\.|[^"\\])*?)")/ 10 | pp.strictDirective = function(start) { 11 | for (;;) { 12 | // Try to find string literal. 13 | skipWhiteSpace.lastIndex = start 14 | start += skipWhiteSpace.exec(this.input)[0].length 15 | let match = literal.exec(this.input.slice(start)) 16 | if (!match) return false 17 | if ((match[1] || match[2]) === "use strict") { 18 | skipWhiteSpace.lastIndex = start + match[0].length 19 | let spaceAfter = skipWhiteSpace.exec(this.input), end = spaceAfter.index + spaceAfter[0].length 20 | let next = this.input.charAt(end) 21 | return next === ";" || next === "}" || 22 | (lineBreak.test(spaceAfter[0]) && 23 | !(/[(`.[+\-/*%<>=,?^&]/.test(next) || next === "!" && this.input.charAt(end + 1) === "=")) 24 | } 25 | start += match[0].length 26 | 27 | // Skip semicolon, if any. 28 | skipWhiteSpace.lastIndex = start 29 | start += skipWhiteSpace.exec(this.input)[0].length 30 | if (this.input[start] === ";") 31 | start++ 32 | } 33 | } 34 | 35 | // Predicate that tests whether the next token is of the given 36 | // type, and if yes, consumes it as a side effect. 37 | 38 | pp.eat = function(type) { 39 | if (this.type === type) { 40 | this.next() 41 | return true 42 | } else { 43 | return false 44 | } 45 | } 46 | 47 | // Tests whether parsed token is a contextual keyword. 48 | 49 | pp.isContextual = function(name) { 50 | return this.type === tt.name && this.value === name && !this.containsEsc 51 | } 52 | 53 | // Consumes contextual keyword if possible. 54 | 55 | pp.eatContextual = function(name) { 56 | if (!this.isContextual(name)) return false 57 | this.next() 58 | return true 59 | } 60 | 61 | // Asserts that following token is given contextual keyword. 62 | 63 | pp.expectContextual = function(name) { 64 | if (!this.eatContextual(name)) this.unexpected() 65 | } 66 | 67 | // Test whether a semicolon can be inserted at the current position. 68 | 69 | pp.canInsertSemicolon = function() { 70 | return this.type === tt.eof || 71 | this.type === tt.braceR || 72 | lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) 73 | } 74 | 75 | pp.insertSemicolon = function() { 76 | if (this.canInsertSemicolon()) { 77 | if (this.options.onInsertedSemicolon) 78 | this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) 79 | return true 80 | } 81 | } 82 | 83 | // Consume a semicolon, or, failing that, see if we are allowed to 84 | // pretend that there is a semicolon at this position. 85 | 86 | pp.semicolon = function() { 87 | if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected() 88 | } 89 | 90 | pp.afterTrailingComma = function(tokType, notNext) { 91 | if (this.type === tokType) { 92 | if (this.options.onTrailingComma) 93 | this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) 94 | if (!notNext) 95 | this.next() 96 | return true 97 | } 98 | } 99 | 100 | // Expect a token of a given type. If found, consume it, otherwise, 101 | // raise an unexpected token error. 102 | 103 | pp.expect = function(type) { 104 | this.eat(type) || this.unexpected() 105 | } 106 | 107 | // Raise an unexpected token error. 108 | 109 | pp.unexpected = function(pos) { 110 | this.raise(pos != null ? pos : this.start, "Unexpected token") 111 | } 112 | 113 | export function DestructuringErrors() { 114 | this.shorthandAssign = 115 | this.trailingComma = 116 | this.parenthesizedAssign = 117 | this.parenthesizedBind = 118 | this.doubleProto = 119 | -1 120 | } 121 | 122 | pp.checkPatternErrors = function(refDestructuringErrors, isAssign) { 123 | if (!refDestructuringErrors) return 124 | if (refDestructuringErrors.trailingComma > -1) 125 | this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element") 126 | let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind 127 | if (parens > -1) this.raiseRecoverable(parens, "Parenthesized pattern") 128 | } 129 | 130 | pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { 131 | if (!refDestructuringErrors) return false 132 | let {shorthandAssign, doubleProto} = refDestructuringErrors 133 | if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0 134 | if (shorthandAssign >= 0) 135 | this.raise(shorthandAssign, "Shorthand property assignments are valid only in destructuring patterns") 136 | if (doubleProto >= 0) 137 | this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property") 138 | } 139 | 140 | pp.checkYieldAwaitInDefaultParams = function() { 141 | if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos)) 142 | this.raise(this.yieldPos, "Yield expression cannot be a default value") 143 | if (this.awaitPos) 144 | this.raise(this.awaitPos, "Await expression cannot be a default value") 145 | } 146 | 147 | pp.isSimpleAssignTarget = function(expr) { 148 | if (expr.type === "ParenthesizedExpression") 149 | return this.isSimpleAssignTarget(expr.expression) 150 | return expr.type === "Identifier" || expr.type === "MemberExpression" 151 | } 152 | -------------------------------------------------------------------------------- /acorn/src/scope.js: -------------------------------------------------------------------------------- 1 | import {Parser} from "./state.js" 2 | import {SCOPE_VAR, SCOPE_FUNCTION, SCOPE_TOP, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, BIND_LEXICAL, BIND_SIMPLE_CATCH, BIND_FUNCTION} from "./scopeflags.js" 3 | 4 | const pp = Parser.prototype 5 | 6 | class Scope { 7 | constructor(flags) { 8 | this.flags = flags 9 | // A list of var-declared names in the current lexical scope 10 | this.var = [] 11 | // A list of lexically-declared names in the current lexical scope 12 | this.lexical = [] 13 | // A list of lexically-declared FunctionDeclaration names in the current lexical scope 14 | this.functions = [] 15 | // A switch to disallow the identifier reference 'arguments' 16 | this.inClassFieldInit = false 17 | } 18 | } 19 | 20 | // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names. 21 | 22 | pp.enterScope = function(flags) { 23 | this.scopeStack.push(new Scope(flags)) 24 | } 25 | 26 | pp.exitScope = function() { 27 | this.scopeStack.pop() 28 | } 29 | 30 | // The spec says: 31 | // > At the top level of a function, or script, function declarations are 32 | // > treated like var declarations rather than like lexical declarations. 33 | pp.treatFunctionsAsVarInScope = function(scope) { 34 | return (scope.flags & SCOPE_FUNCTION) || !this.inModule && (scope.flags & SCOPE_TOP) 35 | } 36 | 37 | pp.declareName = function(name, bindingType, pos) { 38 | let redeclared = false 39 | if (bindingType === BIND_LEXICAL) { 40 | const scope = this.currentScope() 41 | redeclared = scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1 42 | scope.lexical.push(name) 43 | if (this.inModule && (scope.flags & SCOPE_TOP)) 44 | delete this.undefinedExports[name] 45 | } else if (bindingType === BIND_SIMPLE_CATCH) { 46 | const scope = this.currentScope() 47 | scope.lexical.push(name) 48 | } else if (bindingType === BIND_FUNCTION) { 49 | const scope = this.currentScope() 50 | if (this.treatFunctionsAsVar) 51 | redeclared = scope.lexical.indexOf(name) > -1 52 | else 53 | redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1 54 | scope.functions.push(name) 55 | } else { 56 | for (let i = this.scopeStack.length - 1; i >= 0; --i) { 57 | const scope = this.scopeStack[i] 58 | if (scope.lexical.indexOf(name) > -1 && !((scope.flags & SCOPE_SIMPLE_CATCH) && scope.lexical[0] === name) || 59 | !this.treatFunctionsAsVarInScope(scope) && scope.functions.indexOf(name) > -1) { 60 | redeclared = true 61 | break 62 | } 63 | scope.var.push(name) 64 | if (this.inModule && (scope.flags & SCOPE_TOP)) 65 | delete this.undefinedExports[name] 66 | if (scope.flags & SCOPE_VAR) break 67 | } 68 | } 69 | if (redeclared) this.raiseRecoverable(pos, `Identifier '${name}' has already been declared`) 70 | } 71 | 72 | pp.checkLocalExport = function(id) { 73 | // scope.functions must be empty as Module code is always strict. 74 | if (this.scopeStack[0].lexical.indexOf(id.name) === -1 && 75 | this.scopeStack[0].var.indexOf(id.name) === -1) { 76 | this.undefinedExports[id.name] = id 77 | } 78 | } 79 | 80 | pp.currentScope = function() { 81 | return this.scopeStack[this.scopeStack.length - 1] 82 | } 83 | 84 | pp.currentVarScope = function() { 85 | for (let i = this.scopeStack.length - 1;; i--) { 86 | let scope = this.scopeStack[i] 87 | if (scope.flags & SCOPE_VAR) return scope 88 | } 89 | } 90 | 91 | // Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. 92 | pp.currentThisScope = function() { 93 | for (let i = this.scopeStack.length - 1;; i--) { 94 | let scope = this.scopeStack[i] 95 | if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) return scope 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /acorn/src/scopeflags.js: -------------------------------------------------------------------------------- 1 | // Each scope gets a bitset that may contain these flags 2 | export const 3 | SCOPE_TOP = 1, 4 | SCOPE_FUNCTION = 2, 5 | SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION, 6 | SCOPE_ASYNC = 4, 7 | SCOPE_GENERATOR = 8, 8 | SCOPE_ARROW = 16, 9 | SCOPE_SIMPLE_CATCH = 32, 10 | SCOPE_SUPER = 64, 11 | SCOPE_DIRECT_SUPER = 128 12 | 13 | export function functionFlags(async, generator) { 14 | return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) 15 | } 16 | 17 | // Used in checkLVal* and declareName to determine the type of a binding 18 | export const 19 | BIND_NONE = 0, // Not a binding 20 | BIND_VAR = 1, // Var-style binding 21 | BIND_LEXICAL = 2, // Let- or const-style binding 22 | BIND_FUNCTION = 3, // Function declaration 23 | BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding 24 | BIND_OUTSIDE = 5 // Special case for function names as bound inside the function 25 | -------------------------------------------------------------------------------- /acorn/src/state.js: -------------------------------------------------------------------------------- 1 | import {reservedWords, keywords} from "./identifier.js" 2 | import {types as tt} from "./tokentype.js" 3 | import {lineBreak} from "./whitespace.js" 4 | import {getOptions} from "./options.js" 5 | import {wordsRegexp} from "./util.js" 6 | import {SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR, SCOPE_SUPER, SCOPE_DIRECT_SUPER} from "./scopeflags.js" 7 | 8 | export class Parser { 9 | constructor(options, input, startPos) { 10 | this.options = options = getOptions(options) 11 | this.sourceFile = options.sourceFile 12 | this.keywords = wordsRegexp(keywords[options.ecmaVersion >= 6 ? 6 : options.sourceType === "module" ? "5module" : 5]) 13 | let reserved = "" 14 | if (options.allowReserved !== true) { 15 | reserved = reservedWords[options.ecmaVersion >= 6 ? 6 : options.ecmaVersion === 5 ? 5 : 3] 16 | if (options.sourceType === "module") reserved += " await" 17 | } 18 | this.reservedWords = wordsRegexp(reserved) 19 | let reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict 20 | this.reservedWordsStrict = wordsRegexp(reservedStrict) 21 | this.reservedWordsStrictBind = wordsRegexp(reservedStrict + " " + reservedWords.strictBind) 22 | this.input = String(input) 23 | 24 | // Used to signal to callers of `readWord1` whether the word 25 | // contained any escape sequences. This is needed because words with 26 | // escape sequences must not be interpreted as keywords. 27 | this.containsEsc = false 28 | 29 | // Set up token state 30 | 31 | // The current position of the tokenizer in the input. 32 | if (startPos) { 33 | this.pos = startPos 34 | this.lineStart = this.input.lastIndexOf("\n", startPos - 1) + 1 35 | this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length 36 | } else { 37 | this.pos = this.lineStart = 0 38 | this.curLine = 1 39 | } 40 | 41 | // Properties of the current token: 42 | // Its type 43 | this.type = tt.eof 44 | // For tokens that include more information than their type, the value 45 | this.value = null 46 | // Its start and end offset 47 | this.start = this.end = this.pos 48 | // And, if locations are used, the {line, column} object 49 | // corresponding to those offsets 50 | this.startLoc = this.endLoc = this.curPosition() 51 | 52 | // Position information for the previous token 53 | this.lastTokEndLoc = this.lastTokStartLoc = null 54 | this.lastTokStart = this.lastTokEnd = this.pos 55 | 56 | // The context stack is used to superficially track syntactic 57 | // context to predict whether a regular expression is allowed in a 58 | // given position. 59 | this.context = this.initialContext() 60 | this.exprAllowed = true 61 | 62 | // Figure out if it's a module code. 63 | this.inModule = options.sourceType === "module" 64 | this.strict = this.inModule || this.strictDirective(this.pos) 65 | 66 | // Used to signify the start of a potential arrow function 67 | this.potentialArrowAt = -1 68 | this.potentialArrowInForAwait = false 69 | 70 | // Positions to delayed-check that yield/await does not exist in default parameters. 71 | this.yieldPos = this.awaitPos = this.awaitIdentPos = 0 72 | // Labels in scope. 73 | this.labels = [] 74 | // Thus-far undefined exports. 75 | this.undefinedExports = Object.create(null) 76 | 77 | // If enabled, skip leading hashbang line. 78 | if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === "#!") 79 | this.skipLineComment(2) 80 | 81 | // Scope tracking for duplicate variable names (see scope.js) 82 | this.scopeStack = [] 83 | this.enterScope(SCOPE_TOP) 84 | 85 | // For RegExp validation 86 | this.regexpState = null 87 | 88 | // The stack of private names. 89 | // Each element has two properties: 'declared' and 'used'. 90 | // When it exited from the outermost class definition, all used private names must be declared. 91 | this.privateNameStack = [] 92 | } 93 | 94 | parse() { 95 | let node = this.options.program || this.startNode() 96 | this.nextToken() 97 | return this.parseTopLevel(node) 98 | } 99 | 100 | get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 } 101 | get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 && !this.currentVarScope().inClassFieldInit } 102 | get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 && !this.currentVarScope().inClassFieldInit } 103 | get canAwait() { 104 | for (let i = this.scopeStack.length - 1; i >= 0; i--) { 105 | let scope = this.scopeStack[i] 106 | if (scope.inClassFieldInit) return false 107 | if (scope.flags & SCOPE_FUNCTION) return (scope.flags & SCOPE_ASYNC) > 0 108 | } 109 | return (this.inModule && this.options.ecmaVersion >= 13) || this.options.allowAwaitOutsideFunction 110 | } 111 | get allowSuper() { 112 | const {flags, inClassFieldInit} = this.currentThisScope() 113 | return (flags & SCOPE_SUPER) > 0 || inClassFieldInit || this.options.allowSuperOutsideMethod 114 | } 115 | get allowDirectSuper() { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 } 116 | get treatFunctionsAsVar() { return this.treatFunctionsAsVarInScope(this.currentScope()) } 117 | get inNonArrowFunction() { 118 | const {flags, inClassFieldInit} = this.currentThisScope() 119 | return (flags & SCOPE_FUNCTION) > 0 || inClassFieldInit 120 | } 121 | 122 | static extend(...plugins) { 123 | let cls = this 124 | for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls) 125 | return cls 126 | } 127 | 128 | static parse(input, options) { 129 | return new this(options, input).parse() 130 | } 131 | 132 | static parseExpressionAt(input, pos, options) { 133 | let parser = new this(options, input, pos) 134 | parser.nextToken() 135 | return parser.parseExpression() 136 | } 137 | 138 | static tokenizer(input, options) { 139 | return new this(options, input) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /acorn/src/tokencontext.js: -------------------------------------------------------------------------------- 1 | // The algorithm used to determine whether a regexp can appear at a 2 | // given point in the program is loosely based on sweet.js' approach. 3 | // See https://github.com/mozilla/sweet.js/wiki/design 4 | 5 | import {Parser} from "./state.js" 6 | import {types as tt} from "./tokentype.js" 7 | import {lineBreak} from "./whitespace.js" 8 | 9 | export class TokContext { 10 | constructor(token, isExpr, preserveSpace, override, generator) { 11 | this.token = token 12 | this.isExpr = !!isExpr 13 | this.preserveSpace = !!preserveSpace 14 | this.override = override 15 | this.generator = !!generator 16 | } 17 | } 18 | 19 | export const types = { 20 | b_stat: new TokContext("{", false), 21 | b_expr: new TokContext("{", true), 22 | b_tmpl: new TokContext("${", false), 23 | p_stat: new TokContext("(", false), 24 | p_expr: new TokContext("(", true), 25 | q_tmpl: new TokContext("`", true, true, p => p.tryReadTemplateToken()), 26 | f_stat: new TokContext("function", false), 27 | f_expr: new TokContext("function", true), 28 | f_expr_gen: new TokContext("function", true, false, null, true), 29 | f_gen: new TokContext("function", false, false, null, true) 30 | } 31 | 32 | const pp = Parser.prototype 33 | 34 | pp.initialContext = function() { 35 | return [types.b_stat] 36 | } 37 | 38 | pp.braceIsBlock = function(prevType) { 39 | let parent = this.curContext() 40 | if (parent === types.f_expr || parent === types.f_stat) 41 | return true 42 | if (prevType === tt.colon && (parent === types.b_stat || parent === types.b_expr)) 43 | return !parent.isExpr 44 | 45 | // The check for `tt.name && exprAllowed` detects whether we are 46 | // after a `yield` or `of` construct. See the `updateContext` for 47 | // `tt.name`. 48 | if (prevType === tt._return || prevType === tt.name && this.exprAllowed) 49 | return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) 50 | if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType === tt.arrow) 51 | return true 52 | if (prevType === tt.braceL) 53 | return parent === types.b_stat 54 | if (prevType === tt._var || prevType === tt._const || prevType === tt.name) 55 | return false 56 | return !this.exprAllowed 57 | } 58 | 59 | pp.inGeneratorContext = function() { 60 | for (let i = this.context.length - 1; i >= 1; i--) { 61 | let context = this.context[i] 62 | if (context.token === "function") 63 | return context.generator 64 | } 65 | return false 66 | } 67 | 68 | pp.updateContext = function(prevType) { 69 | let update, type = this.type 70 | if (type.keyword && prevType === tt.dot) 71 | this.exprAllowed = false 72 | else if (update = type.updateContext) 73 | update.call(this, prevType) 74 | else 75 | this.exprAllowed = type.beforeExpr 76 | } 77 | 78 | // Token-specific context update code 79 | 80 | tt.parenR.updateContext = tt.braceR.updateContext = function() { 81 | if (this.context.length === 1) { 82 | this.exprAllowed = true 83 | return 84 | } 85 | let out = this.context.pop() 86 | if (out === types.b_stat && this.curContext().token === "function") { 87 | out = this.context.pop() 88 | } 89 | this.exprAllowed = !out.isExpr 90 | } 91 | 92 | tt.braceL.updateContext = function(prevType) { 93 | this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) 94 | this.exprAllowed = true 95 | } 96 | 97 | tt.dollarBraceL.updateContext = function() { 98 | this.context.push(types.b_tmpl) 99 | this.exprAllowed = true 100 | } 101 | 102 | tt.parenL.updateContext = function(prevType) { 103 | let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while 104 | this.context.push(statementParens ? types.p_stat : types.p_expr) 105 | this.exprAllowed = true 106 | } 107 | 108 | tt.incDec.updateContext = function() { 109 | // tokExprAllowed stays unchanged 110 | } 111 | 112 | tt._function.updateContext = tt._class.updateContext = function(prevType) { 113 | if (prevType.beforeExpr && prevType !== tt._else && 114 | !(prevType === tt.semi && this.curContext() !== types.p_stat) && 115 | !(prevType === tt._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && 116 | !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) 117 | this.context.push(types.f_expr) 118 | else 119 | this.context.push(types.f_stat) 120 | this.exprAllowed = false 121 | } 122 | 123 | tt.backQuote.updateContext = function() { 124 | if (this.curContext() === types.q_tmpl) 125 | this.context.pop() 126 | else 127 | this.context.push(types.q_tmpl) 128 | this.exprAllowed = false 129 | } 130 | 131 | tt.star.updateContext = function(prevType) { 132 | if (prevType === tt._function) { 133 | let index = this.context.length - 1 134 | if (this.context[index] === types.f_expr) 135 | this.context[index] = types.f_expr_gen 136 | else 137 | this.context[index] = types.f_gen 138 | } 139 | this.exprAllowed = true 140 | } 141 | 142 | tt.name.updateContext = function(prevType) { 143 | let allowed = false 144 | if (this.options.ecmaVersion >= 6 && prevType !== tt.dot) { 145 | if (this.value === "of" && !this.exprAllowed || 146 | this.value === "yield" && this.inGeneratorContext()) 147 | allowed = true 148 | } 149 | this.exprAllowed = allowed 150 | } 151 | -------------------------------------------------------------------------------- /acorn/src/tokentype.js: -------------------------------------------------------------------------------- 1 | // ## Token types 2 | 3 | // The assignment of fine-grained, information-carrying type objects 4 | // allows the tokenizer to store the information it has about a 5 | // token in a way that is very cheap for the parser to look up. 6 | 7 | // All token type variables start with an underscore, to make them 8 | // easy to recognize. 9 | 10 | // The `beforeExpr` property is used to disambiguate between regular 11 | // expressions and divisions. It is set on all token types that can 12 | // be followed by an expression (thus, a slash after them would be a 13 | // regular expression). 14 | // 15 | // The `startsExpr` property is used to check if the token ends a 16 | // `yield` expression. It is set on all token types that either can 17 | // directly start an expression (like a quotation mark) or can 18 | // continue an expression (like the body of a string). 19 | // 20 | // `isLoop` marks a keyword as starting a loop, which is important 21 | // to know when parsing a label, in order to allow or disallow 22 | // continue jumps to that label. 23 | 24 | export class TokenType { 25 | constructor(label, conf = {}) { 26 | this.label = label 27 | this.keyword = conf.keyword 28 | this.beforeExpr = !!conf.beforeExpr 29 | this.startsExpr = !!conf.startsExpr 30 | this.isLoop = !!conf.isLoop 31 | this.isAssign = !!conf.isAssign 32 | this.prefix = !!conf.prefix 33 | this.postfix = !!conf.postfix 34 | this.binop = conf.binop || null 35 | this.updateContext = null 36 | } 37 | } 38 | 39 | function binop(name, prec) { 40 | return new TokenType(name, {beforeExpr: true, binop: prec}) 41 | } 42 | const beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true} 43 | 44 | // Map keyword names to token types. 45 | 46 | export const keywords = {} 47 | 48 | // Succinct definitions of keyword token types 49 | function kw(name, options = {}) { 50 | options.keyword = name 51 | return keywords[name] = new TokenType(name, options) 52 | } 53 | 54 | export const types = { 55 | num: new TokenType("num", startsExpr), 56 | regexp: new TokenType("regexp", startsExpr), 57 | string: new TokenType("string", startsExpr), 58 | name: new TokenType("name", startsExpr), 59 | privateId: new TokenType("privateId", startsExpr), 60 | eof: new TokenType("eof"), 61 | 62 | // Punctuation token types. 63 | bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}), 64 | bracketR: new TokenType("]"), 65 | braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}), 66 | braceR: new TokenType("}"), 67 | parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}), 68 | parenR: new TokenType(")"), 69 | comma: new TokenType(",", beforeExpr), 70 | semi: new TokenType(";", beforeExpr), 71 | colon: new TokenType(":", beforeExpr), 72 | dot: new TokenType("."), 73 | question: new TokenType("?", beforeExpr), 74 | questionDot: new TokenType("?."), 75 | arrow: new TokenType("=>", beforeExpr), 76 | template: new TokenType("template"), 77 | invalidTemplate: new TokenType("invalidTemplate"), 78 | ellipsis: new TokenType("...", beforeExpr), 79 | backQuote: new TokenType("`", startsExpr), 80 | dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}), 81 | 82 | // Operators. These carry several kinds of properties to help the 83 | // parser use them properly (the presence of these properties is 84 | // what categorizes them as operators). 85 | // 86 | // `binop`, when present, specifies that this operator is a binary 87 | // operator, and will refer to its precedence. 88 | // 89 | // `prefix` and `postfix` mark the operator as a prefix or postfix 90 | // unary operator. 91 | // 92 | // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as 93 | // binary operators with a very low precedence, that should result 94 | // in AssignmentExpression nodes. 95 | 96 | eq: new TokenType("=", {beforeExpr: true, isAssign: true}), 97 | assign: new TokenType("_=", {beforeExpr: true, isAssign: true}), 98 | incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}), 99 | prefix: new TokenType("!/~", {beforeExpr: true, prefix: true, startsExpr: true}), 100 | logicalOR: binop("||", 1), 101 | logicalAND: binop("&&", 2), 102 | bitwiseOR: binop("|", 3), 103 | bitwiseXOR: binop("^", 4), 104 | bitwiseAND: binop("&", 5), 105 | equality: binop("==/!=/===/!==", 6), 106 | relational: binop("/<=/>=", 7), 107 | bitShift: binop("<>/>>>", 8), 108 | plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}), 109 | modulo: binop("%", 10), 110 | star: binop("*", 10), 111 | slash: binop("/", 10), 112 | starstar: new TokenType("**", {beforeExpr: true}), 113 | coalesce: binop("??", 1), 114 | 115 | // Keyword token types. 116 | _break: kw("break"), 117 | _case: kw("case", beforeExpr), 118 | _catch: kw("catch"), 119 | _continue: kw("continue"), 120 | _debugger: kw("debugger"), 121 | _default: kw("default", beforeExpr), 122 | _do: kw("do", {isLoop: true, beforeExpr: true}), 123 | _else: kw("else", beforeExpr), 124 | _finally: kw("finally"), 125 | _for: kw("for", {isLoop: true}), 126 | _function: kw("function", startsExpr), 127 | _if: kw("if"), 128 | _return: kw("return", beforeExpr), 129 | _switch: kw("switch"), 130 | _throw: kw("throw", beforeExpr), 131 | _try: kw("try"), 132 | _var: kw("var"), 133 | _const: kw("const"), 134 | _while: kw("while", {isLoop: true}), 135 | _with: kw("with"), 136 | _new: kw("new", {beforeExpr: true, startsExpr: true}), 137 | _this: kw("this", startsExpr), 138 | _super: kw("super", startsExpr), 139 | _class: kw("class", startsExpr), 140 | _extends: kw("extends", beforeExpr), 141 | _export: kw("export"), 142 | _import: kw("import", startsExpr), 143 | _null: kw("null", startsExpr), 144 | _true: kw("true", startsExpr), 145 | _false: kw("false", startsExpr), 146 | _in: kw("in", {beforeExpr: true, binop: 7}), 147 | _instanceof: kw("instanceof", {beforeExpr: true, binop: 7}), 148 | _typeof: kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true}), 149 | _void: kw("void", {beforeExpr: true, prefix: true, startsExpr: true}), 150 | _delete: kw("delete", {beforeExpr: true, prefix: true, startsExpr: true}) 151 | } 152 | -------------------------------------------------------------------------------- /acorn/src/unicode-property-data.js: -------------------------------------------------------------------------------- 1 | import {wordsRegexp} from "./util.js" 2 | 3 | // This file contains Unicode properties extracted from the ECMAScript 4 | // specification. The lists are extracted like so: 5 | // $$('#table-binary-unicode-properties > figure > table > tbody > tr > td:nth-child(1) code').map(el => el.innerText) 6 | 7 | // #table-binary-unicode-properties 8 | const ecma9BinaryProperties = "ASCII ASCII_Hex_Digit AHex Alphabetic Alpha Any Assigned Bidi_Control Bidi_C Bidi_Mirrored Bidi_M Case_Ignorable CI Cased Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Changes_When_Titlecased CWT Changes_When_Uppercased CWU Dash Default_Ignorable_Code_Point DI Deprecated Dep Diacritic Dia Emoji Emoji_Component Emoji_Modifier Emoji_Modifier_Base Emoji_Presentation Extender Ext Grapheme_Base Gr_Base Grapheme_Extend Gr_Ext Hex_Digit Hex IDS_Binary_Operator IDSB IDS_Trinary_Operator IDST ID_Continue IDC ID_Start IDS Ideographic Ideo Join_Control Join_C Logical_Order_Exception LOE Lowercase Lower Math Noncharacter_Code_Point NChar Pattern_Syntax Pat_Syn Pattern_White_Space Pat_WS Quotation_Mark QMark Radical Regional_Indicator RI Sentence_Terminal STerm Soft_Dotted SD Terminal_Punctuation Term Unified_Ideograph UIdeo Uppercase Upper Variation_Selector VS White_Space space XID_Continue XIDC XID_Start XIDS" 9 | const ecma10BinaryProperties = ecma9BinaryProperties + " Extended_Pictographic" 10 | const ecma11BinaryProperties = ecma10BinaryProperties 11 | const ecma12BinaryProperties = ecma11BinaryProperties + " EBase EComp EMod EPres ExtPict" 12 | const unicodeBinaryProperties = { 13 | 9: ecma9BinaryProperties, 14 | 10: ecma10BinaryProperties, 15 | 11: ecma11BinaryProperties, 16 | 12: ecma12BinaryProperties 17 | } 18 | 19 | // #table-unicode-general-category-values 20 | const unicodeGeneralCategoryValues = "Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu" 21 | 22 | // #table-unicode-script-values 23 | const ecma9ScriptValues = "Adlam Adlm Ahom Ahom Anatolian_Hieroglyphs Hluw Arabic Arab Armenian Armn Avestan Avst Balinese Bali Bamum Bamu Bassa_Vah Bass Batak Batk Bengali Beng Bhaiksuki Bhks Bopomofo Bopo Brahmi Brah Braille Brai Buginese Bugi Buhid Buhd Canadian_Aboriginal Cans Carian Cari Caucasian_Albanian Aghb Chakma Cakm Cham Cham Cherokee Cher Common Zyyy Coptic Copt Qaac Cuneiform Xsux Cypriot Cprt Cyrillic Cyrl Deseret Dsrt Devanagari Deva Duployan Dupl Egyptian_Hieroglyphs Egyp Elbasan Elba Ethiopic Ethi Georgian Geor Glagolitic Glag Gothic Goth Grantha Gran Greek Grek Gujarati Gujr Gurmukhi Guru Han Hani Hangul Hang Hanunoo Hano Hatran Hatr Hebrew Hebr Hiragana Hira Imperial_Aramaic Armi Inherited Zinh Qaai Inscriptional_Pahlavi Phli Inscriptional_Parthian Prti Javanese Java Kaithi Kthi Kannada Knda Katakana Kana Kayah_Li Kali Kharoshthi Khar Khmer Khmr Khojki Khoj Khudawadi Sind Lao Laoo Latin Latn Lepcha Lepc Limbu Limb Linear_A Lina Linear_B Linb Lisu Lisu Lycian Lyci Lydian Lydi Mahajani Mahj Malayalam Mlym Mandaic Mand Manichaean Mani Marchen Marc Masaram_Gondi Gonm Meetei_Mayek Mtei Mende_Kikakui Mend Meroitic_Cursive Merc Meroitic_Hieroglyphs Mero Miao Plrd Modi Modi Mongolian Mong Mro Mroo Multani Mult Myanmar Mymr Nabataean Nbat New_Tai_Lue Talu Newa Newa Nko Nkoo Nushu Nshu Ogham Ogam Ol_Chiki Olck Old_Hungarian Hung Old_Italic Ital Old_North_Arabian Narb Old_Permic Perm Old_Persian Xpeo Old_South_Arabian Sarb Old_Turkic Orkh Oriya Orya Osage Osge Osmanya Osma Pahawh_Hmong Hmng Palmyrene Palm Pau_Cin_Hau Pauc Phags_Pa Phag Phoenician Phnx Psalter_Pahlavi Phlp Rejang Rjng Runic Runr Samaritan Samr Saurashtra Saur Sharada Shrd Shavian Shaw Siddham Sidd SignWriting Sgnw Sinhala Sinh Sora_Sompeng Sora Soyombo Soyo Sundanese Sund Syloti_Nagri Sylo Syriac Syrc Tagalog Tglg Tagbanwa Tagb Tai_Le Tale Tai_Tham Lana Tai_Viet Tavt Takri Takr Tamil Taml Tangut Tang Telugu Telu Thaana Thaa Thai Thai Tibetan Tibt Tifinagh Tfng Tirhuta Tirh Ugaritic Ugar Vai Vaii Warang_Citi Wara Yi Yiii Zanabazar_Square Zanb" 24 | const ecma10ScriptValues = ecma9ScriptValues + " Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd" 25 | const ecma11ScriptValues = ecma10ScriptValues + " Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho" 26 | const ecma12ScriptValues = ecma11ScriptValues + " Chorasmian Chrs Diak Dives_Akuru Khitan_Small_Script Kits Yezi Yezidi" 27 | const unicodeScriptValues = { 28 | 9: ecma9ScriptValues, 29 | 10: ecma10ScriptValues, 30 | 11: ecma11ScriptValues, 31 | 12: ecma12ScriptValues 32 | } 33 | 34 | const data = {} 35 | function buildUnicodeData(ecmaVersion) { 36 | let d = data[ecmaVersion] = { 37 | binary: wordsRegexp(unicodeBinaryProperties[ecmaVersion] + " " + unicodeGeneralCategoryValues), 38 | nonBinary: { 39 | General_Category: wordsRegexp(unicodeGeneralCategoryValues), 40 | Script: wordsRegexp(unicodeScriptValues[ecmaVersion]) 41 | } 42 | } 43 | d.nonBinary.Script_Extensions = d.nonBinary.Script 44 | 45 | d.nonBinary.gc = d.nonBinary.General_Category 46 | d.nonBinary.sc = d.nonBinary.Script 47 | d.nonBinary.scx = d.nonBinary.Script_Extensions 48 | } 49 | buildUnicodeData(9) 50 | buildUnicodeData(10) 51 | buildUnicodeData(11) 52 | buildUnicodeData(12) 53 | 54 | export default data 55 | -------------------------------------------------------------------------------- /acorn/src/util.js: -------------------------------------------------------------------------------- 1 | const {hasOwnProperty, toString} = Object.prototype 2 | 3 | // Checks if an object has a property. 4 | 5 | export function has(obj, propName) { 6 | return hasOwnProperty.call(obj, propName) 7 | } 8 | 9 | export const isArray = Array.isArray || ((obj) => ( 10 | toString.call(obj) === "[object Array]" 11 | )) 12 | 13 | export function wordsRegexp(words) { 14 | return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$") 15 | } 16 | -------------------------------------------------------------------------------- /acorn/src/whitespace.js: -------------------------------------------------------------------------------- 1 | // Matches a whole line break (where CRLF is considered a single 2 | // line break). Used to count lines. 3 | 4 | export const lineBreak = /\r\n?|\n|\u2028|\u2029/ 5 | export const lineBreakG = new RegExp(lineBreak.source, "g") 6 | 7 | export function isNewLine(code, ecma2019String) { 8 | return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029)) 9 | } 10 | 11 | export const nonASCIIwhitespace = /[\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]/ 12 | 13 | export const skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g 14 | -------------------------------------------------------------------------------- /bin/generate-identifier-regex.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Which Unicode version should be used? 4 | let pkg = require('../package.json') 5 | let dependencies = Object.keys(pkg.devDependencies) 6 | let unicodeVersion = dependencies.find((name) => /^unicode-\d/.test(name)) 7 | 8 | let start = require(unicodeVersion + '/Binary_Property/ID_Start/code-points.js').filter(ch => ch > 0x7f) 9 | let last = -1 10 | let cont = [0x200c, 0x200d].concat(require(unicodeVersion + '/Binary_Property/ID_Continue/code-points.js') 11 | .filter(ch => ch > 0x7f && search(start, ch, last + 1) === -1)) 12 | 13 | function search(arr, ch, starting) { 14 | for (let i = starting; arr[i] <= ch && i < arr.length; last = i++) 15 | if (arr[i] === ch) return i 16 | return -1 17 | } 18 | 19 | function esc(code) { 20 | let hex = code.toString(16) 21 | return hex.length <= 2 ? "\\x" + hex.padStart(2, "0") : "\\u" + hex.padStart(4, "0") 22 | } 23 | 24 | function generate(chars) { 25 | let astral = [], re = "" 26 | for (let i = 0, at = 0x10000; i < chars.length; i++) { 27 | let from = chars[i], to = from 28 | while (i < chars.length - 1 && chars[i + 1] === to + 1) {i++; to++} 29 | if (to <= 0xffff) { 30 | if (from === to) re += esc(from) 31 | else if (from + 1 === to) re += esc(from) + esc(to) 32 | else re += esc(from) + "-" + esc(to) 33 | } else { 34 | astral.push(from - at, to - from) 35 | at = to 36 | } 37 | } 38 | return {nonASCII: re, astral: astral} 39 | } 40 | 41 | let startData = generate(start), contData = generate(cont) 42 | 43 | let code = [ 44 | ` let nonASCIIidentifierStartChars = "${startData.nonASCII}"`, 45 | ` let nonASCIIidentifierChars = "${contData.nonASCII}"`, 46 | ` const astralIdentifierStartCodes = ${JSON.stringify(startData.astral)}`, 47 | ` const astralIdentifierCodes = ${JSON.stringify(contData.astral)}` 48 | ] 49 | 50 | if (process.argv.length != 3) { 51 | console.log(code.join("\n")) 52 | } else { 53 | let {readFile} = require('fs') 54 | readFile(process.argv[2], "utf8", function(err, data) { 55 | if (err) throw err 56 | for (let line of code) 57 | data = data.replace(new RegExp(/.* = /.exec(line)[0] + ".*"), line) 58 | process.stdout.write(data) 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /bin/run_test262.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path") 3 | const run = require("test262-parser-runner") 4 | const parse = require("../acorn").parse 5 | 6 | const unsupportedFeatures = [ 7 | "regexp-match-indices", 8 | "arbitrary-module-namespace-names", 9 | "class-fields-private-in" 10 | ]; 11 | 12 | run( 13 | (content, {sourceType}) => parse(content, {sourceType, ecmaVersion: 13, allowHashBang: true, allowAwaitOutsideFunction: sourceType === "module"}), 14 | { 15 | testsDirectory: path.dirname(require.resolve("test262/package.json")), 16 | skip: test => (test.attrs.features && unsupportedFeatures.some(f => test.attrs.features.includes(f))), 17 | whitelist: fs.readFileSync("./bin/test262.whitelist", "utf8") 18 | .split("\n") 19 | .filter(Boolean) 20 | .map(filename => path.sep !== "/" ? filename.split("/").join(path.sep) : filename) 21 | } 22 | ) 23 | -------------------------------------------------------------------------------- /bin/test262.whitelist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farhan7reza7/acorn/46d2f69ec61c7dc2fde2f029212aa6e4d69c4757/bin/test262.whitelist -------------------------------------------------------------------------------- /bin/update_authors.sh: -------------------------------------------------------------------------------- 1 | echo "List of Acorn contributors. Updated before every release." > AUTHORS 2 | echo >> AUTHORS 3 | git log --format='%aN' | sort -uf >> AUTHORS 4 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "maintainers": [ 3 | { 4 | "name": "Marijn Haverbeke", 5 | "email": "marijnh@gmail.com", 6 | "web": "http://marijnhaverbeke.nl" 7 | }, 8 | { 9 | "name": "Ingvar Stepanyan", 10 | "email": "me@rreverser.com", 11 | "web": "http://rreverser.com/" 12 | }, 13 | { 14 | "name": "Adrian Heine", 15 | "web": "http://adrianheine.de" 16 | } 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/acornjs/acorn.git" 21 | }, 22 | "license": "MIT", 23 | "scripts": { 24 | "prepare": "npm run test", 25 | "test": "node test/run.js && node test/lint.js", 26 | "pretest": "npm run build:main && npm run build:loose", 27 | "test:test262": "node bin/run_test262.js", 28 | "build": "npm run build:main && npm run build:walk && npm run build:loose && npm run build:bin", 29 | "build:main": "rollup -c acorn/rollup.config.js", 30 | "build:walk": "rollup -c acorn-walk/rollup.config.js", 31 | "build:loose": "rollup -c acorn-loose/rollup.config.js", 32 | "build:bin": "rollup -c acorn/rollup.config.bin.js", 33 | "lint": "eslint acorn/src/ acorn-walk/src/ acorn-loose/src/" 34 | }, 35 | "devDependencies": { 36 | "eslint": "^4.10.0", 37 | "eslint-config-standard": "^10.2.1", 38 | "eslint-plugin-import": "^2.2.0", 39 | "eslint-plugin-node": "^5.2.1", 40 | "eslint-plugin-promise": "^3.5.0", 41 | "eslint-plugin-standard": "^3.0.1", 42 | "rollup": "^1.7.0", 43 | "rollup-plugin-buble": "^0.19.0", 44 | "test262": "git+https://github.com/tc39/test262.git#61c6f8214bd0c6d72059578e80ce7659aff984bd", 45 | "test262-parser-runner": "^0.5.0", 46 | "test262-stream": "^1.2.1", 47 | "unicode-13.0.0": "^0.8.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/bench/common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isWorker = typeof importScripts !== 'undefined'; 4 | 5 | // var because must leak into globals 6 | var module, exports, req; 7 | 8 | // CommonJS shim for Web Worker 9 | if (isWorker) { 10 | exports = self; 11 | 12 | req = (name, urlPrefix = 'https://unpkg.com/') => { 13 | let oldModule = module, oldExports = exports; 14 | exports = {}; 15 | module = { exports }; 16 | importScripts(urlPrefix + name); 17 | let exported = module.exports; 18 | module = oldModule; 19 | exports = oldExports; 20 | return exported; 21 | }; 22 | } else { 23 | req = require; 24 | } 25 | 26 | exports.parsers = { 27 | 'Acorn (dev)'() { 28 | const { parse } = req('../../acorn/dist/acorn.js', ''); 29 | return { 30 | version: '', 31 | parse: s => parse(s, { locations: true }) 32 | }; 33 | }, 34 | 35 | 'Acorn'() { 36 | const { version, parse } = req('acorn'); 37 | return { 38 | version, 39 | parse: s => parse(s, { locations: true }) 40 | }; 41 | }, 42 | 43 | 'Esprima'() { 44 | const { version, parse } = req('esprima'); 45 | return { 46 | version, 47 | parse: s => parse(s, { loc: true }) 48 | } 49 | }, 50 | 51 | 'TypeScript'() { 52 | const { version, createSourceFile, ScriptTarget: { ES6 } } = req('typescript'); 53 | return { 54 | version, 55 | parse: s => createSourceFile('source.js', s, ES6) 56 | }; 57 | }, 58 | 59 | 'Traceur'() { 60 | req('traceur/bin/traceur.js'); // it creates a global :( 61 | const { SourceFile, Parser } = traceur.syntax; 62 | return { 63 | version: traceur.loader.TraceurLoader.prototype.version, 64 | parse: s => new Parser(new SourceFile('source.js', s)).parseScript() 65 | } 66 | }, 67 | 68 | 'Flow'() { 69 | const { parse } = req('flow-parser'); 70 | return { 71 | version: isWorker ? '' : require('flow-parser/package.json').version, 72 | parse 73 | }; 74 | }, 75 | 76 | 'Babylon'() { 77 | const { parse } = req('babylon'); 78 | return { 79 | version: isWorker ? '' : require('babylon/package.json').version, 80 | parse 81 | }; 82 | }, 83 | }; 84 | 85 | exports.parserNames = Object.keys(exports.parsers); 86 | 87 | exports.inputNames = [ 88 | 'angular.js', 89 | 'backbone.js', 90 | 'ember.js', 91 | 'jquery.js', 92 | 'react-dom.js', 93 | 'react.js' 94 | ]; 95 | 96 | let read; 97 | 98 | if (isWorker) { 99 | read = name => fetch(name).then(response => response.text()); 100 | } else { 101 | const { readFile } = require('fs'); 102 | 103 | read = name => new Promise((resolve, reject) => { 104 | readFile(`${__dirname}/${name}`, 'utf-8', (err, data) => { 105 | err ? reject(err) : resolve(data); 106 | }); 107 | }); 108 | } 109 | 110 | exports.inputs = Promise.all( 111 | exports.inputNames 112 | .map(name => read(`fixtures/${name}`)) 113 | ); 114 | -------------------------------------------------------------------------------- /test/bench/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Acorn benchmark 5 | 35 | 36 | 37 |

JavaScript parsers speed comparison

38 | 39 |

The table below will contain generic summary (ops/sec or type of error) for 40 | each parser/input combination. If something doesn't look right, you can find 41 | more details in the devtools console afterwards.

42 | 43 |

Note that having the developer tools open in browser heavily 44 | influences the numbers you get. In Chrome, the effect even lingers (in the tab) 45 | after you close the developer tools. Load in a fresh tab to get (halfway) stable 46 | numbers.

47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
58 | 59 | 177 | -------------------------------------------------------------------------------- /test/bench/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BenchTable = require('benchtable'); 4 | const { parsers, parserNames, inputs, inputNames } = require('./common'); 5 | 6 | const yargs = require('yargs') 7 | .help() 8 | .alias('?', 'help'); 9 | 10 | const optionNames = new Map(parserNames.map(name => [ 11 | name, 12 | 13 | name 14 | .toLowerCase() 15 | .replace(/[^a-z]+/g, '-') 16 | .replace(/(^-|-$)/g, '') 17 | ])); 18 | 19 | parserNames.forEach(name => { 20 | yargs.option(optionNames.get(name), { 21 | group: 'Benchmark parsers:', 22 | describe: name, 23 | type: 'boolean', 24 | default: name.startsWith('Acorn') || undefined 25 | }); 26 | }); 27 | 28 | const { argv } = yargs; 29 | 30 | let suite = new BenchTable('parsers', { isTransposed: true }); 31 | 32 | parserNames.forEach(name => { 33 | if (!argv[optionNames.get(name)]) { 34 | return; 35 | } 36 | const { version, parse } = parsers[name](); 37 | if (version) { 38 | name += ` ${version}`; 39 | } 40 | console.log(`Enabled ${name}`); 41 | suite.addFunction(name, parse); 42 | }); 43 | 44 | console.log('Running benchmarks...'); 45 | 46 | inputs.then(inputs => { 47 | inputNames.forEach((inputName, i) => { 48 | suite.addInput(inputName, [inputs[i]]); 49 | }); 50 | 51 | suite 52 | .on('cycle', function (event) { 53 | console.log(event.target.toString()); 54 | }) 55 | .on('error', function (event) { 56 | throw event.target.error; 57 | }) 58 | .on('complete', function () { 59 | console.log(suite.table.toString()); 60 | }) 61 | .run() 62 | }).catch(console.error); 63 | -------------------------------------------------------------------------------- /test/bench/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acorn-benchmarks", 3 | "description": "Acorn benchmarks meta-package", 4 | "version": "0.0.0", 5 | "private": true, 6 | "maintainers": [ 7 | { 8 | "name": "Marijn Haverbeke", 9 | "email": "marijnh@gmail.com", 10 | "web": "http://marijnhaverbeke.nl" 11 | }, 12 | { 13 | "name": "Ingvar Stepanyan", 14 | "email": "me@rreverser.com", 15 | "web": "http://rreverser.com/" 16 | } 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/acornjs/acorn.git" 21 | }, 22 | "license": "MIT", 23 | "dependencies": { 24 | "acorn": "*", 25 | "babylon": "*", 26 | "benchtable": "^0.1.0", 27 | "esprima": "*", 28 | "flow-parser": "*", 29 | "traceur": "*", 30 | "typescript": "*", 31 | "yargs": "^8.0.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/bench/worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | importScripts('common.js'); 4 | 5 | const Benchmark = req('benchmark').runInContext({ 6 | _: req('lodash') 7 | }); 8 | 9 | postMessage({ 10 | parserNames, 11 | inputNames 12 | }); 13 | 14 | function getCell(bench) { 15 | return parserNames.indexOf(bench.name); 16 | } 17 | 18 | onmessage = ({ data: indices }) => { 19 | // Using block to workaround https://github.com/Microsoft/ChakraCore/issues/2606 20 | inputs.then(inputs => { 21 | let chosenParsers = 22 | parserNames 23 | .filter((_, i) => indices.includes(i)) 24 | .map(name => Object.assign(parsers[name](), { name })); 25 | 26 | postMessage({ 27 | type: 'versions', 28 | versions: chosenParsers.map(parser => parser.version) 29 | }); 30 | 31 | inputs.forEach((input, row) => { 32 | let suite = new Benchmark.Suite(); 33 | 34 | chosenParsers.forEach(({ name, parse }) => { 35 | suite.add(name, () => parse(input)); 36 | }); 37 | 38 | let indicesIter = indices[Symbol.iterator](); 39 | 40 | console.group(`Parsing ${inputNames[row]}`); 41 | 42 | postMessage({ 43 | type: 'start', 44 | row, 45 | cell: indicesIter.next().value 46 | }); 47 | 48 | function reportCell(bench, type, text) { 49 | postMessage({ 50 | type, 51 | row, 52 | cell: getCell(bench), 53 | nextCell: indicesIter.next().value, 54 | text 55 | }); 56 | } 57 | 58 | suite 59 | .on('cycle', ({ target: bench }) => { 60 | console.log(bench.toString()); 61 | reportCell(bench, 'cycle', `${bench.hz.toFixed(2)} ops/sec`); 62 | }) 63 | .on('error', ({ target: bench }) => { 64 | console.error(bench.error); 65 | reportCell(bench, 'error', bench.error.name); 66 | }) 67 | .on('complete', ({ target }) => { 68 | postMessage({ 69 | type: 'complete', 70 | row, 71 | slowest: suite.filter('slowest').map(getCell), 72 | fastest: suite.filter('fastest').map(getCell) 73 | }); 74 | }) 75 | .run(); 76 | 77 | console.groupEnd(); 78 | }); 79 | }).catch(console.error); 80 | }; 81 | -------------------------------------------------------------------------------- /test/driver.js: -------------------------------------------------------------------------------- 1 | var tests = []; 2 | 3 | exports.test = function(code, ast, options) { 4 | tests.push({code: code, ast: ast, options: options}); 5 | }; 6 | exports.testFail = function(code, message, options) { 7 | tests.push({code: code, error: message, options: options}); 8 | }; 9 | exports.testAssert = function(code, assert, options) { 10 | tests.push({code: code, assert: assert, options: options}); 11 | }; 12 | 13 | exports.runTests = function(config, callback) { 14 | var parse = config.parse; 15 | 16 | for (var i = 0; i < tests.length; ++i) { 17 | var test = tests[i]; 18 | if (config.filter && !config.filter(test)) continue; 19 | var testOpts = test.options || {locations: true}; 20 | if (!testOpts.ecmaVersion) testOpts.ecmaVersion = 5; 21 | var expected = {}; 22 | if (expected.onComment = testOpts.onComment) 23 | testOpts.onComment = [] 24 | if (expected.onToken = testOpts.onToken) 25 | testOpts.onToken = []; 26 | 27 | try { 28 | var ast = parse(test.code, testOpts); 29 | } catch(e) { 30 | if (!(e instanceof SyntaxError)) { console.log(e.stack); throw e; } 31 | if (test.error) { 32 | if (test.error.charAt(0) == "~" ? e.message.indexOf(test.error.slice(1)) > -1 : e.message == test.error) 33 | callback("ok", test.code); 34 | else 35 | callback("fail", test.code, "Expected error message: " + test.error + "\nGot error message: " + e.message); 36 | } else { 37 | callback("error", test.code, e.message || e.toString()); 38 | } 39 | continue 40 | } 41 | 42 | if (test.error) { 43 | if (config.loose) callback("ok", test.code); 44 | else callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded."); 45 | } else if (test.assert) { 46 | var error = test.assert(ast); 47 | if (error) callback("fail", test.code, "\n Assertion failed:\n " + error); 48 | else callback("ok", test.code); 49 | } else { 50 | var mis = misMatch(test.ast, ast); 51 | for (var name in expected) { 52 | if (mis) break; 53 | if (expected[name]) { 54 | mis = misMatch(expected[name], testOpts[name]); 55 | testOpts[name] = expected[name]; 56 | } 57 | } 58 | if (mis) callback("fail", test.code, mis); 59 | else callback("ok", test.code); 60 | } 61 | } 62 | }; 63 | 64 | function ppJSON(v) { return v instanceof RegExp ? v.toString() : (typeof v == "bigint" ? v.toString() : JSON.stringify(v, null, 2)); } 65 | function addPath(str, pt) { 66 | if (str.charAt(str.length-1) == ")") 67 | return str.slice(0, str.length-1) + "/" + pt + ")"; 68 | return str + " (" + pt + ")"; 69 | } 70 | 71 | var misMatch = exports.misMatch = function(exp, act) { 72 | if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) { 73 | if (exp !== act && typeof exp != "function") 74 | return ppJSON(exp) + " !== " + ppJSON(act); 75 | } else if (exp instanceof RegExp || act instanceof RegExp) { 76 | var left = ppJSON(exp), right = ppJSON(act); 77 | if (left !== right) return left + " !== " + right; 78 | } else if (exp.splice) { 79 | if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act); 80 | if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length; 81 | for (var i = 0; i < act.length; ++i) { 82 | var mis = misMatch(exp[i], act[i]); 83 | if (mis) return addPath(mis, i); 84 | } 85 | } else { 86 | for (var prop in exp) { 87 | var mis = misMatch(exp[prop], act[prop]); 88 | if (mis) return addPath(mis, prop); 89 | } 90 | } 91 | }; 92 | 93 | function mangle(ast) { 94 | if (typeof ast != "object" || !ast) return; 95 | if (ast.slice) { 96 | for (var i = 0; i < ast.length; ++i) mangle(ast[i]); 97 | } else { 98 | var loc = ast.start && ast.end && {start: ast.start, end: ast.end}; 99 | if (loc) { delete ast.start; delete ast.end; } 100 | for (var name in ast) if (ast.hasOwnProperty(name)) mangle(ast[name]); 101 | if (loc) ast.loc = loc; 102 | } 103 | } 104 | 105 | -------------------------------------------------------------------------------- /test/lint.js: -------------------------------------------------------------------------------- 1 | if (parseInt(process.versions.node) > 4) { 2 | console.log("Linting...") 3 | var join = require("path").join 4 | try { 5 | require("child_process").execSync( 6 | join("node_modules", ".bin", "eslint") + " " + join(__dirname, "..", "*", "src"), 7 | {encoding: "utf8", stdio: "inherit"} 8 | ) 9 | console.log("OK") 10 | } catch (_) { 11 | process.exit(1) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/run.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var driver = require("./driver.js") 3 | require("./tests.js"); 4 | require("./tests-harmony.js"); 5 | require("./tests-es7.js"); 6 | require("./tests-asyncawait.js"); 7 | require("./tests-await-top-level.js"); 8 | require("./tests-trailing-commas-in-func.js"); 9 | require("./tests-template-literal-revision.js"); 10 | require("./tests-directive.js"); 11 | require("./tests-rest-spread-properties.js"); 12 | require("./tests-async-iteration.js"); 13 | require("./tests-regexp.js"); 14 | require("./tests-regexp-2018.js"); 15 | require("./tests-regexp-2020.js"); 16 | require("./tests-regexp-2022.js"); 17 | require("./tests-json-superset.js"); 18 | require("./tests-optional-catch-binding.js"); 19 | require("./tests-bigint.js"); 20 | require("./tests-dynamic-import.js"); 21 | require("./tests-export-all-as-ns-from-source.js"); 22 | require("./tests-import-meta.js"); 23 | require("./tests-nullish-coalescing.js"); 24 | require("./tests-optional-chaining.js"); 25 | require("./tests-logical-assignment-operators.js"); 26 | require("./tests-numeric-separators.js"); 27 | require("./tests-class-features-2022.js"); 28 | var acorn = require("../acorn") 29 | var acorn_loose = require("../acorn-loose") 30 | 31 | var htmlLog = typeof document === "object" && document.getElementById('log'); 32 | var htmlGroup = htmlLog; 33 | 34 | function group(name) { 35 | if (htmlGroup) { 36 | var parentGroup = htmlGroup; 37 | htmlGroup = document.createElement("ul"); 38 | var item = document.createElement("li"); 39 | item.textContent = name; 40 | item.appendChild(htmlGroup); 41 | parentGroup.appendChild(item); 42 | } 43 | if (typeof console === "object" && console.group) { 44 | console.group(name); 45 | } 46 | } 47 | 48 | function groupEnd() { 49 | if (htmlGroup) { 50 | htmlGroup = htmlGroup.parentElement.parentElement; 51 | } 52 | if (typeof console === "object" && console.groupEnd) { 53 | console.groupEnd(name); 54 | } 55 | } 56 | 57 | function log(title, message) { 58 | if (htmlGroup) { 59 | var elem = document.createElement("li"); 60 | elem.innerHTML = "" + title + " " + message; 61 | htmlGroup.appendChild(elem); 62 | } 63 | if (typeof console === "object") console.log(title, message); 64 | } 65 | 66 | var stats, modes = { 67 | Normal: { 68 | config: { 69 | parse: acorn.parse 70 | } 71 | }, 72 | Loose: { 73 | config: { 74 | parse: acorn_loose.parse, 75 | loose: true, 76 | filter: function (test) { 77 | var opts = test.options || {}; 78 | return opts.loose !== false; 79 | } 80 | } 81 | } 82 | }; 83 | 84 | function report(state, code, message) { 85 | if (state != "ok") {++stats.failed; log(code, message);} 86 | ++stats.testsRun; 87 | } 88 | 89 | group("Errors"); 90 | 91 | for (var name in modes) { 92 | group(name); 93 | var mode = modes[name]; 94 | stats = mode.stats = {testsRun: 0, failed: 0}; 95 | var t0 = +new Date; 96 | driver.runTests(mode.config, report); 97 | mode.stats.duration = +new Date - t0; 98 | groupEnd(); 99 | } 100 | 101 | groupEnd(); 102 | 103 | function outputStats(name, stats) { 104 | log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " + 105 | (stats.failed ? stats.failed + " failures." : "all passed.")); 106 | } 107 | 108 | var total = {testsRun: 0, failed: 0, duration: 0}; 109 | 110 | group("Stats"); 111 | 112 | for (var name in modes) { 113 | var stats = modes[name].stats; 114 | outputStats(name + " parser", stats); 115 | for (var key in stats) total[key] += stats[key]; 116 | } 117 | 118 | outputStats("Total", total); 119 | 120 | groupEnd(); 121 | 122 | if (total.failed && typeof process === "object") { 123 | process.stdout.write("", function() { 124 | process.exit(1); 125 | }); 126 | } 127 | })(); 128 | -------------------------------------------------------------------------------- /test/tests-await-top-level.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | //------------------------------------------------------------------------------ 7 | // await-top-level 8 | //------------------------------------------------------------------------------ 9 | 10 | testFail("await 1", "Unexpected token (1:6)", {ecmaVersion: 8}) 11 | test("await 1", { 12 | "type": "Program", 13 | "start": 0, 14 | "end": 7, 15 | "body": [ 16 | { 17 | "type": "ExpressionStatement", 18 | "start": 0, 19 | "end": 7, 20 | "expression": { 21 | "type": "AwaitExpression", 22 | "start": 0, 23 | "end": 7, 24 | "argument": { 25 | "type": "Literal", 26 | "start": 6, 27 | "end": 7, 28 | "value": 1 29 | } 30 | } 31 | } 32 | ] 33 | }, {allowAwaitOutsideFunction: true, ecmaVersion: 8}) 34 | testFail("function foo() {return await 1}", "Unexpected token (1:29)", {ecmaVersion: 8}) 35 | testFail("function foo() {return await 1}", "Unexpected token (1:29)", { 36 | allowAwaitOutsideFunction: true, 37 | ecmaVersion: 8 38 | }) 39 | // ES2022 40 | test("await 1", { 41 | "type": "Program", 42 | "start": 0, 43 | "end": 7, 44 | "body": [ 45 | { 46 | "type": "ExpressionStatement", 47 | "start": 0, 48 | "end": 7, 49 | "expression": { 50 | "type": "AwaitExpression", 51 | "start": 0, 52 | "end": 7, 53 | "argument": { 54 | "type": "Literal", 55 | "start": 6, 56 | "end": 7, 57 | "value": 1 58 | } 59 | } 60 | } 61 | ] 62 | }, {ecmaVersion: 13, sourceType: "module"}) 63 | testFail("function foo() {return await 1}", "Unexpected token (1:29)", {ecmaVersion: 13}) 64 | testFail("await 1", "Unexpected token (1:6)", { 65 | allowAwaitOutsideFunction: false, 66 | ecmaVersion: 13 67 | }) 68 | testFail("await 1", "Unexpected token (1:6)", {ecmaVersion: 12}) 69 | -------------------------------------------------------------------------------- /test/tests-bigint.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test; 3 | var testFail = require("./driver.js").testFail; 4 | } 5 | 6 | const newBigIntLiteral = (start, stringValue) => ({ 7 | start: start, 8 | type: "Literal", 9 | end: start + stringValue.length + 1, 10 | value: typeof BigInt !== "undefined" ? BigInt(stringValue) : null, 11 | raw: `${stringValue}n`, 12 | bigint: stringValue 13 | }) 14 | 15 | const digits = [ 16 | {d: "0", ast: start => newBigIntLiteral(start, "0")}, 17 | {d: "2", ast: start => newBigIntLiteral(start, "2")}, 18 | {d: "0x2", ast: start => newBigIntLiteral(start, "0x2")}, 19 | {d: "0o2", ast: start => newBigIntLiteral(start, "0o2")}, 20 | {d: "0b10", ast: start => newBigIntLiteral(start, "0b10")}, 21 | {d: "-0xbf2ed51ff75d380fd3be813ec6185780", ast: start => ({ 22 | start: start, 23 | type: "UnaryExpression", 24 | end: start + 36, 25 | operator: "-", 26 | prefix: true, 27 | argument: newBigIntLiteral(start + 1, "0xbf2ed51ff75d380fd3be813ec6185780") 28 | })}, 29 | {d: "02", error: start => `Identifier directly after number (1:${start + 2})`}, 30 | {d: "2e2", error: start => `Identifier directly after number (1:${start + 3})`}, 31 | {d: "2.4", error: start => `Identifier directly after number (1:${start + 3})`}, 32 | {d: ".4", error: start => `Identifier directly after number (1:${start + 2})`}, 33 | ] 34 | const statements = [ 35 | {s: "let i = %s", ast: content => ({ 36 | start: 0, 37 | type: "VariableDeclaration", 38 | end: content.end, 39 | kind: "let", 40 | declarations: [{ 41 | start: 4, 42 | type: "VariableDeclarator", 43 | end: content.end, 44 | id: { 45 | start: 4, 46 | type: "Identifier", 47 | end: 5, 48 | name: "i" 49 | }, 50 | init: content 51 | }] 52 | })}, 53 | 54 | {s: "i = %s", ast: content => ({ 55 | start: 0, 56 | type: "ExpressionStatement", 57 | end: content.end, 58 | expression: { 59 | start: 0, 60 | type: "AssignmentExpression", 61 | end: content.end, 62 | operator: "=", 63 | left: { 64 | start: 0, 65 | type: "Identifier", 66 | end: 1, 67 | name: "i" 68 | }, 69 | right: content 70 | } 71 | })}, 72 | 73 | {s: "((i = %s) => {})", ast: content => ({ 74 | start: 0, 75 | type: "ExpressionStatement", 76 | end: content.end + 8, 77 | expression: { 78 | start: 1, 79 | type: "ArrowFunctionExpression", 80 | end: content.end + 7, 81 | id: null, 82 | generator: false, 83 | expression: false, 84 | async: false, 85 | params: [ 86 | { 87 | start: 2, 88 | type: "AssignmentPattern", 89 | end: content.end, 90 | left: { 91 | start: 2, 92 | type: "Identifier", 93 | end: 3, 94 | name: "i" 95 | }, 96 | right: content 97 | } 98 | ], 99 | body: { 100 | start: content.end + 5, 101 | type: "BlockStatement", 102 | end: content.end + 7, 103 | body: [] 104 | } 105 | } 106 | })}, 107 | 108 | {s: "for (let i = 0n; i < %s;++i) {}", ast: content => ({ 109 | start: 0, 110 | type: "ForStatement", 111 | end: content.end + 8, 112 | init: { 113 | start: 5, 114 | type: "VariableDeclaration", 115 | end: 15, 116 | declarations: [ 117 | { 118 | start: 9, 119 | type: "VariableDeclarator", 120 | end: 15, 121 | id: { 122 | start: 9, 123 | type: "Identifier", 124 | end: 10, 125 | name: "i" 126 | }, 127 | init: newBigIntLiteral(13, "0") 128 | } 129 | ], 130 | kind: "let" 131 | }, 132 | test: { 133 | start: 17, 134 | type: "BinaryExpression", 135 | end: content.end, 136 | left: { 137 | start: 17, 138 | type: "Identifier", 139 | start: 17, 140 | end: 18, 141 | name: "i" 142 | }, 143 | operator: "<", 144 | right: content 145 | }, 146 | update: { 147 | start: content.end + 1, 148 | type: "UpdateExpression", 149 | end: content.end + 4, 150 | operator: "++", 151 | prefix: true, 152 | argument: { 153 | start: content.end + 3, 154 | type: "Identifier", 155 | end: content.end + 4, 156 | name: "i" 157 | } 158 | }, 159 | body: { 160 | start: content.end + 6, 161 | type: "BlockStatement", 162 | end: content.end + 8, 163 | body: [] 164 | } 165 | })}, 166 | 167 | {s: "i + %s", ast: content => ({ 168 | start: 0, 169 | type: "ExpressionStatement", 170 | end: content.end, 171 | expression: { 172 | start: 0, 173 | type: "BinaryExpression", 174 | end: content.end, 175 | left: { 176 | start: 0, 177 | type: "Identifier", 178 | start: 0, 179 | end: 1, 180 | name: "i" 181 | }, 182 | operator: "+", 183 | right: content 184 | } 185 | })} 186 | ] 187 | statements.forEach(statement => { 188 | const start = statement.s.indexOf("%s") 189 | digits.forEach(d => { 190 | (d.error ? testFail : test)( 191 | statement.s.replace("%s", `${d.d}n`), 192 | d.error ? d.error(start) : { type: "Program", body: [ 193 | statement.ast(d.ast(start)) 194 | ]}, { ecmaVersion: 11 } 195 | ) 196 | }) 197 | }) 198 | -------------------------------------------------------------------------------- /test/tests-dynamic-import.js: -------------------------------------------------------------------------------- 1 | // Tests for ECMAScript 2020 dynamic import 2 | 3 | if (typeof exports != 'undefined') { 4 | var test = require('./driver.js').test; 5 | var testFail = require('./driver.js').testFail; 6 | } 7 | 8 | test( 9 | "import('dynamicImport.js')", 10 | { 11 | type: 'Program', 12 | start: 0, 13 | end: 26, 14 | body: [ 15 | { 16 | type: 'ExpressionStatement', 17 | start: 0, 18 | end: 26, 19 | expression: { 20 | type: 'ImportExpression', 21 | start: 0, 22 | end: 26, 23 | source: { 24 | type: 'Literal', 25 | start: 7, 26 | end: 25, 27 | value: 'dynamicImport.js', 28 | raw: "'dynamicImport.js'" 29 | } 30 | } 31 | } 32 | ], 33 | sourceType: 'script' 34 | }, 35 | { ecmaVersion: 11 } 36 | ); 37 | 38 | // Assignment is OK. 39 | test( 40 | "import(a = 'dynamicImport.js')", 41 | { 42 | "type": "Program", 43 | "start": 0, 44 | "end": 30, 45 | "body": [ 46 | { 47 | "type": "ExpressionStatement", 48 | "start": 0, 49 | "end": 30, 50 | "expression": { 51 | "type": "ImportExpression", 52 | "start": 0, 53 | "end": 30, 54 | "source": { 55 | "type": "AssignmentExpression", 56 | "start": 7, 57 | "end": 29, 58 | "operator": "=", 59 | "left": { 60 | "type": "Identifier", 61 | "start": 7, 62 | "end": 8, 63 | "name": "a" 64 | }, 65 | "right": { 66 | "type": "Literal", 67 | "start": 11, 68 | "end": 29, 69 | "value": "dynamicImport.js", 70 | "raw": "'dynamicImport.js'" 71 | } 72 | } 73 | } 74 | } 75 | ], 76 | "sourceType": "script" 77 | }, 78 | { ecmaVersion: 11 } 79 | ); 80 | 81 | test( 82 | "function* a() { yield import('http'); }", 83 | { 84 | type: 'Program', 85 | start: 0, 86 | end: 39, 87 | body: [ 88 | { 89 | type: 'FunctionDeclaration', 90 | start: 0, 91 | end: 39, 92 | id: { type: 'Identifier', start: 10, end: 11, name: 'a' }, 93 | expression: false, 94 | generator: true, 95 | async: false, 96 | params: [], 97 | body: { 98 | type: 'BlockStatement', 99 | start: 14, 100 | end: 39, 101 | body: [ 102 | { 103 | type: 'ExpressionStatement', 104 | start: 16, 105 | end: 37, 106 | expression: { 107 | type: 'YieldExpression', 108 | start: 16, 109 | end: 36, 110 | delegate: false, 111 | argument: { 112 | type: 'ImportExpression', 113 | start: 22, 114 | end: 36, 115 | source: { type: 'Literal', start: 29, end: 35, value: 'http', raw: "'http'" } 116 | } 117 | } 118 | } 119 | ] 120 | } 121 | } 122 | ], 123 | sourceType: 'script' 124 | }, 125 | { ecmaVersion: 11 } 126 | ); 127 | 128 | // `new import(s)` is syntax error, but `new (import(s))` is not. 129 | test( 130 | "new (import(s))", 131 | { 132 | "type": "Program", 133 | "start": 0, 134 | "end": 15, 135 | "body": [ 136 | { 137 | "type": "ExpressionStatement", 138 | "start": 0, 139 | "end": 15, 140 | "expression": { 141 | "type": "NewExpression", 142 | "start": 0, 143 | "end": 15, 144 | "callee": { 145 | "type": "ImportExpression", 146 | "start": 5, 147 | "end": 14, 148 | "source": { 149 | "type": "Identifier", 150 | "start": 12, 151 | "end": 13, 152 | "name": "s" 153 | } 154 | }, 155 | "arguments": [] 156 | } 157 | } 158 | ], 159 | "sourceType": "script" 160 | }, 161 | { ecmaVersion: 11 } 162 | ); 163 | 164 | // `import(s,t)` is syntax error, but `import((s,t))` is not. 165 | test( 166 | "import((s,t))", 167 | { 168 | "type": "Program", 169 | "start": 0, 170 | "end": 13, 171 | "body": [ 172 | { 173 | "type": "ExpressionStatement", 174 | "start": 0, 175 | "end": 13, 176 | "expression": { 177 | "type": "ImportExpression", 178 | "start": 0, 179 | "end": 13, 180 | "source": { 181 | "type": "SequenceExpression", 182 | "start": 8, 183 | "end": 11, 184 | "expressions": [ 185 | { 186 | "type": "Identifier", 187 | "start": 8, 188 | "end": 9, 189 | "name": "s" 190 | }, 191 | { 192 | "type": "Identifier", 193 | "start": 10, 194 | "end": 11, 195 | "name": "t" 196 | } 197 | ] 198 | } 199 | } 200 | } 201 | ], 202 | "sourceType": "script" 203 | }, 204 | { ecmaVersion: 11 } 205 | ); 206 | 207 | testFail('function failsParse() { return import.then(); }', 'The only valid meta property for import is \'import.meta\' (1:38)', { 208 | ecmaVersion: 11, 209 | loose: false 210 | }); 211 | 212 | testFail("var dynImport = import; dynImport('http');", 'Unexpected token (1:22)', { 213 | ecmaVersion: 11, 214 | loose: false 215 | }); 216 | 217 | testFail("import('test.js')", 'Unexpected token (1:6)', { 218 | ecmaVersion: 10, 219 | loose: false, 220 | sourceType: 'module' 221 | }); 222 | 223 | testFail("import()", 'Unexpected token (1:7)', { 224 | ecmaVersion: 11, 225 | loose: false 226 | }); 227 | 228 | testFail("import(a, b)", 'Unexpected token (1:8)', { 229 | ecmaVersion: 11, 230 | loose: false 231 | }); 232 | 233 | testFail("import(...[a])", 'Unexpected token (1:7)', { 234 | ecmaVersion: 11, 235 | loose: false 236 | }); 237 | 238 | testFail("import(source,)", 'Trailing comma is not allowed in import() (1:13)', { 239 | ecmaVersion: 11, 240 | loose: false 241 | }); 242 | 243 | testFail("new import(source)", 'Cannot use new with import() (1:4)', { 244 | ecmaVersion: 11, 245 | loose: false 246 | }); 247 | 248 | testFail("(import)(s)", 'Unexpected token (1:7)', { 249 | ecmaVersion: 11, 250 | loose: false 251 | }); 252 | -------------------------------------------------------------------------------- /test/tests-es7.js: -------------------------------------------------------------------------------- 1 | // Tests for ECMAScript 7 syntax changes 2 | 3 | if (typeof exports != "undefined") { 4 | var test = require("./driver.js").test; 5 | var testFail = require("./driver.js").testFail; 6 | } 7 | 8 | test("x **= 42", { 9 | type: "Program", 10 | body: [ 11 | { 12 | type: "ExpressionStatement", 13 | expression: { 14 | type: "AssignmentExpression", 15 | operator: "**=", 16 | left: { 17 | type: "Identifier", 18 | name: "x", 19 | loc: { 20 | start: { 21 | line: 1, 22 | column: 0 23 | }, 24 | end: { 25 | line: 1, 26 | column: 1 27 | } 28 | } 29 | }, 30 | right: { 31 | type: "Literal", 32 | value: 42, 33 | loc: { 34 | start: { 35 | line: 1, 36 | column: 6 37 | }, 38 | end: { 39 | line: 1, 40 | column: 8 41 | } 42 | } 43 | }, 44 | loc: { 45 | start: { 46 | line: 1, 47 | column: 0 48 | }, 49 | end: { 50 | line: 1, 51 | column: 8 52 | } 53 | } 54 | }, 55 | loc: { 56 | start: { 57 | line: 1, 58 | column: 0 59 | }, 60 | end: { 61 | line: 1, 62 | column: 8 63 | } 64 | } 65 | } 66 | ], 67 | loc: { 68 | start: { 69 | line: 1, 70 | column: 0 71 | }, 72 | end: { 73 | line: 1, 74 | column: 8 75 | } 76 | } 77 | }, { 78 | ecmaVersion: 7, 79 | locations: true 80 | }); 81 | 82 | testFail("x **= 42", "Unexpected token (1:3)", { ecmaVersion: 6 }); 83 | 84 | test("x ** y", { 85 | type: "Program", 86 | body: [ 87 | { 88 | type: "ExpressionStatement", 89 | expression: { 90 | type: "BinaryExpression", 91 | left: { 92 | type: "Identifier", 93 | name: "x", 94 | loc: { 95 | start: { 96 | line: 1, 97 | column: 0 98 | }, 99 | end: { 100 | line: 1, 101 | column: 1 102 | } 103 | } 104 | }, 105 | operator: "**", 106 | right: { 107 | type: "Identifier", 108 | name: "y", 109 | loc: { 110 | start: { 111 | line: 1, 112 | column: 5 113 | }, 114 | end: { 115 | line: 1, 116 | column: 6 117 | } 118 | } 119 | }, 120 | loc: { 121 | start: { 122 | line: 1, 123 | column: 0 124 | }, 125 | end: { 126 | line: 1, 127 | column: 6 128 | } 129 | } 130 | }, 131 | loc: { 132 | start: { 133 | line: 1, 134 | column: 0 135 | }, 136 | end: { 137 | line: 1, 138 | column: 6 139 | } 140 | } 141 | } 142 | ], 143 | loc: { 144 | start: { 145 | line: 1, 146 | column: 0 147 | }, 148 | end: { 149 | line: 1, 150 | column: 6 151 | } 152 | } 153 | }, { 154 | ecmaVersion: 7, 155 | locations: true 156 | }); 157 | 158 | testFail("x ** y", "Unexpected token (1:3)", { ecmaVersion: 6 }); 159 | 160 | // ** has highest precedence 161 | test("3 ** 5 * 1", { 162 | type: "Program", 163 | body: [ 164 | { 165 | type: "ExpressionStatement", 166 | expression: { 167 | type: "BinaryExpression", 168 | operator: "*", 169 | left: { 170 | type: "BinaryExpression", 171 | operator: "**", 172 | left: { 173 | type: "Literal", 174 | value: 3 175 | }, 176 | right: { 177 | type: "Literal", 178 | value: 5 179 | } 180 | }, 181 | right: { 182 | type: "Literal", 183 | value: 1 184 | } 185 | } 186 | } 187 | ] 188 | }, { 189 | ecmaVersion: 7, 190 | }); 191 | 192 | test("3 % 5 ** 1", { 193 | type: "Program", 194 | body: [ 195 | { 196 | type: "ExpressionStatement", 197 | expression: { 198 | type: "BinaryExpression", 199 | operator: "%", 200 | left: { 201 | type: "Literal", 202 | value: 3 203 | }, 204 | right: { 205 | type: "BinaryExpression", 206 | operator: "**", 207 | left: { 208 | type: "Literal", 209 | value: 5 210 | }, 211 | right: { 212 | type: "Literal", 213 | value: 1 214 | } 215 | } 216 | } 217 | } 218 | ] 219 | }, { 220 | ecmaVersion: 7, 221 | }); 222 | 223 | // Disallowed unary ops 224 | testFail("delete o.p ** 2;", "Unexpected token (1:11)", { ecmaVersion: 7 }); 225 | testFail("void 2 ** 2;", "Unexpected token (1:7)", { ecmaVersion: 7 }); 226 | testFail("typeof 2 ** 2;", "Unexpected token (1:9)", { ecmaVersion: 7 }); 227 | testFail("~3 ** 2;", "Unexpected token (1:3)", { ecmaVersion: 7 }); 228 | testFail("!1 ** 2;", "Unexpected token (1:3)", { ecmaVersion: 7 }); 229 | testFail("-2** 2;", "Unexpected token (1:2)", { ecmaVersion: 7 }); 230 | testFail("+2** 2;", "Unexpected token (1:2)", { ecmaVersion: 7 }); 231 | testFail("-(i--) ** 2", "Unexpected token (1:7)", {ecmaVersion: 7}); 232 | testFail("+(i--) ** 2", "Unexpected token (1:7)", {ecmaVersion: 7}); 233 | 234 | // make sure base operand check doesn't affect other operators 235 | test("-a * 5", { 236 | type: "Program", 237 | body: [ 238 | { 239 | type: "ExpressionStatement", 240 | expression: { 241 | type: "BinaryExpression", 242 | left: { 243 | type: "UnaryExpression", 244 | operator: "-", 245 | prefix: true, 246 | argument: { 247 | type: "Identifier", 248 | name: "a" 249 | } 250 | }, 251 | operator: "*", 252 | right: { 253 | type: "Literal", 254 | value: 5, 255 | } 256 | } 257 | } 258 | ], 259 | sourceType: "script" 260 | }, { ecmaVersion: 6 }) 261 | 262 | 263 | test("(-5) ** y", { 264 | type: "Program", 265 | body: [ 266 | { 267 | type: "ExpressionStatement", 268 | expression: { 269 | type: "BinaryExpression", 270 | left: { 271 | type: "UnaryExpression", 272 | operator: "-", 273 | prefix: true, 274 | argument: { 275 | type: "Literal", 276 | value: 5 277 | } 278 | }, 279 | operator: "**", 280 | right: { 281 | type: "Identifier", 282 | name: "y" 283 | } 284 | } 285 | } 286 | ] 287 | }, { 288 | ecmaVersion: 7 289 | }); 290 | 291 | test("++a ** 2", { 292 | "type": "Program", 293 | "body": [ 294 | { 295 | "type": "ExpressionStatement", 296 | "expression": { 297 | "type": "BinaryExpression", 298 | "left": { 299 | "type": "UpdateExpression", 300 | "operator": "++", 301 | "prefix": true, 302 | "argument": { 303 | "type": "Identifier", 304 | "name": "a" 305 | } 306 | }, 307 | "operator": "**", 308 | "right": { 309 | "type": "Literal", 310 | "value": 2, 311 | "raw": "2" 312 | } 313 | } 314 | } 315 | ], 316 | "sourceType": "script" 317 | }, {ecmaVersion: 7}) 318 | 319 | test("a-- ** 2", { 320 | "type": "Program", 321 | "body": [ 322 | { 323 | "type": "ExpressionStatement", 324 | "expression": { 325 | "type": "BinaryExpression", 326 | "left": { 327 | "type": "UpdateExpression", 328 | "operator": "--", 329 | "prefix": false, 330 | "argument": { 331 | "type": "Identifier", 332 | "name": "a" 333 | } 334 | }, 335 | "operator": "**", 336 | "right": { 337 | "type": "Literal", 338 | "value": 2, 339 | "raw": "2" 340 | } 341 | } 342 | } 343 | ], 344 | "sourceType": "script" 345 | }, {ecmaVersion: 7}) 346 | 347 | testFail("x %* y", "Unexpected token (1:3)", { ecmaVersion: 7 }); 348 | 349 | testFail("x %*= y", "Unexpected token (1:3)", { ecmaVersion: 7 }); 350 | 351 | testFail("function foo(a=2) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 }) 352 | testFail("(a=2) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 }) 353 | testFail("function foo({a}) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 }) 354 | testFail("({a}) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 }) 355 | test("function foo(a) { 'use strict'; }", {}, { ecmaVersion: 7 }); 356 | 357 | // Tests for B.3.4 FunctionDeclarations in IfStatement Statement Clauses 358 | test( 359 | "if (x) function f() {}", 360 | { 361 | type: "Program", 362 | body: [{ 363 | type: "IfStatement", 364 | consequent: { 365 | type: "FunctionDeclaration" 366 | }, 367 | alternate: null 368 | }] 369 | }, 370 | { ecmaVersion: 7 } 371 | ) 372 | 373 | test( 374 | "if (x) function f() { return 23; } else function f() { return 42; }", 375 | { 376 | type: "Program", 377 | body: [{ 378 | type: "IfStatement", 379 | consequent: { 380 | type: "FunctionDeclaration" 381 | }, 382 | alternate: { 383 | type: "FunctionDeclaration" 384 | } 385 | }] 386 | }, 387 | { ecmaVersion: 7 } 388 | ) 389 | 390 | testFail( 391 | "'use strict'; if(x) function f() {}", 392 | "Unexpected token (1:20)", 393 | { ecmaVersion: 7 } 394 | ) 395 | 396 | testFail("'use strict'; function y(x = 1) { 'use strict' }", 397 | "Illegal 'use strict' directive in function with non-simple parameter list (1:14)", 398 | {ecmaVersion: 7}) 399 | -------------------------------------------------------------------------------- /test/tests-export-all-as-ns-from-source.js: -------------------------------------------------------------------------------- 1 | 2 | if (typeof exports != "undefined") { 3 | var driver = require("./driver.js"); 4 | var test = driver.test, testFail = driver.testFail; 5 | var acorn = require("../acorn"); 6 | } 7 | 8 | //------------------------------------------------------------------------------ 9 | // export * as ns from "source" 10 | //------------------------------------------------------------------------------ 11 | 12 | test("export * as ns from \"source\"", { 13 | "type": "Program", 14 | "start": 0, 15 | "end": 28, 16 | "body": [ 17 | { 18 | "type": "ExportAllDeclaration", 19 | "start": 0, 20 | "end": 28, 21 | "exported": { 22 | "type": "Identifier", 23 | "start": 12, 24 | "end": 14, 25 | "name": "ns" 26 | }, 27 | "source": { 28 | "type": "Literal", 29 | "start": 20, 30 | "end": 28, 31 | "value": "source", 32 | "raw": "\"source\"" 33 | } 34 | } 35 | ], 36 | "sourceType": "module" 37 | }, { sourceType: "module", ecmaVersion: 11 }) 38 | 39 | test("export * as foo from \"bar\"", { 40 | "type": "Program", 41 | "start": 0, 42 | "end": 26, 43 | "body": [ 44 | { 45 | "type": "ExportAllDeclaration", 46 | "start": 0, 47 | "end": 26, 48 | "exported": { 49 | "type": "Identifier", 50 | "start": 12, 51 | "end": 15, 52 | "name": "foo" 53 | }, 54 | "source": { 55 | "type": "Literal", 56 | "start": 21, 57 | "end": 26, 58 | "value": "bar", 59 | "raw": "\"bar\"" 60 | } 61 | } 62 | ], 63 | "sourceType": "module" 64 | }, { sourceType: "module", ecmaVersion: 11 }) 65 | 66 | test("export * from \"source\"", { 67 | "type": "Program", 68 | "start": 0, 69 | "end": 22, 70 | "body": [ 71 | { 72 | "type": "ExportAllDeclaration", 73 | "start": 0, 74 | "end": 22, 75 | "exported": null, 76 | "source": { 77 | "type": "Literal", 78 | "start": 14, 79 | "end": 22, 80 | "value": "source", 81 | "raw": "\"source\"" 82 | } 83 | } 84 | ], 85 | "sourceType": "module" 86 | }, { sourceType: "module", ecmaVersion: 11 }) 87 | 88 | testFail("export * as ns from \"source\"", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 89 | testFail("export * as ns from \"source\"", "Unexpected token (1:9)", { sourceType: "module", ecmaVersion: 10 }) 90 | testFail("export * as ns", "Unexpected token (1:14)", { sourceType: "module", ecmaVersion: 11 }) 91 | testFail("export * as from \"source\"", "Unexpected token (1:17)", { sourceType: "module", ecmaVersion: 11 }) 92 | testFail("export * as ns \"source\"", "Unexpected token (1:15)", { sourceType: "module", ecmaVersion: 11 }) 93 | testFail("export {} as ns from \"source\"", "Unexpected token (1:10)", { sourceType: "module", ecmaVersion: 11 }) 94 | -------------------------------------------------------------------------------- /test/tests-import-meta.js: -------------------------------------------------------------------------------- 1 | // Tests for ECMAScript 2020 `import.meta` 2 | 3 | if (typeof exports != 'undefined') { 4 | var test = require('./driver.js').test; 5 | var testFail = require('./driver.js').testFail; 6 | } 7 | 8 | test( 9 | "import.meta", 10 | { 11 | "type": "Program", 12 | "start": 0, 13 | "end": 11, 14 | "body": [ 15 | { 16 | "type": "ExpressionStatement", 17 | "start": 0, 18 | "end": 11, 19 | "expression": { 20 | "type": "MetaProperty", 21 | "start": 0, 22 | "end": 11, 23 | "meta": { 24 | "type": "Identifier", 25 | "start": 0, 26 | "end": 6, 27 | "name": "import" 28 | }, 29 | "property": { 30 | "type": "Identifier", 31 | "start": 7, 32 | "end": 11, 33 | "name": "meta" 34 | } 35 | } 36 | } 37 | ], 38 | "sourceType": "module" 39 | }, 40 | { ecmaVersion: 11, sourceType: "module" } 41 | ); 42 | 43 | test( 44 | "import.meta", 45 | { 46 | "type": "Program", 47 | "start": 0, 48 | "end": 11, 49 | "body": [ 50 | { 51 | "type": "ExpressionStatement", 52 | "start": 0, 53 | "end": 11, 54 | "expression": { 55 | "type": "MetaProperty", 56 | "start": 0, 57 | "end": 11, 58 | "meta": { 59 | "type": "Identifier", 60 | "start": 0, 61 | "end": 6, 62 | "name": "import" 63 | }, 64 | "property": { 65 | "type": "Identifier", 66 | "start": 7, 67 | "end": 11, 68 | "name": "meta" 69 | } 70 | } 71 | } 72 | ], 73 | "sourceType": "script" 74 | }, 75 | { ecmaVersion: 11, sourceType: "script", allowImportExportEverywhere: true } 76 | ); 77 | 78 | test( 79 | "import.meta.url", 80 | { 81 | "type": "Program", 82 | "start": 0, 83 | "end": 15, 84 | "body": [ 85 | { 86 | "type": "ExpressionStatement", 87 | "start": 0, 88 | "end": 15, 89 | "expression": { 90 | "type": "MemberExpression", 91 | "start": 0, 92 | "end": 15, 93 | "object": { 94 | "type": "MetaProperty", 95 | "start": 0, 96 | "end": 11, 97 | "meta": { 98 | "type": "Identifier", 99 | "start": 0, 100 | "end": 6, 101 | "name": "import" 102 | }, 103 | "property": { 104 | "type": "Identifier", 105 | "start": 7, 106 | "end": 11, 107 | "name": "meta" 108 | } 109 | }, 110 | "property": { 111 | "type": "Identifier", 112 | "start": 12, 113 | "end": 15, 114 | "name": "url" 115 | }, 116 | "computed": false 117 | } 118 | } 119 | ], 120 | "sourceType": "module" 121 | }, 122 | { ecmaVersion: 11, sourceType: "module" } 123 | ); 124 | 125 | testFail("import.meta", "Unexpected token (1:6)", { ecmaVersion: 10, sourceType: "module" }); 126 | testFail("import.meta", "Cannot use 'import.meta' outside a module (1:0)", { ecmaVersion: 11, sourceType: "script" }); 127 | testFail("import['meta']", "Unexpected token (1:6)", { ecmaVersion: 11, sourceType: "module" }); 128 | testFail("a = import['meta']", "Unexpected token (1:10)", { ecmaVersion: 11, sourceType: "module" }); 129 | testFail("import.target", "The only valid meta property for import is 'import.meta' (1:7)", { ecmaVersion: 11, sourceType: "module" }); 130 | testFail("new.meta", "The only valid meta property for new is 'new.target' (1:4)", { ecmaVersion: 11, sourceType: "module" }); 131 | testFail("im\\u0070ort.meta", "Escape sequence in keyword import (1:0)", { ecmaVersion: 11, sourceType: "module" }); 132 | testFail("import.\\u006d\\u0065\\u0074\\u0061", "'import.meta' must not contain escaped characters (1:0)", { ecmaVersion: 11, sourceType: "module" }); 133 | -------------------------------------------------------------------------------- /test/tests-json-superset.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | test("'\u2029'", {}, {ecmaVersion: 2019}) 7 | test("'\u2028'", {}, {ecmaVersion: 2019}) 8 | test("\"\u2029\"", {}, {ecmaVersion: 2019}) 9 | test("\"\u2028\"", {}, {ecmaVersion: 2019}) 10 | test("`\u2029`", {}, {ecmaVersion: 2019}) 11 | test("`\u2028`", {}, {ecmaVersion: 2019}) 12 | testFail("/\u2029/", "Unterminated regular expression (1:1)", {ecmaVersion: 2019}) 13 | testFail("/\u2028/", "Unterminated regular expression (1:1)", {ecmaVersion: 2019}) 14 | -------------------------------------------------------------------------------- /test/tests-logical-assignment-operators.js: -------------------------------------------------------------------------------- 1 | // Tests for ECMAScript 2021 `&&=`, `||=`, `??=` 2 | 3 | if (typeof exports != 'undefined') { 4 | var test = require('./driver.js').test; 5 | var testFail = require('./driver.js').testFail; 6 | } 7 | 8 | test( 9 | "a &&= b", 10 | { 11 | "type": "Program", 12 | "start": 0, 13 | "end": 7, 14 | "body": [ 15 | { 16 | "type": "ExpressionStatement", 17 | "start": 0, 18 | "end": 7, 19 | "expression": { 20 | "type": "AssignmentExpression", 21 | "start": 0, 22 | "end": 7, 23 | "operator": "&&=", 24 | "left": { 25 | "type": "Identifier", 26 | "start": 0, 27 | "end": 1, 28 | "name": "a" 29 | }, 30 | "right": { 31 | "type": "Identifier", 32 | "start": 6, 33 | "end": 7, 34 | "name": "b" 35 | } 36 | } 37 | } 38 | ], 39 | "sourceType": "script" 40 | }, 41 | { ecmaVersion: 12 } 42 | ); 43 | 44 | test( 45 | "a ||= b", 46 | { 47 | "type": "Program", 48 | "start": 0, 49 | "end": 7, 50 | "body": [ 51 | { 52 | "type": "ExpressionStatement", 53 | "start": 0, 54 | "end": 7, 55 | "expression": { 56 | "type": "AssignmentExpression", 57 | "start": 0, 58 | "end": 7, 59 | "operator": "||=", 60 | "left": { 61 | "type": "Identifier", 62 | "start": 0, 63 | "end": 1, 64 | "name": "a" 65 | }, 66 | "right": { 67 | "type": "Identifier", 68 | "start": 6, 69 | "end": 7, 70 | "name": "b" 71 | } 72 | } 73 | } 74 | ], 75 | "sourceType": "script" 76 | }, 77 | { ecmaVersion: 12 } 78 | ); 79 | 80 | test( 81 | "a ??= b", 82 | { 83 | "type": "Program", 84 | "start": 0, 85 | "end": 7, 86 | "body": [ 87 | { 88 | "type": "ExpressionStatement", 89 | "start": 0, 90 | "end": 7, 91 | "expression": { 92 | "type": "AssignmentExpression", 93 | "start": 0, 94 | "end": 7, 95 | "operator": "??=", 96 | "left": { 97 | "type": "Identifier", 98 | "start": 0, 99 | "end": 1, 100 | "name": "a" 101 | }, 102 | "right": { 103 | "type": "Identifier", 104 | "start": 6, 105 | "end": 7, 106 | "name": "b" 107 | } 108 | } 109 | } 110 | ], 111 | "sourceType": "script" 112 | }, 113 | { ecmaVersion: 12 } 114 | ); 115 | 116 | test( 117 | "a &&= b ||= c ??= d", 118 | { 119 | "type": "Program", 120 | "start": 0, 121 | "end": 19, 122 | "body": [ 123 | { 124 | "type": "ExpressionStatement", 125 | "start": 0, 126 | "end": 19, 127 | "expression": { 128 | "type": "AssignmentExpression", 129 | "start": 0, 130 | "end": 19, 131 | "operator": "&&=", 132 | "left": { 133 | "type": "Identifier", 134 | "start": 0, 135 | "end": 1, 136 | "name": "a" 137 | }, 138 | "right": { 139 | "type": "AssignmentExpression", 140 | "start": 6, 141 | "end": 19, 142 | "operator": "||=", 143 | "left": { 144 | "type": "Identifier", 145 | "start": 6, 146 | "end": 7, 147 | "name": "b" 148 | }, 149 | "right": { 150 | "type": "AssignmentExpression", 151 | "start": 12, 152 | "end": 19, 153 | "operator": "??=", 154 | "left": { 155 | "type": "Identifier", 156 | "start": 12, 157 | "end": 13, 158 | "name": "c" 159 | }, 160 | "right": { 161 | "type": "Identifier", 162 | "start": 18, 163 | "end": 19, 164 | "name": "d" 165 | } 166 | } 167 | } 168 | } 169 | } 170 | ], 171 | "sourceType": "script" 172 | }, 173 | { ecmaVersion: 12 } 174 | ); 175 | 176 | testFail("a &&= b", "Unexpected token (1:4)", { ecmaVersion: 11 }); 177 | testFail("a ||= b", "Unexpected token (1:4)", { ecmaVersion: 11 }); 178 | testFail("a ??= b", "Unexpected token (1:4)", { ecmaVersion: 11 }); 179 | 180 | testFail("({a} &&= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 }); 181 | testFail("({a} ||= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 }); 182 | testFail("({a} ??= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 }); 183 | -------------------------------------------------------------------------------- /test/tests-numeric-separators.js: -------------------------------------------------------------------------------- 1 | // Tests for ECMAScript 2021 Numeric Separators 2 | 3 | if (typeof exports != 'undefined') { 4 | var test = require('./driver.js').test; 5 | var testFail = require('./driver.js').testFail; 6 | } 7 | 8 | function bigint(str) { 9 | if (typeof BigInt !== "function") { 10 | return null 11 | } 12 | return BigInt(str) 13 | } 14 | 15 | test( 16 | "123_456", 17 | { 18 | "type": "Program", 19 | "start": 0, 20 | "end": 7, 21 | "body": [ 22 | { 23 | "type": "ExpressionStatement", 24 | "start": 0, 25 | "end": 7, 26 | "expression": { 27 | "type": "Literal", 28 | "start": 0, 29 | "end": 7, 30 | "value": 123456, 31 | "raw": "123_456" 32 | } 33 | } 34 | ], 35 | "sourceType": "script" 36 | }, 37 | { ecmaVersion: 12 } 38 | ); 39 | 40 | test( 41 | "123_456.123_456e+123_456", 42 | { 43 | "type": "Program", 44 | "start": 0, 45 | "end": 24, 46 | "body": [ 47 | { 48 | "type": "ExpressionStatement", 49 | "start": 0, 50 | "end": 24, 51 | "expression": { 52 | "type": "Literal", 53 | "start": 0, 54 | "end": 24, 55 | "value": 123456.123456e+123456, 56 | "raw": "123_456.123_456e+123_456" 57 | } 58 | } 59 | ], 60 | "sourceType": "script" 61 | }, 62 | { ecmaVersion: 12 } 63 | ); 64 | 65 | test( 66 | "0b1010_0001", 67 | { 68 | "type": "Program", 69 | "start": 0, 70 | "end": 11, 71 | "body": [ 72 | { 73 | "type": "ExpressionStatement", 74 | "start": 0, 75 | "end": 11, 76 | "expression": { 77 | "type": "Literal", 78 | "start": 0, 79 | "end": 11, 80 | "value": 0b10100001, 81 | "raw": "0b1010_0001" 82 | } 83 | } 84 | ], 85 | "sourceType": "script" 86 | }, 87 | { ecmaVersion: 12 } 88 | ); 89 | 90 | test( 91 | "0xDEAD_BEAF", 92 | { 93 | "type": "Program", 94 | "start": 0, 95 | "end": 11, 96 | "body": [ 97 | { 98 | "type": "ExpressionStatement", 99 | "start": 0, 100 | "end": 11, 101 | "expression": { 102 | "type": "Literal", 103 | "start": 0, 104 | "end": 11, 105 | "value": 0xDEADBEAF, 106 | "raw": "0xDEAD_BEAF" 107 | } 108 | } 109 | ], 110 | "sourceType": "script" 111 | }, 112 | { ecmaVersion: 12 } 113 | ); 114 | 115 | test( 116 | "0o755_666", 117 | { 118 | "type": "Program", 119 | "start": 0, 120 | "end": 9, 121 | "body": [ 122 | { 123 | "type": "ExpressionStatement", 124 | "start": 0, 125 | "end": 9, 126 | "expression": { 127 | "type": "Literal", 128 | "start": 0, 129 | "end": 9, 130 | "value": 0o755666, 131 | "raw": "0o755_666" 132 | } 133 | } 134 | ], 135 | "sourceType": "script" 136 | }, 137 | { ecmaVersion: 12 } 138 | ); 139 | 140 | test( 141 | "123_456n", 142 | { 143 | "type": "Program", 144 | "start": 0, 145 | "end": 8, 146 | "body": [ 147 | { 148 | "type": "ExpressionStatement", 149 | "start": 0, 150 | "end": 8, 151 | "expression": { 152 | "type": "Literal", 153 | "start": 0, 154 | "end": 8, 155 | "value": bigint("123456"), 156 | "raw": "123_456n", 157 | "bigint": "123456" 158 | } 159 | } 160 | ], 161 | "sourceType": "script" 162 | }, 163 | { ecmaVersion: 12 } 164 | ); 165 | 166 | test( 167 | ".012_345", 168 | { 169 | "type": "Program", 170 | "start": 0, 171 | "end": 8, 172 | "body": [ 173 | { 174 | "type": "ExpressionStatement", 175 | "start": 0, 176 | "end": 8, 177 | "expression": { 178 | "type": "Literal", 179 | "start": 0, 180 | "end": 8, 181 | "value": 0.012345, 182 | "raw": ".012_345" 183 | } 184 | } 185 | ], 186 | "sourceType": "script" 187 | }, 188 | { ecmaVersion: 12 } 189 | ); 190 | 191 | testFail("123_456", "Identifier directly after number (1:3)", { ecmaVersion: 11 }); 192 | testFail("123__456", "Numeric separator must be exactly one underscore (1:4)", { ecmaVersion: 12 }); 193 | testFail("0._123456", "Numeric separator is not allowed at the first of digits (1:2)", { ecmaVersion: 12 }); 194 | testFail("123456_", "Numeric separator is not allowed at the last of digits (1:6)", { ecmaVersion: 12 }); 195 | testFail("012_345", "Numeric separator is not allowed in legacy octal numeric literals (1:3)", { ecmaVersion: 12 }); 196 | 197 | testFail("'\\x2_0'", "Bad character escape sequence (1:3)", { ecmaVersion: 12 }); 198 | testFail("'\\u00_20'", "Bad character escape sequence (1:3)", { ecmaVersion: 12 }); 199 | testFail("'\\u{2_0}'", "Bad character escape sequence (1:4)", { ecmaVersion: 12 }); 200 | -------------------------------------------------------------------------------- /test/tests-optional-catch-binding.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | test("try {} catch {}", { 7 | type: "Program", 8 | start: 0, 9 | end: 15, 10 | body: [ 11 | { 12 | type: "TryStatement", 13 | start: 0, 14 | end: 15, 15 | block: { 16 | type: "BlockStatement", 17 | start: 4, 18 | end: 6, 19 | body: [] 20 | }, 21 | handler: { 22 | type: "CatchClause", 23 | start: 7, 24 | end: 15, 25 | param: null, 26 | body: { 27 | type: "BlockStatement", 28 | start: 13, 29 | end: 15, 30 | body: [] 31 | } 32 | }, 33 | finalizer: null 34 | } 35 | ], 36 | sourceType: "script" 37 | }, {ecmaVersion: 10}) 38 | -------------------------------------------------------------------------------- /test/tests-regexp-2020.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | // https://github.com/tc39/ecma262/pull/1869 7 | testFail("/(?<\\ud835\\udc9c>.)/", "Invalid regular expression: /(?<\\ud835\\udc9c>.)/: Invalid capture group name (1:1)", { ecmaVersion: 2019 }) 8 | test("/(?<\\ud835\\udc9c>.)/", {}, { ecmaVersion: 2020 }) 9 | test("/(?<\\ud835\\udc9c>.)/u", {}, { ecmaVersion: 2019 }) 10 | test("/(?<\\ud835\\udc9c>.)/u", {}, { ecmaVersion: 2020 }) 11 | 12 | testFail("/(?<\\u{1d49c}>.)/", "Invalid regular expression: /(?<\\u{1d49c}>.)/: Invalid capture group name (1:1)", { ecmaVersion: 2019 }) 13 | test("/(?<\\u{1d49c}>.)/", {}, { ecmaVersion: 2020 }) 14 | test("/(?<\\u{1d49c}>.)/u", {}, { ecmaVersion: 2019 }) 15 | test("/(?<\\u{1d49c}>.)/u", {}, { ecmaVersion: 2020 }) 16 | 17 | testFail("/(?<𝒜>.)/", "Invalid regular expression: /(?<𝒜>.)/: Invalid capture group name (1:1)", { ecmaVersion: 2019 }) 18 | test("/(?<𝒜>.)/", {}, { ecmaVersion: 2020 }) 19 | test("/(?<𝒜>.)/u", {}, { ecmaVersion: 2019 }) 20 | test("/(?<𝒜>.)/u", {}, { ecmaVersion: 2020 }) 21 | 22 | -------------------------------------------------------------------------------- /test/tests-regexp-2022.js: -------------------------------------------------------------------------------- 1 | if (typeof exports != "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | // https://github.com/tc39/ecma262/pull/1713 7 | testFail("/a+(?z)?/d", "Invalid regular expression flag (1:1)", { ecmaVersion: 2021 }) 8 | test("/a+(?z)?/d", {}, { ecmaVersion: 2022 }) 9 | --------------------------------------------------------------------------------