diff --git a/AUTHORS b/AUTHORS index 0fec871d9..6195b1ae8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,6 @@ List of Acorn contributors. Updated before every release. +Adam Walsh Adrian Heine Adrian Rakovsky Alistair Braidwood @@ -18,8 +19,10 @@ Charles Hughes Charmander Chris McKnight Conrad Irwin +Cyril Auburtin Daniel Tschinder David Bonnet +dnalborczyk Domenico Matteo ehmicky Eugene Obrezkov @@ -27,6 +30,7 @@ Fabien LOISON Felix Maier Forbes Lindesay Gilad Peleg +Huáng Jùnliàng impinball Ingvar Stepanyan Jackson Ray Hamilton @@ -35,6 +39,7 @@ Jiaxing Wang Joel Kemp Johannes Herr John-David Dalton +Jordan Gensler Jordan Klassen Jürg Lehni Kai Cataldo @@ -64,7 +69,9 @@ Olivier Thomann Oskar Schöldström Paul Harper Peter Rust +piotr PlNG +Praveen N Prayag Verma ReadmeCritic r-e-d @@ -75,9 +82,14 @@ Sebastian McKenzie Shahar Soel Sheel Bedi Simen Bekkhus +susiwen +susiwen8 Teddy Katz Timothy Gu Toru Nagashima +tuesmiddt Victor Homyakov +Vladislav Tupikin Wexpo Lyu zsjforcn +龙腾道 diff --git a/acorn-loose/CHANGELOG.md b/acorn-loose/CHANGELOG.md index 495184ece..83d191ec1 100644 --- a/acorn-loose/CHANGELOG.md +++ b/acorn-loose/CHANGELOG.md @@ -1,6 +1,12 @@ +## 7.0.0 (2019-08-12) + +### 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). + ## 6.1.0 (2019-07-04) -## New features +### New features Support bigint syntax. diff --git a/acorn-loose/README.md b/acorn-loose/README.md index 3d8f5bac5..4641bd4fd 100644 --- a/acorn-loose/README.md +++ b/acorn-loose/README.md @@ -60,3 +60,7 @@ take the **`LooseParser`** class exported by the module, and call its static `extend` method with one or more plugins to get a customized parser class. The class has a static `parse` method that acts like the top-level `parse` method. + +**isDummy**`(node)` takes a `Node` and returns `true` if it is a dummy node +inserted by the parser. The function performs a simple equality check on the +node's name. diff --git a/acorn-loose/package.json b/acorn-loose/package.json index 5adabfc9e..4beee085e 100644 --- a/acorn-loose/package.json +++ b/acorn-loose/package.json @@ -4,10 +4,10 @@ "homepage": "https://github.com/acornjs/acorn", "main": "dist/acorn-loose.js", "module": "dist/acorn-loose.mjs", - "version": "6.1.0", + "version": "7.0.0", "engines": {"node": ">=0.4.0"}, "dependencies": { - "acorn": "^6.2.0" + "acorn": "^7.0.0" }, "maintainers": [ { diff --git a/acorn-loose/src/index.js b/acorn-loose/src/index.js index 903781c5f..cfa0b497b 100644 --- a/acorn-loose/src/index.js +++ b/acorn-loose/src/index.js @@ -36,6 +36,7 @@ import "./statement" import "./expression" export {LooseParser} from "./state" +export {isDummy} from "./parseutil" defaultOptions.tabSize = 4 diff --git a/acorn-loose/src/parseutil.js b/acorn-loose/src/parseutil.js index 4501e2d46..534efd4b0 100644 --- a/acorn-loose/src/parseutil.js +++ b/acorn-loose/src/parseutil.js @@ -1 +1,3 @@ -export function isDummy(node) { return node.name === "✖" } +export const dummyValue = "✖" + +export function isDummy(node) { return node.name === dummyValue } diff --git a/acorn-loose/src/state.js b/acorn-loose/src/state.js index 52887231d..322306fe4 100644 --- a/acorn-loose/src/state.js +++ b/acorn-loose/src/state.js @@ -1,4 +1,5 @@ import {Parser, SourceLocation, tokTypes as tt, Node, lineBreak, isNewLine} from "acorn" +import {dummyValue} from "./parseutil" function noop() {} @@ -63,13 +64,13 @@ export class LooseParser { dummyIdent() { let dummy = this.dummyNode("Identifier") - dummy.name = "✖" + dummy.name = dummyValue return dummy } dummyString() { let dummy = this.dummyNode("Literal") - dummy.value = dummy.raw = "✖" + dummy.value = dummy.raw = dummyValue return dummy } diff --git a/acorn-loose/src/tokenize.js b/acorn-loose/src/tokenize.js index e838b48d8..da20b7daf 100644 --- a/acorn-loose/src/tokenize.js +++ b/acorn-loose/src/tokenize.js @@ -1,5 +1,6 @@ import {tokTypes as tt, Token, isNewLine, SourceLocation, getLineInfo, lineBreakG} from "acorn" import {LooseParser} from "./state" +import {dummyValue} from "./parseutil" const lp = LooseParser.prototype @@ -73,7 +74,7 @@ lp.readToken = function() { throw e } this.resetTo(pos) - if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"} + if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: dummyValue} if (replace) { if (this.options.locations) replace.loc = new SourceLocation( diff --git a/acorn-walk/CHANGELOG.md b/acorn-walk/CHANGELOG.md index c02dbd7dd..89114970b 100644 --- a/acorn-walk/CHANGELOG.md +++ b/acorn-walk/CHANGELOG.md @@ -1,3 +1,21 @@ +## 7.1.1 (2020-02-13) + +### Bug fixes + +Clean up the type definitions to actually work well with the main parser. + +## 7.1.0 (2020-02-11) + +### New features + +Add a TypeScript definition file for the library. + +## 7.0.0 (2017-08-12) + +### New features + +Support walking `ImportExpression` nodes. + ## 6.2.0 (2017-07-04) ### New features diff --git a/acorn-walk/dist/walk.d.ts b/acorn-walk/dist/walk.d.ts new file mode 100644 index 000000000..00cc005f1 --- /dev/null +++ b/acorn-walk/dist/walk.d.ts @@ -0,0 +1,112 @@ +import {Node} from 'acorn'; + +declare module "acorn-walk" { + type FullWalkerCallback = ( + node: Node, + state: TState, + type: string + ) => void; + + type FullAncestorWalkerCallback = ( + node: Node, + state: TState | Node[], + ancestors: Node[], + type: string + ) => void; + type WalkerCallback = (node: Node, state: TState) => void; + + type SimpleWalkerFn = ( + node: Node, + state: TState + ) => void; + + type AncestorWalkerFn = ( + node: Node, + state: TState| Node[], + ancestors: Node[] + ) => void; + + type RecursiveWalkerFn = ( + node: Node, + state: TState, + callback: WalkerCallback + ) => void; + + type SimpleVisitors = { + [type: string]: SimpleWalkerFn + }; + + type AncestorVisitors = { + [type: string]: AncestorWalkerFn + }; + + type RecursiveVisitors = { + [type: string]: RecursiveWalkerFn + }; + + type FindPredicate = (type: string, node: Node) => boolean; + + interface Found { + node: Node, + state: TState + } + + export function simple( + node: Node, + visitors: SimpleVisitors, + base?: RecursiveVisitors, + state?: TState + ): void; + + export function ancestor( + node: Node, + visitors: AncestorVisitors, + base?: RecursiveVisitors, + state?: TState + ): void; + + export function recursive( + node: Node, + state: TState, + functions: RecursiveVisitors, + base?: RecursiveVisitors + ): void; + + export function full( + node: Node, + callback: FullWalkerCallback, + base?: RecursiveVisitors, + state?: TState + ): void; + + export function fullAncestor( + node: Node, + callback: FullAncestorWalkerCallback, + base?: RecursiveVisitors, + state?: TState + ): void; + + export function make( + functions: RecursiveVisitors, + base?: RecursiveVisitors + ): RecursiveVisitors; + + export function findNodeAt( + node: Node, + start: number | undefined, + end?: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState + ): Found | undefined; + + export function findNodeAround( + node: Node, + start: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState + ): Found | undefined; + + export const findNodeAfter: typeof findNodeAround; +} diff --git a/acorn-walk/package.json b/acorn-walk/package.json index 239e6c729..a66ca892c 100644 --- a/acorn-walk/package.json +++ b/acorn-walk/package.json @@ -3,8 +3,9 @@ "description": "ECMAScript (ESTree) AST walker", "homepage": "https://github.com/acornjs/acorn", "main": "dist/walk.js", + "types": "dist/walk.d.ts", "module": "dist/walk.mjs", - "version": "6.2.0", + "version": "7.1.1", "engines": {"node": ">=0.4.0"}, "maintainers": [ { diff --git a/acorn-walk/src/index.js b/acorn-walk/src/index.js index b416b35bf..d95af12be 100644 --- a/acorn-walk/src/index.js +++ b/acorn-walk/src/index.js @@ -28,7 +28,7 @@ export function simple(node, visitors, baseVisitor, state, override) { // An ancestor walk keeps an array of ancestor nodes (including the // current node) and passes them to the callback as third parameter // (and also as state parameter when no other state is present). -export function ancestor(node, visitors, baseVisitor, state) { +export function ancestor(node, visitors, baseVisitor, state, override) { let ancestors = [] if (!baseVisitor) baseVisitor = base ;(function c(node, st, override) { @@ -38,7 +38,7 @@ export function ancestor(node, visitors, baseVisitor, state) { baseVisitor[type](node, st, c) if (found) found(node, st || ancestors, ancestors) if (isNew) ancestors.pop() - })(node, state) + })(node, state, override) } // A recursive walk is one where your functions override the default @@ -363,7 +363,7 @@ base.ImportDeclaration = (node, st, c) => { base.ImportExpression = (node, st, c) => { c(node.source, st, "Expression") } -base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = base.Import = ignore +base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore base.TaggedTemplateExpression = (node, st, c) => { c(node.tag, st, "Expression") diff --git a/acorn/CHANGELOG.md b/acorn/CHANGELOG.md index 2d6115e2d..32f5ce8f3 100644 --- a/acorn/CHANGELOG.md +++ b/acorn/CHANGELOG.md @@ -1,3 +1,25 @@ +## 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 @@ -30,9 +52,9 @@ Disallow binding `let` in patterns. ### New features -Support bigint syntax with `ecmaVersion` >= 10. +Support bigint syntax with `ecmaVersion` >= 11. -Support dynamic `import` syntax with `ecmaVersion` >= 10. +Support dynamic `import` syntax with `ecmaVersion` >= 11. Upgrade to Unicode version 12. diff --git a/acorn/README.md b/acorn/README.md index 9b7c0badb..585f2736f 100644 --- a/acorn/README.md +++ b/acorn/README.md @@ -52,9 +52,10 @@ 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) or 10 (2019, partial - support). This influences support for strict mode, the set of - reserved words, and support for new syntax features. Default is 10. + 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 diff --git a/acorn/dist/acorn.d.ts b/acorn/dist/acorn.d.ts index c68e23912..bda5f803c 100644 --- a/acorn/dist/acorn.d.ts +++ b/acorn/dist/acorn.d.ts @@ -12,7 +12,7 @@ declare namespace acorn { } interface Options { - ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 2015 | 2016 | 2017 | 2018 | 2019 + ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 sourceType?: 'script' | 'module' onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void diff --git a/acorn/package.json b/acorn/package.json index 4c4968f41..6a8f03607 100644 --- a/acorn/package.json +++ b/acorn/package.json @@ -3,8 +3,9 @@ "description": "ECMAScript parser", "homepage": "https://github.com/acornjs/acorn", "main": "dist/acorn.js", + "types": "dist/acorn.d.ts", "module": "dist/acorn.mjs", - "version": "7.0.0", + "version": "7.1.1", "engines": {"node": ">=0.4.0"}, "maintainers": [ { diff --git a/acorn/src/expression.js b/acorn/src/expression.js index 8069a2027..71b02016f 100644 --- a/acorn/src/expression.js +++ b/acorn/src/expression.js @@ -44,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 } @@ -111,12 +113,11 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { else this.exprAllowed = false } - let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldShorthandAssign = -1 + let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1 if (refDestructuringErrors) { oldParenAssign = refDestructuringErrors.parenthesizedAssign oldTrailingComma = refDestructuringErrors.trailingComma - oldShorthandAssign = refDestructuringErrors.shorthandAssign - refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.shorthandAssign = -1 + refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = -1 } else { refDestructuringErrors = new DestructuringErrors ownDestructuringErrors = true @@ -131,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) @@ -142,7 +146,6 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { } if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign if (oldTrailingComma > -1) refDestructuringErrors.trailingComma = oldTrailingComma - if (oldShorthandAssign > -1) refDestructuringErrors.shorthandAssign = oldShorthandAssign return left } @@ -247,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 @@ -333,7 +336,7 @@ pp.parseExprAtom = function(refDestructuringErrors) { // 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") @@ -546,6 +549,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)) { @@ -623,7 +627,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) @@ -929,7 +933,7 @@ pp.parseIdent = function(liberal, isBinding) { } else { this.unexpected() } - this.next() + this.next(!!liberal) this.finishNode(node, "Identifier") if (!liberal) { this.checkUnreserved(node) @@ -961,6 +965,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/acorn/src/index.js b/acorn/src/index.js index 7c33e7fdd..f466a3b9f 100644 --- a/acorn/src/index.js +++ b/acorn/src/index.js @@ -22,17 +22,58 @@ import "./expression" import "./location" import "./scope" -export {Parser} 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" - -export const version = "7.0.0" +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 = "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 diff --git a/acorn/src/regexp.js b/acorn/src/regexp.js index ee19bcf55..605bce520 100644 --- a/acorn/src/regexp.js +++ b/acorn/src/regexp.js @@ -50,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) { @@ -59,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 @@ -152,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") } } @@ -837,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. @@ -885,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/acorn/src/tokenize.js b/acorn/src/tokenize.js index f9f6b2f6f..835fdcd96 100644 --- a/acorn/src/tokenize.js +++ b/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)) @@ -445,7 +447,6 @@ pp.readNumber = function(startsWithDot) { if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number") let octal = this.pos - start >= 2 && this.input.charCodeAt(start) === 48 if (octal && this.strict) this.raise(start, "Invalid number") - if (octal && /[89]/.test(this.input.slice(start, this.pos))) octal = false let next = this.input.charCodeAt(this.pos) if (!octal && !startsWithDot && this.options.ecmaVersion >= 11 && next === 110) { let str = this.input.slice(start, this.pos) @@ -454,6 +455,7 @@ pp.readNumber = function(startsWithDot) { if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.pos, "Identifier directly after number") return this.finishToken(tt.num, val) } + if (octal && /[89]/.test(this.input.slice(start, this.pos))) octal = false if (next === 46 && !octal) { // '.' ++this.pos this.readInt(10) @@ -628,6 +630,18 @@ pp.readEscapedChar = function(inTemplate) { case 10: // ' \n' if (this.options.locations) { this.lineStart = this.pos; ++this.curLine } return "" + case 56: + case 57: + if (inTemplate) { + const codePos = this.pos - 1 + + this.invalidStringToken( + codePos, + "Invalid escape sequence in template string" + ) + + return null + } default: if (ch >= 48 && ch <= 55) { let octalStr = this.input.substr(this.pos - 1, 3).match(/^[0-7]+/)[0] @@ -707,7 +721,6 @@ pp.readWord = function() { let word = this.readWord1() let type = tt.name if (this.keywords.test(word)) { - if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword " + word) type = keywordTypes[word] } return this.finishToken(type, word) diff --git a/bin/run_test262.js b/bin/run_test262.js index c540507d7..6a2f9b05c 100644 --- a/bin/run_test262.js +++ b/bin/run_test262.js @@ -10,9 +10,12 @@ const unsupportedFeatures = [ "class-static-fields-private", "class-static-fields-public", "class-static-methods-private", + "coalesce-expression", "export-star-as-namespace-from-module", "import.meta", - "numeric-separator-literal" + "numeric-separator-literal", + "optional-chaining", + "top-level-await" ]; run( diff --git a/logo.svg b/logo.svg new file mode 100644 index 000000000..8290ab83a --- /dev/null +++ b/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/package.json b/package.json index eb0dd1c73..6d06debf8 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "eslint-plugin-standard": "^3.0.1", "rollup": "^1.7.0", "rollup-plugin-buble": "^0.19.0", - "test262": "git+https://github.com/tc39/test262.git#de567d3aa5de4eaa11e00131d26b9fe77997dfb0", + "test262": "git+https://github.com/tc39/test262.git#09380a4ae412e986ea39eb7163f5a6b3e5b04bbc", "test262-parser-runner": "^0.5.0", "test262-stream": "^1.2.1", "unicode-12.0.0": "^0.7.9" diff --git a/test/tests-asyncawait.js b/test/tests-asyncawait.js index 77de3c8b8..aebc6dc73 100644 --- a/test/tests-asyncawait.js +++ b/test/tests-asyncawait.js @@ -3523,3 +3523,5 @@ test( test("({ async delete() {} })", {}, {ecmaVersion: 8}) testFail("abc: async function a() {}", "Unexpected token (1:5)", {ecmaVersion: 8}) + +test("(async() => { await 4 ** 2 })()", {}, {ecmaVersion: 8}) diff --git a/test/tests-harmony.js b/test/tests-harmony.js index ade46a220..c6b58dd5c 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -16512,3 +16512,7 @@ test("let x = 1; x = 2", {}, {ecmaVersion: 6}) test("function *f2() { () => yield / 1 }", {}, {ecmaVersion: 6}) test("({ a = 42, b: c.d } = e)", {}, {ecmaVersion: 6}) + +testFail("({ a = 42, b: c = d })", "Shorthand property assignments are valid only in destructuring patterns (1:5)", {ecmaVersion: 6}) + +test("({ __proto__: x, __proto__: y, __proto__: z }) => {}", {}, {ecmaVersion: 6}) diff --git a/test/tests-regexp.js b/test/tests-regexp.js index 6c4719486..804e00a59 100644 --- a/test/tests-regexp.js +++ b/test/tests-regexp.js @@ -1049,6 +1049,7 @@ test("/[\\d][\\12-\\14]{1,}[^\\d]/", {}, { ecmaVersion: 2015 }) testFail("/[\\d][\\12-\\14]{1,}[^\\d]/u", "Invalid regular expression flag (1:1)", { ecmaVersion: 5 }) testFail("/[\\d][\\12-\\14]{1,}[^\\d]/u", "Invalid regular expression: /[\\d][\\12-\\14]{1,}[^\\d]/: Invalid class escape (1:1)", { ecmaVersion: 2015 }) test("/([a ]\\b)*\\b/", {}, { ecmaVersion: 5 }) +test("/[x-*]/u".replace("*", String.fromCharCode(0xd800)), {}, {ecmaVersion: 6}) /* // This is test case generator.