Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: acornjs/acorn
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8.8.2
Choose a base ref
...
head repository: acornjs/acorn
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8.9.0
Choose a head ref
  • 20 commits
  • 20 files changed
  • 7 contributors

Commits on Feb 2, 2023

  1. Properly forbid dynamic import after 'new'

    FIX: Forbid dynamic import after `new`, even when part of a member expression.
    
    Closes #1192
    marijnh committed Feb 2, 2023
    Copy the full SHA
    3d78c21 View commit details
  2. Please linter

    marijnh committed Feb 2, 2023
    Copy the full SHA
    7373a7e View commit details

Commits on Feb 8, 2023

  1. chore: add unsupport feature

    eryue0220 authored and marijnh committed Feb 8, 2023
    Copy the full SHA
    8a08952 View commit details

Commits on Feb 13, 2023

  1. Copy the full SHA
    b3587a1 View commit details

Commits on Feb 24, 2023

  1. Copy the full SHA
    f89248e View commit details

Commits on Feb 27, 2023

  1. Copy the full SHA
    5558152 View commit details

Commits on Mar 3, 2023

  1. Copy the full SHA
    82dca36 View commit details

Commits on Mar 16, 2023

  1. Copy the full SHA
    ed1425a View commit details

Commits on Mar 28, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f7a1854 View commit details

Commits on Apr 14, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e68e6e6 View commit details

Commits on Apr 29, 2023

  1. Copy the full SHA
    3ef09ce View commit details

Commits on Apr 30, 2023

  1. Add proper .d.mts types for acorn-walk

    Andarist authored and marijnh committed Apr 30, 2023
    Copy the full SHA
    d93dffc View commit details

Commits on May 1, 2023

  1. Copy the full SHA
    544dc38 View commit details

Commits on May 6, 2023

  1. Copy the full SHA
    96c721d View commit details

Commits on May 20, 2023

  1. Update unicode-property-data.js

    FIX: Add Unicode properties for ES2023.
    ota-meshi authored May 20, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    bb9de99 View commit details

Commits on May 24, 2023

  1. Add support for ES2024 Regex v flag

    ota-meshi authored and marijnh committed May 24, 2023
    Copy the full SHA
    1f8c7f1 View commit details
  2. Use integers as return values in regexp set parsing

    And make some random code style changes
    
    FEATURE: Add support for the `v` flag to regular expressions.
    
    Closes #1216
    marijnh committed May 24, 2023
    Copy the full SHA
    fb4c582 View commit details

Commits on Jun 14, 2023

  1. chore: bump deps, test262

    dnalborczyk committed Jun 14, 2023
    Copy the full SHA
    3d90580 View commit details

Commits on Jun 16, 2023

  1. Copy the full SHA
    8906b82 View commit details
  2. Mark version 8.9.0

    marijnh committed Jun 16, 2023
    Copy the full SHA
    a354538 View commit details
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -8,4 +8,6 @@
/acorn-walk/dist
/yarn.lock
!/acorn/dist/acorn.d.ts
!/acorn/dist/acorn.mjs.d.ts
!/acorn/dist/acorn.d.mts
!/acorn-walk/dist/walk.d.ts
!/acorn-walk/dist/walk.d.mts
7 changes: 6 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ Domenico Matteo
ehmicky
elixiao
ericrannaud
eryue0220
Eugene Obrezkov
Fabien LOISON
Felix Maier
@@ -70,6 +71,7 @@ luckyzeng
Marek
Marijn Haverbeke
Martin Carlberg
Mateusz Burzyński
Mat Garcia
Mathias Bynens
Mathieu 'p01' Henri
@@ -85,6 +87,7 @@ Nicholas C. Zakas
Nick Fitzgerald
Olivier Thomann
Oskar Schöldström
ota-meshi
Paul Harper
peakchen90
Peter Rust
@@ -114,13 +117,15 @@ Tim van der Lippe
Tony Ross
Toru Nagashima
tuesmiddt
tyrealhu
Victor Homyakov
Vladislav Tupikin
Wexpo Lyu
yosuke ota
Yosuke Ota
Žiga Zupančič
zsjforcn
就是喜欢陈粒
成仕伟
星灵
胡文彬
龙腾道
1 change: 1 addition & 0 deletions acorn-walk/dist/walk.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './walk.js'
12 changes: 12 additions & 0 deletions acorn/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 8.9.0 (2023-06-16)

### Bug fixes

Forbid dynamic import after `new`, even when part of a member expression.

### New features

Add Unicode properties for ES2023.

Add support for the `v` flag to regular expressions.

## 8.8.2 (2023-01-23)

