├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .mailmap ├── .npmignore ├── .npmrc ├── .nvmrc ├── .tern-project ├── AUTHORS ├── README.md ├── acorn-loose ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── node_modules │ └── acorn ├── package.json ├── rollup.config.mjs └── src │ ├── acorn-loose.d.ts │ ├── expression.js │ ├── index.js │ ├── package.json │ ├── parseutil.js │ ├── state.js │ ├── statement.js │ └── tokenize.js ├── acorn-walk ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── node_modules │ └── acorn ├── package.json ├── rollup.config.mjs └── src │ ├── index.js │ ├── package.json │ └── walk.d.ts ├── acorn ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin │ └── acorn ├── package.json ├── rollup.config.mjs └── src │ ├── acorn.d.ts │ ├── bin │ └── acorn.js │ ├── expression.js │ ├── generated │ ├── astralIdentifierCodes.js │ ├── astralIdentifierStartCodes.js │ ├── nonASCIIidentifierChars.js │ ├── nonASCIIidentifierStartChars.js │ └── scriptValuesAddedInUnicode.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 ├── generate-unicode-script-values.js ├── run_test262.js ├── test262.unsupported-features ├── test262.whitelist └── update_authors.sh ├── logo.svg ├── package-lock.json ├── 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 ├── 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-export-named.js ├── tests-harmony.js ├── tests-import-attributes.js ├── tests-import-meta.js ├── tests-json-superset.js ├── tests-logical-assignment-operators.js ├── tests-module-string-names.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-2024.js ├── tests-regexp-2025.js ├── tests-regexp.js ├── tests-rest-spread-properties.js ├── tests-template-literal-revision.js ├── tests-trailing-commas-in-func.js ├── tests-using.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | test 3 | local 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | module.exports = { 4 | extends: [ 5 | "eslint:recommended", 6 | "standard", 7 | "plugin:import/errors", 8 | "plugin:import/warnings" 9 | ], 10 | globals: { 11 | BigInt: false, 12 | Packages: false 13 | }, 14 | overrides: [ 15 | { 16 | files: ["acorn/src/bin/*.js", "bin/generate-identifier-regex.js", "bin/generate-unicode-script-values.js"], 17 | rules: { 18 | "no-console": "off" 19 | } 20 | } 21 | ], 22 | plugins: ["eslint-plugin-import"], 23 | rules: { 24 | "no-unreachable-loop": "off", 25 | "no-empty": "off", 26 | curly: "off", 27 | eqeqeq: ["error", "always", {null: "ignore"}], 28 | indent: [ 29 | "error", 30 | 2, 31 | { 32 | SwitchCase: 0, 33 | VariableDeclarator: 2, 34 | CallExpression: {arguments: "off"} 35 | } 36 | ], 37 | "new-parens": "off", 38 | "no-case-declarations": "off", 39 | "no-cond-assign": "off", 40 | "no-console": ["error", {allow: ["warn", "error"]}], 41 | "no-fallthrough": "off", 42 | "no-labels": "off", 43 | "no-mixed-operators": "off", 44 | "no-return-assign": "off", 45 | "no-unused-labels": "error", 46 | "no-var": "error", 47 | "object-curly-spacing": ["error", "never"], 48 | "object-shorthand": "off", 49 | "one-var": "off", 50 | "prefer-const": "off", 51 | quotes: ["error", "double"], 52 | "semi-spacing": "off", 53 | "space-before-function-paren": ["error", "never"] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: ci 4 | 5 | on: 6 | pull_request: 7 | branches: [ master ] 8 | push: 9 | branches: [ master ] 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | lint: 16 | runs-on: ubuntu-latest 17 | name: Check code style 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version-file: '.nvmrc' 23 | cache: 'npm' 24 | - run: npm ci 25 | - run: node --run lint 26 | 27 | build-and-test: 28 | runs-on: ubuntu-latest 29 | name: Build and test 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: actions/setup-node@v4 33 | with: 34 | node-version-file: '.nvmrc' 35 | cache: 'npm' 36 | - run: npm ci 37 | - run: node --run test 38 | - run: node --run test:test262 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .tern-port 3 | /node_modules 4 | /local 5 | /acorn/dist 6 | /acorn-loose/dist 7 | /acorn-walk/dist 8 | /yarn.lock 9 | -------------------------------------------------------------------------------- /.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 = true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.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 | adams85 4 | Adam Walsh 5 | Adrian Heine 6 | Adrian Rakovsky 7 | Alex 8 | Alistair Braidwood 9 | Amila Welihinda 10 | Andres Suarez 11 | Angelo 12 | Aparajita Fishman 13 | Arian Stolwijk 14 | Artem Govorov 15 | Benedikt Meurer 16 | Ben Page 17 | bojavou 18 | Boopesh Mahendran 19 | Bradley Heinz 20 | Brandon Mills 21 | Brett Zamir 22 | Brian Donovan 23 | Brian Orora 24 | bvanjoi 25 | Charles Hughes 26 | Charmander 27 | Chris McKnight 28 | Conrad Irwin 29 | Cyril Auburtin 30 | Daniel Nalborczyk 31 | Daniel Tschinder 32 | David Bonnet 33 | daychongyang 34 | dnalborczyk 35 | Domenico Matteo 36 | ehmicky 37 | elixiao 38 | ericrannaud 39 | eryue0220 40 | Eugene Obrezkov 41 | Fabien LOISON 42 | Felix Maier 43 | fn ⌃ ⌥ 44 | Forbes Lindesay 45 | Gilad Peleg 46 | HonkingGoose 47 | Huáng Jùnliàng 48 | ibr4qr 49 | impinball 50 | Ingvar Stepanyan 51 | Jackson Ray Hamilton 52 | Jan Štola 53 | Jesse McCarthy 54 | Jiaxing Wang 55 | Joe Krump 56 | Joel Kemp 57 | Johannes Herr 58 | John-David Dalton 59 | Jordan Gensler 60 | Jordan Harband 61 | Jordan Klassen 62 | Julian Wyzykowski 63 | Jürg Lehni 64 | Kai Cataldo 65 | keeyipchan 66 | Keheliya Gallaba 67 | Kevin Irish 68 | Kevin Kwok 69 | Koichi ITO 70 | krator 71 | kyranet 72 | laosb 73 | Lucas Mirelmann 74 | luckyzeng 75 | Marek 76 | Marijn Haverbeke 77 | Martin Carlberg 78 | Mateusz Burzyński 79 | Mat Garcia 80 | Mathias Bynens 81 | Mathieu 'p01' Henri 82 | Matthew Bastien 83 | Max Schaefer 84 | Max Zerzouri 85 | mickey-gs 86 | Mihai Bazon 87 | Mike Rennie 88 | naoh 89 | Nauja 90 | Nicholas C. Zakas 91 | Nick Fitzgerald 92 | Norbiros 93 | Olivier Thomann 94 | Oskar Schöldström 95 | ota-meshi 96 | overlookmotel 97 | Paul Harper 98 | peakchen90 99 | Peter Rust 100 | piotr 101 | PlNG 102 | Praveen N 103 | Prayag Verma 104 | ReadmeCritic 105 | r-e-d 106 | Renée Kooi 107 | Richard Gibson 108 | Rich Harris 109 | Robert Palmer 110 | Rouven Weßling 111 | Sebastian McKenzie 112 | Shahar Soel 113 | Sheel Bedi 114 | Simen Bekkhus 115 | sosukesuzuki 116 | susiwen 117 | susiwen8 118 | Tanimodori 119 | Teddy Katz 120 | Timothy Gu 121 | Timo Tijhof 122 | Tim van der Lippe 123 | Tony Ross 124 | Toru Nagashima 125 | tuesmiddt 126 | tyrealhu 127 | Vanilla 128 | Victor Homyakov 129 | Vladislav Tupikin 130 | Wexpo Lyu 131 | Yosuke Ota 132 | Žiga Zupančič 133 | zsjforcn 134 | 就是喜欢陈粒 135 | 成仕伟 136 | 星灵 137 | 胡文彬 138 | 龙腾道 139 | -------------------------------------------------------------------------------- /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 | 12 | 13 | Acorn is open source software released under an 14 | [MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE). 15 | 16 | You are welcome to 17 | [report bugs](https://github.com/acornjs/acorn/issues) or create pull 18 | requests on [github](https://github.com/acornjs/acorn). 19 | 20 | ## Packages 21 | 22 | This repository holds three packages: 23 | 24 | - [acorn](https://github.com/acornjs/acorn/tree/master/acorn/): The 25 | main parser 26 | - [acorn-loose](https://github.com/acornjs/acorn/tree/master/acorn-loose/): The 27 | error-tolerant parser 28 | - [acorn-walk](https://github.com/acornjs/acorn/tree/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.5.0 (2025-04-17) 2 | 3 | ### New features 4 | 5 | Support ES2025 import attributes. 6 | 7 | ## 8.4.0 (2023-10-26) 8 | 9 | ### Bug fixes 10 | 11 | Fix an issue where a slash after a call to a propery named the same as some keywords would be tokenized as a regular expression. 12 | 13 | Fix a bug where the parser would raise an error when an invalid escape was included in an identifier after a keyword. 14 | 15 | ### New features 16 | 17 | Use a set of new, much more precise, TypeScript types. 18 | 19 | ## 8.3.0 (2021-12-27) 20 | 21 | ### New features 22 | 23 | Support quoted export names. 24 | 25 | Support class private fields with the `in` operator. 26 | 27 | ### Bug fixes 28 | 29 | Fix a bug that caused semicolons after `export *` statements to be parsed as empty statements. 30 | 31 | ## 8.2.1 (2021-09-06) 32 | 33 | ### Bug fixes 34 | 35 | Depend on the proper version of acorn. 36 | 37 | ## 8.2.0 (2021-09-06) 38 | 39 | ### New features 40 | 41 | Add support for ES2022 class static blocks. 42 | 43 | ## 8.1.0 (2021-04-24) 44 | 45 | ### New features 46 | 47 | Add support for ES2022 class fields and private methods. 48 | 49 | ## 8.0.2 (2021-01-25) 50 | 51 | ### Bug fixes 52 | 53 | Adjust package.json to work with Node 12.16.0 and 13.0-13.6. 54 | 55 | ## 8.0.1 (2020-10-11) 56 | 57 | ### Bug fixes 58 | 59 | Allow `for await` at the top level. 60 | 61 | ## 8.0.0 (2020-08-12) 62 | 63 | ### New features 64 | 65 | The package can now be loaded directly as an ECMAScript module in node 13+. 66 | 67 | ### Breaking changes 68 | 69 | 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. 70 | 71 | ## 7.1.0 (2020-06-11) 72 | 73 | ### Bug fixes 74 | 75 | Fix various issues in regexp validation. 76 | 77 | ### New features 78 | 79 | Add support for `import.meta`. 80 | 81 | Add support for optional chaining (`?.`) and nullish coalescing (`??`). 82 | 83 | Support `export * as ns from "source"`. 84 | 85 | ## 7.0.0 (2019-08-12) 86 | 87 | ### Breaking changes 88 | 89 | 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). 90 | 91 | ## 6.1.0 (2019-07-04) 92 | 93 | ### New features 94 | 95 | Support bigint syntax. 96 | 97 | Support dynamic import. 98 | 99 | ## 6.0.0 (2018-09-14) 100 | 101 | ### Breaking changes 102 | 103 | This module has been moved into its own package, `acorn-loose`. 104 | 105 | Plugins work differently, and will have to be rewritten to work with this version. 106 | 107 | The `parse_dammit` function is now simply called `parse`. 108 | 109 | ## 5.1.0 (2017-07-05) 110 | 111 | ### Bug fixes 112 | 113 | Make the ES module version of the loose parser actually work. 114 | 115 | ## 4.0.4 (2016-12-19) 116 | 117 | ### Bug fixes 118 | 119 | Fix issue with loading acorn_loose.js with an AMD loader. 120 | 121 | ## 3.2.0 (2016-06-07) 122 | 123 | ### Bug fixes 124 | 125 | Don't crash when the loose parser is called without options object. 126 | 127 | ## 3.1.0 (2016-04-18) 128 | 129 | ### Bug fixes 130 | 131 | Fix issue where the loose parser created invalid TemplateElement nodes for unclosed template literals. 132 | 133 | ## 2.7.0 (2016-01-04) 134 | 135 | ### Fixes 136 | 137 | Make sure the loose parser always attaches a `local` property to `ImportNamespaceSpecifier` nodes. 138 | 139 | ## 2.6.4 (2015-11-12) 140 | 141 | ### Fixes 142 | 143 | Fix crash in loose parser when parsing invalid object pattern. 144 | 145 | ### New features 146 | 147 | Support plugins in the loose parser. 148 | 149 | ## 2.5.0 (2015-10-27) 150 | 151 | ### Fixes 152 | 153 | In the loose parser, don't allow non-string-literals as import sources. 154 | -------------------------------------------------------------------------------- /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). 24 | 25 | ## Installation 26 | 27 | The easiest way to install acorn-loose is from [`npm`](https://www.npmjs.com/): 28 | 29 | ```sh 30 | npm install acorn-loose 31 | ``` 32 | 33 | Alternately, you can download the source and build acorn yourself: 34 | 35 | ```sh 36 | git clone https://github.com/acornjs/acorn.git 37 | cd acorn 38 | npm install 39 | ``` 40 | 41 | ## Interface 42 | 43 | **parse**`(input, options)` takes an input string and a set of options 44 | (the same options as 45 | [acorn](https://github.com/acornjs/acorn/blob/master/acorn/README.md) 46 | takes), and returns a syntax tree, even if the code isn't 47 | syntactically valid. It'll insert identifier nodes with name `"✖"` as 48 | placeholders in places where it can't make sense of the input. Depends 49 | on the `acorn` package, because it uses the same tokenizer. 50 | 51 | ```javascript 52 | var acornLoose = require("acorn-loose"); 53 | console.log(acornLoose.parse("1 / * 4 )[2]", {ecmaVersion: 2020})); 54 | ``` 55 | 56 | Like the regular parser, the loose parser supports plugins. You can 57 | take the **`LooseParser`** class exported by the module, and call its 58 | static `extend` method with one or more plugins to get a customized 59 | parser class. The class has a static `parse` method that acts like the 60 | top-level `parse` method. 61 | 62 | **isDummy**`(node)` takes a `Node` and returns `true` if it is a dummy node 63 | inserted by the parser. The function performs a simple equality check on the 64 | node's name. 65 | -------------------------------------------------------------------------------- /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 | "types": "dist/acorn-loose.d.ts", 8 | "exports": { 9 | ".": [ 10 | { 11 | "import": "./dist/acorn-loose.mjs", 12 | "require": "./dist/acorn-loose.js", 13 | "default": "./dist/acorn-loose.js" 14 | }, 15 | "./dist/acorn-loose.js" 16 | ], 17 | "./package.json": "./package.json" 18 | }, 19 | "version": "8.5.0", 20 | "engines": { 21 | "node": ">=0.4.0" 22 | }, 23 | "dependencies": { 24 | "acorn": "^8.14.0" 25 | }, 26 | "maintainers": [ 27 | { 28 | "name": "Marijn Haverbeke", 29 | "email": "marijnh@gmail.com", 30 | "web": "https://marijnhaverbeke.nl" 31 | }, 32 | { 33 | "name": "Ingvar Stepanyan", 34 | "email": "me@rreverser.com", 35 | "web": "https://rreverser.com/" 36 | }, 37 | { 38 | "name": "Adrian Heine", 39 | "web": "http://adrianheine.de" 40 | } 41 | ], 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/acornjs/acorn.git" 45 | }, 46 | "scripts": { 47 | "prepare": "cd ..; npm run build:loose" 48 | }, 49 | "license": "MIT" 50 | } 51 | -------------------------------------------------------------------------------- /acorn-loose/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import {readFile, writeFile} from "node:fs/promises" 2 | import buble from "@rollup/plugin-buble" 3 | 4 | const copy = (from, to) => ({ 5 | async writeBundle() { await writeFile(to, await readFile(from)) } 6 | }) 7 | 8 | export default { 9 | external: ["acorn"], 10 | input: "acorn-loose/src/index.js", 11 | output: [ 12 | { 13 | file: "acorn-loose/dist/acorn-loose.js", 14 | format: "umd", 15 | name: "acorn.loose", 16 | globals: {acorn: "acorn"} 17 | }, 18 | { 19 | file: "acorn-loose/dist/acorn-loose.mjs", 20 | format: "es", 21 | globals: {acorn: "acorn"} 22 | } 23 | ], 24 | plugins: [ 25 | buble({transforms: {dangerousForOf: true}}), 26 | copy("acorn-loose/src/acorn-loose.d.ts", "acorn-loose/dist/acorn-loose.d.ts"), 27 | copy("acorn-loose/src/acorn-loose.d.ts", "acorn-loose/dist/acorn-loose.d.mts") 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /acorn-loose/src/acorn-loose.d.ts: -------------------------------------------------------------------------------- 1 | import * as acorn from "acorn" 2 | 3 | export const LooseParser: typeof acorn.Parser 4 | 5 | export function parse (input: string, options: acorn.Options): acorn.Program 6 | 7 | /** 8 | * returns `true` if it is a dummy node inserted by the parser. The function performs a simple equality check on the node's name. 9 | */ 10 | export function isDummy(node: acorn.Node): boolean 11 | -------------------------------------------------------------------------------- /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 [ESTree spec][estree], 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 | // [estree]: https://github.com/estree/estree 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|numeric separator/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 | this.toks.containsEsc = false 93 | let ch = this.input.charAt(pos - 1) 94 | this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) || 95 | /[enwfd]/.test(ch) && 96 | /\b(case|else|return|throw|new|in|(instance|type)?of|delete|void)$/.test(this.input.slice(pos - 10, pos)) 97 | 98 | if (this.options.locations) { 99 | this.toks.curLine = 1 100 | this.toks.lineStart = lineBreakG.lastIndex = 0 101 | let match 102 | while ((match = lineBreakG.exec(this.input)) && match.index < pos) { 103 | ++this.toks.curLine 104 | this.toks.lineStart = match.index + match[0].length 105 | } 106 | } 107 | } 108 | 109 | lp.lookAhead = function(n) { 110 | while (n > this.ahead.length) 111 | this.ahead.push(this.readToken()) 112 | return this.ahead[n - 1] 113 | } 114 | -------------------------------------------------------------------------------- /acorn-walk/.npmignore: -------------------------------------------------------------------------------- 1 | .tern-* 2 | /rollup.config.* 3 | /src 4 | -------------------------------------------------------------------------------- /acorn-walk/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.3.4 (2024-09-09) 2 | 3 | ### Bug fixes 4 | 5 | Walk SwitchCase nodes as separate nodes. 6 | 7 | ## 8.3.3 (2024-01-11) 8 | 9 | ### Bug fixes 10 | 11 | Make acorn a dependency because acorn-walk uses the types from that package. 12 | 13 | ## 8.3.2 (2024-01-11) 14 | 15 | ### Bug fixes 16 | 17 | Add missing type for `findNodeBefore`. 18 | 19 | ## 8.3.1 (2023-12-06) 20 | 21 | ### Bug fixes 22 | 23 | Add `Function` and `Class` to the `AggregateType` type, so that they can be used in walkers without raising a type error. 24 | 25 | Visitor functions are now called in such a way that their `this` refers to the object they are part of. 26 | 27 | ## 8.3.0 (2023-10-26) 28 | 29 | ### New features 30 | 31 | Use a set of new, much more precise, TypeScript types. 32 | 33 | ## 8.2.0 (2021-09-06) 34 | 35 | ### New features 36 | 37 | Add support for walking ES2022 class static blocks. 38 | 39 | ## 8.1.1 (2021-06-29) 40 | 41 | ### Bug fixes 42 | 43 | Include `base` in the type declarations. 44 | 45 | ## 8.1.0 (2021-04-24) 46 | 47 | ### New features 48 | 49 | Support node types for class fields and private methods. 50 | 51 | ## 8.0.2 (2021-01-25) 52 | 53 | ### Bug fixes 54 | 55 | Adjust package.json to work with Node 12.16.0 and 13.0-13.6. 56 | 57 | ## 8.0.0 (2021-01-05) 58 | 59 | ### Bug fixes 60 | 61 | Fix a bug where `full` and `fullAncestor` would skip nodes with overridden types. 62 | 63 | ## 8.0.0 (2020-08-12) 64 | 65 | ### New features 66 | 67 | The package can now be loaded directly as an ECMAScript module in node 13+. 68 | 69 | ## 7.2.0 (2020-06-17) 70 | 71 | ### New features 72 | 73 | Support optional chaining and nullish coalescing. 74 | 75 | Support `import.meta`. 76 | 77 | Add support for `export * as ns from "source"`. 78 | 79 | ## 7.1.1 (2020-02-13) 80 | 81 | ### Bug fixes 82 | 83 | Clean up the type definitions to actually work well with the main parser. 84 | 85 | ## 7.1.0 (2020-02-11) 86 | 87 | ### New features 88 | 89 | Add a TypeScript definition file for the library. 90 | 91 | ## 7.0.0 (2017-08-12) 92 | 93 | ### New features 94 | 95 | Support walking `ImportExpression` nodes. 96 | 97 | ## 6.2.0 (2017-07-04) 98 | 99 | ### New features 100 | 101 | Add support for `Import` nodes. 102 | 103 | ## 6.1.0 (2018-09-28) 104 | 105 | ### New features 106 | 107 | The walker now walks `TemplateElement` nodes. 108 | 109 | ## 6.0.1 (2018-09-14) 110 | 111 | ### Bug fixes 112 | 113 | Fix bad "main" field in package.json. 114 | 115 | ## 6.0.0 (2018-09-14) 116 | 117 | ### Breaking changes 118 | 119 | This is now a separate package, `acorn-walk`, rather than part of the main `acorn` package. 120 | 121 | The `ScopeBody` and `ScopeExpression` meta-node-types are no longer supported. 122 | 123 | ## 5.7.1 (2018-06-15) 124 | 125 | ### Bug fixes 126 | 127 | Make sure the walker and bin files are rebuilt on release (the previous release didn't get the up-to-date versions). 128 | 129 | ## 5.7.0 (2018-06-15) 130 | 131 | ### Bug fixes 132 | 133 | Fix crash in walker when walking a binding-less catch node. 134 | 135 | ## 5.6.2 (2018-06-05) 136 | 137 | ### Bug fixes 138 | 139 | In the walker, go back to allowing the `baseVisitor` argument to be null to default to the default base everywhere. 140 | 141 | ## 5.6.1 (2018-06-01) 142 | 143 | ### Bug fixes 144 | 145 | Fix regression when passing `null` as fourth argument to `walk.recursive`. 146 | 147 | ## 5.6.0 (2018-05-31) 148 | 149 | ### Bug fixes 150 | 151 | Fix a bug in the walker that caused a crash when walking an object pattern spread. 152 | 153 | ## 5.5.1 (2018-03-06) 154 | 155 | ### Bug fixes 156 | 157 | Fix regression in walker causing property values in object patterns to be walked as expressions. 158 | 159 | ## 5.5.0 (2018-02-27) 160 | 161 | ### Bug fixes 162 | 163 | Support object spread in the AST walker. 164 | 165 | ## 5.4.1 (2018-02-02) 166 | 167 | ### Bug fixes 168 | 169 | 5.4.0 somehow accidentally included an old version of walk.js. 170 | 171 | ## 5.2.0 (2017-10-30) 172 | 173 | ### Bug fixes 174 | 175 | The `full` and `fullAncestor` walkers no longer visit nodes multiple times. 176 | 177 | ## 5.1.0 (2017-07-05) 178 | 179 | ### New features 180 | 181 | New walker functions `full` and `fullAncestor`. 182 | 183 | ## 3.2.0 (2016-06-07) 184 | 185 | ### New features 186 | 187 | Make it possible to use `visit.ancestor` with a walk state. 188 | 189 | ## 3.1.0 (2016-04-18) 190 | 191 | ### New features 192 | 193 | The walker now allows defining handlers for `CatchClause` nodes. 194 | 195 | ## 2.5.2 (2015-10-27) 196 | 197 | ### Fixes 198 | 199 | Fix bug where the walker walked an exported `let` statement as an expression. 200 | -------------------------------------------------------------------------------- /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). 14 | 15 | ## Installation 16 | 17 | The easiest way to install acorn is from [`npm`](https://www.npmjs.com/): 18 | 19 | ```sh 20 | npm install acorn-walk 21 | ``` 22 | 23 | Alternately, you can download the source and build acorn yourself: 24 | 25 | ```sh 26 | git clone https://github.com/acornjs/acorn.git 27 | cd acorn 28 | npm install 29 | ``` 30 | 31 | ## Interface 32 | 33 | An algorithm for recursing through a syntax tree is stored as an 34 | object, with a property for each tree node type holding a function 35 | that will recurse through such a node. There are several ways to run 36 | such a walker. 37 | 38 | **simple**`(node, visitors, base, state)` does a 'simple' walk over a 39 | tree. `node` should be the AST node to walk, and `visitors` an object 40 | with properties whose names correspond to node types in the [ESTree 41 | spec](https://github.com/estree/estree). The properties should contain 42 | functions that will be called with the node object and, if applicable 43 | the state at that point. The last two arguments are optional. `base` 44 | is a walker algorithm, and `state` is a start state. The default 45 | walker will simply visit all statements and expressions and not 46 | produce a meaningful state. (An example of a use of state is to track 47 | scope at each point in the tree.) 48 | 49 | ```js 50 | const acorn = require("acorn") 51 | const walk = require("acorn-walk") 52 | 53 | walk.simple(acorn.parse("let x = 10"), { 54 | Literal(node) { 55 | console.log(`Found a literal: ${node.value}`) 56 | } 57 | }) 58 | ``` 59 | 60 | **ancestor**`(node, visitors, base, state)` does a 'simple' walk over 61 | a tree, building up an array of ancestor nodes (including the current node) 62 | and passing the array to the callbacks as a third parameter. 63 | 64 | ```js 65 | const acorn = require("acorn") 66 | const walk = require("acorn-walk") 67 | 68 | walk.ancestor(acorn.parse("foo('hi')"), { 69 | Literal(_node, _state, ancestors) { 70 | console.log("This literal's ancestors are:", ancestors.map(n => n.type)) 71 | } 72 | }) 73 | ``` 74 | 75 | **recursive**`(node, state, functions, base)` does a 'recursive' 76 | walk, where the walker functions are responsible for continuing the 77 | walk on the child nodes of their target node. `state` is the start 78 | state, and `functions` should contain an object that maps node types 79 | to walker functions. Such functions are called with `(node, state, c)` 80 | arguments, and can cause the walk to continue on a sub-node by calling 81 | the `c` argument on it with `(node, state)` arguments. The optional 82 | `base` argument provides the fallback walker functions for node types 83 | that aren't handled in the `functions` object. If not given, the 84 | default walkers will be used. 85 | 86 | **make**`(functions, base)` builds a new walker object by using the 87 | walker functions in `functions` and filling in the missing ones by 88 | taking defaults from `base`. 89 | 90 | **full**`(node, callback, base, state)` does a 'full' walk over a 91 | tree, calling the callback with the arguments (node, state, type) for 92 | each node 93 | 94 | **fullAncestor**`(node, callback, base, state)` does a 'full' walk 95 | over a tree, building up an array of ancestor nodes (including the 96 | current node) and passing the array to the callbacks as a third 97 | parameter. 98 | 99 | ```js 100 | const acorn = require("acorn") 101 | const walk = require("acorn-walk") 102 | 103 | walk.full(acorn.parse("1 + 1"), node => { 104 | console.log(`There's a ${node.type} node at ${node.ch}`) 105 | }) 106 | ``` 107 | 108 | **findNodeAt**`(node, start, end, test, base, state)` tries to locate 109 | a node in a tree at the given start and/or end offsets, which 110 | satisfies the predicate `test`. `start` and `end` can be either `null` 111 | (as wildcard) or a number. `test` may be a string (indicating a node 112 | type) or a function that takes `(nodeType, node)` arguments and 113 | returns a boolean indicating whether this node is interesting. `base` 114 | and `state` are optional, and can be used to specify a custom walker. 115 | Nodes are tested from inner to outer, so if two nodes match the 116 | boundaries, the inner one will be preferred. 117 | 118 | **findNodeAround**`(node, pos, test, base, state)` is a lot like 119 | `findNodeAt`, but will match any node that exists 'around' (spanning) 120 | the given position. 121 | 122 | **findNodeAfter**`(node, pos, test, base, state)` is similar to 123 | `findNodeAround`, but will match all nodes *after* the given position 124 | (testing outer nodes before inner nodes). 125 | -------------------------------------------------------------------------------- /acorn-walk/node_modules/acorn: -------------------------------------------------------------------------------- 1 | ../../acorn -------------------------------------------------------------------------------- /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.3.4", 20 | "engines": { 21 | "node": ">=0.4.0" 22 | }, 23 | "dependencies": { 24 | "acorn": "^8.11.0" 25 | }, 26 | "maintainers": [ 27 | { 28 | "name": "Marijn Haverbeke", 29 | "email": "marijnh@gmail.com", 30 | "web": "https://marijnhaverbeke.nl" 31 | }, 32 | { 33 | "name": "Ingvar Stepanyan", 34 | "email": "me@rreverser.com", 35 | "web": "https://rreverser.com/" 36 | }, 37 | { 38 | "name": "Adrian Heine", 39 | "web": "http://adrianheine.de" 40 | } 41 | ], 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/acornjs/acorn.git" 45 | }, 46 | "scripts": { 47 | "prepare": "cd ..; npm run build:walk" 48 | }, 49 | "license": "MIT" 50 | } 51 | -------------------------------------------------------------------------------- /acorn-walk/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import {readFile, writeFile} from "node:fs/promises" 2 | import buble from "@rollup/plugin-buble" 3 | 4 | const copy = (from, to) => ({ 5 | async writeBundle() { await writeFile(to, await readFile(from)) } 6 | }) 7 | 8 | export default { 9 | input: "acorn-walk/src/index.js", 10 | output: [ 11 | { 12 | file: "acorn-walk/dist/walk.js", 13 | format: "umd", 14 | name: "acorn.walk" 15 | }, 16 | { 17 | file: "acorn-walk/dist/walk.mjs", 18 | format: "es" 19 | } 20 | ], 21 | plugins: [ 22 | buble({transforms: {dangerousForOf: true}}), 23 | copy("acorn-walk/src/walk.d.ts", "acorn-walk/dist/walk.d.ts"), 24 | copy("acorn-walk/src/walk.d.ts", "acorn-walk/dist/walk.d.mts") 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /acorn-walk/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /acorn-walk/src/walk.d.ts: -------------------------------------------------------------------------------- 1 | import * as acorn from "acorn" 2 | 3 | export type FullWalkerCallback = ( 4 | node: acorn.AnyNode, 5 | state: TState, 6 | type: string 7 | ) => void 8 | 9 | export type FullAncestorWalkerCallback = ( 10 | node: acorn.AnyNode, 11 | state: TState, 12 | ancestors: acorn.AnyNode[], 13 | type: string 14 | ) => void 15 | 16 | type AggregateType = { 17 | Expression: acorn.Expression, 18 | Statement: acorn.Statement, 19 | Function: acorn.Function, 20 | Class: acorn.Class, 21 | Pattern: acorn.Pattern, 22 | ForInit: acorn.VariableDeclaration | acorn.Expression 23 | } 24 | 25 | export type SimpleVisitors = { 26 | [type in acorn.AnyNode["type"]]?: (node: Extract, state: TState) => void 27 | } & { 28 | [type in keyof AggregateType]?: (node: AggregateType[type], state: TState) => void 29 | } 30 | 31 | export type AncestorVisitors = { 32 | [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, ancestors: acorn.AnyNode[] 33 | ) => void 34 | } & { 35 | [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, ancestors: acorn.AnyNode[]) => void 36 | } 37 | 38 | export type WalkerCallback = (node: acorn.AnyNode, state: TState) => void 39 | 40 | export type RecursiveVisitors = { 41 | [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, callback: WalkerCallback) => void 42 | } & { 43 | [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, callback: WalkerCallback) => void 44 | } 45 | 46 | export type FindPredicate = (type: string, node: acorn.AnyNode) => boolean 47 | 48 | export interface Found { 49 | node: acorn.AnyNode, 50 | state: TState 51 | } 52 | 53 | /** 54 | * does a 'simple' walk over a tree 55 | * @param node the AST node to walk 56 | * @param visitors an object with properties whose names correspond to node types in the {@link https://github.com/estree/estree | ESTree spec}. The properties should contain functions that will be called with the node object and, if applicable the state at that point. 57 | * @param base a walker algorithm 58 | * @param state a start state. The default walker will simply visit all statements and expressions and not produce a meaningful state. (An example of a use of state is to track scope at each point in the tree.) 59 | */ 60 | export function simple( 61 | node: acorn.Node, 62 | visitors: SimpleVisitors, 63 | base?: RecursiveVisitors, 64 | state?: TState 65 | ): void 66 | 67 | /** 68 | * does a 'simple' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. 69 | */ 70 | export function ancestor( 71 | node: acorn.Node, 72 | visitors: AncestorVisitors, 73 | base?: RecursiveVisitors, 74 | state?: TState 75 | ): void 76 | 77 | /** 78 | * does a 'recursive' walk, where the walker functions are responsible for continuing the walk on the child nodes of their target node. 79 | * @param node 80 | * @param state the start state 81 | * @param functions contain an object that maps node types to walker functions 82 | * @param base provides the fallback walker functions for node types that aren't handled in the {@link functions} object. If not given, the default walkers will be used. 83 | */ 84 | export function recursive( 85 | node: acorn.Node, 86 | state: TState, 87 | functions: RecursiveVisitors, 88 | base?: RecursiveVisitors 89 | ): void 90 | 91 | /** 92 | * does a 'full' walk over a tree, calling the {@link callback} with the arguments (node, state, type) for each node 93 | */ 94 | export function full( 95 | node: acorn.Node, 96 | callback: FullWalkerCallback, 97 | base?: RecursiveVisitors, 98 | state?: TState 99 | ): void 100 | 101 | /** 102 | * does a 'full' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. 103 | */ 104 | export function fullAncestor( 105 | node: acorn.Node, 106 | callback: FullAncestorWalkerCallback, 107 | base?: RecursiveVisitors, 108 | state?: TState 109 | ): void 110 | 111 | /** 112 | * builds a new walker object by using the walker functions in {@link functions} and filling in the missing ones by taking defaults from {@link base}. 113 | */ 114 | export function make( 115 | functions: RecursiveVisitors, 116 | base?: RecursiveVisitors 117 | ): RecursiveVisitors 118 | 119 | /** 120 | * tries to locate a node in a tree at the given start and/or end offsets, which satisfies the predicate test. {@link start} and {@link end} can be either `null` (as wildcard) or a `number`. {@link test} may be a string (indicating a node type) or a function that takes (nodeType, node) arguments and returns a boolean indicating whether this node is interesting. {@link base} and {@link state} are optional, and can be used to specify a custom walker. Nodes are tested from inner to outer, so if two nodes match the boundaries, the inner one will be preferred. 121 | */ 122 | export function findNodeAt( 123 | node: acorn.Node, 124 | start: number | undefined | null, 125 | end?: number | undefined | null, 126 | type?: FindPredicate | string, 127 | base?: RecursiveVisitors, 128 | state?: TState 129 | ): Found | undefined 130 | 131 | /** 132 | * like {@link findNodeAt}, but will match any node that exists 'around' (spanning) the given position. 133 | */ 134 | export function findNodeAround( 135 | node: acorn.Node, 136 | start: number | undefined | null, 137 | type?: FindPredicate | string, 138 | base?: RecursiveVisitors, 139 | state?: TState 140 | ): Found | undefined 141 | 142 | /** 143 | * Find the outermost matching node after a given position. 144 | */ 145 | export const findNodeAfter: typeof findNodeAround 146 | 147 | /** 148 | * Find the outermost matching node before a given position. 149 | */ 150 | export const findNodeBefore: typeof findNodeAround 151 | 152 | export const base: RecursiveVisitors 153 | -------------------------------------------------------------------------------- /acorn/.npmignore: -------------------------------------------------------------------------------- 1 | .tern-* 2 | /rollup.config.* 3 | /src 4 | -------------------------------------------------------------------------------- /acorn/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2012-2022 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/bin/acorn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict" 3 | 4 | require("../dist/bin.js") 5 | -------------------------------------------------------------------------------- /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.14.1", 20 | "engines": { 21 | "node": ">=0.4.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": "git+https://github.com/acornjs/acorn.git" 42 | }, 43 | "license": "MIT", 44 | "scripts": { 45 | "prepare": "cd ..; npm run build:main" 46 | }, 47 | "bin": { 48 | "acorn": "bin/acorn" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /acorn/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import {readFile, writeFile} from "node:fs/promises" 2 | import buble from "@rollup/plugin-buble" 3 | 4 | const copy = (from, to) => ({ 5 | async writeBundle() { await writeFile(to, await readFile(from)) } 6 | }) 7 | 8 | export default [ 9 | { 10 | input: "acorn/src/index.js", 11 | output: [ 12 | { 13 | file: "acorn/dist/acorn.js", 14 | format: "umd", 15 | name: "acorn" 16 | }, 17 | { 18 | file: "acorn/dist/acorn.mjs", 19 | format: "es" 20 | } 21 | ], 22 | plugins: [ 23 | buble({transforms: {dangerousForOf: true}}), 24 | copy("acorn/src/acorn.d.ts", "acorn/dist/acorn.d.ts"), 25 | copy("acorn/src/acorn.d.ts", "acorn/dist/acorn.d.mts") 26 | ] 27 | }, 28 | { 29 | external: ["acorn", "fs", "path"], 30 | input: "acorn/src/bin/acorn.js", 31 | output: { 32 | file: "acorn/dist/bin.js", 33 | format: "cjs", 34 | paths: {acorn: "./acorn.js"} 35 | }, 36 | plugins: [ 37 | buble({transforms: {dangerousForOf: true}}) 38 | ] 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /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 inputFilePaths = [], forceFileName = false, fileMode = false, 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] [--] [...]") 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[0] !== "-" || arg === "-") inputFilePaths.push(arg) 18 | else if (arg === "--") { 19 | inputFilePaths.push(...process.argv.slice(i + 1)) 20 | forceFileName = true 21 | break 22 | } else if (arg === "--locations") options.locations = true 23 | else if (arg === "--allow-hash-bang") options.allowHashBang = true 24 | else if (arg === "--allow-await-outside-function") options.allowAwaitOutsideFunction = true 25 | else if (arg === "--silent") silent = true 26 | else if (arg === "--compact") compact = true 27 | else if (arg === "--help") help(0) 28 | else if (arg === "--tokenize") tokenize = true 29 | else if (arg === "--module") options.sourceType = "module" 30 | else { 31 | let match = arg.match(/^--ecma(\d+)$/) 32 | if (match) 33 | options.ecmaVersion = +match[1] 34 | else 35 | help(1) 36 | } 37 | } 38 | 39 | function run(codeList) { 40 | let result = [], fileIdx = 0 41 | try { 42 | codeList.forEach((code, idx) => { 43 | fileIdx = idx 44 | if (!tokenize) { 45 | result = acorn.parse(code, options) 46 | options.program = result 47 | } else { 48 | let tokenizer = acorn.tokenizer(code, options), token 49 | do { 50 | token = tokenizer.getToken() 51 | result.push(token) 52 | } while (token.type !== acorn.tokTypes.eof) 53 | } 54 | }) 55 | } catch (e) { 56 | console.error(fileMode ? e.message.replace(/\(\d+:\d+\)$/, m => m.slice(0, 1) + inputFilePaths[fileIdx] + " " + m.slice(1)) : e.message) 57 | process.exit(1) 58 | } 59 | if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)) 60 | } 61 | 62 | if (fileMode = inputFilePaths.length && (forceFileName || !inputFilePaths.includes("-") || inputFilePaths.length !== 1)) { 63 | run(inputFilePaths.map(path => readFile(path, "utf8"))) 64 | } else { 65 | let code = "" 66 | process.stdin.resume() 67 | process.stdin.on("data", chunk => code += chunk) 68 | process.stdin.on("end", () => run([code])) 69 | } 70 | -------------------------------------------------------------------------------- /acorn/src/generated/astralIdentifierCodes.js: -------------------------------------------------------------------------------- 1 | // This file was generated. Do not modify manually! 2 | export default [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 80, 3, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 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, 343, 9, 54, 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, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 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, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 726, 6, 110, 6, 6, 9, 4759, 9, 787719, 239] 3 | -------------------------------------------------------------------------------- /acorn/src/generated/astralIdentifierStartCodes.js: -------------------------------------------------------------------------------- 1 | // This file was generated. Do not modify manually! 2 | export default [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, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 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, 39, 27, 10, 22, 251, 41, 7, 1, 17, 2, 60, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 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, 20, 1, 64, 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, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 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, 38, 6, 186, 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, 19, 72, 200, 32, 32, 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, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 129, 74, 6, 0, 67, 12, 65, 1, 2, 0, 29, 6135, 9, 1237, 42, 9, 8936, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 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, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 496, 6, 2, 3, 2, 1, 2, 14, 2, 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, 42719, 33, 4153, 7, 221, 3, 5761, 15, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 4191] 3 | -------------------------------------------------------------------------------- /acorn/src/generated/nonASCIIidentifierChars.js: -------------------------------------------------------------------------------- 1 | // This file was generated. Do not modify manually! 2 | export default "\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\u0897-\u089f\u08ca-\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\u0c3c\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\u0cf3\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-\u0ece\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-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\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-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\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\uff65" 3 | -------------------------------------------------------------------------------- /acorn/src/generated/nonASCIIidentifierStartChars.js: -------------------------------------------------------------------------------- 1 | // This file was generated. Do not modify manually! 2 | export default "\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\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\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\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\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-\u1711\u171f-\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-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\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-\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-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7cd\ua7d0\ua7d1\ua7d3\ua7d5-\ua7dc\ua7f2-\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" 3 | -------------------------------------------------------------------------------- /acorn/src/generated/scriptValuesAddedInUnicode.js: -------------------------------------------------------------------------------- 1 | // This file was generated by "bin/generate-unicode-script-values.js". Do not modify manually! 2 | export default "Gara Garay Gukh Gurung_Khema Hrkt Katakana_Or_Hiragana Kawi Kirat_Rai Krai Nag_Mundari Nagm Ol_Onal Onao Sunu Sunuwar Todhri Todr Tulu_Tigalari Tutg Unknown Zzzz" 3 | -------------------------------------------------------------------------------- /acorn/src/identifier.js: -------------------------------------------------------------------------------- 1 | // These are a run-length and offset encoded representation of the 2 | // >0xffff code points that are a valid part of identifiers. The 3 | // offset starts at 0x10000, and each pair of numbers represents an 4 | // offset to the next range, and then a size of the range. 5 | import astralIdentifierCodes from "./generated/astralIdentifierCodes.js" 6 | import astralIdentifierStartCodes from "./generated/astralIdentifierStartCodes.js" 7 | // Big ugly regular expressions that match characters in the 8 | // whitespace, identifier, and identifier-start categories. These 9 | // are only applied when a character is found to actually have a 10 | // code point above 128. 11 | import nonASCIIidentifierChars from "./generated/nonASCIIidentifierChars.js" 12 | import nonASCIIidentifierStartChars from "./generated/nonASCIIidentifierStartChars.js" 13 | 14 | // Reserved word lists for various dialects of the language 15 | 16 | export const reservedWords = { 17 | 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", 18 | 5: "class enum extends super const export import", 19 | 6: "enum", 20 | strict: "implements interface let package private protected public static yield", 21 | strictBind: "eval arguments" 22 | } 23 | 24 | // And the keywords 25 | 26 | 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" 27 | 28 | export const keywords = { 29 | 5: ecma5AndLessKeywords, 30 | "5module": ecma5AndLessKeywords + " export import", 31 | 6: ecma5AndLessKeywords + " const class extends export import super" 32 | } 33 | 34 | export const keywordRelationalOperator = /^in(stanceof)?$/ 35 | 36 | // ## Character categories 37 | 38 | const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") 39 | const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") 40 | 41 | // This has a complexity linear to the value of the code. The 42 | // assumption is that looking up astral identifier characters is 43 | // rare. 44 | function isInAstralSet(code, set) { 45 | let pos = 0x10000 46 | for (let i = 0; i < set.length; i += 2) { 47 | pos += set[i] 48 | if (pos > code) return false 49 | pos += set[i + 1] 50 | if (pos >= code) return true 51 | } 52 | return false 53 | } 54 | 55 | // Test whether a given character code starts an identifier. 56 | 57 | export function isIdentifierStart(code, astral) { 58 | if (code < 65) return code === 36 59 | if (code < 91) return true 60 | if (code < 97) return code === 95 61 | if (code < 123) return true 62 | if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) 63 | if (astral === false) return false 64 | return isInAstralSet(code, astralIdentifierStartCodes) 65 | } 66 | 67 | // Test whether a given character is part of an identifier. 68 | 69 | export function isIdentifierChar(code, astral) { 70 | if (code < 48) return code === 36 71 | if (code < 58) return true 72 | if (code < 65) return false 73 | if (code < 91) return true 74 | if (code < 97) return code === 95 75 | if (code < 123) return true 76 | if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) 77 | if (astral === false) return false 78 | return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) 79 | } 80 | -------------------------------------------------------------------------------- /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 | import {Parser} from "./state.js" 16 | import "./parseutil.js" 17 | import "./statement.js" 18 | import "./lval.js" 19 | import "./expression.js" 20 | import "./location.js" 21 | import "./scope.js" 22 | 23 | import {defaultOptions} from "./options.js" 24 | import {Position, SourceLocation, getLineInfo} from "./locutil.js" 25 | import {Node} from "./node.js" 26 | import {TokenType, types as tokTypes, keywords as keywordTypes} from "./tokentype.js" 27 | import {TokContext, types as tokContexts} from "./tokencontext.js" 28 | import {isIdentifierChar, isIdentifierStart} from "./identifier.js" 29 | import {Token} from "./tokenize.js" 30 | import {isNewLine, lineBreak, lineBreakG, nonASCIIwhitespace} from "./whitespace.js" 31 | 32 | export const version = "8.14.1" 33 | export { 34 | Parser, 35 | defaultOptions, 36 | Position, 37 | SourceLocation, 38 | getLineInfo, 39 | Node, 40 | TokenType, 41 | tokTypes, 42 | keywordTypes, 43 | TokContext, 44 | tokContexts, 45 | isIdentifierChar, 46 | isIdentifierStart, 47 | Token, 48 | isNewLine, 49 | lineBreak, 50 | lineBreakG, 51 | nonASCIIwhitespace 52 | } 53 | 54 | Parser.acorn = { 55 | Parser, 56 | version, 57 | defaultOptions, 58 | Position, 59 | SourceLocation, 60 | getLineInfo, 61 | Node, 62 | TokenType, 63 | tokTypes, 64 | keywordTypes, 65 | TokContext, 66 | tokContexts, 67 | isIdentifierChar, 68 | isIdentifierStart, 69 | Token, 70 | isNewLine, 71 | lineBreak, 72 | lineBreakG, 73 | nonASCIIwhitespace 74 | } 75 | 76 | // The main exported interface (under `self.acorn` when in the 77 | // browser) is a `parse` function that takes a code string and returns 78 | // an abstract syntax tree as specified by the [ESTree spec][estree]. 79 | // 80 | // [estree]: https://github.com/estree/estree 81 | 82 | export function parse(input, options) { 83 | return Parser.parse(input, options) 84 | } 85 | 86 | // This function tries to parse a single expression at a given 87 | // offset in a string. Useful for parsing mixed-language formats 88 | // that embed JavaScript expressions. 89 | 90 | export function parseExpressionAt(input, pos, options) { 91 | return Parser.parseExpressionAt(input, pos, options) 92 | } 93 | 94 | // Acorn is organized as a tokenizer and a recursive-descent parser. 95 | // The `tokenizer` export provides an interface to the tokenizer. 96 | 97 | export function tokenizer(input, options) { 98 | return Parser.tokenizer(input, options) 99 | } 100 | -------------------------------------------------------------------------------- /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 | if (this.sourceFile) { 16 | message += " in " + this.sourceFile 17 | } 18 | let err = new SyntaxError(message) 19 | err.pos = pos; err.loc = loc; err.raisedAt = this.pos 20 | throw err 21 | } 22 | 23 | pp.raiseRecoverable = pp.raise 24 | 25 | pp.curPosition = function() { 26 | if (this.options.locations) { 27 | return new Position(this.curLine, this.pos - this.lineStart) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /acorn/src/locutil.js: -------------------------------------------------------------------------------- 1 | import {nextLineBreak} 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 | let nextBreak = nextLineBreak(input, cur, offset) 34 | if (nextBreak < 0) return new Position(line, offset - cur) 35 | ++line 36 | cur = nextBreak 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /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 {hasOwn, 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), 14 (2023), or `"latest"` 11 | // (the latest version the library supports). This influences 12 | // support for strict mode, the set of reserved words, and support 13 | // for 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 when 20 | // a semicolon is automatically inserted. It will be passed the 21 | // position of the inserted semicolon as an offset, and if 22 | // `locations` is enabled, it is given the location as a `{line, 23 | // column}` object 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 is 48 | // allowed and treated as a line comment. Enabled by default when 49 | // `ecmaVersion` >= 2023. 50 | allowHashBang: false, 51 | // By default, the parser will verify that private properties are 52 | // only used in places where they are valid and have been declared. 53 | // Set this to false to turn such checks off. 54 | checkPrivateFields: true, 55 | // When `locations` is on, `loc` properties holding objects with 56 | // `start` and `end` properties in `{line, column}` form (with 57 | // line being 1-based and column 0-based) will be attached to the 58 | // nodes. 59 | locations: false, 60 | // A function can be passed as `onToken` option, which will 61 | // cause Acorn to call that function with object in the same 62 | // format as tokens returned from `tokenizer().getToken()`. Note 63 | // that you are not allowed to call the parser from the 64 | // callback—that will corrupt its internal state. 65 | onToken: null, 66 | // A function can be passed as `onComment` option, which will 67 | // cause Acorn to call that function with `(block, text, start, 68 | // end)` parameters whenever a comment is skipped. `block` is a 69 | // boolean indicating whether this is a block (`/* */`) comment, 70 | // `text` is the content of the comment, and `start` and `end` are 71 | // character offsets that denote the start and end of the comment. 72 | // When the `locations` option is on, two more parameters are 73 | // passed, the full `{line, column}` locations of the start and 74 | // end of the comments. Note that you are not allowed to call the 75 | // parser from the callback—that will corrupt its internal state. 76 | // When this option has an array as value, objects representing the 77 | // comments are pushed to it. 78 | onComment: null, 79 | // Nodes have their start and end characters offsets recorded in 80 | // `start` and `end` properties (directly on the node, rather than 81 | // the `loc` object, which holds line/column data. To also add a 82 | // [semi-standardized][range] `range` property holding a `[start, 83 | // end]` array with the same numbers, set the `ranges` option to 84 | // `true`. 85 | // 86 | // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 87 | ranges: false, 88 | // It is possible to parse multiple files into a single AST by 89 | // passing the tree produced by parsing the first file as 90 | // `program` option in subsequent parses. This will add the 91 | // toplevel forms of the parsed file to the `Program` (top) node 92 | // of an existing parse tree. 93 | program: null, 94 | // When `locations` is on, you can pass this to record the source 95 | // file in every node's `loc` object. 96 | sourceFile: null, 97 | // This value, if given, is stored in every node, whether 98 | // `locations` is on or off. 99 | directSourceFile: null, 100 | // When enabled, parenthesized expressions are represented by 101 | // (non-standard) ParenthesizedExpression nodes 102 | preserveParens: false 103 | } 104 | 105 | // Interpret and default an options object 106 | 107 | let warnedAboutEcmaVersion = false 108 | 109 | export function getOptions(opts) { 110 | let options = {} 111 | 112 | for (let opt in defaultOptions) 113 | options[opt] = opts && hasOwn(opts, opt) ? opts[opt] : defaultOptions[opt] 114 | 115 | if (options.ecmaVersion === "latest") { 116 | options.ecmaVersion = 1e8 117 | } else if (options.ecmaVersion == null) { 118 | if (!warnedAboutEcmaVersion && typeof console === "object" && console.warn) { 119 | warnedAboutEcmaVersion = true 120 | console.warn("Since Acorn 8.0.0, options.ecmaVersion is required.\nDefaulting to 2020, but this will stop working in the future.") 121 | } 122 | options.ecmaVersion = 11 123 | } else if (options.ecmaVersion >= 2015) { 124 | options.ecmaVersion -= 2009 125 | } 126 | 127 | if (options.allowReserved == null) 128 | options.allowReserved = options.ecmaVersion < 5 129 | 130 | if (!opts || opts.allowHashBang == null) 131 | options.allowHashBang = options.ecmaVersion >= 14 132 | 133 | if (isArray(options.onToken)) { 134 | let tokens = options.onToken 135 | options.onToken = (token) => tokens.push(token) 136 | } 137 | if (isArray(options.onComment)) 138 | options.onComment = pushComment(options, options.onComment) 139 | 140 | return options 141 | } 142 | 143 | function pushComment(options, array) { 144 | return function(block, text, start, end, startLoc, endLoc) { 145 | let comment = { 146 | type: block ? "Block" : "Line", 147 | value: text, 148 | start: start, 149 | end: end 150 | } 151 | if (options.locations) 152 | comment.loc = new SourceLocation(this, startLoc, endLoc) 153 | if (options.ranges) 154 | comment.range = [start, end] 155 | array.push(comment) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /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 | if (this.options.ecmaVersion < 5) return false 12 | for (;;) { 13 | // Try to find string literal. 14 | skipWhiteSpace.lastIndex = start 15 | start += skipWhiteSpace.exec(this.input)[0].length 16 | let match = literal.exec(this.input.slice(start)) 17 | if (!match) return false 18 | if ((match[1] || match[2]) === "use strict") { 19 | skipWhiteSpace.lastIndex = start + match[0].length 20 | let spaceAfter = skipWhiteSpace.exec(this.input), end = spaceAfter.index + spaceAfter[0].length 21 | let next = this.input.charAt(end) 22 | return next === ";" || next === "}" || 23 | (lineBreak.test(spaceAfter[0]) && 24 | !(/[(`.[+\-/*%<>=,?^&]/.test(next) || next === "!" && this.input.charAt(end + 1) === "=")) 25 | } 26 | start += match[0].length 27 | 28 | // Skip semicolon, if any. 29 | skipWhiteSpace.lastIndex = start 30 | start += skipWhiteSpace.exec(this.input)[0].length 31 | if (this.input[start] === ";") 32 | start++ 33 | } 34 | } 35 | 36 | // Predicate that tests whether the next token is of the given 37 | // type, and if yes, consumes it as a side effect. 38 | 39 | pp.eat = function(type) { 40 | if (this.type === type) { 41 | this.next() 42 | return true 43 | } else { 44 | return false 45 | } 46 | } 47 | 48 | // Tests whether parsed token is a contextual keyword. 49 | 50 | pp.isContextual = function(name) { 51 | return this.type === tt.name && this.value === name && !this.containsEsc 52 | } 53 | 54 | // Consumes contextual keyword if possible. 55 | 56 | pp.eatContextual = function(name) { 57 | if (!this.isContextual(name)) return false 58 | this.next() 59 | return true 60 | } 61 | 62 | // Asserts that following token is given contextual keyword. 63 | 64 | pp.expectContextual = function(name) { 65 | if (!this.eatContextual(name)) this.unexpected() 66 | } 67 | 68 | // Test whether a semicolon can be inserted at the current position. 69 | 70 | pp.canInsertSemicolon = function() { 71 | return this.type === tt.eof || 72 | this.type === tt.braceR || 73 | lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) 74 | } 75 | 76 | pp.insertSemicolon = function() { 77 | if (this.canInsertSemicolon()) { 78 | if (this.options.onInsertedSemicolon) 79 | this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) 80 | return true 81 | } 82 | } 83 | 84 | // Consume a semicolon, or, failing that, see if we are allowed to 85 | // pretend that there is a semicolon at this position. 86 | 87 | pp.semicolon = function() { 88 | if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected() 89 | } 90 | 91 | pp.afterTrailingComma = function(tokType, notNext) { 92 | if (this.type === tokType) { 93 | if (this.options.onTrailingComma) 94 | this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) 95 | if (!notNext) 96 | this.next() 97 | return true 98 | } 99 | } 100 | 101 | // Expect a token of a given type. If found, consume it, otherwise, 102 | // raise an unexpected token error. 103 | 104 | pp.expect = function(type) { 105 | this.eat(type) || this.unexpected() 106 | } 107 | 108 | // Raise an unexpected token error. 109 | 110 | pp.unexpected = function(pos) { 111 | this.raise(pos != null ? pos : this.start, "Unexpected token") 112 | } 113 | 114 | export class DestructuringErrors { 115 | constructor() { 116 | this.shorthandAssign = 117 | this.trailingComma = 118 | this.parenthesizedAssign = 119 | this.parenthesizedBind = 120 | this.doubleProto = 121 | -1 122 | } 123 | } 124 | 125 | pp.checkPatternErrors = function(refDestructuringErrors, isAssign) { 126 | if (!refDestructuringErrors) return 127 | if (refDestructuringErrors.trailingComma > -1) 128 | this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element") 129 | let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind 130 | if (parens > -1) this.raiseRecoverable(parens, isAssign ? "Assigning to rvalue" : "Parenthesized pattern") 131 | } 132 | 133 | pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { 134 | if (!refDestructuringErrors) return false 135 | let {shorthandAssign, doubleProto} = refDestructuringErrors 136 | if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0 137 | if (shorthandAssign >= 0) 138 | this.raise(shorthandAssign, "Shorthand property assignments are valid only in destructuring patterns") 139 | if (doubleProto >= 0) 140 | this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property") 141 | } 142 | 143 | pp.checkYieldAwaitInDefaultParams = function() { 144 | if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos)) 145 | this.raise(this.yieldPos, "Yield expression cannot be a default value") 146 | if (this.awaitPos) 147 | this.raise(this.awaitPos, "Await expression cannot be a default value") 148 | } 149 | 150 | pp.isSimpleAssignTarget = function(expr) { 151 | if (expr.type === "ParenthesizedExpression") 152 | return this.isSimpleAssignTarget(expr.expression) 153 | return expr.type === "Identifier" || expr.type === "MemberExpression" 154 | } 155 | -------------------------------------------------------------------------------- /acorn/src/scope.js: -------------------------------------------------------------------------------- 1 | import {Parser} from "./state.js" 2 | import { 3 | SCOPE_VAR, SCOPE_FUNCTION, SCOPE_TOP, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, BIND_LEXICAL, 4 | BIND_SIMPLE_CATCH, BIND_FUNCTION, SCOPE_CLASS_FIELD_INIT, SCOPE_CLASS_STATIC_BLOCK 5 | } from "./scopeflags.js" 6 | 7 | const pp = Parser.prototype 8 | 9 | class Scope { 10 | constructor(flags) { 11 | this.flags = flags 12 | // A list of var-declared names in the current lexical scope 13 | this.var = [] 14 | // A list of lexically-declared names in the current lexical scope 15 | this.lexical = [] 16 | // A list of lexically-declared FunctionDeclaration names in the current lexical scope 17 | this.functions = [] 18 | } 19 | } 20 | 21 | // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names. 22 | 23 | pp.enterScope = function(flags) { 24 | this.scopeStack.push(new Scope(flags)) 25 | } 26 | 27 | pp.exitScope = function() { 28 | this.scopeStack.pop() 29 | } 30 | 31 | // The spec says: 32 | // > At the top level of a function, or script, function declarations are 33 | // > treated like var declarations rather than like lexical declarations. 34 | pp.treatFunctionsAsVarInScope = function(scope) { 35 | return (scope.flags & SCOPE_FUNCTION) || !this.inModule && (scope.flags & SCOPE_TOP) 36 | } 37 | 38 | pp.declareName = function(name, bindingType, pos) { 39 | let redeclared = false 40 | if (bindingType === BIND_LEXICAL) { 41 | const scope = this.currentScope() 42 | redeclared = scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1 43 | scope.lexical.push(name) 44 | if (this.inModule && (scope.flags & SCOPE_TOP)) 45 | delete this.undefinedExports[name] 46 | } else if (bindingType === BIND_SIMPLE_CATCH) { 47 | const scope = this.currentScope() 48 | scope.lexical.push(name) 49 | } else if (bindingType === BIND_FUNCTION) { 50 | const scope = this.currentScope() 51 | if (this.treatFunctionsAsVar) 52 | redeclared = scope.lexical.indexOf(name) > -1 53 | else 54 | redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1 55 | scope.functions.push(name) 56 | } else { 57 | for (let i = this.scopeStack.length - 1; i >= 0; --i) { 58 | const scope = this.scopeStack[i] 59 | if (scope.lexical.indexOf(name) > -1 && !((scope.flags & SCOPE_SIMPLE_CATCH) && scope.lexical[0] === name) || 60 | !this.treatFunctionsAsVarInScope(scope) && scope.functions.indexOf(name) > -1) { 61 | redeclared = true 62 | break 63 | } 64 | scope.var.push(name) 65 | if (this.inModule && (scope.flags & SCOPE_TOP)) 66 | delete this.undefinedExports[name] 67 | if (scope.flags & SCOPE_VAR) break 68 | } 69 | } 70 | if (redeclared) this.raiseRecoverable(pos, `Identifier '${name}' has already been declared`) 71 | } 72 | 73 | pp.checkLocalExport = function(id) { 74 | // scope.functions must be empty as Module code is always strict. 75 | if (this.scopeStack[0].lexical.indexOf(id.name) === -1 && 76 | this.scopeStack[0].var.indexOf(id.name) === -1) { 77 | this.undefinedExports[id.name] = id 78 | } 79 | } 80 | 81 | pp.currentScope = function() { 82 | return this.scopeStack[this.scopeStack.length - 1] 83 | } 84 | 85 | pp.currentVarScope = function() { 86 | for (let i = this.scopeStack.length - 1;; i--) { 87 | let scope = this.scopeStack[i] 88 | if (scope.flags & (SCOPE_VAR | SCOPE_CLASS_FIELD_INIT | SCOPE_CLASS_STATIC_BLOCK)) return scope 89 | } 90 | } 91 | 92 | // Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. 93 | pp.currentThisScope = function() { 94 | for (let i = this.scopeStack.length - 1;; i--) { 95 | let scope = this.scopeStack[i] 96 | if (scope.flags & (SCOPE_VAR | SCOPE_CLASS_FIELD_INIT | SCOPE_CLASS_STATIC_BLOCK) && 97 | !(scope.flags & SCOPE_ARROW)) return scope 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /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_ASYNC = 4, 6 | SCOPE_GENERATOR = 8, 7 | SCOPE_ARROW = 16, 8 | SCOPE_SIMPLE_CATCH = 32, 9 | SCOPE_SUPER = 64, 10 | SCOPE_DIRECT_SUPER = 128, 11 | SCOPE_CLASS_STATIC_BLOCK = 256, 12 | SCOPE_CLASS_FIELD_INIT = 512, 13 | SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION | SCOPE_CLASS_STATIC_BLOCK 14 | 15 | export function functionFlags(async, generator) { 16 | return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) 17 | } 18 | 19 | // Used in checkLVal* and declareName to determine the type of a binding 20 | export const 21 | BIND_NONE = 0, // Not a binding 22 | BIND_VAR = 1, // Var-style binding 23 | BIND_LEXICAL = 2, // Let- or const-style binding 24 | BIND_FUNCTION = 3, // Function declaration 25 | BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding 26 | BIND_OUTSIDE = 5 // Special case for function names as bound inside the function 27 | -------------------------------------------------------------------------------- /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 { 7 | SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR, SCOPE_SUPER, SCOPE_DIRECT_SUPER, 8 | SCOPE_ARROW, SCOPE_CLASS_STATIC_BLOCK, SCOPE_CLASS_FIELD_INIT 9 | } from "./scopeflags.js" 10 | 11 | export class Parser { 12 | constructor(options, input, startPos) { 13 | this.options = options = getOptions(options) 14 | this.sourceFile = options.sourceFile 15 | this.keywords = wordsRegexp(keywords[options.ecmaVersion >= 6 ? 6 : options.sourceType === "module" ? "5module" : 5]) 16 | let reserved = "" 17 | if (options.allowReserved !== true) { 18 | reserved = reservedWords[options.ecmaVersion >= 6 ? 6 : options.ecmaVersion === 5 ? 5 : 3] 19 | if (options.sourceType === "module") reserved += " await" 20 | } 21 | this.reservedWords = wordsRegexp(reserved) 22 | let reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict 23 | this.reservedWordsStrict = wordsRegexp(reservedStrict) 24 | this.reservedWordsStrictBind = wordsRegexp(reservedStrict + " " + reservedWords.strictBind) 25 | this.input = String(input) 26 | 27 | // Used to signal to callers of `readWord1` whether the word 28 | // contained any escape sequences. This is needed because words with 29 | // escape sequences must not be interpreted as keywords. 30 | this.containsEsc = false 31 | 32 | // Set up token state 33 | 34 | // The current position of the tokenizer in the input. 35 | if (startPos) { 36 | this.pos = startPos 37 | this.lineStart = this.input.lastIndexOf("\n", startPos - 1) + 1 38 | this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length 39 | } else { 40 | this.pos = this.lineStart = 0 41 | this.curLine = 1 42 | } 43 | 44 | // Properties of the current token: 45 | // Its type 46 | this.type = tt.eof 47 | // For tokens that include more information than their type, the value 48 | this.value = null 49 | // Its start and end offset 50 | this.start = this.end = this.pos 51 | // And, if locations are used, the {line, column} object 52 | // corresponding to those offsets 53 | this.startLoc = this.endLoc = this.curPosition() 54 | 55 | // Position information for the previous token 56 | this.lastTokEndLoc = this.lastTokStartLoc = null 57 | this.lastTokStart = this.lastTokEnd = this.pos 58 | 59 | // The context stack is used to superficially track syntactic 60 | // context to predict whether a regular expression is allowed in a 61 | // given position. 62 | this.context = this.initialContext() 63 | this.exprAllowed = true 64 | 65 | // Figure out if it's a module code. 66 | this.inModule = options.sourceType === "module" 67 | this.strict = this.inModule || this.strictDirective(this.pos) 68 | 69 | // Used to signify the start of a potential arrow function 70 | this.potentialArrowAt = -1 71 | this.potentialArrowInForAwait = false 72 | 73 | // Positions to delayed-check that yield/await does not exist in default parameters. 74 | this.yieldPos = this.awaitPos = this.awaitIdentPos = 0 75 | // Labels in scope. 76 | this.labels = [] 77 | // Thus-far undefined exports. 78 | this.undefinedExports = Object.create(null) 79 | 80 | // If enabled, skip leading hashbang line. 81 | if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === "#!") 82 | this.skipLineComment(2) 83 | 84 | // Scope tracking for duplicate variable names (see scope.js) 85 | this.scopeStack = [] 86 | this.enterScope(SCOPE_TOP) 87 | 88 | // For RegExp validation 89 | this.regexpState = null 90 | 91 | // The stack of private names. 92 | // Each element has two properties: 'declared' and 'used'. 93 | // When it exited from the outermost class definition, all used private names must be declared. 94 | this.privateNameStack = [] 95 | } 96 | 97 | parse() { 98 | let node = this.options.program || this.startNode() 99 | this.nextToken() 100 | return this.parseTopLevel(node) 101 | } 102 | 103 | get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 } 104 | 105 | get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 } 106 | 107 | get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 } 108 | 109 | get canAwait() { 110 | for (let i = this.scopeStack.length - 1; i >= 0; i--) { 111 | let {flags} = this.scopeStack[i] 112 | if (flags & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT)) return false 113 | if (flags & SCOPE_FUNCTION) return (flags & SCOPE_ASYNC) > 0 114 | } 115 | return (this.inModule && this.options.ecmaVersion >= 13) || this.options.allowAwaitOutsideFunction 116 | } 117 | 118 | get allowSuper() { 119 | const {flags} = this.currentThisScope() 120 | return (flags & SCOPE_SUPER) > 0 || this.options.allowSuperOutsideMethod 121 | } 122 | 123 | get allowDirectSuper() { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 } 124 | 125 | get treatFunctionsAsVar() { return this.treatFunctionsAsVarInScope(this.currentScope()) } 126 | 127 | get allowNewDotTarget() { 128 | for (let i = this.scopeStack.length - 1; i >= 0; i--) { 129 | let {flags} = this.scopeStack[i] 130 | if (flags & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT) || 131 | ((flags & SCOPE_FUNCTION) && !(flags & SCOPE_ARROW))) return true 132 | } 133 | return false 134 | } 135 | 136 | get inClassStaticBlock() { 137 | return (this.currentVarScope().flags & SCOPE_CLASS_STATIC_BLOCK) > 0 138 | } 139 | 140 | static extend(...plugins) { 141 | let cls = this 142 | for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls) 143 | return cls 144 | } 145 | 146 | static parse(input, options) { 147 | return new this(options, input).parse() 148 | } 149 | 150 | static parseExpressionAt(input, pos, options) { 151 | let parser = new this(options, input, pos) 152 | parser.nextToken() 153 | return parser.parseExpression() 154 | } 155 | 156 | static tokenizer(input, options) { 157 | return new this(options, input) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /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.curContext = function() { 39 | return this.context[this.context.length - 1] 40 | } 41 | 42 | pp.braceIsBlock = function(prevType) { 43 | let parent = this.curContext() 44 | if (parent === types.f_expr || parent === types.f_stat) 45 | return true 46 | if (prevType === tt.colon && (parent === types.b_stat || parent === types.b_expr)) 47 | return !parent.isExpr 48 | 49 | // The check for `tt.name && exprAllowed` detects whether we are 50 | // after a `yield` or `of` construct. See the `updateContext` for 51 | // `tt.name`. 52 | if (prevType === tt._return || prevType === tt.name && this.exprAllowed) 53 | return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) 54 | if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType === tt.arrow) 55 | return true 56 | if (prevType === tt.braceL) 57 | return parent === types.b_stat 58 | if (prevType === tt._var || prevType === tt._const || prevType === tt.name) 59 | return false 60 | return !this.exprAllowed 61 | } 62 | 63 | pp.inGeneratorContext = function() { 64 | for (let i = this.context.length - 1; i >= 1; i--) { 65 | let context = this.context[i] 66 | if (context.token === "function") 67 | return context.generator 68 | } 69 | return false 70 | } 71 | 72 | pp.updateContext = function(prevType) { 73 | let update, type = this.type 74 | if (type.keyword && prevType === tt.dot) 75 | this.exprAllowed = false 76 | else if (update = type.updateContext) 77 | update.call(this, prevType) 78 | else 79 | this.exprAllowed = type.beforeExpr 80 | } 81 | 82 | // Used to handle edge cases when token context could not be inferred correctly during tokenization phase 83 | 84 | pp.overrideContext = function(tokenCtx) { 85 | if (this.curContext() !== tokenCtx) { 86 | this.context[this.context.length - 1] = tokenCtx 87 | } 88 | } 89 | 90 | // Token-specific context update code 91 | 92 | tt.parenR.updateContext = tt.braceR.updateContext = function() { 93 | if (this.context.length === 1) { 94 | this.exprAllowed = true 95 | return 96 | } 97 | let out = this.context.pop() 98 | if (out === types.b_stat && this.curContext().token === "function") { 99 | out = this.context.pop() 100 | } 101 | this.exprAllowed = !out.isExpr 102 | } 103 | 104 | tt.braceL.updateContext = function(prevType) { 105 | this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) 106 | this.exprAllowed = true 107 | } 108 | 109 | tt.dollarBraceL.updateContext = function() { 110 | this.context.push(types.b_tmpl) 111 | this.exprAllowed = true 112 | } 113 | 114 | tt.parenL.updateContext = function(prevType) { 115 | let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while 116 | this.context.push(statementParens ? types.p_stat : types.p_expr) 117 | this.exprAllowed = true 118 | } 119 | 120 | tt.incDec.updateContext = function() { 121 | // tokExprAllowed stays unchanged 122 | } 123 | 124 | tt._function.updateContext = tt._class.updateContext = function(prevType) { 125 | if (prevType.beforeExpr && prevType !== tt._else && 126 | !(prevType === tt.semi && this.curContext() !== types.p_stat) && 127 | !(prevType === tt._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && 128 | !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) 129 | this.context.push(types.f_expr) 130 | else 131 | this.context.push(types.f_stat) 132 | this.exprAllowed = false 133 | } 134 | 135 | tt.colon.updateContext = function() { 136 | if (this.curContext().token === "function") this.context.pop() 137 | this.exprAllowed = true 138 | } 139 | 140 | tt.backQuote.updateContext = function() { 141 | if (this.curContext() === types.q_tmpl) 142 | this.context.pop() 143 | else 144 | this.context.push(types.q_tmpl) 145 | this.exprAllowed = false 146 | } 147 | 148 | tt.star.updateContext = function(prevType) { 149 | if (prevType === tt._function) { 150 | let index = this.context.length - 1 151 | if (this.context[index] === types.f_expr) 152 | this.context[index] = types.f_expr_gen 153 | else 154 | this.context[index] = types.f_gen 155 | } 156 | this.exprAllowed = true 157 | } 158 | 159 | tt.name.updateContext = function(prevType) { 160 | let allowed = false 161 | if (this.options.ecmaVersion >= 6 && prevType !== tt.dot) { 162 | if (this.value === "of" && !this.exprAllowed || 163 | this.value === "yield" && this.inGeneratorContext()) 164 | allowed = true 165 | } 166 | this.exprAllowed = allowed 167 | } 168 | -------------------------------------------------------------------------------- /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 | import scriptValuesAddedInUnicode from "./generated/scriptValuesAddedInUnicode.js" 3 | 4 | // This file contains Unicode properties extracted from the ECMAScript specification. 5 | // The lists are extracted like so: 6 | // $$('#table-binary-unicode-properties > figure > table > tbody > tr > td:nth-child(1) code').map(el => el.innerText) 7 | 8 | // #table-binary-unicode-properties 9 | 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" 10 | const ecma10BinaryProperties = ecma9BinaryProperties + " Extended_Pictographic" 11 | const ecma11BinaryProperties = ecma10BinaryProperties 12 | const ecma12BinaryProperties = ecma11BinaryProperties + " EBase EComp EMod EPres ExtPict" 13 | const ecma13BinaryProperties = ecma12BinaryProperties 14 | const ecma14BinaryProperties = ecma13BinaryProperties 15 | 16 | const unicodeBinaryProperties = { 17 | 9: ecma9BinaryProperties, 18 | 10: ecma10BinaryProperties, 19 | 11: ecma11BinaryProperties, 20 | 12: ecma12BinaryProperties, 21 | 13: ecma13BinaryProperties, 22 | 14: ecma14BinaryProperties 23 | } 24 | 25 | // #table-binary-unicode-properties-of-strings 26 | const ecma14BinaryPropertiesOfStrings = "Basic_Emoji Emoji_Keycap_Sequence RGI_Emoji_Modifier_Sequence RGI_Emoji_Flag_Sequence RGI_Emoji_Tag_Sequence RGI_Emoji_ZWJ_Sequence RGI_Emoji" 27 | 28 | const unicodeBinaryPropertiesOfStrings = { 29 | 9: "", 30 | 10: "", 31 | 11: "", 32 | 12: "", 33 | 13: "", 34 | 14: ecma14BinaryPropertiesOfStrings 35 | } 36 | 37 | // #table-unicode-general-category-values 38 | 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" 39 | 40 | // #table-unicode-script-values 41 | const ecma9ScriptValues = "Adlam Adlm 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 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" 42 | const ecma10ScriptValues = ecma9ScriptValues + " Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd" 43 | const ecma11ScriptValues = ecma10ScriptValues + " Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho" 44 | const ecma12ScriptValues = ecma11ScriptValues + " Chorasmian Chrs Diak Dives_Akuru Khitan_Small_Script Kits Yezi Yezidi" 45 | const ecma13ScriptValues = ecma12ScriptValues + " Cypro_Minoan Cpmn Old_Uyghur Ougr Tangsa Tnsa Toto Vithkuqi Vith" 46 | const ecma14ScriptValues = ecma13ScriptValues + " " + scriptValuesAddedInUnicode 47 | 48 | const unicodeScriptValues = { 49 | 9: ecma9ScriptValues, 50 | 10: ecma10ScriptValues, 51 | 11: ecma11ScriptValues, 52 | 12: ecma12ScriptValues, 53 | 13: ecma13ScriptValues, 54 | 14: ecma14ScriptValues 55 | } 56 | 57 | const data = {} 58 | function buildUnicodeData(ecmaVersion) { 59 | const d = data[ecmaVersion] = { 60 | binary: wordsRegexp(unicodeBinaryProperties[ecmaVersion] + " " + unicodeGeneralCategoryValues), 61 | binaryOfStrings: wordsRegexp(unicodeBinaryPropertiesOfStrings[ecmaVersion]), 62 | nonBinary: { 63 | General_Category: wordsRegexp(unicodeGeneralCategoryValues), 64 | Script: wordsRegexp(unicodeScriptValues[ecmaVersion]) 65 | } 66 | } 67 | d.nonBinary.Script_Extensions = d.nonBinary.Script 68 | 69 | d.nonBinary.gc = d.nonBinary.General_Category 70 | d.nonBinary.sc = d.nonBinary.Script 71 | d.nonBinary.scx = d.nonBinary.Script_Extensions 72 | } 73 | 74 | for (const ecmaVersion of [9, 10, 11, 12, 13, 14]) { 75 | buildUnicodeData(ecmaVersion) 76 | } 77 | 78 | export default data 79 | -------------------------------------------------------------------------------- /acorn/src/util.js: -------------------------------------------------------------------------------- 1 | const {hasOwnProperty, toString} = Object.prototype 2 | 3 | export const hasOwn = Object.hasOwn || ((obj, propName) => ( 4 | hasOwnProperty.call(obj, propName) 5 | )) 6 | 7 | export const isArray = Array.isArray || ((obj) => ( 8 | toString.call(obj) === "[object Array]" 9 | )) 10 | 11 | const regexpCache = Object.create(null) 12 | 13 | export function wordsRegexp(words) { 14 | return regexpCache[words] || (regexpCache[words] = new RegExp("^(?:" + words.replace(/ /g, "|") + ")$")) 15 | } 16 | 17 | export function codePointToString(code) { 18 | // UTF-16 Decoding 19 | if (code <= 0xFFFF) return String.fromCharCode(code) 20 | code -= 0x10000 21 | return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00) 22 | } 23 | 24 | export const loneSurrogate = /[\uD800-\uDFFF]/u 25 | -------------------------------------------------------------------------------- /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) { 8 | return code === 10 || code === 13 || code === 0x2028 || code === 0x2029 9 | } 10 | 11 | export function nextLineBreak(code, from, end = code.length) { 12 | for (let i = from; i < end; i++) { 13 | let next = code.charCodeAt(i) 14 | if (isNewLine(next)) 15 | return i < end - 1 && next === 13 && code.charCodeAt(i + 1) === 10 ? i + 2 : i + 1 16 | } 17 | return -1 18 | } 19 | 20 | export const nonASCIIwhitespace = /[\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]/ 21 | 22 | export const skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g 23 | -------------------------------------------------------------------------------- /bin/generate-identifier-regex.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const fs = require("fs") 4 | const path = require("path") 5 | const pkg = require("../package.json") 6 | const dependencies = Object.keys(pkg.devDependencies) 7 | const unicodeVersion = dependencies.find((name) => /^@unicode\/unicode-\d/.test(name)) 8 | 9 | const start = require(unicodeVersion + "/Binary_Property/ID_Start/code-points.js").filter(ch => ch > 0x7f) 10 | let last = -1 11 | const cont = [0x200c, 0x200d].concat(require(unicodeVersion + "/Binary_Property/ID_Continue/code-points.js") 12 | .filter(ch => ch > 0x7f && search(start, ch, last + 1) === -1)) 13 | 14 | function search(arr, ch, starting) { 15 | for (let i = starting; arr[i] <= ch && i < arr.length; last = i++) 16 | if (arr[i] === ch) return i 17 | return -1 18 | } 19 | 20 | function esc(code) { 21 | const hex = code.toString(16) 22 | return hex.length <= 2 ? "\\x" + hex.padStart(2, "0") : "\\u" + hex.padStart(4, "0") 23 | } 24 | 25 | function generate(chars) { 26 | const astral = [] 27 | let re = "" 28 | for (let i = 0, at = 0x10000; i < chars.length; i++) { 29 | let from = chars[i], to = from 30 | while (i < chars.length - 1 && chars[i + 1] === to + 1) { i++; to++ } 31 | if (to <= 0xffff) { 32 | if (from === to) re += esc(from) 33 | else if (from + 1 === to) re += esc(from) + esc(to) 34 | else re += esc(from) + "-" + esc(to) 35 | } else { 36 | astral.push(from - at, to - from) 37 | at = to 38 | } 39 | } 40 | return {nonASCII: re, astral: astral} 41 | } 42 | 43 | const startData = generate(start), contData = generate(cont) 44 | 45 | const astralIdentifierStartCodes = "export default " + JSON.stringify(startData.astral).split(",").join(", ") 46 | const astralIdentifierCodes = "export default " + JSON.stringify(contData.astral).split(",").join(", ") 47 | const nonASCIIidentifierStartChars = "export default \"" + startData.nonASCII + "\"" 48 | const nonASCIIidentifierChars = "export default \"" + contData.nonASCII + "\"" 49 | 50 | const comment = "// This file was generated. Do not modify manually!" 51 | 52 | function writeGeneratedFile(filename, content) { 53 | fs.writeFileSync(path.resolve("./acorn/src/generated", filename + ".js"), comment + "\n" + content + "\n", "utf8") 54 | } 55 | 56 | writeGeneratedFile("astralIdentifierStartCodes", astralIdentifierStartCodes) 57 | writeGeneratedFile("astralIdentifierCodes", astralIdentifierCodes) 58 | writeGeneratedFile("nonASCIIidentifierStartChars", nonASCIIidentifierStartChars) 59 | writeGeneratedFile("nonASCIIidentifierChars", nonASCIIidentifierChars) 60 | 61 | console.log("Done. The generated files must be committed.") 62 | -------------------------------------------------------------------------------- /bin/generate-unicode-script-values.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const fs = require("fs") 4 | const path = require("path") 5 | 6 | import("../acorn/src/unicode-property-data.js") 7 | .then(m => { 8 | return m.default[13].nonBinary.Script 9 | }) 10 | .then(async(reScriptValuesAddedInES) => { 11 | const scriptValues = new Set() 12 | for await (const value of getLatestUnicodeScriptValues()) { 13 | scriptValues.add(value) 14 | } 15 | const scriptValuesAddedInUnicode = "export default " + 16 | JSON.stringify( 17 | [...scriptValues] 18 | // The unicode script values now follow the Unicode spec as of ES2023, 19 | // but prior to ES2022 they were listed in the ES2022 spec. 20 | // The generated file lists all the unicode script values except those listed before ES2022. 21 | .filter(value => !reScriptValuesAddedInES.test(value)) 22 | .sort() 23 | .join(" ") 24 | ) 25 | 26 | writeGeneratedFile("scriptValuesAddedInUnicode", scriptValuesAddedInUnicode) 27 | 28 | console.log("Done. The generated files must be committed.") 29 | }) 30 | 31 | function writeGeneratedFile(filename, content) { 32 | const comment = "// This file was generated by \"bin/" + path.basename(__filename) + "\". Do not modify manually!" 33 | fs.writeFileSync(path.resolve("./acorn/src/generated", filename + ".js"), comment + "\n" + content + "\n", "utf8") 34 | } 35 | 36 | /** 37 | * Gets the all unicode script values from the latest PropertyValueAliases. 38 | */ 39 | async function * getLatestUnicodeScriptValues() { 40 | const response = await fetch("https://unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt") 41 | const lines = (await response.text()).split("\n") 42 | for (const line of lines) { 43 | if (!line || line.startsWith("#")) { 44 | continue 45 | } 46 | const [propertyAlias, alias, canonical, ...remaining] = line 47 | .split("#")[0] // strip comments 48 | .split(";") // split by semicolon 49 | .map((x) => x.trim()) // trim 50 | 51 | if (propertyAlias !== "sc") { 52 | continue 53 | } 54 | 55 | yield canonical 56 | yield alias 57 | yield * remaining 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /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 | function loadList(filename) { 7 | return fs.readFileSync(filename, "utf8") 8 | .split("\n") 9 | .filter(Boolean) 10 | } 11 | 12 | run( 13 | (content, {sourceType}) => parse(content, {sourceType, ecmaVersion: "latest", preserveParens: true}), 14 | { 15 | testsDirectory: path.dirname(require.resolve("test262/package.json")), 16 | skip: test => test.attrs.features && 17 | loadList("./bin/test262.unsupported-features").some(f => test.attrs.features.includes(f)), 18 | whitelist: loadList("./bin/test262.whitelist") 19 | .map(filename => path.sep === "/" ? filename : filename.split("/").join(path.sep)) 20 | } 21 | ) 22 | -------------------------------------------------------------------------------- /bin/test262.unsupported-features: -------------------------------------------------------------------------------- 1 | decorators 2 | import-defer 3 | source-phase-imports 4 | -------------------------------------------------------------------------------- /bin/test262.whitelist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acornjs/acorn/b4ae0d29384f2bf3fafac7d42f1c3e2ee9a48204/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 | "build": "npm run build:main && npm run build:walk && npm run build:loose", 25 | "build:loose": "rollup -c acorn-loose/rollup.config.mjs", 26 | "build:main": "rollup -c acorn/rollup.config.mjs", 27 | "build:walk": "rollup -c acorn-walk/rollup.config.mjs", 28 | "generate": "npm run generate:identifier-regex && npm run generate:unicode-script-values", 29 | "generate:identifier-regex": "node bin/generate-identifier-regex.js", 30 | "generate:unicode-script-values": "node bin/generate-unicode-script-values.js", 31 | "lint": "eslint .", 32 | "lint:fix": "eslint . --fix", 33 | "prepare": "npm run test", 34 | "pretest": "npm run build:main && npm run build:loose", 35 | "test": "node test/run.js", 36 | "test:test262": "node bin/run_test262.js" 37 | }, 38 | "devDependencies": { 39 | "@rollup/plugin-buble": "^1.0.2", 40 | "@unicode/unicode-16.0.0": "^1.6.0", 41 | "eslint": "^8.57.0", 42 | "eslint-config-standard": "^17.1.0", 43 | "eslint-plugin-import": "^2.30.0", 44 | "eslint-plugin-n": "^16.6.2", 45 | "rollup": "^3.29.4", 46 | "test262": "git+https://github.com/tc39/test262.git#9b127c190cd418b2451c556784aae3d0ac7e9bcf", 47 | "test262-parser-runner": "^0.5.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 | -------------------------------------------------------------------------------- /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-regexp-2024.js"); 18 | require("./tests-regexp-2025.js"); 19 | require("./tests-json-superset.js"); 20 | require("./tests-optional-catch-binding.js"); 21 | require("./tests-bigint.js"); 22 | require("./tests-dynamic-import.js"); 23 | require("./tests-export-named.js"); 24 | require("./tests-export-all-as-ns-from-source.js"); 25 | require("./tests-import-meta.js"); 26 | require("./tests-nullish-coalescing.js"); 27 | require("./tests-optional-chaining.js"); 28 | require("./tests-logical-assignment-operators.js"); 29 | require("./tests-numeric-separators.js"); 30 | require("./tests-class-features-2022.js"); 31 | require("./tests-module-string-names.js"); 32 | require("./tests-import-attributes.js"); 33 | require("./tests-using.js"); 34 | var acorn = require("../acorn") 35 | var acorn_loose = require("../acorn-loose") 36 | 37 | var htmlLog = typeof document === "object" && document.getElementById('log'); 38 | var htmlGroup = htmlLog; 39 | 40 | function group(name) { 41 | if (htmlGroup) { 42 | var parentGroup = htmlGroup; 43 | htmlGroup = document.createElement("ul"); 44 | var item = document.createElement("li"); 45 | item.textContent = name; 46 | item.appendChild(htmlGroup); 47 | parentGroup.appendChild(item); 48 | } 49 | if (typeof console === "object" && console.group) { 50 | console.group(name); 51 | } 52 | } 53 | 54 | function groupEnd() { 55 | if (htmlGroup) { 56 | htmlGroup = htmlGroup.parentElement.parentElement; 57 | } 58 | if (typeof console === "object" && console.groupEnd) { 59 | console.groupEnd(name); 60 | } 61 | } 62 | 63 | function log(title, message) { 64 | if (htmlGroup) { 65 | var elem = document.createElement("li"); 66 | elem.innerHTML = "" + title + " " + message; 67 | htmlGroup.appendChild(elem); 68 | } 69 | if (typeof console === "object") console.log(title, message); 70 | } 71 | 72 | var stats, modes = { 73 | Normal: { 74 | config: { 75 | parse: acorn.parse 76 | } 77 | }, 78 | Loose: { 79 | config: { 80 | parse: acorn_loose.parse, 81 | loose: true, 82 | filter: function (test) { 83 | var opts = test.options || {}; 84 | return opts.loose !== false; 85 | } 86 | } 87 | } 88 | }; 89 | 90 | function report(state, code, message) { 91 | if (state !== "ok") {++stats.failed; log(code, message);} 92 | ++stats.testsRun; 93 | } 94 | 95 | group("Errors"); 96 | 97 | for (var name in modes) { 98 | group(name); 99 | var mode = modes[name]; 100 | stats = mode.stats = {testsRun: 0, failed: 0}; 101 | var t0 = +new Date; 102 | driver.runTests(mode.config, report); 103 | mode.stats.duration = +new Date - t0; 104 | groupEnd(); 105 | } 106 | 107 | groupEnd(); 108 | 109 | function outputStats(name, stats) { 110 | log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " + 111 | (stats.failed ? stats.failed + " failures." : "all passed.")); 112 | } 113 | 114 | var total = {testsRun: 0, failed: 0, duration: 0}; 115 | 116 | group("Stats"); 117 | 118 | for (var name in modes) { 119 | var stats = modes[name].stats; 120 | outputStats(name + " parser", stats); 121 | for (var key in stats) total[key] += stats[key]; 122 | } 123 | 124 | outputStats("Total", total); 125 | 126 | groupEnd(); 127 | 128 | if (total.failed && typeof process === "object") { 129 | process.stdout.write("", function() { 130 | process.exit(1); 131 | }); 132 | } 133 | })(); 134 | -------------------------------------------------------------------------------- /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)", 'Unexpected token (1:10)', { 244 | ecmaVersion: 11, 245 | loose: false 246 | }); 247 | 248 | testFail("new import(source).foo", 'Unexpected token (1:10)', { 249 | ecmaVersion: 11, 250 | loose: false 251 | }); 252 | 253 | testFail("(import)(s)", 'Unexpected token (1:7)', { 254 | ecmaVersion: 11, 255 | loose: false 256 | }); 257 | -------------------------------------------------------------------------------- /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 | } 6 | 7 | //------------------------------------------------------------------------------ 8 | // export * as ns from "source" 9 | //------------------------------------------------------------------------------ 10 | 11 | test("export * as ns from \"source\"", { 12 | "type": "Program", 13 | "start": 0, 14 | "end": 28, 15 | "body": [ 16 | { 17 | "type": "ExportAllDeclaration", 18 | "start": 0, 19 | "end": 28, 20 | "exported": { 21 | "type": "Identifier", 22 | "start": 12, 23 | "end": 14, 24 | "name": "ns" 25 | }, 26 | "source": { 27 | "type": "Literal", 28 | "start": 20, 29 | "end": 28, 30 | "value": "source", 31 | "raw": "\"source\"" 32 | } 33 | } 34 | ], 35 | "sourceType": "module" 36 | }, { sourceType: "module", ecmaVersion: 11 }) 37 | 38 | test("export * as foo from \"bar\"", { 39 | "type": "Program", 40 | "start": 0, 41 | "end": 26, 42 | "body": [ 43 | { 44 | "type": "ExportAllDeclaration", 45 | "start": 0, 46 | "end": 26, 47 | "exported": { 48 | "type": "Identifier", 49 | "start": 12, 50 | "end": 15, 51 | "name": "foo" 52 | }, 53 | "source": { 54 | "type": "Literal", 55 | "start": 21, 56 | "end": 26, 57 | "value": "bar", 58 | "raw": "\"bar\"" 59 | } 60 | } 61 | ], 62 | "sourceType": "module" 63 | }, { sourceType: "module", ecmaVersion: 11 }) 64 | 65 | test("export * from \"source\"", { 66 | "type": "Program", 67 | "start": 0, 68 | "end": 22, 69 | "body": [ 70 | { 71 | "type": "ExportAllDeclaration", 72 | "start": 0, 73 | "end": 22, 74 | "exported": null, 75 | "source": { 76 | "type": "Literal", 77 | "start": 14, 78 | "end": 22, 79 | "value": "source", 80 | "raw": "\"source\"" 81 | } 82 | } 83 | ], 84 | "sourceType": "module" 85 | }, { sourceType: "module", ecmaVersion: 11 }) 86 | 87 | test("export * from 'a';", { 88 | type: "Program", 89 | body: [ 90 | { 91 | type: "ExportAllDeclaration", 92 | exported: null, 93 | source: { 94 | type: "Literal", 95 | } 96 | } 97 | ] 98 | }, {sourceType: "module", ecmaVersion: 11}) 99 | 100 | testFail("export * as ns from \"source\"", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 101 | testFail("export * as ns from \"source\"", "Unexpected token (1:9)", { sourceType: "module", ecmaVersion: 10 }) 102 | testFail("export * as ns", "Unexpected token (1:14)", { sourceType: "module", ecmaVersion: 11 }) 103 | testFail("export * as from \"source\"", "Unexpected token (1:17)", { sourceType: "module", ecmaVersion: 11 }) 104 | testFail("export * as ns \"source\"", "Unexpected token (1:15)", { sourceType: "module", ecmaVersion: 11 }) 105 | testFail("export {} as ns from \"source\"", "Unexpected token (1:10)", { sourceType: "module", ecmaVersion: 11 }) 106 | -------------------------------------------------------------------------------- /test/tests-export-named.js: -------------------------------------------------------------------------------- 1 | // Tests for `ExportNamedDeclaration` 2 | 3 | if (typeof exports !== "undefined") { 4 | var driver = require("./driver.js"); 5 | var test = driver.test, testFail = driver.testFail; 6 | } 7 | 8 | //------------------------------------------------------------------------------ 9 | // export {x} from "source" 10 | //------------------------------------------------------------------------------ 11 | 12 | test("export {x} from \"source\"", { 13 | "type": "Program", 14 | "start": 0, 15 | "end": 24, 16 | "body": [ 17 | { 18 | "type": "ExportNamedDeclaration", 19 | "start": 0, 20 | "end": 24, 21 | "declaration": null, 22 | "specifiers": [ 23 | { 24 | "type": "ExportSpecifier", 25 | "start": 8, 26 | "end": 9, 27 | "local": { 28 | "type": "Identifier", 29 | "start": 8, 30 | "end": 9, 31 | "name": "x" 32 | }, 33 | "exported": { 34 | "type": "Identifier", 35 | "start": 8, 36 | "end": 9, 37 | "name": "x" 38 | } 39 | } 40 | ], 41 | "source": { 42 | "type": "Literal", 43 | "start": 16, 44 | "end": 24, 45 | "value": "source", 46 | "raw": "\"source\"" 47 | }, 48 | "attributes": [] 49 | } 50 | ], 51 | "sourceType": "module" 52 | }, { sourceType: "module", ecmaVersion: 16 }) 53 | 54 | test("export {x as y} from \"source\"", { 55 | "type": "Program", 56 | "start": 0, 57 | "end": 29, 58 | "body": [ 59 | { 60 | "type": "ExportNamedDeclaration", 61 | "start": 0, 62 | "end": 29, 63 | "declaration": null, 64 | "specifiers": [ 65 | { 66 | "type": "ExportSpecifier", 67 | "start": 8, 68 | "end": 14, 69 | "local": { 70 | "type": "Identifier", 71 | "start": 8, 72 | "end": 9, 73 | "name": "x" 74 | }, 75 | "exported": { 76 | "type": "Identifier", 77 | "start": 13, 78 | "end": 14, 79 | "name": "y" 80 | } 81 | } 82 | ], 83 | "source": { 84 | "type": "Literal", 85 | "start": 21, 86 | "end": 29, 87 | "value": "source", 88 | "raw": "\"source\"" 89 | }, 90 | "attributes": [] 91 | } 92 | ], 93 | "sourceType": "module" 94 | }, { sourceType: "module", ecmaVersion: 16 }) 95 | 96 | //------------------------------------------------------------------------------ 97 | // export {x} 98 | //------------------------------------------------------------------------------ 99 | 100 | test("let x; export {x};", { 101 | "type": "Program", 102 | "start": 0, 103 | "end": 18, 104 | "body": [ 105 | { 106 | "type": "VariableDeclaration", 107 | "start": 0, 108 | "end": 6, 109 | "declarations": [ 110 | { 111 | "type": "VariableDeclarator", 112 | "start": 4, 113 | "end": 5, 114 | "id": { 115 | "type": "Identifier", 116 | "start": 4, 117 | "end": 5, 118 | "name": "x" 119 | }, 120 | "init": null 121 | } 122 | ], 123 | "kind": "let" 124 | }, 125 | { 126 | "type": "ExportNamedDeclaration", 127 | "start": 7, 128 | "end": 18, 129 | "declaration": null, 130 | "specifiers": [ 131 | { 132 | "type": "ExportSpecifier", 133 | "start": 15, 134 | "end": 16, 135 | "local": { 136 | "type": "Identifier", 137 | "start": 15, 138 | "end": 16, 139 | "name": "x" 140 | }, 141 | "exported": { 142 | "type": "Identifier", 143 | "start": 15, 144 | "end": 16, 145 | "name": "x" 146 | } 147 | } 148 | ], 149 | "source": null, 150 | "attributes": [] 151 | } 152 | ], 153 | "sourceType": "module" 154 | }, { sourceType: "module", ecmaVersion: 16 }) 155 | 156 | test("let x; export {x as y};", { 157 | "type": "Program", 158 | "start": 0, 159 | "end": 23, 160 | "body": [ 161 | { 162 | "type": "VariableDeclaration", 163 | "start": 0, 164 | "end": 6, 165 | "declarations": [ 166 | { 167 | "type": "VariableDeclarator", 168 | "start": 4, 169 | "end": 5, 170 | "id": { 171 | "type": "Identifier", 172 | "start": 4, 173 | "end": 5, 174 | "name": "x" 175 | }, 176 | "init": null 177 | } 178 | ], 179 | "kind": "let" 180 | }, 181 | { 182 | "type": "ExportNamedDeclaration", 183 | "start": 7, 184 | "end": 23, 185 | "declaration": null, 186 | "specifiers": [ 187 | { 188 | "type": "ExportSpecifier", 189 | "start": 15, 190 | "end": 21, 191 | "local": { 192 | "type": "Identifier", 193 | "start": 15, 194 | "end": 16, 195 | "name": "x" 196 | }, 197 | "exported": { 198 | "type": "Identifier", 199 | "start": 20, 200 | "end": 21, 201 | "name": "y" 202 | } 203 | } 204 | ], 205 | "source": null, 206 | "attributes": [] 207 | } 208 | ], 209 | "sourceType": "module" 210 | }, {sourceType: "module", ecmaVersion: 16}) 211 | 212 | testFail("export {x} from \"source\"", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 213 | testFail("export {x as y} from \"source\"", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 214 | testFail("export {x}; let x;", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 215 | testFail("export {x as y}; let x;", "'import' and 'export' may appear only with 'sourceType: module' (1:0)", { sourceType: "script", ecmaVersion: 11 }) 216 | -------------------------------------------------------------------------------- /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-module-string-names.js: -------------------------------------------------------------------------------- 1 | if (typeof exports !== "undefined") { 2 | var test = require("./driver.js").test; 3 | var testFail = require("./driver.js").testFail; 4 | } 5 | 6 | test( 7 | 'import {"學而時習之,不亦說乎?" as quotation} from "Confucius";', 8 | { 9 | type: "Program", 10 | start: 0, 11 | end: 53, 12 | body: [ 13 | { 14 | type: "ImportDeclaration", 15 | start: 0, 16 | end: 53, 17 | specifiers: [ 18 | { 19 | type: "ImportSpecifier", 20 | start: 8, 21 | end: 34, 22 | imported: { 23 | type: "Literal", 24 | start: 8, 25 | end: 21, 26 | value: "學而時習之,不亦說乎?", 27 | raw: '"學而時習之,不亦說乎?"', 28 | }, 29 | local: { 30 | type: "Identifier", 31 | start: 25, 32 | end: 34, 33 | name: "quotation", 34 | }, 35 | }, 36 | ], 37 | source: { 38 | type: "Literal", 39 | start: 41, 40 | end: 52, 41 | value: "Confucius", 42 | raw: '"Confucius"', 43 | }, 44 | }, 45 | ], 46 | sourceType: "module", 47 | }, 48 | { sourceType: "module", ecmaVersion: 13 } 49 | ); 50 | 51 | test( 52 | 'const quotation = ""; export { quotation as "學而時習之,不亦說乎?" };', 53 | { 54 | type: "Program", 55 | start: 0, 56 | end: 60, 57 | body: [ 58 | { 59 | type: "VariableDeclaration", 60 | start: 0, 61 | end: 21, 62 | declarations: [ 63 | { 64 | type: "VariableDeclarator", 65 | start: 6, 66 | end: 20, 67 | id: { 68 | type: "Identifier", 69 | start: 6, 70 | end: 15, 71 | name: "quotation", 72 | }, 73 | init: { 74 | type: "Literal", 75 | start: 18, 76 | end: 20, 77 | value: "", 78 | raw: '""', 79 | }, 80 | }, 81 | ], 82 | kind: "const", 83 | }, 84 | { 85 | type: "ExportNamedDeclaration", 86 | start: 22, 87 | end: 60, 88 | declaration: null, 89 | specifiers: [ 90 | { 91 | type: "ExportSpecifier", 92 | start: 31, 93 | end: 57, 94 | local: { 95 | type: "Identifier", 96 | start: 31, 97 | end: 40, 98 | name: "quotation", 99 | }, 100 | exported: { 101 | type: "Literal", 102 | start: 44, 103 | end: 57, 104 | value: "學而時習之,不亦說乎?", 105 | raw: '"學而時習之,不亦說乎?"', 106 | }, 107 | }, 108 | ], 109 | source: null, 110 | }, 111 | ], 112 | sourceType: "module", 113 | }, 114 | { sourceType: "module", ecmaVersion: 13 } 115 | ); 116 | 117 | test( 118 | 'export * as "忠恕。" from "Confucius";', 119 | { 120 | type: "Program", 121 | start: 0, 122 | end: 35, 123 | body: [ 124 | { 125 | type: "ExportAllDeclaration", 126 | start: 0, 127 | end: 35, 128 | exported: { 129 | type: "Literal", 130 | start: 12, 131 | end: 17, 132 | value: "忠恕。", 133 | raw: '"忠恕。"', 134 | }, 135 | source: { 136 | type: "Literal", 137 | start: 23, 138 | end: 34, 139 | value: "Confucius", 140 | raw: '"Confucius"', 141 | }, 142 | }, 143 | ], 144 | sourceType: "module", 145 | }, 146 | { sourceType: "module", ecmaVersion: 13 } 147 | ); 148 | 149 | test( 150 | 'export { "學而時習之,不亦說乎?", "吾道一以貫之。" as "忠恕。" } from "Confucius";', 151 | { 152 | type: "Program", 153 | start: 0, 154 | end: 62, 155 | body: [ 156 | { 157 | type: "ExportNamedDeclaration", 158 | start: 0, 159 | end: 62, 160 | declaration: null, 161 | specifiers: [ 162 | { 163 | type: "ExportSpecifier", 164 | start: 9, 165 | end: 22, 166 | local: { 167 | type: "Literal", 168 | start: 9, 169 | end: 22, 170 | value: "學而時習之,不亦說乎?", 171 | raw: '"學而時習之,不亦說乎?"', 172 | }, 173 | exported: { 174 | type: "Literal", 175 | start: 9, 176 | end: 22, 177 | value: "學而時習之,不亦說乎?", 178 | raw: '"學而時習之,不亦說乎?"', 179 | }, 180 | }, 181 | { 182 | type: "ExportSpecifier", 183 | start: 24, 184 | end: 42, 185 | local: { 186 | type: "Literal", 187 | start: 24, 188 | end: 33, 189 | value: "吾道一以貫之。", 190 | raw: '"吾道一以貫之。"', 191 | }, 192 | exported: { 193 | type: "Literal", 194 | start: 37, 195 | end: 42, 196 | value: "忠恕。", 197 | raw: '"忠恕。"', 198 | }, 199 | }, 200 | ], 201 | source: { 202 | type: "Literal", 203 | start: 50, 204 | end: 61, 205 | value: "Confucius", 206 | raw: '"Confucius"', 207 | }, 208 | }, 209 | ], 210 | sourceType: "module", 211 | }, 212 | { sourceType: "module", ecmaVersion: 13 } 213 | ); 214 | 215 | test( 216 | 'import { "foo" as bar, "default" as qux } from "module-a";', 217 | { 218 | type: "Program", 219 | start: 0, 220 | end: 58, 221 | body: [ 222 | { 223 | type: "ImportDeclaration", 224 | start: 0, 225 | end: 58, 226 | specifiers: [ 227 | { 228 | type: "ImportSpecifier", 229 | start: 9, 230 | end: 21, 231 | imported: { 232 | type: "Literal", 233 | start: 9, 234 | end: 14, 235 | value: "foo", 236 | raw: '"foo"', 237 | }, 238 | local: { 239 | type: "Identifier", 240 | start: 18, 241 | end: 21, 242 | name: "bar", 243 | }, 244 | }, 245 | { 246 | type: "ImportSpecifier", 247 | start: 23, 248 | end: 39, 249 | imported: { 250 | type: "Literal", 251 | start: 23, 252 | end: 32, 253 | value: "default", 254 | raw: '"default"', 255 | }, 256 | local: { 257 | type: "Identifier", 258 | start: 36, 259 | end: 39, 260 | name: "qux", 261 | }, 262 | }, 263 | ], 264 | source: { 265 | type: "Literal", 266 | start: 47, 267 | end: 57, 268 | value: "module-a", 269 | raw: '"module-a"', 270 | }, 271 | }, 272 | ], 273 | sourceType: "module", 274 | }, 275 | { sourceType: "module", ecmaVersion: 13 } 276 | ); 277 | 278 | test( 279 | 'import { "default" as quotation } from "Confucius";', 280 | { 281 | type: "Program", 282 | start: 0, 283 | end: 51, 284 | body: [ 285 | { 286 | type: "ImportDeclaration", 287 | start: 0, 288 | end: 51, 289 | specifiers: [ 290 | { 291 | type: "ImportSpecifier", 292 | start: 9, 293 | end: 31, 294 | imported: { 295 | type: "Literal", 296 | start: 9, 297 | end: 18, 298 | value: "default", 299 | raw: '"default"', 300 | }, 301 | local: { 302 | type: "Identifier", 303 | start: 22, 304 | end: 31, 305 | name: "quotation", 306 | }, 307 | }, 308 | ], 309 | source: { 310 | type: "Literal", 311 | start: 39, 312 | end: 50, 313 | value: "Confucius", 314 | raw: '"Confucius"', 315 | }, 316 | }, 317 | ], 318 | sourceType: "module", 319 | }, 320 | { sourceType: "module", ecmaVersion: 13 } 321 | ); 322 | 323 | testFail( 324 | 'export { "學而時習之,不亦說乎?", "吾道一以貫之。" as "忠恕。" };', 325 | "A string literal cannot be used as an exported binding without `from`. (1:9)", 326 | { sourceType: "module", ecmaVersion: 13 } 327 | ); 328 | 329 | testFail( 330 | 'const foo = 42; export { foo as "\ud800\udbff" }', 331 | "An export name cannot include a lone surrogate. (1:32)", 332 | { sourceType: "module", ecmaVersion: 13 } 333 | ); 334 | 335 | testFail( 336 | 'const foo = 43, bar = 32; export { foo, bar as "foo" };', 337 | "Duplicate export 'foo' (1:47)", 338 | { sourceType: "module", ecmaVersion: 13 } 339 | ); 340 | 341 | test('export * as "a" from "mod1"\nexport * as "b" from "mod2"', {}, 342 | { sourceType: "module", ecmaVersion: 13 }); 343 | -------------------------------------------------------------------------------- /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 | } 4 | 5 | test("try {} catch {}", { 6 | type: "Program", 7 | start: 0, 8 | end: 15, 9 | body: [ 10 | { 11 | type: "TryStatement", 12 | start: 0, 13 | end: 15, 14 | block: { 15 | type: "BlockStatement", 16 | start: 4, 17 | end: 6, 18 | body: [] 19 | }, 20 | handler: { 21 | type: "CatchClause", 22 | start: 7, 23 | end: 15, 24 | param: null, 25 | body: { 26 | type: "BlockStatement", 27 | start: 13, 28 | end: 15, 29 | body: [] 30 | } 31 | }, 32 | finalizer: null 33 | } 34 | ], 35 | sourceType: "script" 36 | }, {ecmaVersion: 10}) 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/tests-regexp-2024.js: -------------------------------------------------------------------------------- 1 | if (typeof exports !== "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | test("/a/v", {}, { ecmaVersion: 2024 }) 7 | testFail("/a/v", "Invalid regular expression flag (1:1)", { ecmaVersion: 2023 }) 8 | testFail("/a/uv", "Invalid regular expression flag (1:1)", { ecmaVersion: 2024 }) 9 | test("/[]/v", {}, { ecmaVersion: 2024 }) 10 | test("/[^]/v", {}, { ecmaVersion: 2024 }) 11 | test("/[&]/v", {}, { ecmaVersion: 2024 }) 12 | test("/[\\b]/v", {}, { ecmaVersion: 2024 }) 13 | test("/[\\&]/v", {}, { ecmaVersion: 2024 }) 14 | testFail("/[\\z]/v", "Invalid regular expression: /[\\z]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 15 | testFail("/[a\\z]/v", "Invalid regular expression: /[a\\z]/: Unterminated character class (1:1)", { ecmaVersion: 2024 }) 16 | // Union 17 | test("/[abc]/v", {}, { ecmaVersion: 2024 }) 18 | test("/[a-c]/v", {}, { ecmaVersion: 2024 }) 19 | test("/[a-bc]/v", {}, { ecmaVersion: 2024 }) 20 | test("/[ab-c]/v", {}, { ecmaVersion: 2024 }) 21 | testFail("/[c-a]/v", "Invalid regular expression: /[c-a]/: Range out of order in character class (1:1)", { ecmaVersion: 2024 }) 22 | testFail("/[a-\\b]/v", "Invalid regular expression: /[a-\\b]/: Range out of order in character class (1:1)", { ecmaVersion: 2024 }) 23 | // Expression 24 | test("/[a&&b]/v", {}, { ecmaVersion: 2024 }) 25 | test("/[a--b]/v", {}, { ecmaVersion: 2024 }) 26 | test("/[a&&b&&c]/v", {}, { ecmaVersion: 2024 }) 27 | test("/[a--b--c]/v", {}, { ecmaVersion: 2024 }) 28 | testFail("/[a--]/v", "Invalid regular expression: /[a--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 29 | testFail("/[a&&]/v", "Invalid regular expression: /[a&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 30 | testFail("/[a--b&&c]/v", "Invalid regular expression: /[a--b&&c]/: Unterminated character class (1:1)", { ecmaVersion: 2024 }) 31 | testFail("/[a&&b--c]/v", "Invalid regular expression: /[a&&b--c]/: Unterminated character class (1:1)", { ecmaVersion: 2024 }) 32 | testFail("/[a&&&]/v", "Invalid regular expression: /[a&&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 33 | testFail("/[a&&b&&]/v", "Invalid regular expression: /[a&&b&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 34 | testFail("/[a--b--]/v", "Invalid regular expression: /[a--b--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 35 | test("/[a&&\\&]/v", {}, { ecmaVersion: 2024 }) 36 | testFail("/[&&]/v", "Invalid regular expression: /[&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 37 | testFail("/[!!]/v", "Invalid regular expression: /[!!]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 38 | testFail("/[##]/v", "Invalid regular expression: /[##]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 39 | testFail("/[--]/v", "Invalid regular expression: /[--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 40 | // Nested 41 | test("/[[a&&b]--[c&&d]]/v", {}, { ecmaVersion: 2024 }) 42 | test("/[[a--b]&&[c--d]]/v", {}, { ecmaVersion: 2024 }) 43 | test("/[[a&&b][c--d][ef]]/v", {}, { ecmaVersion: 2024 }) 44 | // Class String 45 | test("/[\\q{a|b}]/v", {}, { ecmaVersion: 2024 }) 46 | test("/[\\q{abc}]/v", {}, { ecmaVersion: 2024 }) 47 | test("/[\\q{}]/v", {}, { ecmaVersion: 2024 }) 48 | test("/[\\q{abc|def}]/v", {}, { ecmaVersion: 2024 }) 49 | test("/[\\q{abc|d|ef}]/v", {}, { ecmaVersion: 2024 }) 50 | test("/[\\q{|||abc||||}]/v", {}, { ecmaVersion: 2024 }) 51 | testFail("/\\q{a|b}/v", "Invalid regular expression: /\\q{a|b}/: Invalid escape (1:1)", { ecmaVersion: 2024 }) 52 | testFail("/[\\q{a|b]/v", "Invalid regular expression: /[\\q{a|b]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 }) 53 | testFail("/[\\q{a|b}]/u", "Invalid regular expression: /[\\q{a|b}]/: Invalid escape (1:1)", { ecmaVersion: 2024 }) 54 | // Unicode binary properties of strings 55 | test("/\\p{Basic_Emoji}/v", {}, { ecmaVersion: 2024 }) 56 | testFail("/\\p{Basic_Emoji}/u", "Invalid regular expression: /\\p{Basic_Emoji}/: Invalid property name (1:1)", { ecmaVersion: 2024 }) 57 | test("/\\p{Basic_Emoji}/", {}, { ecmaVersion: 2024 }) // Non unicode binary properties of strings 58 | // MayContainStrings 59 | testFail("/\\P{Basic_Emoji}/v", "Invalid regular expression: /\\P{Basic_Emoji}/: Invalid property name (1:1)", { ecmaVersion: 2024 }) 60 | test("/\\p{ASCII}/v", {}, { ecmaVersion: 2024 }) 61 | test("/\\P{General_Category=Letter}/v", {}, { ecmaVersion: 2024 }) 62 | testFail("/[^\\p{Basic_Emoji}]/v", "Invalid regular expression: /[^\\p{Basic_Emoji}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 63 | testFail("/[^[\\p{Basic_Emoji}]]/v", "Invalid regular expression: /[^[\\p{Basic_Emoji}]]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 64 | test("/[^\\d]/v", {}, { ecmaVersion: 2024 }) 65 | test("/[^\\D]/v", {}, { ecmaVersion: 2024 }) 66 | test("/[^\\s]/v", {}, { ecmaVersion: 2024 }) 67 | test("/[^\\S]/v", {}, { ecmaVersion: 2024 }) 68 | test("/[^\\w]/v", {}, { ecmaVersion: 2024 }) 69 | test("/[^\\W]/v", {}, { ecmaVersion: 2024 }) 70 | test("/[^\\p{ASCII}]/v", {}, { ecmaVersion: 2024 }) 71 | test("/[^\\p{General_Category=Letter}]/v", {}, { ecmaVersion: 2024 }) 72 | test("/[^[^\\p{ASCII}]]/v", {}, { ecmaVersion: 2024 }) 73 | test("/[\\p{Basic_Emoji}][^]/v", {}, { ecmaVersion: 2024 }) 74 | test("/[^[\\p{ASCII}]]/v", {}, { ecmaVersion: 2024 }) 75 | test("/[^\\q{a}]/v", {}, { ecmaVersion: 2024 }) 76 | test("/[^\\q{a|b}]/v", {}, { ecmaVersion: 2024 }) 77 | testFail("/[^\\q{}]/v", "Invalid regular expression: /[^\\q{}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 78 | testFail("/[^\\q{ab}]/v", "Invalid regular expression: /[^\\q{ab}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 79 | testFail("/[^\\q{a|bc}]/v", "Invalid regular expression: /[^\\q{a|bc}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 80 | test("/[^\\q{a}\\q{b}]/v", {}, { ecmaVersion: 2024 }) 81 | testFail("/[^\\q{a}\\q{bc}]/v", "Invalid regular expression: /[^\\q{a}\\q{bc}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 82 | test("/[^\\q{a}&&\\q{bc}]/v", {}, { ecmaVersion: 2024 }) 83 | test("/[^\\q{ab}&&\\q{c}]/v", {}, { ecmaVersion: 2024 }) 84 | testFail("/[^\\q{ab}&&\\q{cd}]/v", "Invalid regular expression: /[^\\q{ab}&&\\q{cd}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 85 | test("/[^\\q{a}--\\q{bc}]/v", {}, { ecmaVersion: 2024 }) 86 | testFail("/[^\\q{ab}--\\q{c}]/v", "Invalid regular expression: /[^\\q{ab}--\\q{c}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 }) 87 | -------------------------------------------------------------------------------- /test/tests-regexp-2025.js: -------------------------------------------------------------------------------- 1 | if (typeof exports !== "undefined") { 2 | var test = require("./driver.js").test 3 | var testFail = require("./driver.js").testFail 4 | } 5 | 6 | // Duplicate named capture groups 7 | test("/(?a)|(?b)/", {}, {ecmaVersion: 2025}) 8 | testFail("/(?a)|(?b)/", "Invalid regular expression: /(?a)|(?b)/: Duplicate capture group name (1:1)", {ecmaVersion: 2024 }) 9 | testFail("/(?a)(?b)/", "Invalid regular expression: /(?a)(?b)/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 10 | test("/(?:(?a)|(?b))\\k/", {}, {ecmaVersion: 2025}) 11 | testFail("/(?:(?a)|(?b))\\k/", "Invalid regular expression: /(?:(?a)|(?b))\\k/: Duplicate capture group name (1:1)", {ecmaVersion: 2024 }) 12 | testFail("/(?:(?a)(?b))\\k/", "Invalid regular expression: /(?:(?a)(?b))\\k/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 13 | test("/(?a)(?a)|(?b)(?b)/", {}, {ecmaVersion: 2025}) 14 | test("/(?a)|(?b)|(?c)/", {}, {ecmaVersion: 2025}) 15 | test("/(?a)|\\k/", {}, {ecmaVersion: 2025}) 16 | testFail("/(?a)|(?b)(?c)/", "Invalid regular expression: /(?a)|(?b)(?c)/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 17 | testFail("/(?:(?a)|(?b))(?c)/", "Invalid regular expression: /(?:(?a)|(?b))(?c)/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 18 | testFail("/(?a)(?:(?b)|(?c))/", "Invalid regular expression: /(?a)(?:(?b)|(?c))/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 19 | testFail("/(?:(?:(?a)|(?b))|(?:))(?c)/", "Invalid regular expression: /(?:(?:(?a)|(?b))|(?:))(?c)/: Duplicate capture group name (1:1)", {ecmaVersion: 2025}) 20 | 21 | // Modifiers 22 | test("/(?i-m:p)?/", {}, {ecmaVersion: 2025}) 23 | test("/(?i-m:p)?/u", {}, {ecmaVersion: 2025}) 24 | test("/(?ims:p)?/", {}, {ecmaVersion: 2025}) 25 | test("/(?ims-:p)?/", {}, {ecmaVersion: 2025}) 26 | test("/(?-ims:p)?/", {}, {ecmaVersion: 2025}) 27 | test("/(?:no modifiers)?/", {}, {ecmaVersion: 2025}) 28 | // In ES2024 29 | testFail("/(?i-m:p)?/", "Invalid regular expression: /(?i-m:p)?/: Invalid group (1:1)", {ecmaVersion: 2024}) 30 | testFail("/(?ims:p)?/", "Invalid regular expression: /(?ims:p)?/: Invalid group (1:1)", {ecmaVersion: 2024}) 31 | testFail("/(?ims-:p)?/", "Invalid regular expression: /(?ims-:p)?/: Invalid group (1:1)", {ecmaVersion: 2024}) 32 | testFail("/(?-ims:p)?/", "Invalid regular expression: /(?-ims:p)?/: Invalid group (1:1)", {ecmaVersion: 2024}) 33 | // It is a Syntax Error if the first modifiers and the second modifiers are both empty. 34 | testFail("/(?-:p)?/", "Invalid regular expression: /(?-:p)?/: Invalid regular expression modifiers (1:1)", {ecmaVersion: 2025}) 35 | // It is a Syntax Error if the first modifiers contains the same code point more than once. 36 | testFail("/(?ii:p)?/", "Invalid regular expression: /(?ii:p)?/: Duplicate regular expression modifiers (1:1)", {ecmaVersion: 2025}) 37 | // It is a Syntax Error if the second modifiers contains the same code point more than once. 38 | testFail("/(?-ii:p)?/", "Invalid regular expression: /(?-ii:p)?/: Duplicate regular expression modifiers (1:1)", {ecmaVersion: 2025}) 39 | testFail("/(?i-mm:p)?/", "Invalid regular expression: /(?i-mm:p)?/: Duplicate regular expression modifiers (1:1)", {ecmaVersion: 2025}) 40 | // It is a Syntax Error if any code point in the first modifiers is also contained in the second modifiers. 41 | testFail("/(?i-i:p)?/", "Invalid regular expression: /(?i-i:p)?/: Duplicate regular expression modifiers (1:1)", {ecmaVersion: 2025}) 42 | // Not modifiers 43 | testFail("/(?u:p)?/", "Invalid regular expression: /(?u:p)?/: Invalid group (1:1)", {ecmaVersion: 2025}) 44 | testFail("/(?u-:p)?/", "Invalid regular expression: /(?u-:p)?/: Invalid group (1:1)", {ecmaVersion: 2025}) 45 | testFail("/(?u-i:p)?/", "Invalid regular expression: /(?u-i:p)?/: Invalid group (1:1)", {ecmaVersion: 2025}) 46 | testFail("/(?-u:p)?/", "Invalid regular expression: /(?-u:p)?/: Invalid group (1:1)", {ecmaVersion: 2025}) 47 | testFail("/(?i-u:p)?/", "Invalid regular expression: /(?i-u:p)?/: Invalid group (1:1)", {ecmaVersion: 2025}) 48 | --------------------------------------------------------------------------------