diff --git a/apps/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts index bceefa51e587c..f0e37fda2742a 100644 --- a/apps/oxlint/src-js/plugins/context.ts +++ b/apps/oxlint/src-js/plugins/context.ts @@ -26,7 +26,7 @@ * and global variables (`filePath`, `settings`, `cwd`). */ -import { ast, initAst, SOURCE_CODE } from "./source_code.ts"; +import { ast, initAst, fileIsJsx, SOURCE_CODE } from "./source_code.ts"; import { report } from "./report.ts"; import { settings, initSettings } from "./settings.ts"; import visitorKeys from "../generated/keys.ts"; @@ -143,6 +143,13 @@ export const ecmaFeaturesOverride: { // Singleton object for ECMA features. const ECMA_FEATURES = Object.freeze({ + /** + * `true` if file was parsed as JSX. + */ + get jsx(): boolean { + return fileIsJsx(); + }, + /** * `true` if file was parsed with top-level `return` statements allowed. */ diff --git a/apps/oxlint/src-js/plugins/source_code.ts b/apps/oxlint/src-js/plugins/source_code.ts index f73d23ba83ac5..70e93cc35aa47 100644 --- a/apps/oxlint/src-js/plugins/source_code.ts +++ b/apps/oxlint/src-js/plugins/source_code.ts @@ -2,6 +2,8 @@ import { DATA_POINTER_POS_32, SOURCE_START_OFFSET, SOURCE_LEN_OFFSET, + IS_JSX_FLAG_POS, + IS_TS_FLAG_POS, } from "../generated/constants.ts"; // We use the deserializer which removes `ParenthesizedExpression`s from AST, @@ -29,7 +31,7 @@ import type { ScopeManager } from "./scope.ts"; const textDecoder = new TextDecoder("utf-8", { ignoreBOM: true }); // Buffer containing AST. Set before linting a file by `setupSourceForFile`. -export let buffer: BufferWithArrays | null = null; +let buffer: BufferWithArrays | null = null; // Indicates if the original source text has a BOM. Set before linting a file by `setupSourceForFile`. let hasBOM = false; @@ -105,6 +107,26 @@ export function resetSourceAndAst(): void { resetTokens(); } +/** + * Get whether file is JSX. + * @returns `true` if file is JSX, `false` if not + */ +export function fileIsJsx(): boolean { + debugAssertIsNonNull(buffer); + // Flag is `bool` in Rust, so 0 = false, 1 = true + return buffer[IS_JSX_FLAG_POS] === 1; +} + +/** + * Get whether file is TypeScript. + * @returns `true` if file is TypeScript, `false` if not + */ +export function fileIsTs(): boolean { + debugAssertIsNonNull(buffer); + // Flag is `bool` in Rust, so 0 = false, 1 = true + return buffer[IS_TS_FLAG_POS] === 1; +} + // `SourceCode` object. // // Only one file is linted at a time, so we can reuse a single object for all files. diff --git a/apps/oxlint/src-js/plugins/tokens_parse.ts b/apps/oxlint/src-js/plugins/tokens_parse.ts index 0e4671ecb2018..88068bde3aa26 100644 --- a/apps/oxlint/src-js/plugins/tokens_parse.ts +++ b/apps/oxlint/src-js/plugins/tokens_parse.ts @@ -5,8 +5,7 @@ import { createRequire } from "node:module"; import { filePath } from "./context.ts"; import { getNodeLoc } from "./location.ts"; -import { buffer, sourceText } from "./source_code.ts"; -import { IS_JSX_FLAG_POS, IS_TS_FLAG_POS } from "../generated/constants.ts"; +import { sourceText, fileIsJsx, fileIsTs } from "./source_code.ts"; import { debugAssert, debugAssertIsNonNull } from "../utils/asserts.ts"; import type * as ts from "typescript"; @@ -41,7 +40,6 @@ const TokenProto = Object.create(Object.prototype, { export function parseTokens(): Token[] { debugAssertIsNonNull(filePath); debugAssertIsNonNull(sourceText); - debugAssertIsNonNull(buffer); // Lazy-load TypeScript. // `./typescript.cjs` is path to the bundle in `dist` directory, as well as relative path in `src-js`, @@ -53,16 +51,12 @@ export function parseTokens(): Token[] { tsSyntaxKind = tsModule.SyntaxKind; } - // Get source type from flags in buffer. - // Both flags are `bool`s in Rust, so 0 = false, 1 = true. - const isTs = buffer[IS_TS_FLAG_POS] === 1, - isJsx = buffer[IS_JSX_FLAG_POS] === 1; - - const scriptKind = isTs - ? isJsx + // Determine language from flags in buffer + const scriptKind = fileIsTs() + ? fileIsJsx() ? tsModule.ScriptKind.TSX : tsModule.ScriptKind.TS - : isJsx + : fileIsJsx() ? tsModule.ScriptKind.JSX : tsModule.ScriptKind.JS; diff --git a/apps/oxlint/test/fixtures/languageOptions/files/index.ts b/apps/oxlint/test/fixtures/languageOptions/files/index.ts new file mode 100644 index 0000000000000..2756c24c45775 --- /dev/null +++ b/apps/oxlint/test/fixtures/languageOptions/files/index.ts @@ -0,0 +1 @@ +let x; diff --git a/apps/oxlint/test/fixtures/languageOptions/output.snap.md b/apps/oxlint/test/fixtures/languageOptions/output.snap.md index 72f5af13c481c..2e320c03fba62 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","ecmaFeatures":{"globalReturn":true,"impliedStrict":false}} + | parserOptions: {"sourceType":"commonjs","ecmaFeatures":{"jsx":true,"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","ecmaFeatures":{"globalReturn":false,"impliedStrict":false}} + | parserOptions: {"sourceType":"script","ecmaFeatures":{"jsx":true,"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","ecmaFeatures":{"globalReturn":false,"impliedStrict":true}} + | parserOptions: {"sourceType":"module","ecmaFeatures":{"jsx":true,"globalReturn":false,"impliedStrict":true}} | globals: {} | env: {"builtin":true} ,-[files/index.mjs:1:1] @@ -813,8 +813,19 @@ : ^ `---- -Found 0 warnings and 4 errors. -Finished in Xms on 3 files with 1 rules using X threads. + x language-options-plugin(lang): languageOptions: + | sourceType: script + | ecmaVersion: 2026 + | parserOptions: {"sourceType":"script","ecmaFeatures":{"jsx":false,"globalReturn":false,"impliedStrict":false}} + | globals: {} + | env: {"builtin":true} + ,-[files/index.ts:1:1] + 1 | let x; + : ^ + `---- + +Found 0 warnings and 5 errors. +Finished in Xms on 4 files with 1 rules using X threads. ``` # stderr