### Bug fixes
9 changes: 5 additions & 4 deletions acorn/README.md
Original file line number Diff line number Diff line change
@@ -96,10 +96,11 @@ required):
(when `sourceType` is not `"module"`).

- **allowAwaitOutsideFunction**: If `false`, `await` expressions can
only appear inside `async` functions. Defaults to `true` for
`ecmaVersion` 2022 and later, `false` for lower versions. Setting this option to
`true` allows to have top-level `await` expressions. They are
still not allowed in non-`async` functions, though.
only appear inside `async` functions. Defaults to `true` in modules
for `ecmaVersion` 2022 and later, `false` for lower versions.
Setting this option to `true` allows to have top-level `await`
expressions. They are still not allowed in non-`async` functions,
though.

- **allowSuperOutsideMethod**: By default, `super` outside a method
raises an error. Set this to `true` to accept such code.
26 changes: 26 additions & 0 deletions acorn/dist/acorn.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export {
Node,
Parser,
Position,
SourceLocation,
TokContext,
Token,
TokenType,
defaultOptions,
getLineInfo,
isIdentifierChar,
isIdentifierStart,
isNewLine,
lineBreak,
lineBreakG,
parse,
parseExpressionAt,
tokContexts,
tokTypes,
tokenizer,
version,
AbstractToken,
Comment,
Options,
ecmaVersion,
} from "./acorn.js";
40 changes: 40 additions & 0 deletions acorn/dist/acorn.d.ts
Original file line number Diff line number Diff line change
@@ -249,4 +249,44 @@ declare namespace acorn {
const lineBreakG: RegExp

const version: string

const nonASCIIwhitespace: RegExp

const keywordTypes: {
_break: TokenType
_case: TokenType
_catch: TokenType
_continue: TokenType
_debugger: TokenType
_default: TokenType
_do: TokenType
_else: TokenType
_finally: TokenType
_for: TokenType
_function: TokenType
_if: TokenType
_return: TokenType
_switch: TokenType
_throw: TokenType
_try: TokenType
_var: TokenType
_const: TokenType
_while: TokenType
_with: TokenType
_new: TokenType
_this: TokenType
_super: TokenType
_class: TokenType
_extends: TokenType
_export: TokenType
_import: TokenType
_null: TokenType
_true: TokenType
_false: TokenType
_in: TokenType
_instanceof: TokenType
_typeof: TokenType
_void: TokenType
_delete: TokenType
}
}
2 changes: 0 additions & 2 deletions acorn/dist/acorn.mjs.d.ts

This file was deleted.

2 changes: 1 addition & 1 deletion acorn/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
],
"./package.json": "./package.json"
},
"version": "8.8.2",
"version": "8.9.0",
"engines": {
"node": ">=0.4.0"
},
106 changes: 66 additions & 40 deletions acorn/src/expression.js
Original file line number Diff line number Diff line change
@@ -324,6 +324,14 @@ pp.parseSubscripts = function(base, startPos, startLoc, noCalls, forInit) {
}
}

pp.shouldParseAsyncArrow = function() {
return !this.canInsertSemicolon() && this.eat(tt.arrow)
}

pp.parseSubscriptAsyncArrow = function(startPos, startLoc, exprList, forInit) {
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true, forInit)
}

pp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
let optionalSupported = this.options.ecmaVersion >= 11
let optional = optionalSupported && this.eat(tt.questionDot)
@@ -352,15 +360,15 @@ pp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow,
this.awaitPos = 0
this.awaitIdentPos = 0
let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors)
if (maybeAsyncArrow && !optional && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
if (maybeAsyncArrow && !optional && this.shouldParseAsyncArrow()) {
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, forInit)
return this.parseSubscriptAsyncArrow(startPos, startLoc, exprList, forInit)
}
this.checkExpressionErrors(refDestructuringErrors, true)
this.yieldPos = oldYieldPos || this.yieldPos
@@ -390,7 +398,7 @@ pp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow,
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.

