diff --git a/apps/oxlint/conformance/snapshot.md b/apps/oxlint/conformance/snapshot.md index c39be979a5ecc..cd22c0f042f4b 100644 --- a/apps/oxlint/conformance/snapshot.md +++ b/apps/oxlint/conformance/snapshot.md @@ -7,8 +7,8 @@ | Status | Count | % | | ----------------- | ----- | ------ | | Total rules | 292 | 100.0% | -| Fully passing | 280 | 95.9% | -| Partially passing | 12 | 4.1% | +| Fully passing | 281 | 96.2% | +| Partially passing | 11 | 3.8% | | Fully failing | 0 | 0.0% | | Load errors | 0 | 0.0% | | No tests run | 0 | 0.0% | @@ -18,8 +18,8 @@ | Status | Count | % | | ----------- | ----- | ------ | | Total tests | 33090 | 100.0% | -| Passing | 32769 | 99.0% | -| Failing | 50 | 0.2% | +| Passing | 32788 | 99.1% | +| Failing | 31 | 0.1% | | Skipped | 271 | 0.8% | ## Fully Passing Rules @@ -293,6 +293,7 @@ - `space-infix-ops` (74 tests) (7 skipped) - `space-unary-ops` (112 tests) - `spaced-comment` (99 tests) +- `strict` (126 tests) - `switch-colon-spacing` (46 tests) - `symbol-description` (8 tests) - `template-curly-spacing` (57 tests) @@ -307,68 +308,26 @@ ## Rules with Failures -- `no-eval` - 98 / 101 (97.0%) +- `no-eval` - 99 / 101 (98.0%) - `no-extra-parens` - 1068 / 1072 (99.6%) - `no-implicit-globals` - 242 / 245 (98.8%) -- `no-invalid-this` - 556 / 562 (98.9%) +- `no-invalid-this` - 558 / 562 (99.3%) - `no-irregular-whitespace` - 279 / 280 (99.6%) - `no-multiple-empty-lines` - 45 / 46 (97.8%) - `no-redeclare` - 68 / 75 (90.7%) - `no-unused-expressions` - 120 / 124 (96.8%) - `no-use-before-define` - 346 / 347 (99.7%) - `prefer-object-spread` - 86 / 87 (98.9%) -- `strict` - 110 / 126 (87.3%) - `unicode-bom` - 4 / 7 (57.1%) ## Rules with Failures Detail ### `no-eval` -Pass: 98 / 101 (97.0%) -Fail: 3 / 101 (3.0%) +Pass: 99 / 101 (98.0%) +Fail: 2 / 101 (2.0%) Skip: 0 / 101 (0.0%) -#### no-eval > valid - -```js -'use strict'; this.eval('foo'); -``` - -```json -{ - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/no-eval', - message: '`eval` can be harmful.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Identifier', - line: 1, - column: 19, - endLine: 1, - endColumn: 23, - suggestions: null - } -] - -1 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - #### no-eval > invalid ```js @@ -668,8 +627,8 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: ### `no-invalid-this` -Pass: 556 / 562 (98.9%) -Fail: 6 / 562 (1.1%) +Pass: 558 / 562 (99.3%) +Fail: 4 / 562 (0.7%) Skip: 0 / 562 (0.0%) #### no-invalid-this > valid @@ -788,81 +747,6 @@ AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ at apps/oxlint/dist/index.js -#### no-invalid-this > invalid - -```js -"use strict"; console.log(this); z(x => console.log(x, this)); /* should error */ -``` - -```json -{ - "languageOptions": { - "ecmaVersion": 6, - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - }, - "errors": [ - { - "messageId": "unexpectedThis" - }, - { - "messageId": "unexpectedThis" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 0: [] - -0 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### no-invalid-this > invalid - -```js -/* implied strict mode */ console.log(this); z(x => console.log(x, this)); /* should error */ -``` - -```json -{ - "languageOptions": { - "ecmaVersion": 6, - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true, - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "unexpectedThis" - }, - { - "messageId": "unexpectedThis" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 0: [] - -0 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - #### no-invalid-this > valid ```js @@ -3771,773 +3655,6 @@ Error: `tokensAndComments` is not correctly ordered at getStartWithSpaces (apps/oxlint/conformance/submodules/eslint/lib/rules/prefer-object-spread.js:143:32) -### `strict` - -Pass: 110 / 126 (87.3%) -Fail: 16 / 126 (12.7%) -Skip: 0 / 126 (0.0%) - -#### strict > valid - -```js -function foo() { return; } -``` - -```json -{ - "options": [ - "global" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the global form of 'use strict'.", - messageId: 'global', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 0, - endLine: 1, - endColumn: 26, - suggestions: null - } -] - -1 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > valid - -```js -function foo() { return; } -``` - -```json -{ - "options": [ - "function" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 0, - endLine: 1, - endColumn: 26, - suggestions: null - } -] - -1 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > valid - -```js -'use strict'; function foo() { return; } -``` - -```json -{ - "options": [ - "safe" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 2: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - }, - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 14, - endLine: 1, - endColumn: 40, - suggestions: null - } -] - -2 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > valid - -```js -function foo() { return; } -``` - -```json -{ - "options": [ - "safe" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 0, - endLine: 1, - endColumn: 26, - suggestions: null - } -] - -1 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > valid - -```js -'use strict'; function foo() { return; } -``` - -```json -{ - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 2: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - }, - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 14, - endLine: 1, - endColumn: 40, - suggestions: null - } -] - -2 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > valid - -```js -function foo() { return; } -``` - -```json -{ - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - } -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'FunctionDeclaration', - line: 1, - column: 0, - endLine: 1, - endColumn: 26, - suggestions: null - } -] - -1 !== 0 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertValidTestCasePasses (apps/oxlint/dist/index.js) - at runValidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo() { 'use strict'; return; } -``` - -```json -{ - "output": " function foo() { return; }", - "options": [ - "never" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied" - }, - { - "messageId": "implied" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: messageId 'never' does not match expected messageId 'implied' - -'never' !== 'implied' - - at assertInvalidTestCaseMessageIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo() { 'use strict'; return; } -``` - -```json -{ - "output": " function foo() { return; }", - "options": [ - "global" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied" - }, - { - "messageId": "implied" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the global form of 'use strict'.", - messageId: 'global', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 31, - endLine: 1, - endColumn: 44, - suggestions: null - } -] - -1 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo() { 'use strict'; return; } -``` - -```json -{ - "output": " function foo() { return; }", - "options": [ - "function" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied" - }, - { - "messageId": "implied" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - } -] - -1 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -function foo() { 'use strict'; return; } -``` - -```json -{ - "output": null, - "options": [ - "safe" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - }, - "errors": [ - { - "messageId": "global" - }, - { - "messageId": "global" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 0: [] - -0 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo() { 'use strict'; return; } -``` - -```json -{ - "output": " function foo() { return; }", - "options": [ - "safe" - ], - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied" - }, - { - "messageId": "implied" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - } -] - -1 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -function foo() { 'use strict'; return; } -``` - -```json -{ - "output": null, - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - }, - "errors": [ - { - "messageId": "global" - }, - { - "messageId": "global" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 0: [] - -0 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo() { 'use strict'; return; } -``` - -```json -{ - "output": " function foo() { return; }", - "languageOptions": { - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied" - }, - { - "messageId": "implied" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - } -] - -1 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -function foo(a = 0) { 'use strict' } -``` - -```json -{ - "output": null, - "options": [], - "languageOptions": { - "ecmaVersion": 6, - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - }, - "errors": [ - "Use the global form of 'use strict'.", - { - "messageId": "nonSimpleParameterList" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/strict', - message: "'use strict' directive inside a function with non-simple parameter list throws a syntax error since ES2016.", - messageId: 'nonSimpleParameterList', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 22, - endLine: 1, - endColumn: 34, - suggestions: null - } -] - -1 !== 2 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -'use strict'; function foo(a = 0) { 'use strict' } -``` - -```json -{ - "output": null, - "options": [], - "languageOptions": { - "ecmaVersion": 6, - "parserOptions": { - "ecmaFeatures": { - "globalReturn": true - } - } - }, - "errors": [ - { - "messageId": "nonSimpleParameterList" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 1 error but had 2: [ - { - ruleId: 'rule-to-test/strict', - message: "Use the function form of 'use strict'.", - messageId: 'function', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 0, - endLine: 1, - endColumn: 13, - suggestions: null - }, - { - ruleId: 'rule-to-test/strict', - message: "'use strict' directive inside a function with non-simple parameter list throws a syntax error since ES2016.", - messageId: 'nonSimpleParameterList', - severity: 1, - nodeType: 'Literal', - line: 1, - column: 36, - endLine: 1, - endColumn: 48, - suggestions: null - } -] - -2 !== 1 - - at assertErrorCountIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - -#### strict > invalid - -```js -class C { static { function foo() { -'use strict'; } } } -``` - -```json -{ - "output": "class C { static { function foo() { \n } } }", - "options": [ - "safe" - ], - "languageOptions": { - "ecmaVersion": 2022, - "parserOptions": { - "ecmaFeatures": { - "impliedStrict": true - } - } - }, - "errors": [ - { - "messageId": "implied", - "line": 2 - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: messageId 'unnecessaryInClasses' does not match expected messageId 'implied' -+ actual - expected - -+ 'unnecessaryInClasses' -- 'implied' - - at assertInvalidTestCaseMessageIsCorrect (apps/oxlint/dist/index.js) - at assertInvalidTestCasePasses (apps/oxlint/dist/index.js) - at runInvalidTestCase (apps/oxlint/dist/index.js) - at apps/oxlint/dist/index.js - - ### `unicode-bom` Pass: 4 / 7 (57.1%) diff --git a/apps/oxlint/src-js/package/rule_tester.ts b/apps/oxlint/src-js/package/rule_tester.ts index 699ce1695e2e4..4090bed1576ae 100644 --- a/apps/oxlint/src-js/package/rule_tester.ts +++ b/apps/oxlint/src-js/package/rule_tester.ts @@ -10,13 +10,12 @@ import { default as assert, AssertionError } from "node:assert"; import util from "node:util"; import stableJsonStringify from "json-stable-stringify-without-jsonify"; -import { setEcmaVersion, ECMA_VERSION } from "../plugins/context.ts"; +import { ecmaFeaturesOverride, setEcmaVersion, ECMA_VERSION } from "../plugins/context.ts"; import { registerPlugin, registeredRules } from "../plugins/load.ts"; import { lintFileImpl, resetStateAfterError } from "../plugins/lint.ts"; import { getLineColumnFromOffset, getNodeByRangeIndex } from "../plugins/location.ts"; import { allOptions, setOptions, DEFAULT_OPTIONS_ID } from "../plugins/options.ts"; import { diagnostics, replacePlaceholders, PLACEHOLDER_REGEX } from "../plugins/report.ts"; -import { analyzeOptionsOverride } from "../plugins/scope.ts"; import { parse } from "./parse.ts"; import type { RequireAtLeastOne } from "type-fest"; @@ -1257,8 +1256,8 @@ function setEcmaVersionAndFeatures(test: TestCase) { const ecmaFeatures = languageOptions?.parserOptions?.ecmaFeatures as | EcmaFeaturesInternal | undefined; - analyzeOptionsOverride.globalReturn = ecmaFeatures?.globalReturn ?? null; - analyzeOptionsOverride.impliedStrict = ecmaFeatures?.impliedStrict ?? null; + ecmaFeaturesOverride.globalReturn = ecmaFeatures?.globalReturn ?? null; + ecmaFeaturesOverride.impliedStrict = ecmaFeatures?.impliedStrict ?? null; } // Regex to match other control characters (except tab, newline, carriage return) diff --git a/apps/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts index 11748bfbadc98..bceefa51e587c 100644 --- a/apps/oxlint/src-js/plugins/context.ts +++ b/apps/oxlint/src-js/plugins/context.ts @@ -132,8 +132,57 @@ const PARSER = Object.freeze({ supportedEcmaVersions: SUPPORTED_ECMA_VERSIONS, }); +// In conformance build, setting properties of this object to `true` or `false` overrides the defaults +export const ecmaFeaturesOverride: { + globalReturn: boolean | null; + impliedStrict: boolean | null; +} = { + globalReturn: null, + impliedStrict: null, +}; + +// Singleton object for ECMA features. +const ECMA_FEATURES = Object.freeze({ + /** + * `true` if file was parsed with top-level `return` statements allowed. + */ + get globalReturn(): boolean { + // TODO: Would be better to get `sourceType` without deserializing whole AST, + // in case it's used in `create` to return an empty visitor if wrong type. + if (ast === null) initAst(); + debugAssertIsNonNull(ast); + + // In conformance build, allow overriding from `languageOptions.parserOptions.ecmaFeatures.globalReturn` config + if (CONFORMANCE) { + const { globalReturn } = ecmaFeaturesOverride; + if (globalReturn !== null) return globalReturn; + } + + return ast.sourceType === "commonjs"; + }, + + /** + * `true` if file was parsed as strict mode code. + */ + get impliedStrict(): boolean { + // TODO: Would be better to get `sourceType` without deserializing whole AST, + // in case it's used in `create` to return an empty visitor if wrong type. + if (ast === null) initAst(); + debugAssertIsNonNull(ast); + + // In conformance build, allow overriding from `languageOptions.parserOptions.ecmaFeatures.impliedStrict` config + if (CONFORMANCE) { + const { impliedStrict } = ecmaFeaturesOverride; + if (impliedStrict !== null) return impliedStrict; + } + + return ast.sourceType === "module"; + }, +}); + // Singleton object for parser options. -// TODO: `sourceType` is the only property ESLint provides. But does TS-ESLint provide any further properties? +// TODO: `sourceType` and `ecmaFeatures` are the only property ESLint provides. +// But does TS-ESLint provide any further properties? const PARSER_OPTIONS = Object.freeze({ /** * Source type of the file being linted. @@ -146,6 +195,11 @@ const PARSER_OPTIONS = Object.freeze({ return ast.sourceType; }, + + /** + * ECMA features. + */ + ecmaFeatures: ECMA_FEATURES, }); // Singleton object for language options. diff --git a/apps/oxlint/src-js/plugins/scope.ts b/apps/oxlint/src-js/plugins/scope.ts index ccf5fcf9bbc7f..315decd3cb935 100644 --- a/apps/oxlint/src-js/plugins/scope.ts +++ b/apps/oxlint/src-js/plugins/scope.ts @@ -3,6 +3,7 @@ */ import { analyze, Variable as TSVariable } from "@typescript-eslint/scope-manager"; +import { ecmaFeaturesOverride } from "./context.ts"; import { ast, initAst } from "./source_code.ts"; import { globals, envs, initGlobals } from "./globals.ts"; import { ENVS } from "../generated/envs.ts"; @@ -110,15 +111,6 @@ const analyzeOptions: AnalyzeOptions = { emitDecoratorMetadata: false, }; -// In conformance build, setting these properties to `true` or `false` overrides the defaults -export const analyzeOptionsOverride: { - globalReturn: boolean | null; - impliedStrict: boolean | null; -} = { - globalReturn: null, - impliedStrict: null, -}; - /** * Initialize TS-ESLint `ScopeManager` for current file. */ @@ -133,7 +125,7 @@ function initTsScopeManager() { // Override `globalReturn` and `impliedStrict` if in conformance build if (CONFORMANCE) { - const { globalReturn, impliedStrict } = analyzeOptionsOverride; + const { globalReturn, impliedStrict } = ecmaFeaturesOverride; if (globalReturn !== null) analyzeOptions.globalReturn = globalReturn; if (impliedStrict !== null) analyzeOptions.impliedStrict = impliedStrict; } diff --git a/apps/oxlint/test/fixtures/languageOptions/output.snap.md b/apps/oxlint/test/fixtures/languageOptions/output.snap.md index 651b20028c80f..72f5af13c481c 100644 --- a/apps/oxlint/test/fixtures/languageOptions/output.snap.md +++ b/apps/oxlint/test/fixtures/languageOptions/output.snap.md @@ -6,7 +6,7 @@ x language-options-plugin(lang): languageOptions: | sourceType: commonjs | ecmaVersion: 2026 - | parserOptions: {"sourceType":"commonjs"} + | parserOptions: {"sourceType":"commonjs","ecmaFeatures":{"globalReturn":true,"impliedStrict":false}} | globals: {} | env: {"builtin":true} ,-[files/index.cjs:1:1] @@ -794,7 +794,7 @@ x language-options-plugin(lang): languageOptions: | sourceType: script | ecmaVersion: 2026 - | parserOptions: {"sourceType":"script"} + | parserOptions: {"sourceType":"script","ecmaFeatures":{"globalReturn":false,"impliedStrict":false}} | globals: {} | env: {"builtin":true} ,-[files/index.js:1:1] @@ -805,7 +805,7 @@ x language-options-plugin(lang): languageOptions: | sourceType: module | ecmaVersion: 2026 - | parserOptions: {"sourceType":"module"} + | parserOptions: {"sourceType":"module","ecmaFeatures":{"globalReturn":false,"impliedStrict":true}} | globals: {} | env: {"builtin":true} ,-[files/index.mjs:1:1]