From 232bb0b4c4bdfbe58808614343ecf2088c3efffe Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sat, 15 Aug 2026 22:12:07 +0300 Subject: [PATCH 1/4] Add ParserOptions.AllowDirectSuperOutsideMethod ECMA-262 PerformEval (https://tc39.es/ecma262/#sec-performeval) passes inDerivedConstructor into the parse of the eval code, so a direct eval called from the constructor of a derived class may contain a super call: class B { } class D extends B { constructor() { eval("super()") } } There was no way to ask the parser for that. AllowSuperOutsideMethod enables super property accesses only, and AllowDirectSuper was derived from the scope flags alone, so any host embedding the parser as the front end of a JS engine (this came up in Jint, which computes inDerivedConstructor correctly but cannot pass it on) reported a SyntaxError for every eval containing a super call. The new option is implemented by seeding the root scope with ScopeFlags.Super | ScopeFlags.DirectSuper rather than by short-circuiting the AllowDirectSuper getter. That way the option follows the this binding for free: EnterScope propagates the current this scope through arrow function scopes but not through ordinary function scopes, so `super()`, `(() => super())()` and `(() => eval("super()"))()` are accepted while `function f() { super() }` remains a SyntaxError, which is exactly what the spec prescribes for eval code in a derived constructor. Seeding Super alongside DirectSuper mirrors what ParseMethod does for the constructor of a derived class (a derived constructor is a method, so super property accesses are allowed there as well). The behavior of AllowSuperOutsideMethod and AllowNewTargetOutsideFunction is left untouched; with the new option disabled, nothing changes. Co-Authored-By: Claude Opus 5 (1M context) --- src/Acornima/Parser.State.cs | 5 +- src/Acornima/ParserOptions.cs | 15 +++++ test/Acornima.Tests/ParserTests.cs | 89 ++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/Acornima/Parser.State.cs b/src/Acornima/Parser.State.cs index aa4f0f6..aff92a6 100644 --- a/src/Acornima/Parser.State.cs +++ b/src/Acornima/Parser.State.cs @@ -105,7 +105,10 @@ internal void Reset(string input, int start, int length, SourceType sourceType, _scopeId = 0; _scopeStack.Clear(); - EnterScope(ScopeFlags.Top); + // NOTE: Seeding the root scope with the super flags (as opposed to just short-circuiting the `AllowDirectSuper` getter) + // makes the option follow the this binding: as `EnterScope` propagates the current this scope through arrow function scopes + // but not through ordinary function scopes, direct super calls are allowed exactly where the top level's this binding is in effect. + EnterScope(ScopeFlags.Top | (_options._allowDirectSuperOutsideMethod ? ScopeFlags.Super | ScopeFlags.DirectSuper : ScopeFlags.None)); _privateNameStack.Clear(); diff --git a/src/Acornima/ParserOptions.cs b/src/Acornima/ParserOptions.cs index d783d76..e3beb18 100644 --- a/src/Acornima/ParserOptions.cs +++ b/src/Acornima/ParserOptions.cs @@ -40,6 +40,7 @@ protected ParserOptions(ParserOptions original) _allowAwaitOutsideFunction = original._allowAwaitOutsideFunction; _allowNewTargetOutsideFunction = original._allowNewTargetOutsideFunction; _allowSuperOutsideMethod = original._allowSuperOutsideMethod; + _allowDirectSuperOutsideMethod = original._allowDirectSuperOutsideMethod; _checkPrivateFields = original._checkPrivateFields; _onInsertedSemicolon = original._onInsertedSemicolon; _onTrailingComma = original._onTrailingComma; @@ -128,6 +129,20 @@ public ExperimentalESFeatures ExperimentalESFeatures /// public bool AllowSuperOutsideMethod { get => _allowSuperOutsideMethod; init => _allowSuperOutsideMethod = value; } + internal readonly bool _allowDirectSuperOutsideMethod; + /// + /// Gets or sets whether to allow super calls to appear outside the constructor of a derived class. + /// Defaults to . + /// + /// + /// This option is intended for parsing code which is evaluated in the context of the constructor of a derived class + /// (see PerformEval and its inDerivedConstructor parameter). + /// Enabling it means that direct super calls (as well as super property accesses) are permitted at the top level + /// of the parsed unit, that is, in the same places where this refers to the top level's this binding. + /// (E.g. they are allowed in arrow functions declared at the top level but not in ordinary functions.) + /// + public bool AllowDirectSuperOutsideMethod { get => _allowDirectSuperOutsideMethod; init => _allowDirectSuperOutsideMethod = value; } + internal readonly bool _allowTopLevelUsing; /// /// Gets or sets whether to allow using declarations to appear at the top level of scripts as well. diff --git a/test/Acornima.Tests/ParserTests.cs b/test/Acornima.Tests/ParserTests.cs index dd9ef69..bce86ba 100644 --- a/test/Acornima.Tests/ParserTests.cs +++ b/test/Acornima.Tests/ParserTests.cs @@ -983,6 +983,95 @@ public void ShouldHandleSuperKeywordEdgeCases(string sourceType, string input, E } } + [Theory] + // Direct super calls are not allowed at the top level unless AllowDirectSuperOutsideMethod is enabled. + // (AllowSuperOutsideMethod alone doesn't enable them.) + [InlineData("script", "super()", false, false, "'super' keyword unexpected here")] + [InlineData("script", "super()", true, false, "'super' keyword unexpected here")] + [InlineData("script", "super()", false, true, null)] + [InlineData("script", "super()", true, true, null)] + [InlineData("module", "super()", false, false, "'super' keyword unexpected here")] + [InlineData("module", "super()", false, true, null)] + [InlineData("expression", "super()", false, false, "'super' keyword unexpected here")] + [InlineData("expression", "super()", false, true, null)] + + // Arrow functions inherit the this binding of the top level, so direct super calls are allowed in them as well. + [InlineData("script", "(() => super())()", false, false, "'super' keyword unexpected here")] + [InlineData("script", "(() => super())()", false, true, null)] + [InlineData("script", "() => () => super()", false, true, null)] + [InlineData("script", "async () => super()", false, true, null)] + // (The argument of the nested eval call is just a string literal to the parser. When the host parses that string, + // the top level cases above apply to it.) + [InlineData("script", "(() => eval('super()'))()", false, false, null)] + [InlineData("script", "(() => eval('super()'))()", false, true, null)] + + // Ordinary functions introduce a this binding of their own, so direct super calls remain disallowed in them. + [InlineData("script", "function f() { super() }", false, true, "'super' keyword unexpected here")] + [InlineData("script", "function f() { super() }", true, true, "'super' keyword unexpected here")] + [InlineData("script", "(function () { super() })", false, true, "'super' keyword unexpected here")] + [InlineData("script", "() => function () { super() }", false, true, "'super' keyword unexpected here")] + [InlineData("script", "({ m() { super() } })", false, true, "'super' keyword unexpected here")] + + // Super property accesses are allowed wherever direct super calls are. + [InlineData("script", "super.x", false, false, "'super' keyword unexpected here")] + [InlineData("script", "super.x", true, false, null)] + [InlineData("script", "super.x", false, true, null)] + [InlineData("script", "(() => super.x)()", false, true, null)] + [InlineData("script", "function f() { super.x }", false, true, "'super' keyword unexpected here")] + // (AllowSuperOutsideMethod is unaffected by AllowDirectSuperOutsideMethod, including that it allows + // super property accesses in nested functions as well.) + [InlineData("script", "function f() { super.x }", true, false, null)] + [InlineData("script", "function f() { super.x }", true, true, null)] + + // Classes are unaffected: the constructor of a derived class remains the only place where direct super calls are allowed. + [InlineData("script", "class A extends B { constructor() { super() } }", false, false, null)] + [InlineData("script", "class A extends B { constructor() { super() } }", false, true, null)] + [InlineData("script", "class A { constructor() { super() } }", false, false, "'super' keyword unexpected here")] + [InlineData("script", "class A { constructor() { super() } }", false, true, "'super' keyword unexpected here")] + [InlineData("script", "class A extends B { m() { super() } }", false, true, "'super' keyword unexpected here")] + [InlineData("script", "class A extends B { constructor() { function f() { super() } } }", false, true, "'super' keyword unexpected here")] + [InlineData("script", "class C { x = super.y }", false, false, null)] + [InlineData("script", "class C { x = super.y }", false, true, null)] + // (Class field initializers don't introduce a this binding of their own. This is why a direct super call is accepted + // in a field initializer of a class declared in the constructor of a derived class - and, with the option enabled, + // in a field initializer of a class declared at the top level as well.) + [InlineData("script", "class A extends B { constructor() { class C { x = super() } } }", false, false, null)] + [InlineData("script", "class C { x = super() }", false, false, "'super' keyword unexpected here")] + [InlineData("script", "class C { x = super() }", false, true, null)] + public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input, bool allowSuperOutsideMethod, bool allowDirectSuperOutsideMethod, string? expectedError) + { + var parser = new Parser(new ParserOptions + { + AllowSuperOutsideMethod = allowSuperOutsideMethod, + AllowDirectSuperOutsideMethod = allowDirectSuperOutsideMethod, + }); + var parseAction = GetParseActionFor(sourceType); + + if (expectedError is null) + { + Assert.NotNull(parseAction(parser, input)); + } + else + { + var ex = Assert.Throws(() => parseAction(parser, input)); + Assert.Equal(expectedError, ex.Description); + } + } + + [Fact] + public void AllowDirectSuperOutsideMethodShouldDefaultToFalse() + { + Assert.False(new ParserOptions().AllowDirectSuperOutsideMethod); + Assert.False(ParserOptions.Default.AllowDirectSuperOutsideMethod); + + var options = ParserOptions.Default with { AllowDirectSuperOutsideMethod = true }; + Assert.True(options.AllowDirectSuperOutsideMethod); + Assert.False(ParserOptions.Default.AllowDirectSuperOutsideMethod); + + // The option must survive further copies of the options object. + Assert.True((options with { EcmaVersion = EcmaVersion.ES2022 }).AllowDirectSuperOutsideMethod); + } + [Theory] [InlineData("script", "(class { x = await })", EcmaVersion.Latest, null)] [InlineData("module", "(class { x = await })", EcmaVersion.Latest, "Unexpected reserved word")] From 08c6a637ec8e390b4585e5b6b3160acbd4292127 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sun, 23 Aug 2026 11:18:33 +0300 Subject: [PATCH 2/4] Make AllowSuperOutsideMethod follow the top level's this binding, like AllowDirectSuperOutsideMethod --- src/Acornima/Parser.State.cs | 19 ++++++++++++++----- src/Acornima/ParserOptions.cs | 11 ++++++++++- test/Acornima.Tests/ParserTests.cs | 29 +++++++++++++++++++---------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/Acornima/Parser.State.cs b/src/Acornima/Parser.State.cs index aff92a6..b774022 100644 --- a/src/Acornima/Parser.State.cs +++ b/src/Acornima/Parser.State.cs @@ -105,10 +105,19 @@ internal void Reset(string input, int start, int length, SourceType sourceType, _scopeId = 0; _scopeStack.Clear(); - // NOTE: Seeding the root scope with the super flags (as opposed to just short-circuiting the `AllowDirectSuper` getter) - // makes the option follow the this binding: as `EnterScope` propagates the current this scope through arrow function scopes - // but not through ordinary function scopes, direct super calls are allowed exactly where the top level's this binding is in effect. - EnterScope(ScopeFlags.Top | (_options._allowDirectSuperOutsideMethod ? ScopeFlags.Super | ScopeFlags.DirectSuper : ScopeFlags.None)); + // NOTE: Seeding the root scope with the super flags (as opposed to just short-circuiting the `AllowSuper`/`AllowDirectSuper` getters) + // makes both options follow the this binding: as `EnterScope` propagates the current this scope through arrow function scopes + // but not through ordinary function scopes, super is allowed exactly where the top level's this binding is in effect. + var superFlags = ScopeFlags.None; + if (_options._allowDirectSuperOutsideMethod) + { + superFlags = ScopeFlags.Super | ScopeFlags.DirectSuper; + } + else if (_options._allowSuperOutsideMethod) + { + superFlags = ScopeFlags.Super; + } + EnterScope(ScopeFlags.Top | superFlags); _privateNameStack.Clear(); @@ -288,7 +297,7 @@ private bool AllowSuper // https://github.com/acornjs/acorn/blob/8.11.3/acorn/src/state.js > `get allowSuper` [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _options._allowSuperOutsideMethod || (CurrentThisScope._flags & (ScopeFlags.Super | ScopeFlags.InClassFieldInit)) != 0; + get => (CurrentThisScope._flags & (ScopeFlags.Super | ScopeFlags.InClassFieldInit)) != 0; } private bool AllowDirectSuper diff --git a/src/Acornima/ParserOptions.cs b/src/Acornima/ParserOptions.cs index e3beb18..bef726e 100644 --- a/src/Acornima/ParserOptions.cs +++ b/src/Acornima/ParserOptions.cs @@ -124,9 +124,17 @@ public ExperimentalESFeatures ExperimentalESFeatures internal readonly bool _allowSuperOutsideMethod; /// - /// Gets or sets whether to allow super identifiers to appear outside methods. + /// Gets or sets whether to allow super property accesses to appear outside methods. /// Defaults to . /// + /// + /// This option is intended for parsing code which is evaluated in the context of a method + /// (see PerformEval and its inMethod parameter). + /// Enabling it means that super property accesses are permitted at the top level of the parsed unit, that is, + /// in the same places where this refers to the top level's this binding. + /// (E.g. they are allowed in arrow functions declared at the top level but not in ordinary functions.) + /// Direct super calls remain disallowed; see for those. + /// public bool AllowSuperOutsideMethod { get => _allowSuperOutsideMethod; init => _allowSuperOutsideMethod = value; } internal readonly bool _allowDirectSuperOutsideMethod; @@ -140,6 +148,7 @@ public ExperimentalESFeatures ExperimentalESFeatures /// Enabling it means that direct super calls (as well as super property accesses) are permitted at the top level /// of the parsed unit, that is, in the same places where this refers to the top level's this binding. /// (E.g. they are allowed in arrow functions declared at the top level but not in ordinary functions.) + /// This option implies . /// public bool AllowDirectSuperOutsideMethod { get => _allowDirectSuperOutsideMethod; init => _allowDirectSuperOutsideMethod = value; } diff --git a/test/Acornima.Tests/ParserTests.cs b/test/Acornima.Tests/ParserTests.cs index bce86ba..b48f41f 100644 --- a/test/Acornima.Tests/ParserTests.cs +++ b/test/Acornima.Tests/ParserTests.cs @@ -1012,16 +1012,20 @@ public void ShouldHandleSuperKeywordEdgeCases(string sourceType, string input, E [InlineData("script", "() => function () { super() }", false, true, "'super' keyword unexpected here")] [InlineData("script", "({ m() { super() } })", false, true, "'super' keyword unexpected here")] - // Super property accesses are allowed wherever direct super calls are. + // Super property accesses are allowed wherever direct super calls are, and AllowSuperOutsideMethod allows + // exactly those, without allowing direct super calls. [InlineData("script", "super.x", false, false, "'super' keyword unexpected here")] [InlineData("script", "super.x", true, false, null)] [InlineData("script", "super.x", false, true, null)] [InlineData("script", "(() => super.x)()", false, true, null)] + [InlineData("script", "(() => super.x)()", true, false, null)] + // (Both options follow the top level's this binding, so neither of them reaches into an ordinary function.) [InlineData("script", "function f() { super.x }", false, true, "'super' keyword unexpected here")] - // (AllowSuperOutsideMethod is unaffected by AllowDirectSuperOutsideMethod, including that it allows - // super property accesses in nested functions as well.) - [InlineData("script", "function f() { super.x }", true, false, null)] - [InlineData("script", "function f() { super.x }", true, true, null)] + [InlineData("script", "function f() { super.x }", true, false, "'super' keyword unexpected here")] + [InlineData("script", "function f() { super.x }", true, true, "'super' keyword unexpected here")] + // (Methods bring a home object of their own, so they are unaffected by either option.) + [InlineData("script", "({ m() { super.x } })", false, false, null)] + [InlineData("script", "({ m() { super.x } })", true, false, null)] // Classes are unaffected: the constructor of a derived class remains the only place where direct super calls are allowed. [InlineData("script", "class A extends B { constructor() { super() } }", false, false, null)] @@ -1032,12 +1036,17 @@ public void ShouldHandleSuperKeywordEdgeCases(string sourceType, string input, E [InlineData("script", "class A extends B { constructor() { function f() { super() } } }", false, true, "'super' keyword unexpected here")] [InlineData("script", "class C { x = super.y }", false, false, null)] [InlineData("script", "class C { x = super.y }", false, true, null)] - // (Class field initializers don't introduce a this binding of their own. This is why a direct super call is accepted - // in a field initializer of a class declared in the constructor of a derived class - and, with the option enabled, - // in a field initializer of a class declared at the top level as well.) - [InlineData("script", "class A extends B { constructor() { class C { x = super() } } }", false, false, null)] + // (Class field initializers don't introduce a this binding of their own, but they are never a place for a direct + // super call either: https://tc39.es/ecma262/#sec-class-definitions-static-semantics-early-errors makes it a + // Syntax Error if the Initializer Contains SuperCall. So neither the constructor of a derived class nor the + // option enables one there.) + [InlineData("script", "class A extends B { constructor() { class C { x = super() } } }", false, false, "'super' keyword unexpected here")] [InlineData("script", "class C { x = super() }", false, false, "'super' keyword unexpected here")] - [InlineData("script", "class C { x = super() }", false, true, null)] + [InlineData("script", "class C { x = super() }", false, true, "'super' keyword unexpected here")] + // (A computed class element name, on the other hand, is evaluated in the enclosing scope, so it inherits + // whatever that scope allows.) + [InlineData("script", "class C { [super()]() { } }", false, false, "'super' keyword unexpected here")] + [InlineData("script", "class C { [super()]() { } }", false, true, null)] public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input, bool allowSuperOutsideMethod, bool allowDirectSuperOutsideMethod, string? expectedError) { var parser = new Parser(new ParserOptions From f1b91b6861dee2c120576b19b1df3b2664607bc3 Mon Sep 17 00:00:00 2001 From: Adam Simon Date: Sun, 23 Aug 2026 11:45:19 +0200 Subject: [PATCH 3/4] Finalize public API naming + minor corrections --- src/Acornima/Parser.State.cs | 15 ++++++--------- src/Acornima/ParserOptions.cs | 17 +++++++++++------ test/Acornima.Tests/ParserTests.cs | 14 +++++++------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Acornima/Parser.State.cs b/src/Acornima/Parser.State.cs index b774022..a31d15e 100644 --- a/src/Acornima/Parser.State.cs +++ b/src/Acornima/Parser.State.cs @@ -105,18 +105,15 @@ internal void Reset(string input, int start, int length, SourceType sourceType, _scopeId = 0; _scopeStack.Clear(); + // NOTE: Seeding the root scope with the super flags (as opposed to just short-circuiting the `AllowSuper`/`AllowDirectSuper` getters) // makes both options follow the this binding: as `EnterScope` propagates the current this scope through arrow function scopes // but not through ordinary function scopes, super is allowed exactly where the top level's this binding is in effect. - var superFlags = ScopeFlags.None; - if (_options._allowDirectSuperOutsideMethod) - { - superFlags = ScopeFlags.Super | ScopeFlags.DirectSuper; - } - else if (_options._allowSuperOutsideMethod) - { - superFlags = ScopeFlags.Super; - } + var superFlags = + _options._allowSuperCallOutsideConstructor ? ScopeFlags.Super | ScopeFlags.DirectSuper + : _options._allowSuperOutsideMethod ? ScopeFlags.Super + : ScopeFlags.None; + EnterScope(ScopeFlags.Top | superFlags); _privateNameStack.Clear(); diff --git a/src/Acornima/ParserOptions.cs b/src/Acornima/ParserOptions.cs index bef726e..4d34b67 100644 --- a/src/Acornima/ParserOptions.cs +++ b/src/Acornima/ParserOptions.cs @@ -40,7 +40,7 @@ protected ParserOptions(ParserOptions original) _allowAwaitOutsideFunction = original._allowAwaitOutsideFunction; _allowNewTargetOutsideFunction = original._allowNewTargetOutsideFunction; _allowSuperOutsideMethod = original._allowSuperOutsideMethod; - _allowDirectSuperOutsideMethod = original._allowDirectSuperOutsideMethod; + _allowSuperCallOutsideConstructor = original._allowSuperCallOutsideConstructor; _checkPrivateFields = original._checkPrivateFields; _onInsertedSemicolon = original._onInsertedSemicolon; _onTrailingComma = original._onTrailingComma; @@ -120,6 +120,11 @@ public ExperimentalESFeatures ExperimentalESFeatures /// Gets or sets whether to allow new.target meta-properties in the top-level scope. /// Defaults to . /// + /// + /// This option is intended for parsing code which is evaluated in the context of a function + /// (see PerformEval and its inFunc parameter). + /// Enabling it means that new.target accesses are permitted at the top level of the parsed code. + /// public bool AllowNewTargetOutsideFunction { get => _allowNewTargetOutsideFunction; init => _allowNewTargetOutsideFunction = value; } internal readonly bool _allowSuperOutsideMethod; @@ -130,14 +135,14 @@ public ExperimentalESFeatures ExperimentalESFeatures /// /// This option is intended for parsing code which is evaluated in the context of a method /// (see PerformEval and its inMethod parameter). - /// Enabling it means that super property accesses are permitted at the top level of the parsed unit, that is, + /// Enabling it means that super property accesses are permitted at the top level of the parsed code, that is, /// in the same places where this refers to the top level's this binding. /// (E.g. they are allowed in arrow functions declared at the top level but not in ordinary functions.) - /// Direct super calls remain disallowed; see for those. + /// Direct super calls remain disallowed; see for those. /// public bool AllowSuperOutsideMethod { get => _allowSuperOutsideMethod; init => _allowSuperOutsideMethod = value; } - internal readonly bool _allowDirectSuperOutsideMethod; + internal readonly bool _allowSuperCallOutsideConstructor; /// /// Gets or sets whether to allow super calls to appear outside the constructor of a derived class. /// Defaults to . @@ -146,11 +151,11 @@ public ExperimentalESFeatures ExperimentalESFeatures /// This option is intended for parsing code which is evaluated in the context of the constructor of a derived class /// (see PerformEval and its inDerivedConstructor parameter). /// Enabling it means that direct super calls (as well as super property accesses) are permitted at the top level - /// of the parsed unit, that is, in the same places where this refers to the top level's this binding. + /// of the parsed code, that is, in the same places where this refers to the top level's this binding. /// (E.g. they are allowed in arrow functions declared at the top level but not in ordinary functions.) /// This option implies . /// - public bool AllowDirectSuperOutsideMethod { get => _allowDirectSuperOutsideMethod; init => _allowDirectSuperOutsideMethod = value; } + public bool AllowSuperCallOutsideConstructor { get => _allowSuperCallOutsideConstructor; init => _allowSuperCallOutsideConstructor = value; } internal readonly bool _allowTopLevelUsing; /// diff --git a/test/Acornima.Tests/ParserTests.cs b/test/Acornima.Tests/ParserTests.cs index b48f41f..0e553f1 100644 --- a/test/Acornima.Tests/ParserTests.cs +++ b/test/Acornima.Tests/ParserTests.cs @@ -1052,7 +1052,7 @@ public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input var parser = new Parser(new ParserOptions { AllowSuperOutsideMethod = allowSuperOutsideMethod, - AllowDirectSuperOutsideMethod = allowDirectSuperOutsideMethod, + AllowSuperCallOutsideConstructor = allowDirectSuperOutsideMethod, }); var parseAction = GetParseActionFor(sourceType); @@ -1070,15 +1070,15 @@ public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input [Fact] public void AllowDirectSuperOutsideMethodShouldDefaultToFalse() { - Assert.False(new ParserOptions().AllowDirectSuperOutsideMethod); - Assert.False(ParserOptions.Default.AllowDirectSuperOutsideMethod); + Assert.False(new ParserOptions().AllowSuperCallOutsideConstructor); + Assert.False(ParserOptions.Default.AllowSuperCallOutsideConstructor); - var options = ParserOptions.Default with { AllowDirectSuperOutsideMethod = true }; - Assert.True(options.AllowDirectSuperOutsideMethod); - Assert.False(ParserOptions.Default.AllowDirectSuperOutsideMethod); + var options = ParserOptions.Default with { AllowSuperCallOutsideConstructor = true }; + Assert.True(options.AllowSuperCallOutsideConstructor); + Assert.False(ParserOptions.Default.AllowSuperCallOutsideConstructor); // The option must survive further copies of the options object. - Assert.True((options with { EcmaVersion = EcmaVersion.ES2022 }).AllowDirectSuperOutsideMethod); + Assert.True((options with { EcmaVersion = EcmaVersion.ES2022 }).AllowSuperCallOutsideConstructor); } [Theory] From b468b8925cdd385e8c8285e186ef907a7041179a Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sun, 23 Aug 2026 17:31:47 +0300 Subject: [PATCH 4/4] Carry the AllowSuperCallOutsideConstructor rename into the tests f1b91b6 renamed the option but left the test method names, the theory parameter and one comment on the old AllowDirectSuperOutsideMethod spelling, so the tests no longer said what they cover. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BGoP6H8jUJ26uj6U5mt8Fn --- test/Acornima.Tests/ParserTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Acornima.Tests/ParserTests.cs b/test/Acornima.Tests/ParserTests.cs index 0e553f1..83f1c27 100644 --- a/test/Acornima.Tests/ParserTests.cs +++ b/test/Acornima.Tests/ParserTests.cs @@ -984,7 +984,7 @@ public void ShouldHandleSuperKeywordEdgeCases(string sourceType, string input, E } [Theory] - // Direct super calls are not allowed at the top level unless AllowDirectSuperOutsideMethod is enabled. + // Direct super calls are not allowed at the top level unless AllowSuperCallOutsideConstructor is enabled. // (AllowSuperOutsideMethod alone doesn't enable them.) [InlineData("script", "super()", false, false, "'super' keyword unexpected here")] [InlineData("script", "super()", true, false, "'super' keyword unexpected here")] @@ -1047,12 +1047,12 @@ public void ShouldHandleSuperKeywordEdgeCases(string sourceType, string input, E // whatever that scope allows.) [InlineData("script", "class C { [super()]() { } }", false, false, "'super' keyword unexpected here")] [InlineData("script", "class C { [super()]() { } }", false, true, null)] - public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input, bool allowSuperOutsideMethod, bool allowDirectSuperOutsideMethod, string? expectedError) + public void ShouldHandleSuperCallOutsideConstructor(string sourceType, string input, bool allowSuperOutsideMethod, bool allowSuperCallOutsideConstructor, string? expectedError) { var parser = new Parser(new ParserOptions { AllowSuperOutsideMethod = allowSuperOutsideMethod, - AllowSuperCallOutsideConstructor = allowDirectSuperOutsideMethod, + AllowSuperCallOutsideConstructor = allowSuperCallOutsideConstructor, }); var parseAction = GetParseActionFor(sourceType); @@ -1068,7 +1068,7 @@ public void ShouldHandleDirectSuperOutsideMethod(string sourceType, string input } [Fact] - public void AllowDirectSuperOutsideMethodShouldDefaultToFalse() + public void AllowSuperCallOutsideConstructorShouldDefaultToFalse() { Assert.False(new ParserOptions().AllowSuperCallOutsideConstructor); Assert.False(ParserOptions.Default.AllowSuperCallOutsideConstructor);