pp.parseExprAtom = function(refDestructuringErrors, forInit) {
pp.parseExprAtom = function(refDestructuringErrors, forInit, forNew) {
// 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()
@@ -491,31 +499,34 @@ pp.parseExprAtom = function(refDestructuringErrors, forInit) {

case tt._import:
if (this.options.ecmaVersion >= 11) {
return this.parseExprImport()
return this.parseExprImport(forNew)
} else {
return this.unexpected()
}

default:
this.unexpected()
return this.parseExprAtomDefault()
}
}

pp.parseExprImport = function() {
pp.parseExprAtomDefault = function() {
this.unexpected()
}

pp.parseExprImport = function(forNew) {
const node = this.startNode()

// Consume `import` as an identifier for `import.meta`.
// Because `this.parseIdent(true)` doesn't check escape sequences, it needs the check of `this.containsEsc`.
if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword import")
const meta = this.parseIdent(true)

switch (this.type) {
case tt.parenL:
if (this.type === tt.parenL && !forNew) {
return this.parseDynamicImport(node)
case tt.dot:
} else if (this.type === tt.dot) {
node.meta = meta
return this.parseImportMeta(node)
default:
} else {
this.unexpected()
}
}
@@ -571,6 +582,10 @@ pp.parseParenExpression = function() {
return val
}

pp.shouldParseArrow = function(exprList) {
return !this.canInsertSemicolon()
}

pp.parseParenAndDistinguishExpression = function(canBeArrow, forInit) {
let startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8
if (this.options.ecmaVersion >= 6) {
@@ -590,7 +605,12 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow, forInit) {
} else if (this.type === tt.ellipsis) {
spreadStart = this.start
exprList.push(this.parseParenItem(this.parseRestBinding()))
if (this.type === tt.comma) this.raise(this.start, "Comma is not permitted after the rest element")
if (this.type === tt.comma) {
this.raiseRecoverable(
this.start,
"Comma is not permitted after the rest element"
)
}
break
} else {
exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem))
@@ -599,7 +619,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow, forInit) {
let innerEndPos = this.lastTokEnd, innerEndLoc = this.lastTokEndLoc
this.expect(tt.parenR)

if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
if (canBeArrow && this.shouldParseArrow(exprList) && this.eat(tt.arrow)) {
this.checkPatternErrors(refDestructuringErrors, false)
this.checkYieldAwaitInDefaultParams()
this.yieldPos = oldYieldPos
@@ -665,11 +685,8 @@ pp.parseNew = function() {
this.raiseRecoverable(node.start, "'new.target' can only be used in functions and class static block")
return this.finishNode(node, "MetaProperty")
}
let startPos = this.start, startLoc = this.startLoc, isImport = this.type === tt._import
node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true, false)
if (isImport && node.callee.type === "ImportExpression") {
this.raise(startPos, "Cannot use new with import()")
}
let startPos = this.start, startLoc = this.startLoc
node.callee = this.parseSubscripts(this.parseExprAtom(null, false, true), startPos, startLoc, true, false)
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")
@@ -746,7 +763,7 @@ pp.parseProperty = function(isPattern, refDestructuringErrors) {
if (isPattern) {
prop.argument = this.parseIdent(false)
if (this.type === tt.comma) {
this.raise(this.start, "Comma is not permitted after the rest element")
this.raiseRecoverable(this.start, "Comma is not permitted after the rest element")
}
return this.finishNode(prop, "RestElement")
}
@@ -782,6 +799,23 @@ pp.parseProperty = function(isPattern, refDestructuringErrors) {
return this.finishNode(prop, "Property")
}

pp.parseGetterSetter = function(prop) {
prop.kind = prop.key.name
this.parsePropertyName(prop)
prop.value = this.parseMethod(false)
let paramCount = prop.kind === "get" ? 0 : 1
if (prop.value.params.length !== paramCount) {
let start = prop.value.start
if (prop.kind === "get")
this.raiseRecoverable(start, "getter should have no params")
else
this.raiseRecoverable(start, "setter should have exactly one param")
} else {
if (prop.kind === "set" && prop.value.params[0].type === "RestElement")
this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params")
}
}

pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc) {
if ((isGenerator || isAsync) && this.type === tt.colon)
this.unexpected()
@@ -799,20 +833,7 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos
(prop.key.name === "get" || prop.key.name === "set") &&
(this.type !== tt.comma && this.type !== tt.braceR && this.type !== tt.eq)) {
if (isGenerator || isAsync) this.unexpected()
prop.kind = prop.key.name
this.parsePropertyName(prop)
prop.value = this.parseMethod(false)
let paramCount = prop.kind === "get" ? 0 : 1
if (prop.value.params.length !== paramCount) {
let start = prop.value.start
if (prop.kind === "get")
this.raiseRecoverable(start, "getter should have no params")
else
this.raiseRecoverable(start, "setter should have exactly one param")
} else {
if (prop.kind === "set" && prop.value.params[0].type === "RestElement")
this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params")
}
this.parseGetterSetter(prop)
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
if (isGenerator || isAsync) this.unexpected()
this.checkUnreserved(prop.key)
@@ -1012,6 +1033,18 @@ pp.checkUnreserved = function({start, end, name}) {
// identifiers.

pp.parseIdent = function(liberal) {
let node = this.parseIdentNode()
this.next(!!liberal)
this.finishNode(node, "Identifier")
if (!liberal) {
this.checkUnreserved(node)
if (node.name === "await" && !this.awaitIdentPos)
this.awaitIdentPos = node.start
}
return node
}

pp.parseIdentNode = function() {
let node = this.startNode()
if (this.type === tt.name) {
node.name = this.value
@@ -1023,19 +1056,12 @@ pp.parseIdent = function(liberal) {
// But there is no chance to pop the context if the keyword is consumed as an identifier such as a property name.
// If the previous token is a dot, this does not apply because the context-managing code already ignored the keyword
if ((node.name === "class" || node.name === "function") &&
(this.lastTokEnd !== this.lastTokStart + 1 || this.input.charCodeAt(this.lastTokStart) !== 46)) {
(this.lastTokEnd !== this.lastTokStart + 1 || this.input.charCodeAt(this.lastTokStart) !== 46)) {
this.context.pop()
}
} else {
this.unexpected()
}
this.next(!!liberal)
this.finishNode(node, "Identifier")
if (!liberal) {
this.checkUnreserved(node)
if (node.name === "await" && !this.awaitIdentPos)
this.awaitIdentPos = node.start
}
return node
}

2 changes: 1 addition & 1 deletion acorn/src/index.js
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ import {isIdentifierChar, isIdentifierStart} from "./identifier.js"
import {Token} from "./tokenize.js"
import {isNewLine, lineBreak, lineBreakG, nonASCIIwhitespace} from "./whitespace.js"

export const version = "8.8.2"
export const version = "8.9.0"
export {
Parser,
defaultOptions,
14 changes: 9 additions & 5 deletions acorn/src/lval.js
Original file line number Diff line number Diff line change
@@ -141,7 +141,7 @@ pp.parseBindingAtom = function() {
return this.parseIdent()
}

pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
pp.parseBindingList = function(close, allowEmpty, allowTrailingComma, allowModifiers) {
let elts = [], first = true
while (!this.eat(close)) {
if (first) first = false
@@ -154,18 +154,22 @@ pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
let rest = this.parseRestBinding()
this.parseBindingListItem(rest)
elts.push(rest)
if (this.type === tt.comma) this.raise(this.start, "Comma is not permitted after the rest element")
if (this.type === tt.comma) this.raiseRecoverable(this.start, "Comma is not permitted after the rest element")
this.expect(close)
break
} else {
let elem = this.parseMaybeDefault(this.start, this.startLoc)
this.parseBindingListItem(elem)
elts.push(elem)
elts.push(this.parseAssignableListItem(allowModifiers))
}
}
return elts
}

pp.parseAssignableListItem = function(allowModifiers) {
let elem = this.parseMaybeDefault(this.start, this.startLoc)
this.parseBindingListItem(elem)
return elem
}

pp.parseBindingListItem = function(param) {
return param
}
296 changes: 274 additions & 22 deletions acorn/src/regexp.js

Large diffs are not rendered by default.

176 changes: 108 additions & 68 deletions acorn/src/statement.js
Original file line number Diff line number Diff line change
@@ -335,6 +335,16 @@ pp.parseThrowStatement = function(node) {

const empty = []

pp.parseCatchClauseParam = function() {
const param = this.parseBindingAtom()
let simple = param.type === "Identifier"
this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0)
this.checkLValPattern(param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL)
this.expect(tt.parenR)

return param
}

pp.parseTryStatement = function(node) {
this.next()
node.block = this.parseBlock()
@@ -343,11 +353,7 @@ pp.parseTryStatement = function(node) {
let clause = this.startNode()
this.next()
if (this.eat(tt.parenL)) {
clause.param = this.parseBindingAtom()
let simple = clause.param.type === "Identifier"
this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0)
this.checkLValPattern(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL)
this.expect(tt.parenR)
clause.param = this.parseCatchClauseParam()
} else {
if (this.options.ecmaVersion < 10) this.unexpected()
clause.param = null
@@ -363,9 +369,9 @@ pp.parseTryStatement = function(node) {
return this.finishNode(node, "TryStatement")
}

pp.parseVarStatement = function(node, kind) {
pp.parseVarStatement = function(node, kind, allowMissingInitializer) {
this.next()
this.parseVar(node, false, kind)
this.parseVar(node, false, kind, allowMissingInitializer)
this.semicolon()
return this.finishNode(node, "VariableDeclaration")
}
@@ -489,17 +495,17 @@ pp.parseForIn = function(node, init) {

// Parse a list of variable declarations.

pp.parseVar = function(node, isFor, kind) {
pp.parseVar = function(node, isFor, kind, allowMissingInitializer) {
node.declarations = []
node.kind = kind
for (;;) {
let decl = this.startNode()
this.parseVarId(decl, kind)
if (this.eat(tt.eq)) {
decl.init = this.parseMaybeAssign(isFor)
} else if (kind === "const" && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) {
} else if (!allowMissingInitializer && 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 (!allowMissingInitializer && 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
@@ -588,7 +594,7 @@ pp.parseClass = function(node, isStatement) {
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")
if (hadConstructor) this.raiseRecoverable(element.start, "Duplicate constructor in the same class")
hadConstructor = true
} else if (element.key && element.key.type === "PrivateIdentifier" && isPrivateNameConflicted(privateNameMap, element)) {
this.raiseRecoverable(element.key.start, `Identifier '#${element.key.name}' has already been declared`)
@@ -834,44 +840,36 @@ function checkKeyName(node, name) {

// Parses module export declaration.

pp.parseExportAllDeclaration = function(node, exports) {
if (this.options.ecmaVersion >= 11) {
if (this.eatContextual("as")) {
node.exported = this.parseModuleExportName()
this.checkExport(exports, node.exported, this.lastTokStart)
} else {
node.exported = null
}
}
this.expectContextual("from")
if (this.type !== tt.string) this.unexpected()
node.source = this.parseExprAtom()
this.semicolon()
return this.finishNode(node, "ExportAllDeclaration")
}

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.parseModuleExportName()
this.checkExport(exports, node.exported, this.lastTokStart)
} else {
node.exported = null
}
}
this.expectContextual("from")
if (this.type !== tt.string) this.unexpected()
node.source = this.parseExprAtom()
this.semicolon()
return this.finishNode(node, "ExportAllDeclaration")
return this.parseExportAllDeclaration(node, exports)
}
if (this.eat(tt._default)) { // export default ...
this.checkExport(exports, "default", this.lastTokStart)
let isAsync
if (this.type === tt._function || (isAsync = this.isAsyncFunction())) {
let fNode = this.startNode()
this.next()
if (isAsync) this.next()
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")
} else {
node.declaration = this.parseMaybeAssign()
this.semicolon()
}
node.declaration = this.parseExportDefaultDeclaration()
return this.finishNode(node, "ExportDefaultDeclaration")
}
// export var|const|let|function|class ...
if (this.shouldParseExportStatement()) {
node.declaration = this.parseStatement(null)
node.declaration = this.parseExportDeclaration(node)
if (node.declaration.type === "VariableDeclaration")
this.checkVariableExport(exports, node.declaration.declarations)
else
@@ -903,6 +901,27 @@ pp.parseExport = function(node, exports) {
return this.finishNode(node, "ExportNamedDeclaration")
}

pp.parseExportDeclaration = function(node) {
return this.parseStatement(null)
}

pp.parseExportDefaultDeclaration = function() {
let isAsync
if (this.type === tt._function || (isAsync = this.isAsyncFunction())) {
let fNode = this.startNode()
this.next()
if (isAsync) this.next()
return this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync)
} else if (this.type === tt._class) {
let cNode = this.startNode()
return this.parseClass(cNode, "nullableID")
} else {
let declaration = this.parseMaybeAssign()
this.semicolon()
return declaration
}
}

pp.checkExport = function(exports, name, pos) {
if (!exports) return
if (typeof name !== "string")
@@ -950,6 +969,20 @@ pp.shouldParseExportStatement = function() {

// Parses a comma-separated list of module exports.

pp.parseExportSpecifier = function(exports) {
let node = this.startNode()
node.local = this.parseModuleExportName()

node.exported = this.eatContextual("as") ? this.parseModuleExportName() : node.local
this.checkExport(
exports,
node.exported,
node.exported.start
)

return this.finishNode(node, "ExportSpecifier")
}

pp.parseExportSpecifiers = function(exports) {
let nodes = [], first = true
// export { x, y as z } [from '...']
@@ -960,15 +993,7 @@ pp.parseExportSpecifiers = function(exports) {
if (this.afterTrailingComma(tt.braceR)) break
} else first = false

let node = this.startNode()
node.local = this.parseModuleExportName()
node.exported = this.eatContextual("as") ? this.parseModuleExportName() : node.local
this.checkExport(
exports,
node.exported,
node.exported.start
)
nodes.push(this.finishNode(node, "ExportSpecifier"))
nodes.push(this.parseExportSpecifier(exports))
}
return nodes
}
@@ -977,6 +1002,7 @@ pp.parseExportSpecifiers = function(exports) {

pp.parseImport = function(node) {
this.next()

// import '...'
if (this.type === tt.string) {
node.specifiers = empty
@@ -992,23 +1018,46 @@ pp.parseImport = function(node) {

// Parses a comma-separated list of module imports.

pp.parseImportSpecifier = function() {
let node = this.startNode()
node.imported = this.parseModuleExportName()

if (this.eatContextual("as")) {
node.local = this.parseIdent()
} else {
this.checkUnreserved(node.imported)
node.local = node.imported
}
this.checkLValSimple(node.local, BIND_LEXICAL)

return this.finishNode(node, "ImportSpecifier")
}

pp.parseImportDefaultSpecifier = function() {
// import defaultObj, { x, y as z } from '...'
let node = this.startNode()
node.local = this.parseIdent()
this.checkLValSimple(node.local, BIND_LEXICAL)
return this.finishNode(node, "ImportDefaultSpecifier")
}

pp.parseImportNamespaceSpecifier = function() {
let node = this.startNode()
this.next()
this.expectContextual("as")
node.local = this.parseIdent()
this.checkLValSimple(node.local, BIND_LEXICAL)
return this.finishNode(node, "ImportNamespaceSpecifier")
}

pp.parseImportSpecifiers = function() {
let nodes = [], first = true
if (this.type === tt.name) {
// import defaultObj, { x, y as z } from '...'
let node = this.startNode()
node.local = this.parseIdent()
this.checkLValSimple(node.local, BIND_LEXICAL)
nodes.push(this.finishNode(node, "ImportDefaultSpecifier"))
nodes.push(this.parseImportDefaultSpecifier())
if (!this.eat(tt.comma)) return nodes
}
if (this.type === tt.star) {
let node = this.startNode()
this.next()
this.expectContextual("as")
node.local = this.parseIdent()
this.checkLValSimple(node.local, BIND_LEXICAL)
nodes.push(this.finishNode(node, "ImportNamespaceSpecifier"))
nodes.push(this.parseImportNamespaceSpecifier())
return nodes
}
this.expect(tt.braceL)
@@ -1018,16 +1067,7 @@ pp.parseImportSpecifiers = function() {
if (this.afterTrailingComma(tt.braceR)) break
} else first = false

let node = this.startNode()
node.imported = this.parseModuleExportName()
if (this.eatContextual("as")) {
node.local = this.parseIdent()
} else {
this.checkUnreserved(node.imported)
node.local = node.imported
}
this.checkLValSimple(node.local, BIND_LEXICAL)
nodes.push(this.finishNode(node, "ImportSpecifier"))
nodes.push(this.parseImportSpecifier())
}
return nodes
}
15 changes: 14 additions & 1 deletion acorn/src/unicode-property-data.js
Original file line number Diff line number Diff line change
@@ -21,6 +21,18 @@ const unicodeBinaryProperties = {
14: ecma14BinaryProperties
}

// #table-binary-unicode-properties-of-strings
const ecma14BinaryPropertiesOfStrings = "Basic_Emoji Emoji_Keycap_Sequence RGI_Emoji_Modifier_Sequence RGI_Emoji_Flag_Sequence RGI_Emoji_Tag_Sequence RGI_Emoji_ZWJ_Sequence RGI_Emoji"

const unicodeBinaryPropertiesOfStrings = {
9: "",
10: "",
11: "",
12: "",
13: "",
14: ecma14BinaryPropertiesOfStrings
}

// #table-unicode-general-category-values
const unicodeGeneralCategoryValues = "Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu"

@@ -30,7 +42,7 @@ const ecma10ScriptValues = ecma9ScriptValues + " Dogra Dogr Gunjala_Gondi Gong H
const ecma11ScriptValues = ecma10ScriptValues + " Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho"
const ecma12ScriptValues = ecma11ScriptValues + " Chorasmian Chrs Diak Dives_Akuru Khitan_Small_Script Kits Yezi Yezidi"
const ecma13ScriptValues = ecma12ScriptValues + " Cypro_Minoan Cpmn Old_Uyghur Ougr Tangsa Tnsa Toto Vithkuqi Vith"
const ecma14ScriptValues = ecma13ScriptValues + " Kawi Nag_Mundari Nagm"
const ecma14ScriptValues = ecma13ScriptValues + " Hrkt Katakana_Or_Hiragana Kawi Nag_Mundari Nagm Unknown Zzzz"

const unicodeScriptValues = {
9: ecma9ScriptValues,
@@ -45,6 +57,7 @@ const data = {}
function buildUnicodeData(ecmaVersion) {
const d = data[ecmaVersion] = {
binary: wordsRegexp(unicodeBinaryProperties[ecmaVersion] + " " + unicodeGeneralCategoryValues),
binaryOfStrings: wordsRegexp(unicodeBinaryPropertiesOfStrings[ecmaVersion]),
nonBinary: {
General_Category: wordsRegexp(unicodeGeneralCategoryValues),
Script: wordsRegexp(unicodeScriptValues[ecmaVersion])
1 change: 0 additions & 1 deletion bin/test262.unsupported-features
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
decorators
import-assertions
regexp-duplicate-named-groups
regexp-v-flag
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -33,15 +33,15 @@
"test:test262": "node bin/run_test262.js"
},
"devDependencies": {
"@rollup/plugin-buble": "^1.0.1",
"@rollup/plugin-buble": "^1.0.2",
"@unicode/unicode-15.0.0": "^1.3.1",
"eslint": "^8.29.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint": "^8.42.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"rollup": "^3.7.4",
"test262": "git+https://github.com/tc39/test262.git#dac69563480b9f22709fd49d61a32b3a0513b6b1",
"rollup": "^3.25.1",
"test262": "git+https://github.com/tc39/test262.git#c5b24c64c3c27544f15e1c18ef274924cff1e32c",
"test262-parser-runner": "^0.5.0"
}
}
1 change: 1 addition & 0 deletions test/run.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
require("./tests-regexp-2018.js");
require("./tests-regexp-2020.js");
require("./tests-regexp-2022.js");
require("./tests-regexp-2024.js");
require("./tests-json-superset.js");
require("./tests-optional-catch-binding.js");
require("./tests-bigint.js");
7 changes: 6 additions & 1 deletion test/tests-dynamic-import.js
Original file line number Diff line number Diff line change
@@ -240,7 +240,12 @@ testFail("import(source,)", 'Trailing comma is not allowed in import() (1:13)',
loose: false
});

testFail("new import(source)", 'Cannot use new with import() (1:4)', {
testFail("new import(source)", 'Unexpected token (1:10)', {
ecmaVersion: 11,
loose: false
});

testFail("new import(source).foo", 'Unexpected token (1:10)', {
ecmaVersion: 11,
loose: false
});
86 changes: 86 additions & 0 deletions test/tests-regexp-2024.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
if (typeof exports !== "undefined") {
var test = require("./driver.js").test
var testFail = require("./driver.js").testFail
}

test("/a/v", {}, { ecmaVersion: 2024 })
testFail("/a/v", "Invalid regular expression flag (1:1)", { ecmaVersion: 2023 })
testFail("/a/uv", "Invalid regular expression flag (1:1)", { ecmaVersion: 2024 })
test("/[]/v", {}, { ecmaVersion: 2024 })
test("/[^]/v", {}, { ecmaVersion: 2024 })
test("/[&]/v", {}, { ecmaVersion: 2024 })
test("/[\\b]/v", {}, { ecmaVersion: 2024 })
test("/[\\&]/v", {}, { ecmaVersion: 2024 })
testFail("/[\\z]/v", "Invalid regular expression: /[\\z]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a\\z]/v", "Invalid regular expression: /[a\\z]/: Unterminated character class (1:1)", { ecmaVersion: 2024 })
// Union
test("/[abc]/v", {}, { ecmaVersion: 2024 })
test("/[a-c]/v", {}, { ecmaVersion: 2024 })
test("/[a-bc]/v", {}, { ecmaVersion: 2024 })
test("/[ab-c]/v", {}, { ecmaVersion: 2024 })
testFail("/[c-a]/v", "Invalid regular expression: /[c-a]/: Range out of order in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a-\\b]/v", "Invalid regular expression: /[a-\\b]/: Range out of order in character class (1:1)", { ecmaVersion: 2024 })
// Expression
test("/[a&&b]/v", {}, { ecmaVersion: 2024 })
test("/[a--b]/v", {}, { ecmaVersion: 2024 })
test("/[a&&b&&c]/v", {}, { ecmaVersion: 2024 })
test("/[a--b--c]/v", {}, { ecmaVersion: 2024 })
testFail("/[a--]/v", "Invalid regular expression: /[a--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a&&]/v", "Invalid regular expression: /[a&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a--b&&c]/v", "Invalid regular expression: /[a--b&&c]/: Unterminated character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a&&b--c]/v", "Invalid regular expression: /[a&&b--c]/: Unterminated character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a&&&]/v", "Invalid regular expression: /[a&&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a&&b&&]/v", "Invalid regular expression: /[a&&b&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[a--b--]/v", "Invalid regular expression: /[a--b--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
test("/[a&&\\&]/v", {}, { ecmaVersion: 2024 })
testFail("/[&&]/v", "Invalid regular expression: /[&&]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[!!]/v", "Invalid regular expression: /[!!]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[##]/v", "Invalid regular expression: /[##]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[--]/v", "Invalid regular expression: /[--]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
// Nested
test("/[[a&&b]--[c&&d]]/v", {}, { ecmaVersion: 2024 })
test("/[[a--b]&&[c--d]]/v", {}, { ecmaVersion: 2024 })
test("/[[a&&b][c--d][ef]]/v", {}, { ecmaVersion: 2024 })
// Class String
test("/[\\q{a|b}]/v", {}, { ecmaVersion: 2024 })
test("/[\\q{abc}]/v", {}, { ecmaVersion: 2024 })
test("/[\\q{}]/v", {}, { ecmaVersion: 2024 })
test("/[\\q{abc|def}]/v", {}, { ecmaVersion: 2024 })
test("/[\\q{abc|d|ef}]/v", {}, { ecmaVersion: 2024 })
test("/[\\q{|||abc||||}]/v", {}, { ecmaVersion: 2024 })
testFail("/\\q{a|b}/v", "Invalid regular expression: /\\q{a|b}/: Invalid escape (1:1)", { ecmaVersion: 2024 })
testFail("/[\\q{a|b]/v", "Invalid regular expression: /[\\q{a|b]/: Invalid character in character class (1:1)", { ecmaVersion: 2024 })
testFail("/[\\q{a|b}]/u", "Invalid regular expression: /[\\q{a|b}]/: Invalid escape (1:1)", { ecmaVersion: 2024 })
// Unicode binary properties of strings
test("/\\p{Basic_Emoji}/v", {}, { ecmaVersion: 2024 })
testFail("/\\p{Basic_Emoji}/u", "Invalid regular expression: /\\p{Basic_Emoji}/: Invalid property name (1:1)", { ecmaVersion: 2024 })
test("/\\p{Basic_Emoji}/", {}, { ecmaVersion: 2024 }) // Non unicode binary properties of strings
// MayContainStrings
testFail("/\\P{Basic_Emoji}/v", "Invalid regular expression: /\\P{Basic_Emoji}/: Invalid property name (1:1)", { ecmaVersion: 2024 })
test("/\\p{ASCII}/v", {}, { ecmaVersion: 2024 })
test("/\\P{General_Category=Letter}/v", {}, { ecmaVersion: 2024 })
testFail("/[^\\p{Basic_Emoji}]/v", "Invalid regular expression: /[^\\p{Basic_Emoji}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
testFail("/[^[\\p{Basic_Emoji}]]/v", "Invalid regular expression: /[^[\\p{Basic_Emoji}]]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
test("/[^\\d]/v", {}, { ecmaVersion: 2024 })
test("/[^\\D]/v", {}, { ecmaVersion: 2024 })
test("/[^\\s]/v", {}, { ecmaVersion: 2024 })
test("/[^\\S]/v", {}, { ecmaVersion: 2024 })
test("/[^\\w]/v", {}, { ecmaVersion: 2024 })
test("/[^\\W]/v", {}, { ecmaVersion: 2024 })
test("/[^\\p{ASCII}]/v", {}, { ecmaVersion: 2024 })
test("/[^\\p{General_Category=Letter}]/v", {}, { ecmaVersion: 2024 })
test("/[^[^\\p{ASCII}]]/v", {}, { ecmaVersion: 2024 })
test("/[\\p{Basic_Emoji}][^]/v", {}, { ecmaVersion: 2024 })
test("/[^[\\p{ASCII}]]/v", {}, { ecmaVersion: 2024 })
test("/[^\\q{a}]/v", {}, { ecmaVersion: 2024 })
test("/[^\\q{a|b}]/v", {}, { ecmaVersion: 2024 })
testFail("/[^\\q{}]/v", "Invalid regular expression: /[^\\q{}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
testFail("/[^\\q{ab}]/v", "Invalid regular expression: /[^\\q{ab}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
testFail("/[^\\q{a|bc}]/v", "Invalid regular expression: /[^\\q{a|bc}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
test("/[^\\q{a}\\q{b}]/v", {}, { ecmaVersion: 2024 })
testFail("/[^\\q{a}\\q{bc}]/v", "Invalid regular expression: /[^\\q{a}\\q{bc}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
test("/[^\\q{a}&&\\q{bc}]/v", {}, { ecmaVersion: 2024 })
test("/[^\\q{ab}&&\\q{c}]/v", {}, { ecmaVersion: 2024 })
testFail("/[^\\q{ab}&&\\q{cd}]/v", "Invalid regular expression: /[^\\q{ab}&&\\q{cd}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })
test("/[^\\q{a}--\\q{bc}]/v", {}, { ecmaVersion: 2024 })
testFail("/[^\\q{ab}--\\q{c}]/v", "Invalid regular expression: /[^\\q{ab}--\\q{c}]/: Negated character class may contain strings (1:1)", { ecmaVersion: 2024 })