From ab839df29a5e52d6987d63e01b4fdf8cbaa862e4 Mon Sep 17 00:00:00 2001 From: Alexander Sterk Date: Sun, 1 Mar 2020 00:07:20 +0100 Subject: [PATCH 01/17] Filtered positional operator in Mongo Update Adds support for the arrayFilters option for Collection.update (see https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/), as described in #10103 . This option only works server-side, for client-side there is a PR: #9721 Fixes #10103 --- packages/mongo/mongo_driver.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mongo/mongo_driver.js b/packages/mongo/mongo_driver.js index 4be68220e6..35709434b3 100644 --- a/packages/mongo/mongo_driver.js +++ b/packages/mongo/mongo_driver.js @@ -506,6 +506,8 @@ MongoConnection.prototype._update = function (collection_name, selector, mod, try { var collection = self.rawCollection(collection_name); var mongoOpts = {safe: true}; + // Add support for filtered positional operator + if (_.has(options, 'arrayFilters')) mongoOpts.arrayFilters = options.arrayFilters; // explictly enumerate options that minimongo supports if (options.upsert) mongoOpts.upsert = true; if (options.multi) mongoOpts.multi = true; From 8c73323c5d7bd1e8fbe2f0b6a91e1c12604163b1 Mon Sep 17 00:00:00 2001 From: Alexander Sterk Date: Sun, 8 Mar 2020 11:10:43 +0100 Subject: [PATCH 02/17] Replace underscore call. --- packages/mongo/mongo_driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mongo/mongo_driver.js b/packages/mongo/mongo_driver.js index 35709434b3..de1c1b999c 100644 --- a/packages/mongo/mongo_driver.js +++ b/packages/mongo/mongo_driver.js @@ -507,7 +507,7 @@ MongoConnection.prototype._update = function (collection_name, selector, mod, var collection = self.rawCollection(collection_name); var mongoOpts = {safe: true}; // Add support for filtered positional operator - if (_.has(options, 'arrayFilters')) mongoOpts.arrayFilters = options.arrayFilters; + if (options.hasOwnProperty('arrayFilters')) mongoOpts.arrayFilters = options.arrayFilters; // explictly enumerate options that minimongo supports if (options.upsert) mongoOpts.upsert = true; if (options.multi) mongoOpts.multi = true; From 20c0dd634f631a36fa7e25f4d468cd91ef143138 Mon Sep 17 00:00:00 2001 From: Alexander Sterk Date: Wed, 11 Mar 2020 18:26:59 +0100 Subject: [PATCH 03/17] Replace hasOwnProperty with undefined check, fixes test failures. --- packages/mongo/mongo_driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mongo/mongo_driver.js b/packages/mongo/mongo_driver.js index de1c1b999c..d1106fc7f6 100644 --- a/packages/mongo/mongo_driver.js +++ b/packages/mongo/mongo_driver.js @@ -507,7 +507,7 @@ MongoConnection.prototype._update = function (collection_name, selector, mod, var collection = self.rawCollection(collection_name); var mongoOpts = {safe: true}; // Add support for filtered positional operator - if (options.hasOwnProperty('arrayFilters')) mongoOpts.arrayFilters = options.arrayFilters; + if (options.arrayFilters !== undefined) mongoOpts.arrayFilters = options.arrayFilters; // explictly enumerate options that minimongo supports if (options.upsert) mongoOpts.upsert = true; if (options.multi) mongoOpts.multi = true; From 7bd76d2b3c1b6d309bd6cc5dafb1e80dae153e84 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Thu, 26 Mar 2020 17:18:12 -0400 Subject: [PATCH 04/17] Bump appcache package version to 1.2.6 Fixes #10986 --- packages/appcache/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/appcache/package.js b/packages/appcache/package.js index 5716bbc802..b3306afb0a 100644 --- a/packages/appcache/package.js +++ b/packages/appcache/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Enable the application cache in the browser", - version: "1.2.5", + version: "1.2.6", }); Package.onUse(api => { From 5e685e664424d34c63fa507478e62f8ddb71a3b5 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Mon, 30 Mar 2020 16:15:20 -0400 Subject: [PATCH 05/17] Bump mongo package version to 1.9.1 --- packages/mongo/package.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mongo/package.js b/packages/mongo/package.js index fd992c6fe8..c3abaf07b1 100644 --- a/packages/mongo/package.js +++ b/packages/mongo/package.js @@ -9,7 +9,7 @@ Package.describe({ summary: "Adaptor for using MongoDB and Minimongo over DDP", - version: '1.9.0' + version: '1.9.1' }); Npm.depends({ @@ -38,8 +38,8 @@ Package.onUse(function (api) { ]); // Make weak use of Decimal type on client - api.use('mongo-decimal', 'client', {weak: true}); - api.use('mongo-decimal', 'server'); + api.use('mongo-decimal@0.1.1', 'client', {weak: true}); + api.use('mongo-decimal@0.1.1', 'server'); api.use('underscore', 'server'); From a1b1846fc056747a05bdd1f4276c50bceb6fbf57 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 31 Mar 2020 10:56:30 -0400 Subject: [PATCH 06/17] Update dynamic-import test app Meteor and npm versions. --- .../apps/dynamic-import/.meteor/packages | 14 +- .../tests/apps/dynamic-import/.meteor/release | 2 +- .../apps/dynamic-import/.meteor/versions | 64 ++--- .../apps/dynamic-import/package-lock.json | 227 +++++++++--------- tools/tests/apps/dynamic-import/package.json | 14 +- tools/tests/apps/dynamic-import/tests.js | 6 +- 6 files changed, 158 insertions(+), 169 deletions(-) diff --git a/tools/tests/apps/dynamic-import/.meteor/packages b/tools/tests/apps/dynamic-import/.meteor/packages index 4271d796fc..b74a849e52 100644 --- a/tools/tests/apps/dynamic-import/.meteor/packages +++ b/tools/tests/apps/dynamic-import/.meteor/packages @@ -5,18 +5,17 @@ # but you can also edit it by hand. meteor-base@1.4.0 # Packages every Meteor app needs to have -mobile-experience@1.0.5 # Packages for a great mobile UX -mongo@1.6.2 # The database Meteor supports right now +mobile-experience@1.1.0 # Packages for a great mobile UX +mongo@1.9.0 # The database Meteor supports right now blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views reactive-var@1.0.11 # Reactive variable for tracker -jquery # Helpful client-side library tracker@1.2.0 # Meteor's client-side reactive programming library -standard-minifier-css@1.5.3 # CSS minifier run for production mode -standard-minifier-js@2.4.1 # JS minifier run for production mode +standard-minifier-css@1.6.0 # CSS minifier run for production mode +standard-minifier-js@2.6.0 # JS minifier run for production mode es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers. -ecmascript@0.12.4 # Enable ECMAScript2015+ syntax in app code -shell-server@0.4.0 # Server-side component of the `meteor shell` command +ecmascript@0.14.2 # Enable ECMAScript2015+ syntax in app code +shell-server@0.5.0 # Server-side component of the `meteor shell` command autopublish@1.0.7 # Publish all data to the clients (for prototyping) insecure@1.0.7 # Allow all DB writes from clients (for prototyping) @@ -26,3 +25,4 @@ helper-package user:colon-name underscore@1.0.10 fetch@0.1.1 +jquery diff --git a/tools/tests/apps/dynamic-import/.meteor/release b/tools/tests/apps/dynamic-import/.meteor/release index 97064e1993..d259781110 100644 --- a/tools/tests/apps/dynamic-import/.meteor/release +++ b/tools/tests/apps/dynamic-import/.meteor/release @@ -1 +1 @@ -METEOR@1.8.1 +METEOR@1.10.1 diff --git a/tools/tests/apps/dynamic-import/.meteor/versions b/tools/tests/apps/dynamic-import/.meteor/versions index 74049f3d5b..a99df3012b 100644 --- a/tools/tests/apps/dynamic-import/.meteor/versions +++ b/tools/tests/apps/dynamic-import/.meteor/versions @@ -1,32 +1,32 @@ allow-deny@1.1.0 autopublish@1.0.7 autoupdate@1.6.0 -babel-compiler@7.3.4 -babel-runtime@1.3.0 -base64@1.0.11 +babel-compiler@7.5.3 +babel-runtime@1.5.0 +base64@1.0.12 binary-heap@1.0.11 -blaze@2.3.3 +blaze@2.3.4 blaze-html-templates@1.1.2 blaze-tools@1.0.10 -boilerplate-generator@1.6.0 +boilerplate-generator@1.7.0 caching-compiler@1.2.1 caching-html-compiler@1.1.3 -callback-hook@1.1.0 +callback-hook@1.3.0 check@1.3.1 -coffeescript@2.3.2_1 -coffeescript-compiler@2.3.2_1 +coffeescript@2.4.1 +coffeescript-compiler@2.4.1 ddp@1.4.0 ddp-client@2.3.3 ddp-common@1.4.0 -ddp-server@2.3.0 +ddp-server@2.3.1 deps@1.0.12 diff-sequence@1.1.1 dynamic-import@0.5.1 -ecmascript@0.12.7 +ecmascript@0.14.3 ecmascript-runtime@0.7.0 -ecmascript-runtime-client@0.8.0 -ecmascript-runtime-server@0.7.1 -ejson@1.1.0 +ecmascript-runtime-client@0.10.0 +ecmascript-runtime-server@0.9.0 +ejson@1.1.1 es5-shim@4.8.0 fetch@0.1.1 geojson-utils@1.0.10 @@ -36,41 +36,41 @@ html-tools@1.0.11 htmljs@1.0.11 id-map@1.1.0 insecure@1.0.7 -inter-process-messaging@0.1.0 -jquery@1.11.11 -launch-screen@1.1.1 +inter-process-messaging@0.1.1 +jquery@3.0.0 +launch-screen@1.2.0 lazy-test-package@0.0.1 livedata@1.0.18 logging@1.1.20 meteor@1.9.3 meteor-base@1.4.0 -minifier-css@1.4.2 -minifier-js@2.4.1 -minimongo@1.4.5 -mobile-experience@1.0.5 -mobile-status-bar@1.0.14 -modern-browsers@0.1.4 -modules@0.13.0 -modules-runtime@0.10.3 -mongo@1.6.2 +minifier-css@1.5.0 +minifier-js@2.6.0 +minimongo@1.5.0 +mobile-experience@1.1.0 +mobile-status-bar@1.1.0 +modern-browsers@0.1.5 +modules@0.15.0 +modules-runtime@0.12.0 +mongo@1.9.1 mongo-decimal@0.1.1 mongo-dev-server@1.1.0 mongo-id@1.0.7 -npm-mongo@3.1.2 +npm-mongo@3.7.0 observe-sequence@1.0.16 ordered-dict@1.1.0 promise@0.11.2 -random@1.1.0 +random@1.2.0 reactive-var@1.0.11 reload@1.3.0 retry@1.1.0 routepolicy@1.1.0 -shell-server@0.4.0 -socket-stream-client@0.2.2 +shell-server@0.5.0 +socket-stream-client@0.2.3 spacebars@1.0.15 spacebars-compiler@1.1.3 -standard-minifier-css@1.5.3 -standard-minifier-js@2.4.1 +standard-minifier-css@1.6.0 +standard-minifier-js@2.6.0 templating@1.3.2 templating-compiler@1.3.3 templating-runtime@1.3.2 @@ -79,5 +79,5 @@ tracker@1.2.0 ui@1.0.13 underscore@1.0.10 user:colon-name@0.0.1 -webapp@1.7.4 +webapp@1.9.0 webapp-hashing@1.0.9 diff --git a/tools/tests/apps/dynamic-import/package-lock.json b/tools/tests/apps/dynamic-import/package-lock.json index 65896c125a..53af0c9685 100644 --- a/tools/tests/apps/dynamic-import/package-lock.json +++ b/tools/tests/apps/dynamic-import/package-lock.json @@ -4,39 +4,35 @@ "lockfileVersion": 1, "dependencies": { "@babel/runtime": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.0.tgz", - "integrity": "sha512-2xsuyZ0R0RBFwjgae5NpXk8FcfH4qovj5cEM5VEeB7KXnKqzaisIu2HSV/mCEISolJJuR4wkViUGYujA8MH9tw==", + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", "requires": { - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.4" } }, - "@types/node": { - "version": "12.0.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.12.tgz", - "integrity": "sha512-Uy0PN4R5vgBUXFoJrKryf5aTk3kJ8Rv3PdlHjl6UaX+Cqp1QE0yPQ68MPXGrZOfG7gZVNDIJZYyot0B9ubXUrQ==" + "@types/mime-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", + "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=" }, "@wry/context": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.4.4.tgz", - "integrity": "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.5.1.tgz", + "integrity": "sha512-VfPjm79RbzEYZigvZFk7DdvYX+8Qb57xOZw8m2iaAmgmBMNhGDN5yKGiplubX958oFAQMXfaftgTa/VFnu2CsQ==", "requires": { - "@types/node": ">=6", "tslib": "^1.9.3" } }, "acorn": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", - "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "requires": { - "es6-promisify": "^5.0.0" - } + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" }, "arson": { "version": "0.2.6", @@ -44,9 +40,9 @@ "integrity": "sha512-wVRnIfjOaCWu3jrf3j1CU/eotDf7tuM34cBswo32EwyLPaMiaWgETfROdYVv47VWEbWSOaZaDnkypGQtQduLbw==" }, "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "balanced-match": { "version": "1.0.0", @@ -62,6 +58,11 @@ "concat-map": "0.0.1" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -96,28 +97,15 @@ "ms": "^2.1.1" } }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, "extract-zip": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", - "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", "requires": { - "concat-stream": "1.6.2", - "debug": "2.6.9", - "mkdirp": "0.5.1", - "yauzl": "2.4.1" + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" }, "dependencies": { "debug": { @@ -136,9 +124,9 @@ } }, "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "requires": { "pend": "~1.2.0" } @@ -149,9 +137,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -162,22 +150,12 @@ } }, "https-proxy-agent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", "requires": { - "agent-base": "^4.1.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } + "agent-base": "5", + "debug": "4" } }, "inflight": { @@ -199,6 +177,11 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -778,6 +761,19 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -787,16 +783,16 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "moment": { @@ -823,11 +819,11 @@ } }, "optimism": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.10.2.tgz", - "integrity": "sha512-zPfBIxFFWMmQboM9+Z4MSJqc1PXp82v1PFq/GfQaufI69mHKlup7ykGNnfuGIGssXJQkmhSodQ/k9EWwjd8O8A==", + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.11.5.tgz", + "integrity": "sha512-twCHmBb64DYzEZ8A3O+TLCuF/RmZPBhXPQYv4agoiALRLlW9SidMzd7lwUP9mL0jOZhzhnBmb8ajqA00ECo/7g==", "requires": { - "@wry/context": "^0.4.0" + "@wry/context": "^0.5.0" } }, "path-is-absolute": { @@ -866,19 +862,21 @@ } }, "proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "puppeteer": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.18.1.tgz", - "integrity": "sha512-luUy0HPSuWPsPZ1wAp6NinE0zgetWtudf5zwZ6dHjMWfYpTQcmKveFRox7VBNhQ98OjNA9PQ9PzQyX8k/KrxTg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.1.tgz", + "integrity": "sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==", "requires": { + "@types/mime-types": "^2.1.0", "debug": "^4.1.0", "extract-zip": "^1.6.6", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^4.0.0", "mime": "^2.0.3", + "mime-types": "^2.1.25", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", "rimraf": "^2.6.1", @@ -886,25 +884,24 @@ } }, "react": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", - "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" + "prop-types": "^15.6.2" } }, "react-is": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", - "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -916,14 +913,14 @@ } }, "regenerator-runtime": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", - "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -933,15 +930,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -951,9 +939,9 @@ } }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" }, "typedarray": { "version": "0.0.6", @@ -966,9 +954,9 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz", + "integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw==" }, "wrappy": { "version": "1.0.2", @@ -984,11 +972,12 @@ } }, "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "requires": { - "fd-slicer": "~1.0.1" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } } } diff --git a/tools/tests/apps/dynamic-import/package.json b/tools/tests/apps/dynamic-import/package.json index cb99c14f0d..95244ef029 100644 --- a/tools/tests/apps/dynamic-import/package.json +++ b/tools/tests/apps/dynamic-import/package.json @@ -6,17 +6,17 @@ "test": "TEST_BROWSER_DRIVER=puppeteer meteor test --full-app --driver-package meteortesting:mocha" }, "dependencies": { - "@babel/runtime": "^7.5.0", - "acorn": "^6.2.0", + "@babel/runtime": "^7.9.2", + "acorn": "^7.1.1", "arson": "^0.2.6", "jquery": "^3.4.1", "meteor-node-stubs": "^1.0.0", "moment": "^2.24.0", - "optimism": "^0.10.2", + "optimism": "^0.11.5", "private": "^0.1.8", - "puppeteer": "^1.18.1", - "react": "^16.8.6", - "regenerator-runtime": "^0.13.2", - "uuid": "^3.3.2" + "puppeteer": "^2.1.1", + "react": "^16.13.1", + "regenerator-runtime": "^0.13.5", + "uuid": "^7.0.2" } } diff --git a/tools/tests/apps/dynamic-import/tests.js b/tools/tests/apps/dynamic-import/tests.js index 3b0451d665..3dd68d24ee 100644 --- a/tools/tests/apps/dynamic-import/tests.js +++ b/tools/tests/apps/dynamic-import/tests.js @@ -247,15 +247,15 @@ describe("dynamic import(...)", function () { }); it('should support object-valued package.json "browser" fields', () => { - return import("uuid").then(({ default: uuid }) => { + return import("uuid").then(({ v4: uuid }) => { const id = uuid(); assert.strictEqual(typeof id, "string"); assert.strictEqual(id.split("-").length, 5); if (Meteor.isClient) { assert.strictEqual( - require.resolve("uuid/lib/rng.js"), - "/node_modules/uuid/lib/rng-browser.js" + require.resolve("uuid/dist/esm-node/index.js"), + "/node_modules/uuid/dist/esm-browser/index.js" ); const uuidPkgJsonId = ["uuid", "package.json"].join("/"); const { browser } = require(uuidPkgJsonId); From f78afca82443a6ccda847933ba3299a6c677560b Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 31 Mar 2020 11:13:31 -0400 Subject: [PATCH 07/17] Update linked copy of acorn source used by modules test app. --- .../modules/imports/links/acorn/.npmignore | 3 + .../modules/imports/links/acorn/CHANGELOG.md | 580 +++++++++++++++++ .../modules/imports/links/acorn/README.md | 270 ++++++++ .../modules/imports/links/acorn/package.json | 42 +- .../modules/imports/links/acorn/src/.eslintrc | 7 +- .../imports/links/acorn/src/bin/acorn.js | 26 +- .../imports/links/acorn/src/expression.js | 284 +++++---- .../imports/links/acorn/src/identifier.js | 10 +- .../modules/imports/links/acorn/src/index.js | 84 ++- .../links/acorn/src/loose/expression.js | 582 ------------------ .../imports/links/acorn/src/loose/index.js | 47 -- .../links/acorn/src/loose/parseutil.js | 1 - .../imports/links/acorn/src/loose/state.js | 170 ----- .../links/acorn/src/loose/statement.js | 459 -------------- .../imports/links/acorn/src/loose/tokenize.js | 111 ---- .../modules/imports/links/acorn/src/lval.js | 27 +- .../imports/links/acorn/src/options.js | 19 +- .../imports/links/acorn/src/parseutil.js | 20 +- .../modules/imports/links/acorn/src/regexp.js | 26 +- .../modules/imports/links/acorn/src/scope.js | 119 ++-- .../imports/links/acorn/src/scopeflags.js | 24 + .../modules/imports/links/acorn/src/state.js | 78 +-- .../imports/links/acorn/src/statement.js | 301 +++++---- .../imports/links/acorn/src/tokencontext.js | 21 +- .../imports/links/acorn/src/tokenize.js | 51 +- .../imports/links/acorn/src/tokentype.js | 2 +- .../links/acorn/src/unicode-property-data.js | 506 ++------------- .../modules/imports/links/acorn/src/util.js | 4 + .../imports/links/acorn/src/walk/index.js | 370 ----------- .../imports/links/acorn/src/whitespace.js | 6 +- tools/tests/apps/modules/tests.js | 1 + 31 files changed, 1589 insertions(+), 2662 deletions(-) create mode 100644 tools/tests/apps/modules/imports/links/acorn/.npmignore create mode 100644 tools/tests/apps/modules/imports/links/acorn/CHANGELOG.md create mode 100644 tools/tests/apps/modules/imports/links/acorn/README.md delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/expression.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/index.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/parseutil.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/state.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/statement.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/loose/tokenize.js create mode 100644 tools/tests/apps/modules/imports/links/acorn/src/scopeflags.js delete mode 100644 tools/tests/apps/modules/imports/links/acorn/src/walk/index.js diff --git a/tools/tests/apps/modules/imports/links/acorn/.npmignore b/tools/tests/apps/modules/imports/links/acorn/.npmignore new file mode 100644 index 0000000000..0e574439e0 --- /dev/null +++ b/tools/tests/apps/modules/imports/links/acorn/.npmignore @@ -0,0 +1,3 @@ +.tern-* +/rollup.config.* +/src diff --git a/tools/tests/apps/modules/imports/links/acorn/CHANGELOG.md b/tools/tests/apps/modules/imports/links/acorn/CHANGELOG.md new file mode 100644 index 0000000000..93837a91a1 --- /dev/null +++ b/tools/tests/apps/modules/imports/links/acorn/CHANGELOG.md @@ -0,0 +1,580 @@ +## 6.4.1 (2020-03-09) + +### Bug fixes + +More carefully check for valid UTF16 surrogate pairs in regexp validator. + +## 7.1.1 (2020-03-01) + +### Bug fixes + +Treat `\8` and `\9` as invalid escapes in template strings. + +Allow unicode escapes in property names that are keywords. + +Don't error on an exponential operator expression as argument to `await`. + +More carefully check for valid UTF16 surrogate pairs in regexp validator. + +## 7.1.0 (2019-09-24) + +### Bug fixes + +Disallow trailing object literal commas when ecmaVersion is less than 5. + +### New features + +Add a static `acorn` property to the `Parser` class that contains the entire module interface, to allow plugins to access the instance of the library that they are acting on. + +## 7.0.0 (2019-08-13) + +### Breaking changes + +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). + +Makes 10 (ES2019) the default value for the `ecmaVersion` option. + +## 6.3.0 (2019-08-12) + +### New features + +`sourceType: "module"` can now be used even when `ecmaVersion` is less than 6, to parse module-style code that otherwise conforms to an older standard. + +## 6.2.1 (2019-07-21) + +### Bug fixes + +Fix bug causing Acorn to treat some characters as identifier characters that shouldn't be treated as such. + +Fix issue where setting the `allowReserved` option to `"never"` allowed reserved words in some circumstances. + +## 6.2.0 (2019-07-04) + +### Bug fixes + +Improve valid assignment checking in `for`/`in` and `for`/`of` loops. + +Disallow binding `let` in patterns. + +### New features + +Support bigint syntax with `ecmaVersion` >= 11. + +Support dynamic `import` syntax with `ecmaVersion` >= 11. + +Upgrade to Unicode version 12. + +## 6.1.1 (2019-02-27) + +### Bug fixes + +Fix bug that caused parsing default exports of with names to fail. + +## 6.1.0 (2019-02-08) + +### Bug fixes + +Fix scope checking when redefining a `var` as a lexical binding. + +### New features + +Split up `parseSubscripts` to use an internal `parseSubscript` method to make it easier to extend with plugins. + +## 6.0.7 (2019-02-04) + +### Bug fixes + +Check that exported bindings are defined. + +Don't treat `\u180e` as a whitespace character. + +Check for duplicate parameter names in methods. + +Don't allow shorthand properties when they are generators or async methods. + +Forbid binding `await` in async arrow function's parameter list. + +## 6.0.6 (2019-01-30) + +### Bug fixes + +The content of class declarations and expressions is now always parsed in strict mode. + +Don't allow `let` or `const` to bind the variable name `let`. + +Treat class declarations as lexical. + +Don't allow a generator function declaration as the sole body of an `if` or `else`. + +Ignore `"use strict"` when after an empty statement. + +Allow string line continuations with special line terminator characters. + +Treat `for` bodies as part of the `for` scope when checking for conflicting bindings. + +Fix bug with parsing `yield` in a `for` loop initializer. + +Implement special cases around scope checking for functions. + +## 6.0.5 (2019-01-02) + +### Bug fixes + +Fix TypeScript type for `Parser.extend` and add `allowAwaitOutsideFunction` to options type. + +Don't treat `let` as a keyword when the next token is `{` on the next line. + +Fix bug that broke checking for parentheses around an object pattern in a destructuring assignment when `preserveParens` was on. + +## 6.0.4 (2018-11-05) + +### Bug fixes + +Further improvements to tokenizing regular expressions in corner cases. + +## 6.0.3 (2018-11-04) + +### Bug fixes + +Fix bug in tokenizing an expression-less return followed by a function followed by a regular expression. + +Remove stray symlink in the package tarball. + +## 6.0.2 (2018-09-26) + +### Bug fixes + +Fix bug where default expressions could fail to parse inside an object destructuring assignment expression. + +## 6.0.1 (2018-09-14) + +### Bug fixes + +Fix wrong value in `version` export. + +## 6.0.0 (2018-09-14) + +### Bug fixes + +Better handle variable-redefinition checks for catch bindings and functions directly under if statements. + +Forbid `new.target` in top-level arrow functions. + +Fix issue with parsing a regexp after `yield` in some contexts. + +### New features + +The package now comes with TypeScript definitions. + +### Breaking changes + +The default value of the `ecmaVersion` option is now 9 (2018). + +Plugins work differently, and will have to be rewritten to work with this version. + +The loose parser and walker have been moved into separate packages (`acorn-loose` and `acorn-walk`). + +## 5.7.3 (2018-09-10) + +### Bug fixes + +Fix failure to tokenize regexps after expressions like `x.of`. + +Better error message for unterminated template literals. + +## 5.7.2 (2018-08-24) + +### Bug fixes + +Properly handle `allowAwaitOutsideFunction` in for statements. + +Treat function declarations at the top level of modules like let bindings. + +Don't allow async function declarations as the only statement under a label. + +## 5.7.0 (2018-06-15) + +### New features + +Upgraded to Unicode 11. + +## 5.6.0 (2018-05-31) + +### New features + +Allow U+2028 and U+2029 in string when ECMAVersion >= 10. + +Allow binding-less catch statements when ECMAVersion >= 10. + +Add `allowAwaitOutsideFunction` option for parsing top-level `await`. + +## 5.5.3 (2018-03-08) + +### Bug fixes + +A _second_ republish of the code in 5.5.1, this time with yarn, to hopefully get valid timestamps. + +## 5.5.2 (2018-03-08) + +### Bug fixes + +A republish of the code in 5.5.1 in an attempt to solve an issue with the file timestamps in the npm package being 0. + +## 5.5.1 (2018-03-06) + +### Bug fixes + +Fix misleading error message for octal escapes in template strings. + +## 5.5.0 (2018-02-27) + +### New features + +The identifier character categorization is now based on Unicode version 10. + +Acorn will now validate the content of regular expressions, including new ES9 features. + +## 5.4.0 (2018-02-01) + +### Bug fixes + +Disallow duplicate or escaped flags on regular expressions. + +Disallow octal escapes in strings in strict mode. + +### New features + +Add support for async iteration. + +Add support for object spread and rest. + +## 5.3.0 (2017-12-28) + +### Bug fixes + +Fix parsing of floating point literals with leading zeroes in loose mode. + +Allow duplicate property names in object patterns. + +Don't allow static class methods named `prototype`. + +Disallow async functions directly under `if` or `else`. + +Parse right-hand-side of `for`/`of` as an assignment expression. + +Stricter parsing of `for`/`in`. + +Don't allow unicode escapes in contextual keywords. + +### New features + +Parsing class members was factored into smaller methods to allow plugins to hook into it. + +## 5.2.1 (2017-10-30) + +### Bug fixes + +Fix a token context corruption bug. + +## 5.2.0 (2017-10-30) + +### Bug fixes + +Fix token context tracking for `class` and `function` in property-name position. + +Make sure `%*` isn't parsed as a valid operator. + +Allow shorthand properties `get` and `set` to be followed by default values. + +Disallow `super` when not in callee or object position. + +### New features + +Support [`directive` property](https://github.com/estree/estree/compare/b3de58c9997504d6fba04b72f76e6dd1619ee4eb...1da8e603237144f44710360f8feb7a9977e905e0) on directive expression statements. + +## 5.1.2 (2017-09-04) + +### Bug fixes + +Disable parsing of legacy HTML-style comments in modules. + +Fix parsing of async methods whose names are keywords. + +## 5.1.1 (2017-07-06) + +### Bug fixes + +Fix problem with disambiguating regexp and division after a class. + +## 5.1.0 (2017-07-05) + +### Bug fixes + +Fix tokenizing of regexps in an object-desctructuring `for`/`of` loop and after `yield`. + +Parse zero-prefixed numbers with non-octal digits as decimal. + +Allow object/array patterns in rest parameters. + +Don't error when `yield` is used as a property name. + +Allow `async` as a shorthand object property. + +### New features + +Implement the [template literal revision proposal](https://github.com/tc39/proposal-template-literal-revision) for ES9. + +## 5.0.3 (2017-04-01) + +### Bug fixes + +Fix spurious duplicate variable definition errors for named functions. + +## 5.0.2 (2017-03-30) + +### Bug fixes + +A binary operator after a parenthesized arrow expression is no longer incorrectly treated as an error. + +## 5.0.0 (2017-03-28) + +### Bug fixes + +Raise an error for duplicated lexical bindings. + +Fix spurious error when an assignement expression occurred after a spread expression. + +Accept regular expressions after `of` (in `for`/`of`), `yield` (in a generator), and braced arrow functions. + +Allow labels in front or `var` declarations, even in strict mode. + +### Breaking changes + +Parse declarations following `export default` as declaration nodes, not expressions. This means that class and function declarations nodes can now have `null` as their `id`. + +## 4.0.11 (2017-02-07) + +### Bug fixes + +Allow all forms of member expressions to be parenthesized as lvalue. + +## 4.0.10 (2017-02-07) + +### Bug fixes + +Don't expect semicolons after default-exported functions or classes, even when they are expressions. + +Check for use of `'use strict'` directives in non-simple parameter functions, even when already in strict mode. + +## 4.0.9 (2017-02-06) + +### Bug fixes + +Fix incorrect error raised for parenthesized simple assignment targets, so that `(x) = 1` parses again. + +## 4.0.8 (2017-02-03) + +### Bug fixes + +Solve spurious parenthesized pattern errors by temporarily erring on the side of accepting programs that our delayed errors don't handle correctly yet. + +## 4.0.7 (2017-02-02) + +### Bug fixes + +Accept invalidly rejected code like `(x).y = 2` again. + +Don't raise an error when a function _inside_ strict code has a non-simple parameter list. + +## 4.0.6 (2017-02-02) + +### Bug fixes + +Fix exponential behavior (manifesting itself as a complete hang for even relatively small source files) introduced by the new 'use strict' check. + +## 4.0.5 (2017-02-02) + +### Bug fixes + +Disallow parenthesized pattern expressions. + +Allow keywords as export names. + +Don't allow the `async` keyword to be parenthesized. + +Properly raise an error when a keyword contains a character escape. + +Allow `"use strict"` to appear after other string literal expressions. + +Disallow labeled declarations. + +## 4.0.4 (2016-12-19) + +### Bug fixes + +Fix crash when `export` was followed by a keyword that can't be +exported. + +## 4.0.3 (2016-08-16) + +### Bug fixes + +Allow regular function declarations inside single-statement `if` branches in loose mode. Forbid them entirely in strict mode. + +Properly parse properties named `async` in ES2017 mode. + +Fix bug where reserved words were broken in ES2017 mode. + +## 4.0.2 (2016-08-11) + +### Bug fixes + +Don't ignore period or 'e' characters after octal numbers. + +Fix broken parsing for call expressions in default parameter values of arrow functions. + +## 4.0.1 (2016-08-08) + +### Bug fixes + +Fix false positives in duplicated export name errors. + +## 4.0.0 (2016-08-07) + +### Breaking changes + +The default `ecmaVersion` option value is now 7. + +A number of internal method signatures changed, so plugins might need to be updated. + +### Bug fixes + +The parser now raises errors on duplicated export names. + +`arguments` and `eval` can now be used in shorthand properties. + +Duplicate parameter names in non-simple argument lists now always produce an error. + +### New features + +The `ecmaVersion` option now also accepts year-style version numbers +(2015, etc). + +Support for `async`/`await` syntax when `ecmaVersion` is >= 8. + +Support for trailing commas in call expressions when `ecmaVersion` is >= 8. + +## 3.3.0 (2016-07-25) + +### Bug fixes + +Fix bug in tokenizing of regexp operator after a function declaration. + +Fix parser crash when parsing an array pattern with a hole. + +### New features + +Implement check against complex argument lists in functions that enable strict mode in ES7. + +## 3.2.0 (2016-06-07) + +### Bug fixes + +Improve handling of lack of unicode regexp support in host +environment. + +Properly reject shorthand properties whose name is a keyword. + +### New features + +Visitors created with `visit.make` now have their base as _prototype_, rather than copying properties into a fresh object. + +## 3.1.0 (2016-04-18) + +### Bug fixes + +Properly tokenize the division operator directly after a function expression. + +Allow trailing comma in destructuring arrays. + +## 3.0.4 (2016-02-25) + +### Fixes + +Allow update expressions as left-hand-side of the ES7 exponential operator. + +## 3.0.2 (2016-02-10) + +### Fixes + +Fix bug that accidentally made `undefined` a reserved word when parsing ES7. + +## 3.0.0 (2016-02-10) + +### Breaking changes + +The default value of the `ecmaVersion` option is now 6 (used to be 5). + +Support for comprehension syntax (which was dropped from the draft spec) has been removed. + +### Fixes + +`let` and `yield` are now “contextual keywords”, meaning you can mostly use them as identifiers in ES5 non-strict code. + +A parenthesized class or function expression after `export default` is now parsed correctly. + +### New features + +When `ecmaVersion` is set to 7, Acorn will parse the exponentiation operator (`**`). + +The identifier character ranges are now based on Unicode 8.0.0. + +Plugins can now override the `raiseRecoverable` method to override the way non-critical errors are handled. + +## 2.7.0 (2016-01-04) + +### Fixes + +Stop allowing rest parameters in setters. + +Disallow `y` rexexp flag in ES5. + +Disallow `\00` and `\000` escapes in strict mode. + +Raise an error when an import name is a reserved word. + +## 2.6.2 (2015-11-10) + +### Fixes + +Don't crash when no options object is passed. + +## 2.6.0 (2015-11-09) + +### Fixes + +Add `await` as a reserved word in module sources. + +Disallow `yield` in a parameter default value for a generator. + +Forbid using a comma after a rest pattern in an array destructuring. + +### New features + +Support parsing stdin in command-line tool. + +## 2.5.0 (2015-10-27) + +### Fixes + +Fix tokenizer support in the command-line tool. + +Stop allowing `new.target` outside of functions. + +Remove legacy `guard` and `guardedHandler` properties from try nodes. + +Stop allowing multiple `__proto__` properties on an object literal in strict mode. + +Don't allow rest parameters to be non-identifier patterns. + +Check for duplicate paramter names in arrow functions. diff --git a/tools/tests/apps/modules/imports/links/acorn/README.md b/tools/tests/apps/modules/imports/links/acorn/README.md new file mode 100644 index 0000000000..585f2736fc --- /dev/null +++ b/tools/tests/apps/modules/imports/links/acorn/README.md @@ -0,0 +1,270 @@ +# Acorn + +A tiny, fast JavaScript parser written in JavaScript. + +## Community + +Acorn is open source software released under an +[MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE). + +You are welcome to +[report bugs](https://github.com/acornjs/acorn/issues) or create pull +requests on [github](https://github.com/acornjs/acorn). For questions +and discussion, please use the +[Tern discussion forum](https://discuss.ternjs.net). + +## Installation + +The easiest way to install acorn is from [`npm`](https://www.npmjs.com/): + +```sh +npm install acorn +``` + +Alternately, you can download the source and build acorn yourself: + +```sh +git clone https://github.com/acornjs/acorn.git +cd acorn +npm install +``` + +## Interface + +**parse**`(input, options)` is the main interface to the library. The +`input` parameter is a string, `options` can be undefined or an object +setting some of the options listed below. The return value will be an +abstract syntax tree object as specified by the [ESTree +spec](https://github.com/estree/estree). + +```javascript +let acorn = require("acorn"); +console.log(acorn.parse("1 + 1")); +``` + +When encountering a syntax error, the parser will raise a +`SyntaxError` object with a meaningful message. The error object will +have a `pos` property that indicates the string offset at which the +error occurred, and a `loc` object that contains a `{line, column}` +object referring to that same position. + +Options can be provided by passing a second argument, which should be +an object containing any of these fields: + +- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be + either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), 10 (2019) or 11 + (2020, partial support). This influences support for strict mode, + the set of reserved words, and support for new syntax features. + Default is 10. + + **NOTE**: Only 'stage 4' (finalized) ECMAScript features are being + implemented by Acorn. Other proposed new features can be implemented + through plugins. + +- **sourceType**: Indicate the mode the code should be parsed in. Can be + either `"script"` or `"module"`. This influences global strict mode + and parsing of `import` and `export` declarations. + + **NOTE**: If set to `"module"`, then static `import` / `export` syntax + will be valid, even if `ecmaVersion` is less than 6. + +- **onInsertedSemicolon**: If given a callback, that callback will be + called whenever a missing semicolon is inserted by the parser. The + callback will be given the character offset of the point where the + semicolon is inserted as argument, and if `locations` is on, also a + `{line, column}` object representing this position. + +- **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing + commas. + +- **allowReserved**: If `false`, using a reserved word will generate + an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher + versions. When given the value `"never"`, reserved words and + keywords can also not be used as property names (as in Internet + Explorer's old parser). + +- **allowReturnOutsideFunction**: By default, a return statement at + the top level raises an error. Set this to `true` to accept such + code. + +- **allowImportExportEverywhere**: By default, `import` and `export` + declarations can only appear at a program's top level. Setting this + option to `true` allows them anywhere where a statement is allowed. + +- **allowAwaitOutsideFunction**: By default, `await` expressions can + only appear inside `async` functions. Setting this option to + `true` allows to have top-level `await` expressions. They are + still not allowed in non-`async` functions, though. + +- **allowHashBang**: When this is enabled (off by default), if the + code starts with the characters `#!` (as in a shellscript), the + first line will be treated as a comment. + +- **locations**: When `true`, each node has a `loc` object attached + with `start` and `end` subobjects, each of which contains the + one-based line and zero-based column numbers in `{line, column}` + form. Default is `false`. + +- **onToken**: If a function is passed for this option, each found + token will be passed in same format as tokens returned from + `tokenizer().getToken()`. + + If array is passed, each found token is pushed to it. + + Note that you are not allowed to call the parser from the + callback—that will corrupt its internal state. + +- **onComment**: If a function is passed for this option, whenever a + comment is encountered the function will be called with the + following parameters: + + - `block`: `true` if the comment is a block comment, false if it + is a line comment. + - `text`: The content of the comment. + - `start`: Character offset of the start of the comment. + - `end`: Character offset of the end of the comment. + + When the `locations` options is on, the `{line, column}` locations + of the comment’s start and end are passed as two additional + parameters. + + If array is passed for this option, each found comment is pushed + to it as object in Esprima format: + + ```javascript + { + "type": "Line" | "Block", + "value": "comment text", + "start": Number, + "end": Number, + // If `locations` option is on: + "loc": { + "start": {line: Number, column: Number} + "end": {line: Number, column: Number} + }, + // If `ranges` option is on: + "range": [Number, Number] + } + ``` + + Note that you are not allowed to call the parser from the + callback—that will corrupt its internal state. + +- **ranges**: Nodes have their start and end characters offsets + recorded in `start` and `end` properties (directly on the node, + rather than the `loc` object, which holds line/column data. To also + add a + [semi-standardized](https://bugzilla.mozilla.org/show_bug.cgi?id=745678) + `range` property holding a `[start, end]` array with the same + numbers, set the `ranges` option to `true`. + +- **program**: It is possible to parse multiple files into a single + AST by passing the tree produced by parsing the first file as the + `program` option in subsequent parses. This will add the toplevel + forms of the parsed file to the "Program" (top) node of an existing + parse tree. + +- **sourceFile**: When the `locations` option is `true`, you can pass + this option to add a `source` attribute in every node’s `loc` + object. Note that the contents of this option are not examined or + processed in any way; you are free to use whatever format you + choose. + +- **directSourceFile**: Like `sourceFile`, but a `sourceFile` property + will be added (regardless of the `location` option) directly to the + nodes, rather than the `loc` object. + +- **preserveParens**: If this option is `true`, parenthesized expressions + are represented by (non-standard) `ParenthesizedExpression` nodes + that have a single `expression` property containing the expression + inside parentheses. + +**parseExpressionAt**`(input, offset, options)` will parse a single +expression in a string, and return its AST. It will not complain if +there is more of the string left after the expression. + +**tokenizer**`(input, options)` returns an object with a `getToken` +method that can be called repeatedly to get the next token, a `{start, +end, type, value}` object (with added `loc` property when the +`locations` option is enabled and `range` property when the `ranges` +option is enabled). When the token's type is `tokTypes.eof`, you +should stop calling the method, since it will keep returning that same +token forever. + +In ES6 environment, returned result can be used as any other +protocol-compliant iterable: + +```javascript +for (let token of acorn.tokenizer(str)) { + // iterate over the tokens +} + +// transform code to array of tokens: +var tokens = [...acorn.tokenizer(str)]; +``` + +**tokTypes** holds an object mapping names to the token type objects +that end up in the `type` properties of tokens. + +**getLineInfo**`(input, offset)` can be used to get a `{line, +column}` object for a given program string and offset. + +### The `Parser` class + +Instances of the **`Parser`** class contain all the state and logic +that drives a parse. It has static methods `parse`, +`parseExpressionAt`, and `tokenizer` that match the top-level +functions by the same name. + +When extending the parser with plugins, you need to call these methods +on the extended version of the class. To extend a parser with plugins, +you can use its static `extend` method. + +```javascript +var acorn = require("acorn"); +var jsx = require("acorn-jsx"); +var JSXParser = acorn.Parser.extend(jsx()); +JSXParser.parse("foo()"); +``` + +The `extend` method takes any number of plugin values, and returns a +new `Parser` class that includes the extra parser logic provided by +the plugins. + +## Command line interface + +The `bin/acorn` utility can be used to parse a file from the command +line. It accepts as arguments its input file and the following +options: + +- `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version + to parse. Default is version 9. + +- `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise. + +- `--locations`: Attaches a "loc" object to each node with "start" and + "end" subobjects, each of which contains the one-based line and + zero-based column numbers in `{line, column}` form. + +- `--allow-hash-bang`: If the code starts with the characters #! (as + in a shellscript), the first line will be treated as a comment. + +- `--compact`: No whitespace is used in the AST output. + +- `--silent`: Do not output the AST, just return the exit status. + +- `--help`: Print the usage information and quit. + +The utility spits out the syntax tree as JSON data. + +## Existing plugins + + - [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx) + +Plugins for ECMAScript proposals: + + - [`acorn-stage3`](https://github.com/acornjs/acorn-stage3): Parse most stage 3 proposals, bundling: + - [`acorn-class-fields`](https://github.com/acornjs/acorn-class-fields): Parse [class fields proposal](https://github.com/tc39/proposal-class-fields) + - [`acorn-import-meta`](https://github.com/acornjs/acorn-import-meta): Parse [import.meta proposal](https://github.com/tc39/proposal-import-meta) + - [`acorn-numeric-separator`](https://github.com/acornjs/acorn-numeric-separator): Parse [numeric separator proposal](https://github.com/tc39/proposal-numeric-separator) + - [`acorn-private-methods`](https://github.com/acornjs/acorn-private-methods): parse [private methods, getters and setters proposal](https://github.com/tc39/proposal-private-methods)n diff --git a/tools/tests/apps/modules/imports/links/acorn/package.json b/tools/tests/apps/modules/imports/links/acorn/package.json index 1b47c365cc..ad2b4564c2 100644 --- a/tools/tests/apps/modules/imports/links/acorn/package.json +++ b/tools/tests/apps/modules/imports/links/acorn/package.json @@ -2,50 +2,28 @@ "name": "acorn", "description": "ECMAScript parser", "homepage": "https://github.com/acornjs/acorn", - "main": "src/index.js", - "version": "5.5.3", - "engines": { - "node": ">=0.4.0" - }, + "module": "src/index.js", + "version": "7.1.1", + "engines": {"node": ">=0.4.0"}, "maintainers": [ { "name": "Marijn Haverbeke", "email": "marijnh@gmail.com", - "web": "http://marijnhaverbeke.nl" + "web": "https://marijnhaverbeke.nl" }, { "name": "Ingvar Stepanyan", "email": "me@rreverser.com", - "web": "http://rreverser.com/" + "web": "https://rreverser.com/" + }, + { + "name": "Adrian Heine", + "web": "http://adrianheine.de" } ], "repository": { "type": "git", "url": "https://github.com/acornjs/acorn.git" }, - "license": "MIT", - "scripts": { - "prepare": "npm test", - "test": "node test/run.js && node test/lint.js", - "pretest": "npm run build:main && npm run build:loose", - "test:test262": "node bin/run_test262.js", - "build": "npm run build:main && npm run build:walk && npm run build:loose && npm run build:bin", - "build:main": "rollup -c rollup/config.main.js", - "build:walk": "rollup -c rollup/config.walk.js", - "build:loose": "rollup -c rollup/config.loose.js && rollup -c rollup/config.loose_es.js", - "lint": "eslint src/" - }, - "devDependencies": { - "eslint": "^4.10.0", - "eslint-config-standard": "^10.2.1", - "eslint-plugin-import": "^2.2.0", - "eslint-plugin-node": "^5.2.1", - "eslint-plugin-promise": "^3.5.0", - "eslint-plugin-standard": "^3.0.1", - "rollup": "^0.45.0", - "rollup-plugin-buble": "^0.16.0", - "test262": "git+https://github.com/tc39/test262.git#18c1e799a01cc976695983b61e225ce7959bdd91", - "test262-parser-runner": "^0.3.1", - "unicode-10.0.0": "^0.7.5" - } + "license": "MIT" } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/.eslintrc b/tools/tests/apps/modules/imports/links/acorn/src/.eslintrc index e636ee75db..181c1b3692 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/.eslintrc +++ b/tools/tests/apps/modules/imports/links/acorn/src/.eslintrc @@ -7,8 +7,8 @@ ], "rules": { "curly": "off", - "eqeqeq": "off", - "indent": ["error", 2, { "SwitchCase": 0, "VariableDeclarator": 2, "CallExpression": { arguments: "off" } }], + "eqeqeq": ["error", "always", { "null": "ignore" }], + "indent": ["error", 2, { "SwitchCase": 0, "VariableDeclarator": 2, "CallExpression": { "arguments": "off" } }], "new-parens": "off", "no-case-declarations": "off", "no-cond-assign": "off", @@ -25,7 +25,8 @@ "space-before-function-paren": ["error", "never"] }, "globals": { - "Packages": false + "Packages": false, + "BigInt": false }, "plugins": [ "import" diff --git a/tools/tests/apps/modules/imports/links/acorn/src/bin/acorn.js b/tools/tests/apps/modules/imports/links/acorn/src/bin/acorn.js index d5fe42521a..9a6712c874 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/bin/acorn.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/bin/acorn.js @@ -6,7 +6,7 @@ let infile, forceFile, silent = false, compact = false, tokenize = false const options = {} function help(status) { - const print = (status == 0) ? console.log : console.error + const print = (status === 0) ? console.log : console.error print("usage: " + basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|...|--ecma2015|--ecma2016|--ecma2017|--ecma2018|...]") print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]") process.exit(status) @@ -14,15 +14,15 @@ function help(status) { for (let i = 2; i < process.argv.length; ++i) { const arg = process.argv[i] - if ((arg == "-" || arg[0] != "-") && !infile) infile = arg - else if (arg == "--" && !infile && i + 2 == process.argv.length) forceFile = infile = process.argv[++i] - else if (arg == "--locations") options.locations = true - else if (arg == "--allow-hash-bang") options.allowHashBang = true - else if (arg == "--silent") silent = true - else if (arg == "--compact") compact = true - else if (arg == "--help") help(0) - else if (arg == "--tokenize") tokenize = true - else if (arg == "--module") options.sourceType = "module" + if ((arg === "-" || arg[0] !== "-") && !infile) infile = arg + else if (arg === "--" && !infile && i + 2 === process.argv.length) forceFile = infile = process.argv[++i] + else if (arg === "--locations") options.locations = true + else if (arg === "--allow-hash-bang") options.allowHashBang = true + else if (arg === "--silent") silent = true + else if (arg === "--compact") compact = true + else if (arg === "--help") help(0) + else if (arg === "--tokenize") tokenize = true + else if (arg === "--module") options.sourceType = "module" else { let match = arg.match(/^--ecma(\d+)$/) if (match) @@ -43,16 +43,16 @@ function run(code) { do { token = tokenizer.getToken() result.push(token) - } while (token.type != acorn.tokTypes.eof) + } while (token.type !== acorn.tokTypes.eof) } } catch (e) { - console.error(e.message) + console.error(infile && infile !== "-" ? e.message.replace(/\(\d+:\d+\)$/, m => m.slice(0, 1) + infile + " " + m.slice(1)) : e.message) process.exit(1) } if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)) } -if (forceFile || infile && infile != "-") { +if (forceFile || infile && infile !== "-") { run(readFile(infile, "utf8")) } else { let code = "" diff --git a/tools/tests/apps/modules/imports/links/acorn/src/expression.js b/tools/tests/apps/modules/imports/links/acorn/src/expression.js index 79cd9b559f..a50ea7531e 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/expression.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/expression.js @@ -20,6 +20,7 @@ import {types as tt} from "./tokentype" import {Parser} from "./state" import {DestructuringErrors} from "./parseutil" import {lineBreak} from "./whitespace" +import {functionFlags, SCOPE_ARROW, SCOPE_SUPER, SCOPE_DIRECT_SUPER, BIND_OUTSIDE, BIND_VAR} from "./scopeflags" const pp = Parser.prototype @@ -43,9 +44,11 @@ pp.checkPropClash = function(prop, propHash, refDestructuringErrors) { if (this.options.ecmaVersion >= 6) { if (name === "__proto__" && kind === "init") { if (propHash.proto) { - if (refDestructuringErrors && refDestructuringErrors.doubleProto < 0) refDestructuringErrors.doubleProto = key.start - // Backwards-compat kludge. Can be removed in version 6.0 - else this.raiseRecoverable(key.start, "Redefinition of __proto__ property") + if (refDestructuringErrors) { + if (refDestructuringErrors.doubleProto < 0) + refDestructuringErrors.doubleProto = key.start + // Backwards-compat kludge. Can be removed in version 6.0 + } else this.raiseRecoverable(key.start, "Redefinition of __proto__ property") } propHash.proto = true } @@ -103,7 +106,12 @@ pp.parseExpression = function(noIn, refDestructuringErrors) { // operators like `+=`. pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { - if (this.inGenerator && this.isContextual("yield")) return this.parseYield() + if (this.isContextual("yield")) { + if (this.inGenerator) return this.parseYield(noIn) + // The tokenizer will assume an expression is allowed after + // `yield`, but this isn't that kind of yield + else this.exprAllowed = false + } let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1 if (refDestructuringErrors) { @@ -116,7 +124,7 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { } let startPos = this.start, startLoc = this.startLoc - if (this.type == tt.parenL || this.type == tt.name) + if (this.type === tt.parenL || this.type === tt.name) this.potentialArrowAt = this.start let left = this.parseMaybeConditional(noIn, refDestructuringErrors) if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc) @@ -124,8 +132,11 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { let node = this.startNodeAt(startPos, startLoc) node.operator = this.value node.left = this.type === tt.eq ? this.toAssignable(left, false, refDestructuringErrors) : left - if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors) - refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly + if (!ownDestructuringErrors) { + refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.doubleProto = -1 + } + if (refDestructuringErrors.shorthandAssign >= node.left.start) + refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly this.checkLVal(left) this.next() node.right = this.parseMaybeAssign(noIn) @@ -161,7 +172,7 @@ pp.parseExprOps = function(noIn, refDestructuringErrors) { let startPos = this.start, startLoc = this.startLoc let expr = this.parseMaybeUnary(refDestructuringErrors, false) if (this.checkExpressionErrors(refDestructuringErrors)) return expr - return expr.start == startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn) + return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn) } // Parse binary operators with the operator precedence parsing @@ -198,7 +209,7 @@ pp.buildBinary = function(startPos, startLoc, left, right, op, logical) { pp.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { let startPos = this.start, startLoc = this.startLoc, expr - if (this.inAsync && this.isContextual("await")) { + if (this.isContextual("await") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) { expr = this.parseAwait() sawUnary = true } else if (this.type.prefix) { @@ -239,8 +250,8 @@ pp.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { pp.parseExprSubscripts = function(refDestructuringErrors) { let startPos = this.start, startLoc = this.startLoc let expr = this.parseExprAtom(refDestructuringErrors) - let skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")" - if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr + if (expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")") + return expr let result = this.parseSubscripts(expr, startPos, startLoc) if (refDestructuringErrors && result.type === "MemberExpression") { if (refDestructuringErrors.parenthesizedAssign >= result.start) refDestructuringErrors.parenthesizedAssign = -1 @@ -251,64 +262,82 @@ pp.parseExprSubscripts = function(refDestructuringErrors) { pp.parseSubscripts = function(base, startPos, startLoc, noCalls) { let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" && - this.lastTokEnd == base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async" - for (let computed;;) { - if ((computed = this.eat(tt.bracketL)) || this.eat(tt.dot)) { - let node = this.startNodeAt(startPos, startLoc) - node.object = base - node.property = computed ? this.parseExpression() : this.parseIdent(true) - node.computed = !!computed - if (computed) this.expect(tt.bracketR) - base = this.finishNode(node, "MemberExpression") - } else if (!noCalls && this.eat(tt.parenL)) { - let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos - this.yieldPos = 0 - this.awaitPos = 0 - let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors) - if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { - this.checkPatternErrors(refDestructuringErrors, false) - this.checkYieldAwaitInDefaultParams() - this.yieldPos = oldYieldPos - this.awaitPos = oldAwaitPos - return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true) - } - this.checkExpressionErrors(refDestructuringErrors, true) - this.yieldPos = oldYieldPos || this.yieldPos - this.awaitPos = oldAwaitPos || this.awaitPos - let node = this.startNodeAt(startPos, startLoc) - node.callee = base - node.arguments = exprList - base = this.finishNode(node, "CallExpression") - } else if (this.type === tt.backQuote) { - let node = this.startNodeAt(startPos, startLoc) - node.tag = base - node.quasi = this.parseTemplate({isTagged: true}) - base = this.finishNode(node, "TaggedTemplateExpression") - } else { - return base - } + this.lastTokEnd === base.end && !this.canInsertSemicolon() && base.end - base.start === 5 && + this.potentialArrowAt === base.start + while (true) { + let element = this.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow) + if (element === base || element.type === "ArrowFunctionExpression") return element + base = element } } +pp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow) { + let computed = this.eat(tt.bracketL) + if (computed || this.eat(tt.dot)) { + let node = this.startNodeAt(startPos, startLoc) + node.object = base + node.property = computed ? this.parseExpression() : this.parseIdent(this.options.allowReserved !== "never") + node.computed = !!computed + if (computed) this.expect(tt.bracketR) + base = this.finishNode(node, "MemberExpression") + } else if (!noCalls && this.eat(tt.parenL)) { + let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos + this.yieldPos = 0 + this.awaitPos = 0 + this.awaitIdentPos = 0 + let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors) + if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { + this.checkPatternErrors(refDestructuringErrors, false) + this.checkYieldAwaitInDefaultParams() + if (this.awaitIdentPos > 0) + this.raise(this.awaitIdentPos, "Cannot use 'await' as identifier inside an async function") + this.yieldPos = oldYieldPos + this.awaitPos = oldAwaitPos + this.awaitIdentPos = oldAwaitIdentPos + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true) + } + this.checkExpressionErrors(refDestructuringErrors, true) + this.yieldPos = oldYieldPos || this.yieldPos + this.awaitPos = oldAwaitPos || this.awaitPos + this.awaitIdentPos = oldAwaitIdentPos || this.awaitIdentPos + let node = this.startNodeAt(startPos, startLoc) + node.callee = base + node.arguments = exprList + base = this.finishNode(node, "CallExpression") + } else if (this.type === tt.backQuote) { + let node = this.startNodeAt(startPos, startLoc) + node.tag = base + node.quasi = this.parseTemplate({isTagged: true}) + base = this.finishNode(node, "TaggedTemplateExpression") + } + return base +} + // Parse an atomic expression — either a single token that is an // expression, an expression started by a keyword like `function` or // `new`, or an expression wrapped in punctuation like `()`, `[]`, // or `{}`. pp.parseExprAtom = function(refDestructuringErrors) { - let node, canBeArrow = this.potentialArrowAt == this.start + // If a division operator appears in an expression position, the + // tokenizer got confused, and we force it to read a regexp instead. + if (this.type === tt.slash) this.readRegexp() + + let node, canBeArrow = this.potentialArrowAt === this.start switch (this.type) { case tt._super: - if (!this.inFunction) - this.raise(this.start, "'super' outside of function or class") + if (!this.allowSuper) + this.raise(this.start, "'super' keyword outside a method") node = this.startNode() this.next() + if (this.type === tt.parenL && !this.allowDirectSuper) + this.raise(node.start, "super() call outside constructor of a subclass") // The `super` keyword can appear at below: // SuperProperty: // super [ Expression ] // super . IdentifierName // SuperCall: - // super Arguments + // super ( Arguments ) if (this.type !== tt.dot && this.type !== tt.bracketL && this.type !== tt.parenL) this.unexpected() return this.finishNode(node, "Super") @@ -320,14 +349,14 @@ pp.parseExprAtom = function(refDestructuringErrors) { case tt.name: let startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc - let id = this.parseIdent(this.type !== tt.name) + let id = this.parseIdent(false) if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(tt._function)) - return this.parseFunction(this.startNodeAt(startPos, startLoc), false, false, true) + return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true) if (canBeArrow && !this.canInsertSemicolon()) { if (this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc) { - id = this.parseIdent() + id = this.parseIdent(false) if (this.canInsertSemicolon() || !this.eat(tt.arrow)) this.unexpected() return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true) @@ -373,7 +402,7 @@ pp.parseExprAtom = function(refDestructuringErrors) { case tt._function: node = this.startNode() this.next() - return this.parseFunction(node, false) + return this.parseFunction(node, 0) case tt._class: return this.parseClass(this.startNode(), false) @@ -384,15 +413,53 @@ pp.parseExprAtom = function(refDestructuringErrors) { case tt.backQuote: return this.parseTemplate() + case tt._import: + if (this.options.ecmaVersion >= 11) { + return this.parseExprImport() + } else { + return this.unexpected() + } + default: this.unexpected() } } +pp.parseExprImport = function() { + const node = this.startNode() + this.next() // skip `import` + switch (this.type) { + case tt.parenL: + return this.parseDynamicImport(node) + default: + this.unexpected() + } +} + +pp.parseDynamicImport = function(node) { + this.next() // skip `(` + + // Parse node.source. + node.source = this.parseMaybeAssign() + + // Verify ending. + if (!this.eat(tt.parenR)) { + const errorPos = this.start + if (this.eat(tt.comma) && this.eat(tt.parenR)) { + this.raiseRecoverable(errorPos, "Trailing comma is not allowed in import()") + } else { + this.unexpected(errorPos) + } + } + + return this.finishNode(node, "ImportExpression") +} + pp.parseLiteral = function(value) { let node = this.startNode() node.value = value node.raw = this.input.slice(this.start, this.end) + if (node.raw.charCodeAt(node.raw.length - 1) === 110) node.bigint = node.raw.slice(0, -1) this.next() return this.finishNode(node, "Literal") } @@ -414,6 +481,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow) { let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart this.yieldPos = 0 this.awaitPos = 0 + // Do not save awaitIdentPos to allow checking awaits nested in parameters while (this.type !== tt.parenR) { first ? first = false : this.expect(tt.comma) if (allowTrailingComma && this.afterTrailingComma(tt.parenR, true)) { @@ -482,6 +550,7 @@ pp.parseParenArrowList = function(startPos, startLoc, exprList) { const empty = [] pp.parseNew = function() { + if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword new") let node = this.startNode() let meta = this.parseIdent(true) if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { @@ -490,12 +559,15 @@ pp.parseNew = function() { node.property = this.parseIdent(true) if (node.property.name !== "target" || containsEsc) this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target") - if (!this.inFunction) + if (!this.inNonArrowFunction()) this.raiseRecoverable(node.start, "new.target can only be used in functions") return this.finishNode(node, "MetaProperty") } - let startPos = this.start, startLoc = this.startLoc + let startPos = this.start, startLoc = this.startLoc, isImport = this.type === tt._import node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true) + if (isImport && node.callee.type === "ImportExpression") { + this.raise(startPos, "Cannot use new with import()") + } if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false) else node.arguments = empty return this.finishNode(node, "NewExpression") @@ -531,6 +603,7 @@ pp.parseTemplate = function({isTagged = false} = {}) { let curElt = this.parseTemplateElement({isTagged}) node.quasis = [curElt] while (!curElt.tail) { + if (this.type === tt.eof) this.raise(this.pos, "Unterminated template literal") this.expect(tt.dollarBraceL) node.expressions.push(this.parseExpression()) this.expect(tt.braceR) @@ -555,7 +628,7 @@ pp.parseObj = function(isPattern, refDestructuringErrors) { while (!this.eat(tt.braceR)) { if (!first) { this.expect(tt.comma) - if (this.afterTrailingComma(tt.braceR)) break + if (this.options.ecmaVersion >= 5 && this.afterTrailingComma(tt.braceR)) break } else first = false const prop = this.parseProperty(isPattern, refDestructuringErrors) @@ -631,7 +704,7 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos } else if (!isPattern && !containsEsc && this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && - (this.type != tt.comma && this.type != tt.braceR)) { + (this.type !== tt.comma && this.type !== tt.braceR)) { if (isGenerator || isAsync) this.unexpected() prop.kind = prop.key.name this.parsePropertyName(prop) @@ -648,7 +721,10 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params") } } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { + if (isGenerator || isAsync) this.unexpected() this.checkUnreserved(prop.key) + if (prop.key.name === "await" && !this.awaitIdentPos) + this.awaitIdentPos = startPos prop.kind = "init" if (isPattern) { prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) @@ -674,26 +750,21 @@ pp.parsePropertyName = function(prop) { prop.computed = false } } - return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true) + return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(this.options.allowReserved !== "never") } // Initialize empty function node. pp.initFunction = function(node) { node.id = null - if (this.options.ecmaVersion >= 6) { - node.generator = false - node.expression = false - } - if (this.options.ecmaVersion >= 8) - node.async = false + if (this.options.ecmaVersion >= 6) node.generator = node.expression = false + if (this.options.ecmaVersion >= 8) node.async = false } // Parse object or class method. -pp.parseMethod = function(isGenerator, isAsync) { - let node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction +pp.parseMethod = function(isGenerator, isAsync, allowDirectSuper) { + let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos this.initFunction(node) if (this.options.ecmaVersion >= 6) @@ -701,57 +772,47 @@ pp.parseMethod = function(isGenerator, isAsync) { if (this.options.ecmaVersion >= 8) node.async = !!isAsync - this.inGenerator = node.generator - this.inAsync = node.async this.yieldPos = 0 this.awaitPos = 0 - this.inFunction = true - this.enterFunctionScope() + this.awaitIdentPos = 0 + this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0)) this.expect(tt.parenL) node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8) this.checkYieldAwaitInDefaultParams() - this.parseFunctionBody(node, false) + this.parseFunctionBody(node, false, true) - this.inGenerator = oldInGen - this.inAsync = oldInAsync this.yieldPos = oldYieldPos this.awaitPos = oldAwaitPos - this.inFunction = oldInFunc + this.awaitIdentPos = oldAwaitIdentPos return this.finishNode(node, "FunctionExpression") } // Parse arrow function expression with given parameters. pp.parseArrowExpression = function(node, params, isAsync) { - let oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction + let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos - this.enterFunctionScope() + this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW) this.initFunction(node) - if (this.options.ecmaVersion >= 8) - node.async = !!isAsync + if (this.options.ecmaVersion >= 8) node.async = !!isAsync - this.inGenerator = false - this.inAsync = node.async this.yieldPos = 0 this.awaitPos = 0 - this.inFunction = true + this.awaitIdentPos = 0 node.params = this.toAssignableList(params, true) - this.parseFunctionBody(node, true) + this.parseFunctionBody(node, true, false) - this.inGenerator = oldInGen - this.inAsync = oldInAsync this.yieldPos = oldYieldPos this.awaitPos = oldAwaitPos - this.inFunction = oldInFunc + this.awaitIdentPos = oldAwaitIdentPos return this.finishNode(node, "ArrowFunctionExpression") } // Parse function body and check parameters. -pp.parseFunctionBody = function(node, isArrowFunction) { +pp.parseFunctionBody = function(node, isArrowFunction, isMethod) { let isExpression = isArrowFunction && this.type !== tt.braceL let oldStrict = this.strict, useStrict = false @@ -777,19 +838,15 @@ pp.parseFunctionBody = function(node, isArrowFunction) { // Add the params to varDeclaredNames to ensure that an error is thrown // if a let/const declaration in the function clashes with one of the params. - this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && this.isSimpleParamList(node.params)) - node.body = this.parseBlock(false) + this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && !isMethod && this.isSimpleParamList(node.params)) + // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval' + if (this.strict && node.id) this.checkLVal(node.id, BIND_OUTSIDE) + node.body = this.parseBlock(false, undefined, useStrict && !oldStrict) node.expression = false this.adaptDirectivePrologue(node.body.body) this.labels = oldLabels } - this.exitFunctionScope() - - if (this.strict && node.id) { - // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval' - this.checkLVal(node.id, "none") - } - this.strict = oldStrict + this.exitScope() } pp.isSimpleParamList = function(params) { @@ -804,7 +861,7 @@ pp.isSimpleParamList = function(params) { pp.checkParams = function(node, allowDuplicates) { let nameHash = {} for (let param of node.params) - this.checkLVal(param, "var", allowDuplicates ? null : nameHash) + this.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash) } // Parses a comma-separated list of expressions, and returns them as @@ -838,17 +895,17 @@ pp.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructur pp.checkUnreserved = function({start, end, name}) { if (this.inGenerator && name === "yield") - this.raiseRecoverable(start, "Can not use 'yield' as identifier inside a generator") + this.raiseRecoverable(start, "Cannot use 'yield' as identifier inside a generator") if (this.inAsync && name === "await") - this.raiseRecoverable(start, "Can not use 'await' as identifier inside an async function") - if (this.isKeyword(name)) + this.raiseRecoverable(start, "Cannot use 'await' as identifier inside an async function") + if (this.keywords.test(name)) this.raise(start, `Unexpected keyword '${name}'`) if (this.options.ecmaVersion < 6 && - this.input.slice(start, end).indexOf("\\") != -1) return + this.input.slice(start, end).indexOf("\\") !== -1) return const re = this.strict ? this.reservedWordsStrict : this.reservedWords if (re.test(name)) { if (!this.inAsync && name === "await") - this.raiseRecoverable(start, "Can not use keyword 'await' outside an async function") + this.raiseRecoverable(start, "Cannot use keyword 'await' outside an async function") this.raiseRecoverable(start, `The keyword '${name}' is reserved`) } } @@ -859,7 +916,6 @@ pp.checkUnreserved = function({start, end, name}) { pp.parseIdent = function(liberal, isBinding) { let node = this.startNode() - if (liberal && this.options.allowReserved == "never") liberal = false if (this.type === tt.name) { node.name = this.value } else if (this.type.keyword) { @@ -876,25 +932,29 @@ pp.parseIdent = function(liberal, isBinding) { } else { this.unexpected() } - this.next() + this.next(!!liberal) this.finishNode(node, "Identifier") - if (!liberal) this.checkUnreserved(node) + if (!liberal) { + this.checkUnreserved(node) + if (node.name === "await" && !this.awaitIdentPos) + this.awaitIdentPos = node.start + } return node } // Parses yield expression inside generator. -pp.parseYield = function() { +pp.parseYield = function(noIn) { if (!this.yieldPos) this.yieldPos = this.start let node = this.startNode() this.next() - if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) { + if (this.type === tt.semi || this.canInsertSemicolon() || (this.type !== tt.star && !this.type.startsExpr)) { node.delegate = false node.argument = null } else { node.delegate = this.eat(tt.star) - node.argument = this.parseMaybeAssign() + node.argument = this.parseMaybeAssign(noIn) } return this.finishNode(node, "YieldExpression") } @@ -904,6 +964,6 @@ pp.parseAwait = function() { let node = this.startNode() this.next() - node.argument = this.parseMaybeUnary(null, true) + node.argument = this.parseMaybeUnary(null, false) return this.finishNode(node, "AwaitExpression") } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/identifier.js b/tools/tests/apps/modules/imports/links/acorn/src/identifier.js index 5b6553b604..0d7c3d1364 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/identifier.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/identifier.js @@ -14,6 +14,7 @@ const ecma5AndLessKeywords = "break case catch continue debugger default do else export const keywords = { 5: ecma5AndLessKeywords, + "5module": ecma5AndLessKeywords + " export import", 6: ecma5AndLessKeywords + " const class extends export import super" } @@ -26,9 +27,8 @@ export const keywordRelationalOperator = /^in(stanceof)?$/ // are only applied when a character is found to actually have a // code point above 128. // Generated by `bin/generate-identifier-regex.js`. - -let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\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\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312e\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fea\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\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-\uab65\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" -let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\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\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\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\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\u1cf2-\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\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" +let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08c7\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\u9ffc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7bf\ua7c2-\ua7ca\ua7f5-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" +let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d3-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf\u1ac0\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") @@ -42,10 +42,10 @@ nonASCIIidentifierStartChars = nonASCIIidentifierChars = null // generated by bin/generate-identifier-regex.js // eslint-disable-next-line comma-spacing -const astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,55,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,698,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,1,31,6124,20,754,9486,286,82,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,4149,196,60,67,1213,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,42710,42,4148,12,221,3,5761,15,7472,3104,541] +const astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,349,41,7,1,79,28,11,0,9,21,107,20,28,22,13,52,76,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,230,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,190,0,80,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,43,8,8952,286,50,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,2357,44,11,6,17,0,370,43,1301,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42717,35,4148,12,221,3,5761,15,7472,3104,541,1507,4938] // eslint-disable-next-line comma-spacing -const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,19719,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239] +const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,370,1,154,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1014,0,2,54,8,3,82,0,12,1,19628,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,419,13,1495,6,110,6,6,9,4759,9,787719,239] // This has a complexity linear to the value of the code. The // assumption is that looking up astral identifier characters is diff --git a/tools/tests/apps/modules/imports/links/acorn/src/index.js b/tools/tests/apps/modules/imports/links/acorn/src/index.js index aaf664da6b..f466a3b9fc 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/index.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/index.js @@ -12,11 +12,6 @@ // // [ghbt]: https://github.com/acornjs/acorn/issues // -// This file defines the main parser interface. The library also comes -// with a [error-tolerant parser][dammit] and an -// [abstract syntax tree walker][walk], defined in other files. -// -// [dammit]: acorn_loose.js // [walk]: util/walk.js import {Parser} from "./state" @@ -27,17 +22,58 @@ import "./expression" import "./location" import "./scope" -export {Parser, plugins} from "./state" -export {defaultOptions} from "./options" -export {Position, SourceLocation, getLineInfo} from "./locutil" -export {Node} from "./node" -export {TokenType, types as tokTypes, keywords as keywordTypes} from "./tokentype" -export {TokContext, types as tokContexts} from "./tokencontext" -export {isIdentifierChar, isIdentifierStart} from "./identifier" -export {Token} from "./tokenize" -export {isNewLine, lineBreak, lineBreakG, nonASCIIwhitespace} from "./whitespace" +import {defaultOptions} from "./options" +import {Position, SourceLocation, getLineInfo} from "./locutil" +import {Node} from "./node" +import {TokenType, types as tokTypes, keywords as keywordTypes} from "./tokentype" +import {TokContext, types as tokContexts} from "./tokencontext" +import {isIdentifierChar, isIdentifierStart} from "./identifier" +import {Token} from "./tokenize" +import {isNewLine, lineBreak, lineBreakG, nonASCIIwhitespace} from "./whitespace" -export const version = "5.5.3" +export const version = "7.1.0" +export { + Parser, + defaultOptions, + Position, + SourceLocation, + getLineInfo, + Node, + TokenType, + tokTypes, + keywordTypes, + TokContext, + tokContexts, + isIdentifierChar, + isIdentifierStart, + Token, + isNewLine, + lineBreak, + lineBreakG, + nonASCIIwhitespace +} + +Parser.acorn = { + Parser, + version, + defaultOptions, + Position, + SourceLocation, + getLineInfo, + Node, + TokenType, + tokTypes, + keywordTypes, + TokContext, + tokContexts, + isIdentifierChar, + isIdentifierStart, + Token, + isNewLine, + lineBreak, + lineBreakG, + nonASCIIwhitespace +} // The main exported interface (under `self.acorn` when in the // browser) is a `parse` function that takes a code string and @@ -47,7 +83,7 @@ export const version = "5.5.3" // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API export function parse(input, options) { - return new Parser(options, input).parse() + return Parser.parse(input, options) } // This function tries to parse a single expression at a given @@ -55,24 +91,12 @@ export function parse(input, options) { // that embed JavaScript expressions. export function parseExpressionAt(input, pos, options) { - let p = new Parser(options, input, pos) - p.nextToken() - return p.parseExpression() + return Parser.parseExpressionAt(input, pos, options) } // Acorn is organized as a tokenizer and a recursive-descent parser. // The `tokenizer` export provides an interface to the tokenizer. export function tokenizer(input, options) { - return new Parser(options, input) -} - -// This is a terrible kludge to support the existing, pre-ES6 -// interface where the loose parser module retroactively adds exports -// to this module. -export let parse_dammit, LooseParser, pluginsLoose // eslint-disable-line camelcase -export function addLooseExports(parse, Parser, plugins) { - parse_dammit = parse // eslint-disable-line camelcase - LooseParser = Parser - pluginsLoose = plugins + return Parser.tokenizer(input, options) } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/expression.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/expression.js deleted file mode 100644 index b6c5ddbcb2..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/expression.js +++ /dev/null @@ -1,582 +0,0 @@ -import {LooseParser} from "./state" -import {isDummy} from "./parseutil" -import {tokTypes as tt} from "../index" - -const lp = LooseParser.prototype - -lp.checkLVal = function(expr) { - if (!expr) return expr - switch (expr.type) { - case "Identifier": - case "MemberExpression": - return expr - - case "ParenthesizedExpression": - expr.expression = this.checkLVal(expr.expression) - return expr - - default: - return this.dummyIdent() - } -} - -lp.parseExpression = function(noIn) { - let start = this.storeCurrentPos() - let expr = this.parseMaybeAssign(noIn) - if (this.tok.type === tt.comma) { - let node = this.startNodeAt(start) - node.expressions = [expr] - while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn)) - return this.finishNode(node, "SequenceExpression") - } - return expr -} - -lp.parseParenExpression = function() { - this.pushCx() - this.expect(tt.parenL) - let val = this.parseExpression() - this.popCx() - this.expect(tt.parenR) - return val -} - -lp.parseMaybeAssign = function(noIn) { - if (this.toks.isContextual("yield")) { - let node = this.startNode() - this.next() - if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type != tt.star && !this.tok.type.startsExpr)) { - node.delegate = false - node.argument = null - } else { - node.delegate = this.eat(tt.star) - node.argument = this.parseMaybeAssign() - } - return this.finishNode(node, "YieldExpression") - } - - let start = this.storeCurrentPos() - let left = this.parseMaybeConditional(noIn) - if (this.tok.type.isAssign) { - let node = this.startNodeAt(start) - node.operator = this.tok.value - node.left = this.tok.type === tt.eq ? this.toAssignable(left) : this.checkLVal(left) - this.next() - node.right = this.parseMaybeAssign(noIn) - return this.finishNode(node, "AssignmentExpression") - } - return left -} - -lp.parseMaybeConditional = function(noIn) { - let start = this.storeCurrentPos() - let expr = this.parseExprOps(noIn) - if (this.eat(tt.question)) { - let node = this.startNodeAt(start) - node.test = expr - node.consequent = this.parseMaybeAssign() - node.alternate = this.expect(tt.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent() - return this.finishNode(node, "ConditionalExpression") - } - return expr -} - -lp.parseExprOps = function(noIn) { - let start = this.storeCurrentPos() - let indent = this.curIndent, line = this.curLineStart - return this.parseExprOp(this.parseMaybeUnary(false), start, -1, noIn, indent, line) -} - -lp.parseExprOp = function(left, start, minPrec, noIn, indent, line) { - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left - let prec = this.tok.type.binop - if (prec != null && (!noIn || this.tok.type !== tt._in)) { - if (prec > minPrec) { - let node = this.startNodeAt(start) - node.left = left - node.operator = this.tok.value - this.next() - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) { - node.right = this.dummyIdent() - } else { - let rightStart = this.storeCurrentPos() - node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line) - } - this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression") - return this.parseExprOp(node, start, minPrec, noIn, indent, line) - } - } - return left -} - -lp.parseMaybeUnary = function(sawUnary) { - let start = this.storeCurrentPos(), expr - if (this.options.ecmaVersion >= 8 && this.inAsync && this.toks.isContextual("await")) { - expr = this.parseAwait() - sawUnary = true - } else if (this.tok.type.prefix) { - let node = this.startNode(), update = this.tok.type === tt.incDec - if (!update) sawUnary = true - node.operator = this.tok.value - node.prefix = true - this.next() - node.argument = this.parseMaybeUnary(true) - if (update) node.argument = this.checkLVal(node.argument) - expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") - } else if (this.tok.type === tt.ellipsis) { - let node = this.startNode() - this.next() - node.argument = this.parseMaybeUnary(sawUnary) - expr = this.finishNode(node, "SpreadElement") - } else { - expr = this.parseExprSubscripts() - while (this.tok.type.postfix && !this.canInsertSemicolon()) { - let node = this.startNodeAt(start) - node.operator = this.tok.value - node.prefix = false - node.argument = this.checkLVal(expr) - this.next() - expr = this.finishNode(node, "UpdateExpression") - } - } - - if (!sawUnary && this.eat(tt.starstar)) { - let node = this.startNodeAt(start) - node.operator = "**" - node.left = expr - node.right = this.parseMaybeUnary(false) - return this.finishNode(node, "BinaryExpression") - } - - return expr -} - -lp.parseExprSubscripts = function() { - let start = this.storeCurrentPos() - return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart) -} - -lp.parseSubscripts = function(base, start, noCalls, startIndent, line) { - for (;;) { - if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) { - if (this.tok.type == tt.dot && this.curIndent == startIndent) - --startIndent - else - return base - } - - let maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this.canInsertSemicolon() - - if (this.eat(tt.dot)) { - let node = this.startNodeAt(start) - node.object = base - if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) - node.property = this.dummyIdent() - else - node.property = this.parsePropertyAccessor() || this.dummyIdent() - node.computed = false - base = this.finishNode(node, "MemberExpression") - } else if (this.tok.type == tt.bracketL) { - this.pushCx() - this.next() - let node = this.startNodeAt(start) - node.object = base - node.property = this.parseExpression() - node.computed = true - this.popCx() - this.expect(tt.bracketR) - base = this.finishNode(node, "MemberExpression") - } else if (!noCalls && this.tok.type == tt.parenL) { - let exprList = this.parseExprList(tt.parenR) - if (maybeAsyncArrow && this.eat(tt.arrow)) - return this.parseArrowExpression(this.startNodeAt(start), exprList, true) - let node = this.startNodeAt(start) - node.callee = base - node.arguments = exprList - base = this.finishNode(node, "CallExpression") - } else if (this.tok.type == tt.backQuote) { - let node = this.startNodeAt(start) - node.tag = base - node.quasi = this.parseTemplate() - base = this.finishNode(node, "TaggedTemplateExpression") - } else { - return base - } - } -} - -lp.parseExprAtom = function() { - let node - switch (this.tok.type) { - case tt._this: - case tt._super: - let type = this.tok.type === tt._this ? "ThisExpression" : "Super" - node = this.startNode() - this.next() - return this.finishNode(node, type) - - case tt.name: - let start = this.storeCurrentPos() - let id = this.parseIdent() - let isAsync = false - if (id.name === "async" && !this.canInsertSemicolon()) { - if (this.eat(tt._function)) - return this.parseFunction(this.startNodeAt(start), false, true) - if (this.tok.type === tt.name) { - id = this.parseIdent() - isAsync = true - } - } - return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id - - case tt.regexp: - node = this.startNode() - let val = this.tok.value - node.regex = {pattern: val.pattern, flags: val.flags} - node.value = val.value - node.raw = this.input.slice(this.tok.start, this.tok.end) - this.next() - return this.finishNode(node, "Literal") - - case tt.num: case tt.string: - node = this.startNode() - node.value = this.tok.value - node.raw = this.input.slice(this.tok.start, this.tok.end) - this.next() - return this.finishNode(node, "Literal") - - case tt._null: case tt._true: case tt._false: - node = this.startNode() - node.value = this.tok.type === tt._null ? null : this.tok.type === tt._true - node.raw = this.tok.type.keyword - this.next() - return this.finishNode(node, "Literal") - - case tt.parenL: - let parenStart = this.storeCurrentPos() - this.next() - let inner = this.parseExpression() - this.expect(tt.parenR) - if (this.eat(tt.arrow)) { - // (a,)=>a // SequenceExpression makes dummy in the last hole. Drop the dummy. - let params = inner.expressions || [inner] - if (params.length && isDummy(params[params.length - 1])) - params.pop() - return this.parseArrowExpression(this.startNodeAt(parenStart), params) - } - if (this.options.preserveParens) { - let par = this.startNodeAt(parenStart) - par.expression = inner - inner = this.finishNode(par, "ParenthesizedExpression") - } - return inner - - case tt.bracketL: - node = this.startNode() - node.elements = this.parseExprList(tt.bracketR, true) - return this.finishNode(node, "ArrayExpression") - - case tt.braceL: - return this.parseObj() - - case tt._class: - return this.parseClass(false) - - case tt._function: - node = this.startNode() - this.next() - return this.parseFunction(node, false) - - case tt._new: - return this.parseNew() - - case tt.backQuote: - return this.parseTemplate() - - default: - return this.dummyIdent() - } -} - -lp.parseNew = function() { - let node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart - let meta = this.parseIdent(true) - if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { - node.meta = meta - node.property = this.parseIdent(true) - return this.finishNode(node, "MetaProperty") - } - let start = this.storeCurrentPos() - node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line) - if (this.tok.type == tt.parenL) { - node.arguments = this.parseExprList(tt.parenR) - } else { - node.arguments = [] - } - return this.finishNode(node, "NewExpression") -} - -lp.parseTemplateElement = function() { - let elem = this.startNode() - - // The loose parser accepts invalid unicode escapes even in untagged templates. - if (this.tok.type === tt.invalidTemplate) { - elem.value = { - raw: this.tok.value, - cooked: null - } - } else { - elem.value = { - raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"), - cooked: this.tok.value - } - } - this.next() - elem.tail = this.tok.type === tt.backQuote - return this.finishNode(elem, "TemplateElement") -} - -lp.parseTemplate = function() { - let node = this.startNode() - this.next() - node.expressions = [] - let curElt = this.parseTemplateElement() - node.quasis = [curElt] - while (!curElt.tail) { - this.next() - node.expressions.push(this.parseExpression()) - if (this.expect(tt.braceR)) { - curElt = this.parseTemplateElement() - } else { - curElt = this.startNode() - curElt.value = {cooked: "", raw: ""} - curElt.tail = true - this.finishNode(curElt, "TemplateElement") - } - node.quasis.push(curElt) - } - this.expect(tt.backQuote) - return this.finishNode(node, "TemplateLiteral") -} - -lp.parseObj = function() { - let node = this.startNode() - node.properties = [] - this.pushCx() - let indent = this.curIndent + 1, line = this.curLineStart - this.eat(tt.braceL) - if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } - while (!this.closes(tt.braceR, indent, line)) { - let prop = this.startNode(), isGenerator, isAsync, start - if (this.options.ecmaVersion >= 9 && this.eat(tt.ellipsis)) { - prop.argument = this.parseMaybeAssign() - node.properties.push(this.finishNode(prop, "SpreadElement")) - this.eat(tt.comma) - continue - } - if (this.options.ecmaVersion >= 6) { - start = this.storeCurrentPos() - prop.method = false - prop.shorthand = false - isGenerator = this.eat(tt.star) - } - this.parsePropertyName(prop) - if (this.toks.isAsyncProp(prop)) { - isAsync = true - isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star) - this.parsePropertyName(prop) - } else { - isAsync = false - } - if (isDummy(prop.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue } - if (this.eat(tt.colon)) { - prop.kind = "init" - prop.value = this.parseMaybeAssign() - } else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) { - prop.kind = "init" - prop.method = true - prop.value = this.parseMethod(isGenerator, isAsync) - } else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && - !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && - (this.tok.type != tt.comma && this.tok.type != tt.braceR && this.tok.type != tt.eq)) { - prop.kind = prop.key.name - this.parsePropertyName(prop) - prop.value = this.parseMethod(false) - } else { - prop.kind = "init" - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.eq)) { - let assign = this.startNodeAt(start) - assign.operator = "=" - assign.left = prop.key - assign.right = this.parseMaybeAssign() - prop.value = this.finishNode(assign, "AssignmentExpression") - } else { - prop.value = prop.key - } - } else { - prop.value = this.dummyIdent() - } - prop.shorthand = true - } - node.properties.push(this.finishNode(prop, "Property")) - this.eat(tt.comma) - } - this.popCx() - if (!this.eat(tt.braceR)) { - // If there is no closing brace, make the node span to the start - // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start - } - return this.finishNode(node, "ObjectExpression") -} - -lp.parsePropertyName = function(prop) { - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.bracketL)) { - prop.computed = true - prop.key = this.parseExpression() - this.expect(tt.bracketR) - return - } else { - prop.computed = false - } - } - let key = (this.tok.type === tt.num || this.tok.type === tt.string) ? this.parseExprAtom() : this.parseIdent() - prop.key = key || this.dummyIdent() -} - -lp.parsePropertyAccessor = function() { - if (this.tok.type === tt.name || this.tok.type.keyword) return this.parseIdent() -} - -lp.parseIdent = function() { - let name = this.tok.type === tt.name ? this.tok.value : this.tok.type.keyword - if (!name) return this.dummyIdent() - let node = this.startNode() - this.next() - node.name = name - return this.finishNode(node, "Identifier") -} - -lp.initFunction = function(node) { - node.id = null - node.params = [] - if (this.options.ecmaVersion >= 6) { - node.generator = false - node.expression = false - } - if (this.options.ecmaVersion >= 8) - node.async = false -} - -// Convert existing expression atom to assignable pattern -// if possible. - -lp.toAssignable = function(node, binding) { - if (!node || node.type == "Identifier" || (node.type == "MemberExpression" && !binding)) { - // Okay - } else if (node.type == "ParenthesizedExpression") { - this.toAssignable(node.expression, binding) - } else if (this.options.ecmaVersion < 6) { - return this.dummyIdent() - } else if (node.type == "ObjectExpression") { - node.type = "ObjectPattern" - for (let prop of node.properties) - this.toAssignable(prop, binding) - } else if (node.type == "ArrayExpression") { - node.type = "ArrayPattern" - this.toAssignableList(node.elements, binding) - } else if (node.type == "Property") { - this.toAssignable(node.value, binding) - } else if (node.type == "SpreadElement") { - node.type = "RestElement" - this.toAssignable(node.argument, binding) - } else if (node.type == "AssignmentExpression") { - node.type = "AssignmentPattern" - delete node.operator - } else { - return this.dummyIdent() - } - return node -} - -lp.toAssignableList = function(exprList, binding) { - for (let expr of exprList) - this.toAssignable(expr, binding) - return exprList -} - -lp.parseFunctionParams = function(params) { - params = this.parseExprList(tt.parenR) - return this.toAssignableList(params, true) -} - -lp.parseMethod = function(isGenerator, isAsync) { - let node = this.startNode(), oldInAsync = this.inAsync - this.initFunction(node) - if (this.options.ecmaVersion >= 6) - node.generator = !!isGenerator - if (this.options.ecmaVersion >= 8) - node.async = !!isAsync - this.inAsync = node.async - node.params = this.parseFunctionParams() - node.body = this.parseBlock() - this.toks.adaptDirectivePrologue(node.body.body) - this.inAsync = oldInAsync - return this.finishNode(node, "FunctionExpression") -} - -lp.parseArrowExpression = function(node, params, isAsync) { - let oldInAsync = this.inAsync - this.initFunction(node) - if (this.options.ecmaVersion >= 8) - node.async = !!isAsync - this.inAsync = node.async - node.params = this.toAssignableList(params, true) - node.expression = this.tok.type !== tt.braceL - if (node.expression) { - node.body = this.parseMaybeAssign() - } else { - node.body = this.parseBlock() - this.toks.adaptDirectivePrologue(node.body.body) - } - this.inAsync = oldInAsync - return this.finishNode(node, "ArrowFunctionExpression") -} - -lp.parseExprList = function(close, allowEmpty) { - this.pushCx() - let indent = this.curIndent, line = this.curLineStart, elts = [] - this.next() // Opening bracket - while (!this.closes(close, indent + 1, line)) { - if (this.eat(tt.comma)) { - elts.push(allowEmpty ? null : this.dummyIdent()) - continue - } - let elt = this.parseMaybeAssign() - if (isDummy(elt)) { - if (this.closes(close, indent, line)) break - this.next() - } else { - elts.push(elt) - } - this.eat(tt.comma) - } - this.popCx() - if (!this.eat(close)) { - // If there is no closing brace, make the node span to the start - // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start - } - return elts -} - -lp.parseAwait = function() { - let node = this.startNode() - this.next() - node.argument = this.parseMaybeUnary() - return this.finishNode(node, "AwaitExpression") -} diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/index.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/index.js deleted file mode 100644 index a698061a8b..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/index.js +++ /dev/null @@ -1,47 +0,0 @@ -// Acorn: Loose parser -// -// This module provides an alternative parser (`parse_dammit`) that -// exposes that same interface as `parse`, but will try to parse -// anything as JavaScript, repairing syntax error the best it can. -// There are circumstances in which it will raise an error and give -// up, but they are very rare. The resulting AST will be a mostly -// valid JavaScript AST (as per the [Mozilla parser API][api], except -// that: -// -// - Return outside functions is allowed -// -// - Label consistency (no conflicts, break only to existing labels) -// is not enforced. -// -// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever -// the parser got too confused to return anything meaningful. -// -// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API -// -// The expected use for this is to *first* try `acorn.parse`, and only -// if that fails switch to `parse_dammit`. The loose parser might -// parse badly indented code incorrectly, so **don't** use it as -// your default parser. -// -// Quite a lot of acorn.js is duplicated here. The alternative was to -// add a *lot* of extra cruft to that file, making it less readable -// and slower. Copying and editing the code allowed me to make -// invasive changes and simplifications without creating a complicated -// tangle. - -import {addLooseExports, defaultOptions} from "../index" -import {LooseParser, pluginsLoose} from "./state" -import "./tokenize" -import "./statement" -import "./expression" - -export {LooseParser, pluginsLoose} from "./state" - -defaultOptions.tabSize = 4 - -// eslint-disable-next-line camelcase -export function parse_dammit(input, options) { - return new LooseParser(input, options).parse() -} - -addLooseExports(parse_dammit, LooseParser, pluginsLoose) diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/parseutil.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/parseutil.js deleted file mode 100644 index b620fdaf0a..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/parseutil.js +++ /dev/null @@ -1 +0,0 @@ -export function isDummy(node) { return node.name == "✖" } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/state.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/state.js deleted file mode 100644 index da068edb51..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/state.js +++ /dev/null @@ -1,170 +0,0 @@ -import {tokenizer, SourceLocation, tokTypes as tt, Node, lineBreak, isNewLine} from "../index" - -function noop() {} - -// Registered plugins -export const pluginsLoose = {} - -export class LooseParser { - constructor(input, options = {}) { - this.toks = tokenizer(input, options) - this.options = this.toks.options - this.input = this.toks.input - this.tok = this.last = {type: tt.eof, start: 0, end: 0} - this.tok.validateRegExpFlags = noop - this.tok.validateRegExpPattern = noop - if (this.options.locations) { - let here = this.toks.curPosition() - this.tok.loc = new SourceLocation(this.toks, here, here) - } - this.ahead = [] // Tokens ahead - this.context = [] // Indentation contexted - this.curIndent = 0 - this.curLineStart = 0 - this.nextLineStart = this.lineEnd(this.curLineStart) + 1 - this.inAsync = false - // Load plugins - this.options.pluginsLoose = options.pluginsLoose || {} - this.loadPlugins(this.options.pluginsLoose) - } - - startNode() { - return new Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) - } - - storeCurrentPos() { - return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start - } - - startNodeAt(pos) { - if (this.options.locations) { - return new Node(this.toks, pos[0], pos[1]) - } else { - return new Node(this.toks, pos) - } - } - - finishNode(node, type) { - node.type = type - node.end = this.last.end - if (this.options.locations) - node.loc.end = this.last.loc.end - if (this.options.ranges) - node.range[1] = this.last.end - return node - } - - dummyNode(type) { - let dummy = this.startNode() - dummy.type = type - dummy.end = dummy.start - if (this.options.locations) - dummy.loc.end = dummy.loc.start - if (this.options.ranges) - dummy.range[1] = dummy.start - this.last = {type: tt.name, start: dummy.start, end: dummy.start, loc: dummy.loc} - return dummy - } - - dummyIdent() { - let dummy = this.dummyNode("Identifier") - dummy.name = "✖" - return dummy - } - - dummyString() { - let dummy = this.dummyNode("Literal") - dummy.value = dummy.raw = "✖" - return dummy - } - - eat(type) { - if (this.tok.type === type) { - this.next() - return true - } else { - return false - } - } - - isContextual(name) { - return this.tok.type === tt.name && this.tok.value === name - } - - eatContextual(name) { - return this.tok.value === name && this.eat(tt.name) - } - - canInsertSemicolon() { - return this.tok.type === tt.eof || this.tok.type === tt.braceR || - lineBreak.test(this.input.slice(this.last.end, this.tok.start)) - } - - semicolon() { - return this.eat(tt.semi) - } - - expect(type) { - if (this.eat(type)) return true - for (let i = 1; i <= 2; i++) { - if (this.lookAhead(i).type == type) { - for (let j = 0; j < i; j++) this.next() - return true - } - } - } - - pushCx() { - this.context.push(this.curIndent) - } - - popCx() { - this.curIndent = this.context.pop() - } - - lineEnd(pos) { - while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos - return pos - } - - indentationAfter(pos) { - for (let count = 0;; ++pos) { - let ch = this.input.charCodeAt(pos) - if (ch === 32) ++count - else if (ch === 9) count += this.options.tabSize - else return count - } - } - - closes(closeTok, indent, line, blockHeuristic) { - if (this.tok.type === closeTok || this.tok.type === tt.eof) return true - return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && - (!blockHeuristic || this.nextLineStart >= this.input.length || - this.indentationAfter(this.nextLineStart) < indent) - } - - tokenStartsLine() { - for (let p = this.tok.start - 1; p >= this.curLineStart; --p) { - let ch = this.input.charCodeAt(p) - if (ch !== 9 && ch !== 32) return false - } - return true - } - - extend(name, f) { - this[name] = f(this[name]) - } - - loadPlugins(pluginConfigs) { - for (let name in pluginConfigs) { - let plugin = pluginsLoose[name] - if (!plugin) throw new Error("Plugin '" + name + "' not found") - plugin(this, pluginConfigs[name]) - } - } - - parse() { - this.next() - return this.parseTopLevel() - } -} diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/statement.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/statement.js deleted file mode 100644 index aa30696c41..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/statement.js +++ /dev/null @@ -1,459 +0,0 @@ -import {LooseParser} from "./state" -import {isDummy} from "./parseutil" -import {getLineInfo, tokTypes as tt} from "../index" - -const lp = LooseParser.prototype - -lp.parseTopLevel = function() { - let node = this.startNodeAt(this.options.locations ? [0, getLineInfo(this.input, 0)] : 0) - node.body = [] - while (this.tok.type !== tt.eof) node.body.push(this.parseStatement()) - this.toks.adaptDirectivePrologue(node.body) - this.last = this.tok - if (this.options.ecmaVersion >= 6) { - node.sourceType = this.options.sourceType - } - return this.finishNode(node, "Program") -} - -lp.parseStatement = function() { - let starttype = this.tok.type, node = this.startNode(), kind - - if (this.toks.isLet()) { - starttype = tt._var - kind = "let" - } - - switch (starttype) { - case tt._break: case tt._continue: - this.next() - let isBreak = starttype === tt._break - if (this.semicolon() || this.canInsertSemicolon()) { - node.label = null - } else { - node.label = this.tok.type === tt.name ? this.parseIdent() : null - this.semicolon() - } - return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") - - case tt._debugger: - this.next() - this.semicolon() - return this.finishNode(node, "DebuggerStatement") - - case tt._do: - this.next() - node.body = this.parseStatement() - node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent() - this.semicolon() - return this.finishNode(node, "DoWhileStatement") - - case tt._for: - this.next() // `for` keyword - let isAwait = this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await") - - this.pushCx() - this.expect(tt.parenL) - if (this.tok.type === tt.semi) return this.parseFor(node, null) - let isLet = this.toks.isLet() - if (isLet || this.tok.type === tt._var || this.tok.type === tt._const) { - let init = this.parseVar(true, isLet ? "let" : this.tok.value) - if (init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) { - if (this.options.ecmaVersion >= 9 && this.tok.type !== tt._in) { - node.await = isAwait - } - return this.parseForIn(node, init) - } - return this.parseFor(node, init) - } - let init = this.parseExpression(true) - if (this.tok.type === tt._in || this.isContextual("of")) { - if (this.options.ecmaVersion >= 9 && this.tok.type !== tt._in) { - node.await = isAwait - } - return this.parseForIn(node, this.toAssignable(init)) - } - return this.parseFor(node, init) - - case tt._function: - this.next() - return this.parseFunction(node, true) - - case tt._if: - this.next() - node.test = this.parseParenExpression() - node.consequent = this.parseStatement() - node.alternate = this.eat(tt._else) ? this.parseStatement() : null - return this.finishNode(node, "IfStatement") - - case tt._return: - this.next() - if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null - else { node.argument = this.parseExpression(); this.semicolon() } - return this.finishNode(node, "ReturnStatement") - - case tt._switch: - let blockIndent = this.curIndent, line = this.curLineStart - this.next() - node.discriminant = this.parseParenExpression() - node.cases = [] - this.pushCx() - this.expect(tt.braceL) - - let cur - while (!this.closes(tt.braceR, blockIndent, line, true)) { - if (this.tok.type === tt._case || this.tok.type === tt._default) { - let isCase = this.tok.type === tt._case - if (cur) this.finishNode(cur, "SwitchCase") - node.cases.push(cur = this.startNode()) - cur.consequent = [] - this.next() - if (isCase) cur.test = this.parseExpression() - else cur.test = null - this.expect(tt.colon) - } else { - if (!cur) { - node.cases.push(cur = this.startNode()) - cur.consequent = [] - cur.test = null - } - cur.consequent.push(this.parseStatement()) - } - } - if (cur) this.finishNode(cur, "SwitchCase") - this.popCx() - this.eat(tt.braceR) - return this.finishNode(node, "SwitchStatement") - - case tt._throw: - this.next() - node.argument = this.parseExpression() - this.semicolon() - return this.finishNode(node, "ThrowStatement") - - case tt._try: - this.next() - node.block = this.parseBlock() - node.handler = null - if (this.tok.type === tt._catch) { - let clause = this.startNode() - this.next() - this.expect(tt.parenL) - clause.param = this.toAssignable(this.parseExprAtom(), true) - this.expect(tt.parenR) - clause.body = this.parseBlock() - node.handler = this.finishNode(clause, "CatchClause") - } - node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null - if (!node.handler && !node.finalizer) return node.block - return this.finishNode(node, "TryStatement") - - case tt._var: - case tt._const: - return this.parseVar(false, kind || this.tok.value) - - case tt._while: - this.next() - node.test = this.parseParenExpression() - node.body = this.parseStatement() - return this.finishNode(node, "WhileStatement") - - case tt._with: - this.next() - node.object = this.parseParenExpression() - node.body = this.parseStatement() - return this.finishNode(node, "WithStatement") - - case tt.braceL: - return this.parseBlock() - - case tt.semi: - this.next() - return this.finishNode(node, "EmptyStatement") - - case tt._class: - return this.parseClass(true) - - case tt._import: - return this.parseImport() - - case tt._export: - return this.parseExport() - - default: - if (this.toks.isAsyncFunction()) { - this.next() - this.next() - return this.parseFunction(node, true, true) - } - let expr = this.parseExpression() - if (isDummy(expr)) { - this.next() - if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement") - return this.parseStatement() - } else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) { - node.body = this.parseStatement() - node.label = expr - return this.finishNode(node, "LabeledStatement") - } else { - node.expression = expr - this.semicolon() - return this.finishNode(node, "ExpressionStatement") - } - } -} - -lp.parseBlock = function() { - let node = this.startNode() - this.pushCx() - this.expect(tt.braceL) - let blockIndent = this.curIndent, line = this.curLineStart - node.body = [] - while (!this.closes(tt.braceR, blockIndent, line, true)) - node.body.push(this.parseStatement()) - this.popCx() - this.eat(tt.braceR) - return this.finishNode(node, "BlockStatement") -} - -lp.parseFor = function(node, init) { - node.init = init - node.test = node.update = null - if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression() - if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression() - this.popCx() - this.expect(tt.parenR) - node.body = this.parseStatement() - return this.finishNode(node, "ForStatement") -} - -lp.parseForIn = function(node, init) { - let type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement" - this.next() - node.left = init - node.right = this.parseExpression() - this.popCx() - this.expect(tt.parenR) - node.body = this.parseStatement() - return this.finishNode(node, type) -} - -lp.parseVar = function(noIn, kind) { - let node = this.startNode() - node.kind = kind - this.next() - node.declarations = [] - do { - let decl = this.startNode() - decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom(), true) : this.parseIdent() - decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null - node.declarations.push(this.finishNode(decl, "VariableDeclarator")) - } while (this.eat(tt.comma)) - if (!node.declarations.length) { - let decl = this.startNode() - decl.id = this.dummyIdent() - node.declarations.push(this.finishNode(decl, "VariableDeclarator")) - } - if (!noIn) this.semicolon() - return this.finishNode(node, "VariableDeclaration") -} - -lp.parseClass = function(isStatement) { - let node = this.startNode() - this.next() - if (this.tok.type === tt.name) node.id = this.parseIdent() - else if (isStatement === true) node.id = this.dummyIdent() - else node.id = null - node.superClass = this.eat(tt._extends) ? this.parseExpression() : null - node.body = this.startNode() - node.body.body = [] - this.pushCx() - let indent = this.curIndent + 1, line = this.curLineStart - this.eat(tt.braceL) - if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } - while (!this.closes(tt.braceR, indent, line)) { - if (this.semicolon()) continue - let method = this.startNode(), isGenerator, isAsync - if (this.options.ecmaVersion >= 6) { - method.static = false - isGenerator = this.eat(tt.star) - } - this.parsePropertyName(method) - if (isDummy(method.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue } - if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && - (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { - method.static = true - isGenerator = this.eat(tt.star) - this.parsePropertyName(method) - } else { - method.static = false - } - if (!method.computed && - method.key.type === "Identifier" && method.key.name === "async" && this.tok.type !== tt.parenL && - !this.canInsertSemicolon()) { - isAsync = true - isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star) - this.parsePropertyName(method) - } else { - isAsync = false - } - if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && - !method.computed && (method.key.name === "get" || method.key.name === "set") && - this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) { - method.kind = method.key.name - this.parsePropertyName(method) - method.value = this.parseMethod(false) - } else { - if (!method.computed && !method.static && !isGenerator && !isAsync && ( - method.key.type === "Identifier" && method.key.name === "constructor" || - method.key.type === "Literal" && method.key.value === "constructor")) { - method.kind = "constructor" - } else { - method.kind = "method" - } - method.value = this.parseMethod(isGenerator, isAsync) - } - node.body.body.push(this.finishNode(method, "MethodDefinition")) - } - this.popCx() - if (!this.eat(tt.braceR)) { - // If there is no closing brace, make the node span to the start - // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start - } - this.semicolon() - this.finishNode(node.body, "ClassBody") - return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") -} - -lp.parseFunction = function(node, isStatement, isAsync) { - let oldInAsync = this.inAsync - this.initFunction(node) - if (this.options.ecmaVersion >= 6) { - node.generator = this.eat(tt.star) - } - if (this.options.ecmaVersion >= 8) { - node.async = !!isAsync - } - if (this.tok.type === tt.name) node.id = this.parseIdent() - else if (isStatement === true) node.id = this.dummyIdent() - this.inAsync = node.async - node.params = this.parseFunctionParams() - node.body = this.parseBlock() - this.toks.adaptDirectivePrologue(node.body.body) - this.inAsync = oldInAsync - return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") -} - -lp.parseExport = function() { - let node = this.startNode() - this.next() - if (this.eat(tt.star)) { - node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString() - return this.finishNode(node, "ExportAllDeclaration") - } - if (this.eat(tt._default)) { - // export default (function foo() {}) // This is FunctionExpression. - let isAsync - if (this.tok.type === tt._function || (isAsync = this.toks.isAsyncFunction())) { - let fNode = this.startNode() - this.next() - if (isAsync) this.next() - node.declaration = this.parseFunction(fNode, "nullableID", isAsync) - } else if (this.tok.type === tt._class) { - node.declaration = this.parseClass("nullableID") - } else { - node.declaration = this.parseMaybeAssign() - this.semicolon() - } - return this.finishNode(node, "ExportDefaultDeclaration") - } - if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) { - node.declaration = this.parseStatement() - node.specifiers = [] - node.source = null - } else { - node.declaration = null - node.specifiers = this.parseExportSpecifierList() - node.source = this.eatContextual("from") ? this.parseExprAtom() : null - this.semicolon() - } - return this.finishNode(node, "ExportNamedDeclaration") -} - -lp.parseImport = function() { - let node = this.startNode() - this.next() - if (this.tok.type === tt.string) { - node.specifiers = [] - node.source = this.parseExprAtom() - } else { - let elt - if (this.tok.type === tt.name && this.tok.value !== "from") { - elt = this.startNode() - elt.local = this.parseIdent() - this.finishNode(elt, "ImportDefaultSpecifier") - this.eat(tt.comma) - } - node.specifiers = this.parseImportSpecifierList() - node.source = this.eatContextual("from") && this.tok.type == tt.string ? this.parseExprAtom() : this.dummyString() - if (elt) node.specifiers.unshift(elt) - } - this.semicolon() - return this.finishNode(node, "ImportDeclaration") -} - -lp.parseImportSpecifierList = function() { - let elts = [] - if (this.tok.type === tt.star) { - let elt = this.startNode() - this.next() - elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent() - elts.push(this.finishNode(elt, "ImportNamespaceSpecifier")) - } else { - let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart - this.pushCx() - this.eat(tt.braceL) - if (this.curLineStart > continuedLine) continuedLine = this.curLineStart - while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { - let elt = this.startNode() - if (this.eat(tt.star)) { - elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent() - this.finishNode(elt, "ImportNamespaceSpecifier") - } else { - if (this.isContextual("from")) break - elt.imported = this.parseIdent() - if (isDummy(elt.imported)) break - elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported - this.finishNode(elt, "ImportSpecifier") - } - elts.push(elt) - this.eat(tt.comma) - } - this.eat(tt.braceR) - this.popCx() - } - return elts -} - -lp.parseExportSpecifierList = function() { - let elts = [] - let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart - this.pushCx() - this.eat(tt.braceL) - if (this.curLineStart > continuedLine) continuedLine = this.curLineStart - while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { - if (this.isContextual("from")) break - let elt = this.startNode() - elt.local = this.parseIdent() - if (isDummy(elt.local)) break - elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local - this.finishNode(elt, "ExportSpecifier") - elts.push(elt) - this.eat(tt.comma) - } - this.eat(tt.braceR) - this.popCx() - return elts -} diff --git a/tools/tests/apps/modules/imports/links/acorn/src/loose/tokenize.js b/tools/tests/apps/modules/imports/links/acorn/src/loose/tokenize.js deleted file mode 100644 index 619b6ee9e4..0000000000 --- a/tools/tests/apps/modules/imports/links/acorn/src/loose/tokenize.js +++ /dev/null @@ -1,111 +0,0 @@ -import {tokTypes as tt, Token, isNewLine, SourceLocation, getLineInfo, lineBreakG} from "../index" -import {LooseParser} from "./state" - -const lp = LooseParser.prototype - -function isSpace(ch) { - return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewLine(ch) -} - -lp.next = function() { - this.last = this.tok - if (this.ahead.length) - this.tok = this.ahead.shift() - else - this.tok = this.readToken() - - if (this.tok.start >= this.nextLineStart) { - while (this.tok.start >= this.nextLineStart) { - this.curLineStart = this.nextLineStart - this.nextLineStart = this.lineEnd(this.curLineStart) + 1 - } - this.curIndent = this.indentationAfter(this.curLineStart) - } -} - -lp.readToken = function() { - for (;;) { - try { - this.toks.next() - if (this.toks.type === tt.dot && - this.input.substr(this.toks.end, 1) === "." && - this.options.ecmaVersion >= 6) { - this.toks.end++ - this.toks.type = tt.ellipsis - } - return new Token(this.toks) - } catch (e) { - if (!(e instanceof SyntaxError)) throw e - - // Try to skip some text, based on the error message, and then continue - let msg = e.message, pos = e.raisedAt, replace = true - if (/unterminated/i.test(msg)) { - pos = this.lineEnd(e.pos + 1) - if (/string/.test(msg)) { - replace = {start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos)} - } else if (/regular expr/i.test(msg)) { - let re = this.input.slice(e.pos, pos) - try { re = new RegExp(re) } catch (e) { /* ignore compilation error due to new syntax */ } - replace = {start: e.pos, end: pos, type: tt.regexp, value: re} - } else if (/template/.test(msg)) { - replace = { - start: e.pos, - end: pos, - type: tt.template, - value: this.input.slice(e.pos, pos) - } - } else { - replace = false - } - } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number|expected number in radix/i.test(msg)) { - while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos - } else if (/character escape|expected hexadecimal/i.test(msg)) { - while (pos < this.input.length) { - let ch = this.input.charCodeAt(pos++) - if (ch === 34 || ch === 39 || isNewLine(ch)) break - } - } else if (/unexpected character/i.test(msg)) { - pos++ - replace = false - } else if (/regular expression/i.test(msg)) { - replace = true - } else { - throw e - } - this.resetTo(pos) - if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"} - if (replace) { - if (this.options.locations) - replace.loc = new SourceLocation( - this.toks, - getLineInfo(this.input, replace.start), - getLineInfo(this.input, replace.end)) - return replace - } - } - } -} - -lp.resetTo = function(pos) { - this.toks.pos = pos - let ch = this.input.charAt(pos - 1) - this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) || - /[enwfd]/.test(ch) && - /\b(case|else|return|throw|new|in|(instance|type)?of|delete|void)$/.test(this.input.slice(pos - 10, pos)) - - if (this.options.locations) { - this.toks.curLine = 1 - this.toks.lineStart = lineBreakG.lastIndex = 0 - let match - while ((match = lineBreakG.exec(this.input)) && match.index < pos) { - ++this.toks.curLine - this.toks.lineStart = match.index + match[0].length - } - } -} - -lp.lookAhead = function(n) { - while (n > this.ahead.length) - this.ahead.push(this.readToken()) - return this.ahead[n - 1] -} diff --git a/tools/tests/apps/modules/imports/links/acorn/src/lval.js b/tools/tests/apps/modules/imports/links/acorn/src/lval.js index 0fc1bc5284..8ad4b26390 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/lval.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/lval.js @@ -1,6 +1,7 @@ import {types as tt} from "./tokentype" import {Parser} from "./state" import {has} from "./util" +import {BIND_NONE, BIND_OUTSIDE, BIND_LEXICAL} from "./scopeflags" const pp = Parser.prototype @@ -12,7 +13,7 @@ pp.toAssignable = function(node, isBinding, refDestructuringErrors) { switch (node.type) { case "Identifier": if (this.inAsync && node.name === "await") - this.raise(node.start, "Can not use 'await' as identifier inside an async function") + this.raise(node.start, "Cannot use 'await' as identifier inside an async function") break case "ObjectPattern": @@ -40,7 +41,7 @@ pp.toAssignable = function(node, isBinding, refDestructuringErrors) { break case "Property": - // AssignmentProperty has type == "Property" + // AssignmentProperty has type === "Property" if (node.kind !== "init") this.raise(node.key.start, "Object pattern can't contain getter or setter") this.toAssignable(node.value, isBinding) break @@ -69,7 +70,7 @@ pp.toAssignable = function(node, isBinding, refDestructuringErrors) { break case "ParenthesizedExpression": - this.toAssignable(node.expression, isBinding) + this.toAssignable(node.expression, isBinding, refDestructuringErrors) break case "MemberExpression": @@ -185,9 +186,11 @@ pp.parseMaybeDefault = function(startPos, startLoc, left) { // 'let' indicating that the lval creates a lexical ('let' or 'const') binding // 'none' indicating that the binding should be checked for illegal identifiers, but not for duplicate references -pp.checkLVal = function(expr, bindingType, checkClashes) { +pp.checkLVal = function(expr, bindingType = BIND_NONE, checkClashes) { switch (expr.type) { case "Identifier": + if (bindingType === BIND_LEXICAL && expr.name === "let") + this.raiseRecoverable(expr.start, "let is disallowed as a lexically bound name") if (this.strict && this.reservedWordsStrictBind.test(expr.name)) this.raiseRecoverable(expr.start, (bindingType ? "Binding " : "Assigning to ") + expr.name + " in strict mode") if (checkClashes) { @@ -195,19 +198,7 @@ pp.checkLVal = function(expr, bindingType, checkClashes) { this.raiseRecoverable(expr.start, "Argument name clash") checkClashes[expr.name] = true } - if (bindingType && bindingType !== "none") { - if ( - bindingType === "var" && !this.canDeclareVarName(expr.name) || - bindingType !== "var" && !this.canDeclareLexicalName(expr.name) - ) { - this.raiseRecoverable(expr.start, `Identifier '${expr.name}' has already been declared`) - } - if (bindingType === "var") { - this.declareVarName(expr.name) - } else { - this.declareLexicalName(expr.name) - } - } + if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) this.declareName(expr.name, bindingType, expr.start) break case "MemberExpression": @@ -220,7 +211,7 @@ pp.checkLVal = function(expr, bindingType, checkClashes) { break case "Property": - // AssignmentProperty has type == "Property" + // AssignmentProperty has type === "Property" this.checkLVal(expr.value, bindingType, checkClashes) break diff --git a/tools/tests/apps/modules/imports/links/acorn/src/options.js b/tools/tests/apps/modules/imports/links/acorn/src/options.js index 9dda44ae88..807251fdfd 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/options.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/options.js @@ -5,18 +5,19 @@ import {SourceLocation} from "./locutil" // the parser process. These options are recognized: export const defaultOptions = { - // `ecmaVersion` indicates the ECMAScript version to parse. Must - // be either 3, 5, 6 (2015), 7 (2016), or 8 (2017). This influences support - // for strict mode, the set of reserved words, and support for - // new syntax features. The default is 7. - ecmaVersion: 7, + // `ecmaVersion` indicates the ECMAScript version to parse. Must be + // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10 + // (2019). This influences support for strict mode, the set of + // reserved words, and support for new syntax features. The default + // is 10. + ecmaVersion: 10, // `sourceType` indicates the mode the code should be parsed in. // Can be either `"script"` or `"module"`. This influences global // strict mode and parsing of `import` and `export` declarations. sourceType: "script", // `onInsertedSemicolon` can be a callback that will be called // when a semicolon is automatically inserted. It will be passed - // th position of the comma as an offset, and if `locations` is + // the position of the comma as an offset, and if `locations` is // enabled, it is given the location as a `{line, column}` object // as second argument. onInsertedSemicolon: null, @@ -34,6 +35,9 @@ export const defaultOptions = { // When enabled, import/export statements are not constrained to // appearing at the top of the program. allowImportExportEverywhere: false, + // When enabled, await identifiers are allowed to appear at the top-level scope, + // but they are still not allowed in non-async functions. + allowAwaitOutsideFunction: false, // When enabled, hashbang directive in the beginning of file // is allowed and treated as a line comment. allowHashBang: false, @@ -82,8 +86,7 @@ export const defaultOptions = { directSourceFile: null, // When enabled, parenthesized expressions are represented by // (non-standard) ParenthesizedExpression nodes - preserveParens: false, - plugins: {} + preserveParens: false } // Interpret and default an options object diff --git a/tools/tests/apps/modules/imports/links/acorn/src/parseutil.js b/tools/tests/apps/modules/imports/links/acorn/src/parseutil.js index e1736372e5..98e35237f5 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/parseutil.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/parseutil.js @@ -6,15 +6,29 @@ const pp = Parser.prototype // ## Parser utilities -const literal = /^(?:'((?:\\.|[^'])*?)'|"((?:\\.|[^"])*?)"|;)/ +const literal = /^(?:'((?:\\.|[^'])*?)'|"((?:\\.|[^"])*?)")/ pp.strictDirective = function(start) { for (;;) { + // Try to find string literal. skipWhiteSpace.lastIndex = start start += skipWhiteSpace.exec(this.input)[0].length let match = literal.exec(this.input.slice(start)) if (!match) return false - if ((match[1] || match[2]) == "use strict") return true + if ((match[1] || match[2]) === "use strict") { + skipWhiteSpace.lastIndex = start + match[0].length + let spaceAfter = skipWhiteSpace.exec(this.input), end = spaceAfter.index + spaceAfter[0].length + let next = this.input.charAt(end) + return next === ";" || next === "}" || + (lineBreak.test(spaceAfter[0]) && + !(/[(`.[+\-/*%<>=,?^&]/.test(next) || next === "!" && this.input.charAt(end + 1) === "=")) + } start += match[0].length + + // Skip semicolon, if any. + skipWhiteSpace.lastIndex = start + start += skipWhiteSpace.exec(this.input)[0].length + if (this.input[start] === ";") + start++ } } @@ -74,7 +88,7 @@ pp.semicolon = function() { } pp.afterTrailingComma = function(tokType, notNext) { - if (this.type == tokType) { + if (this.type === tokType) { if (this.options.onTrailingComma) this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) if (!notNext) diff --git a/tools/tests/apps/modules/imports/links/acorn/src/regexp.js b/tools/tests/apps/modules/imports/links/acorn/src/regexp.js index c5953e3012..605bce5203 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/regexp.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/regexp.js @@ -1,6 +1,7 @@ import {isIdentifierStart, isIdentifierChar} from "./identifier.js" import {Parser} from "./state.js" import UNICODE_PROPERTY_VALUES from "./unicode-property-data.js" +import {has} from "./util.js" const pp = Parser.prototype @@ -8,6 +9,7 @@ export class RegExpValidationState { constructor(parser) { this.parser = parser this.validFlags = `gim${parser.options.ecmaVersion >= 6 ? "uy" : ""}${parser.options.ecmaVersion >= 9 ? "s" : ""}` + this.unicodeProperties = UNICODE_PROPERTY_VALUES[parser.options.ecmaVersion >= 11 ? 11 : parser.options.ecmaVersion] this.source = "" this.flags = "" this.start = 0 @@ -48,7 +50,8 @@ export class RegExpValidationState { if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) { return c } - return (c << 10) + s.charCodeAt(i + 1) - 0x35FDC00 + const next = s.charCodeAt(i + 1) + return next >= 0xDC00 && next <= 0xDFFF ? (c << 10) + next - 0x35FDC00 : c } nextIndex(i) { @@ -57,8 +60,9 @@ export class RegExpValidationState { if (i >= l) { return l } - const c = s.charCodeAt(i) - if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) { + let c = s.charCodeAt(i), next + if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l || + (next = s.charCodeAt(i + 1)) < 0xDC00 || next > 0xDFFF) { return i + 1 } return i + 2 @@ -103,7 +107,7 @@ pp.validateRegExpFlags = function(state) { for (let i = 0; i < flags.length; i++) { const flag = flags.charAt(i) - if (validFlags.indexOf(flag) == -1) { + if (validFlags.indexOf(flag) === -1) { this.raise(state.start, "Invalid regular expression flag") } if (flags.indexOf(flag, i + 1) > -1) { @@ -150,7 +154,7 @@ pp.regexp_pattern = function(state) { if (state.eat(0x29 /* ) */)) { state.raise("Unmatched ')'") } - if (state.eat(0x5D /* [ */) || state.eat(0x7D /* } */)) { + if (state.eat(0x5D /* ] */) || state.eat(0x7D /* } */)) { state.raise("Lone quantifier brackets") } } @@ -784,14 +788,14 @@ pp.regexp_eatUnicodePropertyValueExpression = function(state) { return false } pp.regexp_validateUnicodePropertyNameAndValue = function(state, name, value) { - if (!UNICODE_PROPERTY_VALUES.hasOwnProperty(name) || UNICODE_PROPERTY_VALUES[name].indexOf(value) === -1) { + if (!has(state.unicodeProperties.nonBinary, name)) state.raise("Invalid property name") - } + if (!state.unicodeProperties.nonBinary[name].test(value)) + state.raise("Invalid property value") } pp.regexp_validateUnicodePropertyNameOrValue = function(state, nameOrValue) { - if (UNICODE_PROPERTY_VALUES.$LONE.indexOf(nameOrValue) === -1) { + if (!state.unicodeProperties.binary.test(nameOrValue)) state.raise("Invalid property name") - } } // UnicodePropertyName :: @@ -835,7 +839,7 @@ pp.regexp_eatCharacterClass = function(state) { if (state.eat(0x5B /* [ */)) { state.eat(0x5E /* ^ */) this.regexp_classRanges(state) - if (state.eat(0x5D /* [ */)) { + if (state.eat(0x5D /* ] */)) { return true } // Unreachable since it threw "unterminated regular expression" error before. @@ -883,7 +887,7 @@ pp.regexp_eatClassAtom = function(state) { } const ch = state.current() - if (ch !== 0x5D /* [ */) { + if (ch !== 0x5D /* ] */) { state.lastIntValue = ch state.advance() return true diff --git a/tools/tests/apps/modules/imports/links/acorn/src/scope.js b/tools/tests/apps/modules/imports/links/acorn/src/scope.js index eab0002c04..b0b9866611 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/scope.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/scope.js @@ -1,74 +1,95 @@ import {Parser} from "./state" -import {has} from "./util" +import {SCOPE_VAR, SCOPE_FUNCTION, SCOPE_TOP, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, BIND_LEXICAL, BIND_SIMPLE_CATCH, BIND_FUNCTION} from "./scopeflags" const pp = Parser.prototype -// Object.assign polyfill -const assign = Object.assign || function(target, ...sources) { - for (let source of sources) { - for (const key in source) { - if (has(source, key)) { - target[key] = source[key] - } - } +class Scope { + constructor(flags) { + this.flags = flags + // A list of var-declared names in the current lexical scope + this.var = [] + // A list of lexically-declared names in the current lexical scope + this.lexical = [] + // A list of lexically-declared FunctionDeclaration names in the current lexical scope + this.functions = [] } - return target } // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names. -pp.enterFunctionScope = function() { - // var: a hash of var-declared names in the current lexical scope - // lexical: a hash of lexically-declared names in the current lexical scope - // childVar: a hash of var-declared names in all child lexical scopes of the current lexical scope (within the current function scope) - // parentLexical: a hash of lexically-declared names in all parent lexical scopes of the current lexical scope (within the current function scope) - this.scopeStack.push({var: {}, lexical: {}, childVar: {}, parentLexical: {}}) +pp.enterScope = function(flags) { + this.scopeStack.push(new Scope(flags)) } -pp.exitFunctionScope = function() { +pp.exitScope = function() { this.scopeStack.pop() } -pp.enterLexicalScope = function() { - const parentScope = this.scopeStack[this.scopeStack.length - 1] - const childScope = {var: {}, lexical: {}, childVar: {}, parentLexical: {}} - - this.scopeStack.push(childScope) - assign(childScope.parentLexical, parentScope.lexical, parentScope.parentLexical) +// The spec says: +// > At the top level of a function, or script, function declarations are +// > treated like var declarations rather than like lexical declarations. +pp.treatFunctionsAsVarInScope = function(scope) { + return (scope.flags & SCOPE_FUNCTION) || !this.inModule && (scope.flags & SCOPE_TOP) } -pp.exitLexicalScope = function() { - const childScope = this.scopeStack.pop() - const parentScope = this.scopeStack[this.scopeStack.length - 1] - - assign(parentScope.childVar, childScope.var, childScope.childVar) +pp.declareName = function(name, bindingType, pos) { + let redeclared = false + if (bindingType === BIND_LEXICAL) { + const scope = this.currentScope() + redeclared = scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1 + scope.lexical.push(name) + if (this.inModule && (scope.flags & SCOPE_TOP)) + delete this.undefinedExports[name] + } else if (bindingType === BIND_SIMPLE_CATCH) { + const scope = this.currentScope() + scope.lexical.push(name) + } else if (bindingType === BIND_FUNCTION) { + const scope = this.currentScope() + if (this.treatFunctionsAsVar) + redeclared = scope.lexical.indexOf(name) > -1 + else + redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1 + scope.functions.push(name) + } else { + for (let i = this.scopeStack.length - 1; i >= 0; --i) { + const scope = this.scopeStack[i] + if (scope.lexical.indexOf(name) > -1 && !((scope.flags & SCOPE_SIMPLE_CATCH) && scope.lexical[0] === name) || + !this.treatFunctionsAsVarInScope(scope) && scope.functions.indexOf(name) > -1) { + redeclared = true + break + } + scope.var.push(name) + if (this.inModule && (scope.flags & SCOPE_TOP)) + delete this.undefinedExports[name] + if (scope.flags & SCOPE_VAR) break + } + } + if (redeclared) this.raiseRecoverable(pos, `Identifier '${name}' has already been declared`) } -/** - * A name can be declared with `var` if there are no variables with the same name declared with `let`/`const` - * in the current lexical scope or any of the parent lexical scopes in this function. - */ -pp.canDeclareVarName = function(name) { - const currentScope = this.scopeStack[this.scopeStack.length - 1] - - return !has(currentScope.lexical, name) && !has(currentScope.parentLexical, name) +pp.checkLocalExport = function(id) { + // scope.functions must be empty as Module code is always strict. + if (this.scopeStack[0].lexical.indexOf(id.name) === -1 && + this.scopeStack[0].var.indexOf(id.name) === -1) { + this.undefinedExports[id.name] = id + } } -/** - * A name can be declared with `let`/`const` if there are no variables with the same name declared with `let`/`const` - * in the current scope, and there are no variables with the same name declared with `var` in the current scope or in - * any child lexical scopes in this function. - */ -pp.canDeclareLexicalName = function(name) { - const currentScope = this.scopeStack[this.scopeStack.length - 1] - - return !has(currentScope.lexical, name) && !has(currentScope.var, name) && !has(currentScope.childVar, name) +pp.currentScope = function() { + return this.scopeStack[this.scopeStack.length - 1] } -pp.declareVarName = function(name) { - this.scopeStack[this.scopeStack.length - 1].var[name] = true +pp.currentVarScope = function() { + for (let i = this.scopeStack.length - 1;; i--) { + let scope = this.scopeStack[i] + if (scope.flags & SCOPE_VAR) return scope + } } -pp.declareLexicalName = function(name) { - this.scopeStack[this.scopeStack.length - 1].lexical[name] = true +// Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. +pp.currentThisScope = function() { + for (let i = this.scopeStack.length - 1;; i--) { + let scope = this.scopeStack[i] + if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) return scope + } } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/scopeflags.js b/tools/tests/apps/modules/imports/links/acorn/src/scopeflags.js new file mode 100644 index 0000000000..ccb16ecc48 --- /dev/null +++ b/tools/tests/apps/modules/imports/links/acorn/src/scopeflags.js @@ -0,0 +1,24 @@ +// Each scope gets a bitset that may contain these flags +export const + SCOPE_TOP = 1, + SCOPE_FUNCTION = 2, + SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION, + SCOPE_ASYNC = 4, + SCOPE_GENERATOR = 8, + SCOPE_ARROW = 16, + SCOPE_SIMPLE_CATCH = 32, + SCOPE_SUPER = 64, + SCOPE_DIRECT_SUPER = 128 + +export function functionFlags(async, generator) { + return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) +} + +// Used in checkLVal and declareName to determine the type of a binding +export const + BIND_NONE = 0, // Not a binding + BIND_VAR = 1, // Var-style binding + BIND_LEXICAL = 2, // Let- or const-style binding + BIND_FUNCTION = 3, // Function declaration + BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding + BIND_OUTSIDE = 5 // Special case for function names as bound inside the function diff --git a/tools/tests/apps/modules/imports/links/acorn/src/state.js b/tools/tests/apps/modules/imports/links/acorn/src/state.js index 185fe28648..eb4e0e1208 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/state.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/state.js @@ -2,29 +2,24 @@ import {reservedWords, keywords} from "./identifier" import {types as tt} from "./tokentype" import {lineBreak} from "./whitespace" import {getOptions} from "./options" - -// Registered plugins -export const plugins = {} - -function keywordRegexp(words) { - return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$") -} +import {wordsRegexp} from "./util" +import {SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR, SCOPE_SUPER, SCOPE_DIRECT_SUPER} from "./scopeflags" export class Parser { constructor(options, input, startPos) { this.options = options = getOptions(options) this.sourceFile = options.sourceFile - this.keywords = keywordRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5]) + this.keywords = wordsRegexp(keywords[options.ecmaVersion >= 6 ? 6 : options.sourceType === "module" ? "5module" : 5]) let reserved = "" - if (!options.allowReserved) { + if (options.allowReserved !== true) { for (let v = options.ecmaVersion;; v--) if (reserved = reservedWords[v]) break - if (options.sourceType == "module") reserved += " await" + if (options.sourceType === "module") reserved += " await" } - this.reservedWords = keywordRegexp(reserved) + this.reservedWords = wordsRegexp(reserved) let reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict - this.reservedWordsStrict = keywordRegexp(reservedStrict) - this.reservedWordsStrictBind = keywordRegexp(reservedStrict + " " + reservedWords.strictBind) + this.reservedWordsStrict = wordsRegexp(reservedStrict) + this.reservedWordsStrictBind = wordsRegexp(reservedStrict + " " + reservedWords.strictBind) this.input = String(input) // Used to signal to callers of `readWord1` whether the word @@ -32,9 +27,6 @@ export class Parser { // escape sequences must not be interpreted as keywords. this.containsEsc = false - // Load plugins - this.loadPlugins(options.plugins) - // Set up token state // The current position of the tokenizer in the input. @@ -75,12 +67,12 @@ export class Parser { // Used to signify the start of a potential arrow function this.potentialArrowAt = -1 - // Flags to track whether we are in a function, a generator, an async function. - this.inFunction = this.inGenerator = this.inAsync = false // Positions to delayed-check that yield/await does not exist in default parameters. - this.yieldPos = this.awaitPos = 0 + this.yieldPos = this.awaitPos = this.awaitIdentPos = 0 // Labels in scope. this.labels = [] + // Thus-far undefined exports. + this.undefinedExports = {} // If enabled, skip leading hashbang line. if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === "#!") @@ -88,31 +80,45 @@ export class Parser { // Scope tracking for duplicate variable names (see scope.js) this.scopeStack = [] - this.enterFunctionScope() + this.enterScope(SCOPE_TOP) // For RegExp validation this.regexpState = null } - // DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them - isKeyword(word) { return this.keywords.test(word) } - isReservedWord(word) { return this.reservedWords.test(word) } - - extend(name, f) { - this[name] = f(this[name]) - } - - loadPlugins(pluginConfigs) { - for (let name in pluginConfigs) { - let plugin = plugins[name] - if (!plugin) throw new Error("Plugin '" + name + "' not found") - plugin(this, pluginConfigs[name]) - } - } - parse() { let node = this.options.program || this.startNode() this.nextToken() return this.parseTopLevel(node) } + + get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 } + get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 } + get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 } + get allowSuper() { return (this.currentThisScope().flags & SCOPE_SUPER) > 0 } + get allowDirectSuper() { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 } + get treatFunctionsAsVar() { return this.treatFunctionsAsVarInScope(this.currentScope()) } + + // Switch to a getter for 7.0.0. + inNonArrowFunction() { return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0 } + + static extend(...plugins) { + let cls = this + for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls) + return cls + } + + static parse(input, options) { + return new this(options, input).parse() + } + + static parseExpressionAt(input, pos, options) { + let parser = new this(options, input, pos) + parser.nextToken() + return parser.parseExpression() + } + + static tokenizer(input, options) { + return new this(options, input) + } } diff --git a/tools/tests/apps/modules/imports/links/acorn/src/statement.js b/tools/tests/apps/modules/imports/links/acorn/src/statement.js index 2612125df3..8c7e171a9f 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/statement.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/statement.js @@ -4,6 +4,7 @@ import {lineBreak, skipWhiteSpace} from "./whitespace" import {isIdentifierStart, isIdentifierChar, keywordRelationalOperator} from "./identifier" import {has} from "./util" import {DestructuringErrors} from "./parseutil" +import {functionFlags, SCOPE_SIMPLE_CATCH, BIND_SIMPLE_CATCH, BIND_LEXICAL, BIND_VAR, BIND_FUNCTION} from "./scopeflags" const pp = Parser.prototype @@ -18,25 +19,33 @@ pp.parseTopLevel = function(node) { let exports = {} if (!node.body) node.body = [] while (this.type !== tt.eof) { - let stmt = this.parseStatement(true, true, exports) + let stmt = this.parseStatement(null, true, exports) node.body.push(stmt) } + if (this.inModule) + for (let name of Object.keys(this.undefinedExports)) + this.raiseRecoverable(this.undefinedExports[name].start, `Export '${name}' is not defined`) this.adaptDirectivePrologue(node.body) this.next() - if (this.options.ecmaVersion >= 6) { - node.sourceType = this.options.sourceType - } + node.sourceType = this.options.sourceType return this.finishNode(node, "Program") } const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"} -pp.isLet = function() { +pp.isLet = function(context) { if (this.options.ecmaVersion < 6 || !this.isContextual("let")) return false skipWhiteSpace.lastIndex = this.pos let skip = skipWhiteSpace.exec(this.input) let next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) - if (nextCh === 91 || nextCh == 123) return true // '{' and '[' + // For ambiguous cases, determine if a LexicalDeclaration (or only a + // Statement) is allowed here. If context is not empty then only a Statement + // is allowed. However, `let [` is an explicit negative lookahead for + // ExpressionStatement, so special-case it first. + if (nextCh === 91) return true // '[' + if (context) return false + + if (nextCh === 123) return true // '{' if (isIdentifierStart(nextCh, true)) { let pos = next + 1 while (isIdentifierChar(this.input.charCodeAt(pos), true)) ++pos @@ -58,7 +67,7 @@ pp.isAsyncFunction = function() { let next = this.pos + skip[0].length return !lineBreak.test(this.input.slice(this.pos, next)) && this.input.slice(next, next + 8) === "function" && - (next + 8 == this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) + (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) } // Parse a single statement. @@ -68,10 +77,10 @@ pp.isAsyncFunction = function() { // `if (foo) /blah/.exec(foo)`, where looking at the previous token // does not help. -pp.parseStatement = function(declaration, topLevel, exports) { +pp.parseStatement = function(context, topLevel, exports) { let starttype = this.type, node = this.startNode(), kind - if (this.isLet()) { + if (this.isLet(context)) { starttype = tt._var kind = "let" } @@ -86,10 +95,13 @@ pp.parseStatement = function(declaration, topLevel, exports) { case tt._do: return this.parseDoStatement(node) case tt._for: return this.parseForStatement(node) case tt._function: - if (!declaration && this.options.ecmaVersion >= 6) this.unexpected() - return this.parseFunctionStatement(node, false) + // Function as sole body of either an if statement or a labeled statement + // works, but not when it is part of a labeled statement that is the sole + // body of an if statement. + if ((context && (this.strict || context !== "if" && context !== "label")) && this.options.ecmaVersion >= 6) this.unexpected() + return this.parseFunctionStatement(node, false, !context) case tt._class: - if (!declaration) this.unexpected() + if (context) this.unexpected() return this.parseClass(node, true) case tt._if: return this.parseIfStatement(node) case tt._return: return this.parseReturnStatement(node) @@ -98,14 +110,22 @@ pp.parseStatement = function(declaration, topLevel, exports) { case tt._try: return this.parseTryStatement(node) case tt._const: case tt._var: kind = kind || this.value - if (!declaration && kind != "var") this.unexpected() + if (context && kind !== "var") this.unexpected() return this.parseVarStatement(node, kind) case tt._while: return this.parseWhileStatement(node) case tt._with: return this.parseWithStatement(node) - case tt.braceL: return this.parseBlock() + case tt.braceL: return this.parseBlock(true, node) case tt.semi: return this.parseEmptyStatement(node) case tt._export: case tt._import: + if (this.options.ecmaVersion > 10 && starttype === tt._import) { + skipWhiteSpace.lastIndex = this.pos + let skip = skipWhiteSpace.exec(this.input) + let next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) + if (nextCh === 40) // '(' + return this.parseExpressionStatement(node, this.parseExpression()) + } + if (!this.options.allowImportExportEverywhere) { if (!topLevel) this.raise(this.start, "'import' and 'export' may only appear at the top level") @@ -121,20 +141,20 @@ pp.parseStatement = function(declaration, topLevel, exports) { // Identifier node, we switch to interpreting it as a label. default: if (this.isAsyncFunction()) { - if (!declaration) this.unexpected() + if (context) this.unexpected() this.next() - return this.parseFunctionStatement(node, true) + return this.parseFunctionStatement(node, true, !context) } let maybeName = this.value, expr = this.parseExpression() if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) - return this.parseLabeledStatement(node, maybeName, expr) + return this.parseLabeledStatement(node, maybeName, expr, context) else return this.parseExpressionStatement(node, expr) } } pp.parseBreakContinueStatement = function(node, keyword) { - let isBreak = keyword == "break" + let isBreak = keyword === "break" this.next() if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null else if (this.type !== tt.name) this.unexpected() @@ -166,7 +186,7 @@ pp.parseDebuggerStatement = function(node) { pp.parseDoStatement = function(node) { this.next() this.labels.push(loopLabel) - node.body = this.parseStatement(false) + node.body = this.parseStatement("do") this.labels.pop() this.expect(tt._while) node.test = this.parseParenExpression() @@ -187,9 +207,9 @@ pp.parseDoStatement = function(node) { pp.parseForStatement = function(node) { this.next() - let awaitAt = (this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await")) ? this.lastTokStart : -1 + let awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual("await")) ? this.lastTokStart : -1 this.labels.push(loopLabel) - this.enterLexicalScope() + this.enterScope(0) this.expect(tt.parenL) if (this.type === tt.semi) { if (awaitAt > -1) this.unexpected(awaitAt) @@ -201,8 +221,7 @@ pp.parseForStatement = function(node) { this.next() this.parseVar(init, true, kind) this.finishNode(init, "VariableDeclaration") - if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1 && - !(kind !== "var" && init.declarations[0].init)) { + if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1) { if (this.options.ecmaVersion >= 9) { if (this.type === tt._in) { if (awaitAt > -1) this.unexpected(awaitAt) @@ -231,17 +250,17 @@ pp.parseForStatement = function(node) { return this.parseFor(node, init) } -pp.parseFunctionStatement = function(node, isAsync) { +pp.parseFunctionStatement = function(node, isAsync, declarationPosition) { this.next() - return this.parseFunction(node, true, false, isAsync) + return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync) } pp.parseIfStatement = function(node) { this.next() node.test = this.parseParenExpression() // allow function declarations in branches, but only in non-strict mode - node.consequent = this.parseStatement(!this.strict && this.type == tt._function) - node.alternate = this.eat(tt._else) ? this.parseStatement(!this.strict && this.type == tt._function) : null + node.consequent = this.parseStatement("if") + node.alternate = this.eat(tt._else) ? this.parseStatement("if") : null return this.finishNode(node, "IfStatement") } @@ -265,14 +284,14 @@ pp.parseSwitchStatement = function(node) { node.cases = [] this.expect(tt.braceL) this.labels.push(switchLabel) - this.enterLexicalScope() + this.enterScope(0) // Statements under must be grouped (by label) in SwitchCase // nodes. `cur` is used to keep the node that we are currently // adding statements to. let cur - for (let sawDefault = false; this.type != tt.braceR;) { + for (let sawDefault = false; this.type !== tt.braceR;) { if (this.type === tt._case || this.type === tt._default) { let isCase = this.type === tt._case if (cur) this.finishNode(cur, "SwitchCase") @@ -289,10 +308,10 @@ pp.parseSwitchStatement = function(node) { this.expect(tt.colon) } else { if (!cur) this.unexpected() - cur.consequent.push(this.parseStatement(true)) + cur.consequent.push(this.parseStatement(null)) } } - this.exitLexicalScope() + this.exitScope() if (cur) this.finishNode(cur, "SwitchCase") this.next() // Closing brace this.labels.pop() @@ -319,13 +338,19 @@ pp.parseTryStatement = function(node) { if (this.type === tt._catch) { let clause = this.startNode() this.next() - this.expect(tt.parenL) - clause.param = this.parseBindingAtom() - this.enterLexicalScope() - this.checkLVal(clause.param, "let") - this.expect(tt.parenR) + if (this.eat(tt.parenL)) { + clause.param = this.parseBindingAtom() + let simple = clause.param.type === "Identifier" + this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0) + this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL) + this.expect(tt.parenR) + } else { + if (this.options.ecmaVersion < 10) this.unexpected() + clause.param = null + this.enterScope(0) + } clause.body = this.parseBlock(false) - this.exitLexicalScope() + this.exitScope() node.handler = this.finishNode(clause, "CatchClause") } node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null @@ -345,7 +370,7 @@ pp.parseWhileStatement = function(node) { this.next() node.test = this.parseParenExpression() this.labels.push(loopLabel) - node.body = this.parseStatement(false) + node.body = this.parseStatement("while") this.labels.pop() return this.finishNode(node, "WhileStatement") } @@ -354,7 +379,7 @@ pp.parseWithStatement = function(node) { if (this.strict) this.raise(this.start, "'with' in strict mode") this.next() node.object = this.parseParenExpression() - node.body = this.parseStatement(false) + node.body = this.parseStatement("with") return this.finishNode(node, "WithStatement") } @@ -363,25 +388,21 @@ pp.parseEmptyStatement = function(node) { return this.finishNode(node, "EmptyStatement") } -pp.parseLabeledStatement = function(node, maybeName, expr) { +pp.parseLabeledStatement = function(node, maybeName, expr, context) { for (let label of this.labels) if (label.name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared") let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null for (let i = this.labels.length - 1; i >= 0; i--) { let label = this.labels[i] - if (label.statementStart == node.start) { + if (label.statementStart === node.start) { // Update information about previous labels on this node label.statementStart = this.start label.kind = kind } else break } this.labels.push({name: maybeName, kind, statementStart: this.start}) - node.body = this.parseStatement(true) - if (node.body.type == "ClassDeclaration" || - node.body.type == "VariableDeclaration" && node.body.kind != "var" || - node.body.type == "FunctionDeclaration" && (this.strict || node.body.generator)) - this.raiseRecoverable(node.body.start, "Invalid labeled declaration") + node.body = this.parseStatement(context ? context.indexOf("label") === -1 ? context + "label" : context : "label") this.labels.pop() node.label = expr return this.finishNode(node, "LabeledStatement") @@ -397,20 +418,17 @@ pp.parseExpressionStatement = function(node, expr) { // strict"` declarations when `allowStrict` is true (used for // function bodies). -pp.parseBlock = function(createNewLexicalScope = true) { - let node = this.startNode() +pp.parseBlock = function(createNewLexicalScope = true, node = this.startNode(), exitStrict) { node.body = [] this.expect(tt.braceL) - if (createNewLexicalScope) { - this.enterLexicalScope() - } - while (!this.eat(tt.braceR)) { - let stmt = this.parseStatement(true) + if (createNewLexicalScope) this.enterScope(0) + while (this.type !== tt.braceR) { + let stmt = this.parseStatement(null) node.body.push(stmt) } - if (createNewLexicalScope) { - this.exitLexicalScope() - } + if (exitStrict) this.strict = false + this.next() + if (createNewLexicalScope) this.exitScope() return this.finishNode(node, "BlockStatement") } @@ -425,8 +443,8 @@ pp.parseFor = function(node, init) { this.expect(tt.semi) node.update = this.type === tt.parenR ? null : this.parseExpression() this.expect(tt.parenR) - this.exitLexicalScope() - node.body = this.parseStatement(false) + node.body = this.parseStatement("for") + this.exitScope() this.labels.pop() return this.finishNode(node, "ForStatement") } @@ -435,21 +453,36 @@ pp.parseFor = function(node, init) { // same from parser's perspective. pp.parseForIn = function(node, init) { - let type = this.type === tt._in ? "ForInStatement" : "ForOfStatement" + const isForIn = this.type === tt._in this.next() - if (type == "ForInStatement") { - if (init.type === "AssignmentPattern" || - (init.type === "VariableDeclaration" && init.declarations[0].init != null && - (this.strict || init.declarations[0].id.type !== "Identifier"))) - this.raise(init.start, "Invalid assignment in for-in loop head") + + if ( + init.type === "VariableDeclaration" && + init.declarations[0].init != null && + ( + !isForIn || + this.options.ecmaVersion < 8 || + this.strict || + init.kind !== "var" || + init.declarations[0].id.type !== "Identifier" + ) + ) { + this.raise( + init.start, + `${ + isForIn ? "for-in" : "for-of" + } loop variable declaration may not have an initializer` + ) + } else if (init.type === "AssignmentPattern") { + this.raise(init.start, "Invalid left-hand side in for-loop") } node.left = init - node.right = type == "ForInStatement" ? this.parseExpression() : this.parseMaybeAssign() + node.right = isForIn ? this.parseExpression() : this.parseMaybeAssign() this.expect(tt.parenR) - this.exitLexicalScope() - node.body = this.parseStatement(false) + node.body = this.parseStatement("for") + this.exitScope() this.labels.pop() - return this.finishNode(node, type) + return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement") } // Parse a list of variable declarations. @@ -464,7 +497,7 @@ pp.parseVar = function(node, isFor, kind) { decl.init = this.parseMaybeAssign(isFor) } else if (kind === "const" && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) { this.unexpected() - } else if (decl.id.type != "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) { + } else if (decl.id.type !== "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) { this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value") } else { decl.init = null @@ -476,48 +509,52 @@ pp.parseVar = function(node, isFor, kind) { } pp.parseVarId = function(decl, kind) { - decl.id = this.parseBindingAtom(kind) - this.checkLVal(decl.id, kind, false) + decl.id = this.parseBindingAtom() + this.checkLVal(decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, false) } -// Parse a function declaration or literal (depending on the -// `isStatement` parameter). +const FUNC_STATEMENT = 1, FUNC_HANGING_STATEMENT = 2, FUNC_NULLABLE_ID = 4 -pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) { +// Parse a function declaration or literal (depending on the +// `statement & FUNC_STATEMENT`). + +// Remove `allowExpressionBody` for 7.0.0, as it is only called with false +pp.parseFunction = function(node, statement, allowExpressionBody, isAsync) { this.initFunction(node) - if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync) + if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync) { + if (this.type === tt.star && (statement & FUNC_HANGING_STATEMENT)) + this.unexpected() node.generator = this.eat(tt.star) + } if (this.options.ecmaVersion >= 8) node.async = !!isAsync - if (isStatement) { - node.id = isStatement === "nullableID" && this.type != tt.name ? null : this.parseIdent() - if (node.id) { - this.checkLVal(node.id, "var") - } + if (statement & FUNC_STATEMENT) { + node.id = (statement & FUNC_NULLABLE_ID) && this.type !== tt.name ? null : this.parseIdent() + if (node.id && !(statement & FUNC_HANGING_STATEMENT)) + // If it is a regular function declaration in sloppy mode, then it is + // subject to Annex B semantics (BIND_FUNCTION). Otherwise, the binding + // mode depends on properties of the current scope (see + // treatFunctionsAsVar). + this.checkLVal(node.id, (this.strict || node.generator || node.async) ? this.treatFunctionsAsVar ? BIND_VAR : BIND_LEXICAL : BIND_FUNCTION) } - let oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction - this.inGenerator = node.generator - this.inAsync = node.async + let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos this.yieldPos = 0 this.awaitPos = 0 - this.inFunction = true - this.enterFunctionScope() + this.awaitIdentPos = 0 + this.enterScope(functionFlags(node.async, node.generator)) - if (!isStatement) - node.id = this.type == tt.name ? this.parseIdent() : null + if (!(statement & FUNC_STATEMENT)) + node.id = this.type === tt.name ? this.parseIdent() : null this.parseFunctionParams(node) - this.parseFunctionBody(node, allowExpressionBody) + this.parseFunctionBody(node, allowExpressionBody, false) - this.inGenerator = oldInGen - this.inAsync = oldInAsync this.yieldPos = oldYieldPos this.awaitPos = oldAwaitPos - this.inFunction = oldInFunc - return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") + this.awaitIdentPos = oldAwaitIdentPos + return this.finishNode(node, (statement & FUNC_STATEMENT) ? "FunctionDeclaration" : "FunctionExpression") } pp.parseFunctionParams = function(node) { @@ -532,24 +569,34 @@ pp.parseFunctionParams = function(node) { pp.parseClass = function(node, isStatement) { this.next() + // ecma-262 14.6 Class Definitions + // A class definition is always strict mode code. + const oldStrict = this.strict + this.strict = true + this.parseClassId(node, isStatement) this.parseClassSuper(node) let classBody = this.startNode() let hadConstructor = false classBody.body = [] this.expect(tt.braceL) - while (!this.eat(tt.braceR)) { - const member = this.parseClassMember(classBody) - if (member && member.type === "MethodDefinition" && member.kind === "constructor") { - if (hadConstructor) this.raise(member.start, "Duplicate constructor in the same class") - hadConstructor = true + while (this.type !== tt.braceR) { + const element = this.parseClassElement(node.superClass !== null) + if (element) { + classBody.body.push(element) + if (element.type === "MethodDefinition" && element.kind === "constructor") { + if (hadConstructor) this.raise(element.start, "Duplicate constructor in the same class") + hadConstructor = true + } } } + this.strict = oldStrict + this.next() node.body = this.finishNode(classBody, "ClassBody") return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") } -pp.parseClassMember = function(classBody) { +pp.parseClassElement = function(constructorAllowsSuper) { if (this.eat(tt.semi)) return null let method = this.startNode() @@ -581,16 +628,18 @@ pp.parseClassMember = function(classBody) { } if (!method.key) this.parsePropertyName(method) let {key} = method + let allowsDirectSuper = false if (!method.computed && !method.static && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { if (method.kind !== "method") this.raise(key.start, "Constructor can't have get/set modifier") if (isGenerator) this.raise(key.start, "Constructor can't be a generator") if (isAsync) this.raise(key.start, "Constructor can't be an async method") method.kind = "constructor" + allowsDirectSuper = constructorAllowsSuper } else if (method.static && key.type === "Identifier" && key.name === "prototype") { this.raise(key.start, "Classes may not have a static property named prototype") } - this.parseClassMethod(classBody, method, isGenerator, isAsync) + this.parseClassMethod(method, isGenerator, isAsync, allowsDirectSuper) if (method.kind === "get" && method.value.params.length !== 0) this.raiseRecoverable(method.value.start, "getter should have no params") if (method.kind === "set" && method.value.params.length !== 1) @@ -600,13 +649,21 @@ pp.parseClassMember = function(classBody) { return method } -pp.parseClassMethod = function(classBody, method, isGenerator, isAsync) { - method.value = this.parseMethod(isGenerator, isAsync) - classBody.body.push(this.finishNode(method, "MethodDefinition")) +pp.parseClassMethod = function(method, isGenerator, isAsync, allowsDirectSuper) { + method.value = this.parseMethod(isGenerator, isAsync, allowsDirectSuper) + return this.finishNode(method, "MethodDefinition") } pp.parseClassId = function(node, isStatement) { - node.id = this.type === tt.name ? this.parseIdent() : isStatement === true ? this.unexpected() : null + if (this.type === tt.name) { + node.id = this.parseIdent() + if (isStatement) + this.checkLVal(node.id, BIND_LEXICAL, false) + } else { + if (isStatement === true) + this.unexpected() + node.id = null + } } pp.parseClassSuper = function(node) { @@ -619,6 +676,14 @@ pp.parseExport = function(node, exports) { this.next() // export * from '...' if (this.eat(tt.star)) { + if (this.options.ecmaVersion >= 11) { + if (this.eatContextual("as")) { + node.exported = this.parseIdent(true) + this.checkExport(exports, node.exported.name, this.lastTokStart) + } else { + node.exported = null + } + } this.expectContextual("from") if (this.type !== tt.string) this.unexpected() node.source = this.parseExprAtom() @@ -632,7 +697,7 @@ pp.parseExport = function(node, exports) { let fNode = this.startNode() this.next() if (isAsync) this.next() - node.declaration = this.parseFunction(fNode, "nullableID", false, isAsync) + node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync) } else if (this.type === tt._class) { let cNode = this.startNode() node.declaration = this.parseClass(cNode, "nullableID") @@ -644,7 +709,7 @@ pp.parseExport = function(node, exports) { } // export var|const|let|function|class ... if (this.shouldParseExportStatement()) { - node.declaration = this.parseStatement(true) + node.declaration = this.parseStatement(null) if (node.declaration.type === "VariableDeclaration") this.checkVariableExport(exports, node.declaration.declarations) else @@ -658,9 +723,11 @@ pp.parseExport = function(node, exports) { if (this.type !== tt.string) this.unexpected() node.source = this.parseExprAtom() } else { - // check for keywords used as local names for (let spec of node.specifiers) { + // check for keywords used as local names this.checkUnreserved(spec.local) + // check if export is defined + this.checkLocalExport(spec.local) } node.source = null @@ -679,22 +746,22 @@ pp.checkExport = function(exports, name, pos) { pp.checkPatternExport = function(exports, pat) { let type = pat.type - if (type == "Identifier") + if (type === "Identifier") this.checkExport(exports, pat.name, pat.start) - else if (type == "ObjectPattern") + else if (type === "ObjectPattern") for (let prop of pat.properties) this.checkPatternExport(exports, prop) - else if (type == "ArrayPattern") + else if (type === "ArrayPattern") for (let elt of pat.elements) { if (elt) this.checkPatternExport(exports, elt) } - else if (type == "Property") + else if (type === "Property") this.checkPatternExport(exports, pat.value) - else if (type == "AssignmentPattern") + else if (type === "AssignmentPattern") this.checkPatternExport(exports, pat.left) - else if (type == "RestElement") + else if (type === "RestElement") this.checkPatternExport(exports, pat.argument) - else if (type == "ParenthesizedExpression") + else if (type === "ParenthesizedExpression") this.checkPatternExport(exports, pat.expression) } @@ -759,7 +826,7 @@ pp.parseImportSpecifiers = function() { // import defaultObj, { x, y as z } from '...' let node = this.startNode() node.local = this.parseIdent() - this.checkLVal(node.local, "let") + this.checkLVal(node.local, BIND_LEXICAL) nodes.push(this.finishNode(node, "ImportDefaultSpecifier")) if (!this.eat(tt.comma)) return nodes } @@ -768,7 +835,7 @@ pp.parseImportSpecifiers = function() { this.next() this.expectContextual("as") node.local = this.parseIdent() - this.checkLVal(node.local, "let") + this.checkLVal(node.local, BIND_LEXICAL) nodes.push(this.finishNode(node, "ImportNamespaceSpecifier")) return nodes } @@ -787,7 +854,7 @@ pp.parseImportSpecifiers = function() { this.checkUnreserved(node.imported) node.local = node.imported } - this.checkLVal(node.local, "let") + this.checkLVal(node.local, BIND_LEXICAL) nodes.push(this.finishNode(node, "ImportSpecifier")) } return nodes diff --git a/tools/tests/apps/modules/imports/links/acorn/src/tokencontext.js b/tools/tests/apps/modules/imports/links/acorn/src/tokencontext.js index 18dda85ce6..1ff5556879 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/tokencontext.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/tokencontext.js @@ -45,13 +45,13 @@ pp.braceIsBlock = function(prevType) { // The check for `tt.name && exprAllowed` detects whether we are // after a `yield` or `of` construct. See the `updateContext` for // `tt.name`. - if (prevType === tt._return || prevType == tt.name && this.exprAllowed) + if (prevType === tt._return || prevType === tt.name && this.exprAllowed) return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) - if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType == tt.arrow) + if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType === tt.arrow) return true - if (prevType == tt.braceL) + if (prevType === tt.braceL) return parent === types.b_stat - if (prevType == tt._var || prevType == tt.name) + if (prevType === tt._var || prevType === tt._const || prevType === tt.name) return false return !this.exprAllowed } @@ -67,7 +67,7 @@ pp.inGeneratorContext = function() { pp.updateContext = function(prevType) { let update, type = this.type - if (type.keyword && prevType == tt.dot) + if (type.keyword && prevType === tt.dot) this.exprAllowed = false else if (update = type.updateContext) update.call(this, prevType) @@ -78,7 +78,7 @@ pp.updateContext = function(prevType) { // Token-specific context update code tt.parenR.updateContext = tt.braceR.updateContext = function() { - if (this.context.length == 1) { + if (this.context.length === 1) { this.exprAllowed = true return } @@ -111,6 +111,7 @@ tt.incDec.updateContext = function() { tt._function.updateContext = tt._class.updateContext = function(prevType) { if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && + !(prevType === tt._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) this.context.push(types.f_expr) else @@ -127,7 +128,7 @@ tt.backQuote.updateContext = function() { } tt.star.updateContext = function(prevType) { - if (prevType == tt._function) { + if (prevType === tt._function) { let index = this.context.length - 1 if (this.context[index] === types.f_expr) this.context[index] = types.f_expr_gen @@ -139,9 +140,9 @@ tt.star.updateContext = function(prevType) { tt.name.updateContext = function(prevType) { let allowed = false - if (this.options.ecmaVersion >= 6) { - if (this.value == "of" && !this.exprAllowed || - this.value == "yield" && this.inGeneratorContext()) + if (this.options.ecmaVersion >= 6 && prevType !== tt.dot) { + if (this.value === "of" && !this.exprAllowed || + this.value === "yield" && this.inGeneratorContext()) allowed = true } this.exprAllowed = allowed diff --git a/tools/tests/apps/modules/imports/links/acorn/src/tokenize.js b/tools/tests/apps/modules/imports/links/acorn/src/tokenize.js index 3afb8386f2..835fdcd962 100644 --- a/tools/tests/apps/modules/imports/links/acorn/src/tokenize.js +++ b/tools/tests/apps/modules/imports/links/acorn/src/tokenize.js @@ -28,7 +28,9 @@ const pp = Parser.prototype // Move to the next token -pp.next = function() { +pp.next = function(ignoreEscapeSequenceInKeyword) { + if (!ignoreEscapeSequenceInKeyword && this.type.keyword && this.containsEsc) + this.raiseRecoverable(this.start, "Escape sequence in keyword " + this.type.keyword) if (this.options.onToken) this.options.onToken(new Token(this)) @@ -219,7 +221,7 @@ pp.readToken_mult_modulo_exp = function(code) { // '%*' let tokentype = code === 42 ? tt.star : tt.modulo // exponentiation operator ** and **= - if (this.options.ecmaVersion >= 7 && code == 42 && next === 42) { + if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) { ++size tokentype = tt.starstar next = this.input.charCodeAt(this.pos + 2) @@ -245,7 +247,7 @@ pp.readToken_caret = function() { // '^' pp.readToken_plus_min = function(code) { // '+-' let next = this.input.charCodeAt(this.pos + 1) if (next === code) { - if (next == 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 62 && + if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 && (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) { // A `-->` line comment this.skipLineComment(3) @@ -266,8 +268,8 @@ pp.readToken_lt_gt = function(code) { // '<>' if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) return this.finishOp(tt.bitShift, size) } - if (next == 33 && code == 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 45 && - this.input.charCodeAt(this.pos + 3) == 45) { + if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 && + this.input.charCodeAt(this.pos + 3) === 45) { // `