diff --git a/apps/oxlint/src-js/generated/constants.ts b/apps/oxlint/src-js/generated/constants.ts index 14f4f407d74af..f4092171513f2 100644 --- a/apps/oxlint/src-js/generated/constants.ts +++ b/apps/oxlint/src-js/generated/constants.ts @@ -5,5 +5,6 @@ export const BUFFER_SIZE = 2147483616; export const BUFFER_ALIGN = 4294967296; export const DATA_POINTER_POS_32 = 536870902; export const IS_TS_FLAG_POS = 2147483612; +export const IS_JSX_FLAG_POS = 2147483613; export const PROGRAM_OFFSET = 0; export const SOURCE_LEN_OFFSET = 16; diff --git a/apps/oxlint/src-js/plugins/source_code.ts b/apps/oxlint/src-js/plugins/source_code.ts index bcc1019ad4130..95c6bd2aa4e87 100644 --- a/apps/oxlint/src-js/plugins/source_code.ts +++ b/apps/oxlint/src-js/plugins/source_code.ts @@ -25,7 +25,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`. -let buffer: BufferWithArrays | null = null; +export let buffer: BufferWithArrays | null = null; // Indicates if the original source text has a BOM. Set before linting a file by `setupSourceForFile`. let hasBOM = false; diff --git a/apps/oxlint/src-js/plugins/tokens_parse.ts b/apps/oxlint/src-js/plugins/tokens_parse.ts index e21b63390074b..20bff11e50dcd 100644 --- a/apps/oxlint/src-js/plugins/tokens_parse.ts +++ b/apps/oxlint/src-js/plugins/tokens_parse.ts @@ -5,7 +5,8 @@ import { createRequire } from "node:module"; import { filePath } from "./context.ts"; import { getNodeLoc } from "./location.ts"; -import { sourceText } from "./source_code.ts"; +import { buffer, sourceText } from "./source_code.ts"; +import { IS_JSX_FLAG_POS, IS_TS_FLAG_POS } from "../generated/constants.ts"; import { debugAssert, debugAssertIsNonNull } from "../utils/asserts.ts"; import type * as ts from "typescript"; @@ -35,11 +36,12 @@ const TokenProto = Object.create(Object.prototype, { /** * Initialize TS-ESLint tokens for current file. * - * Caller must ensure `filePath` and `sourceText` are initialized before calling this function. + * Caller must ensure `filePath`, `sourceText`, and `buffer` are initialized before calling this function. */ 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`, @@ -51,6 +53,19 @@ 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 + ? tsModule.ScriptKind.TSX + : tsModule.ScriptKind.TS + : isJsx + ? tsModule.ScriptKind.JSX + : tsModule.ScriptKind.JS; + // Parse source text into TypeScript AST const tsAst = tsModule.createSourceFile( filePath, @@ -62,8 +77,7 @@ export function parseTokens(): Token[] { setExternalModuleIndicator: undefined, }, true, // `setParentNodes` - // TODO: Use `TS` or `TSX` depending on source type - tsModule.ScriptKind.TSX, + scriptKind, ); // Check that TypeScript hasn't altered source text. diff --git a/apps/oxlint/src/js_plugins/parse.rs b/apps/oxlint/src/js_plugins/parse.rs index f1281d1af47c6..f8d75d2bfe232 100644 --- a/apps/oxlint/src/js_plugins/parse.rs +++ b/apps/oxlint/src/js_plugins/parse.rs @@ -193,7 +193,8 @@ unsafe fn parse_raw_impl( // Write metadata into end of buffer #[allow(clippy::cast_possible_truncation)] - let metadata = RawTransferMetadata::new(program_offset); + let metadata = + RawTransferMetadata::new(program_offset, source_type.is_typescript(), source_type.is_jsx()); const RAW_METADATA_OFFSET: usize = BUFFER_SIZE - RAW_METADATA_SIZE; const _: () = assert!(RAW_METADATA_OFFSET.is_multiple_of(BUMP_ALIGN)); // SAFETY: `RAW_METADATA_OFFSET` is less than length of `buffer`. diff --git a/apps/oxlint/test/fixtures/tokens/files/generic_arrow.ts b/apps/oxlint/test/fixtures/tokens/files/generic_arrow.ts new file mode 100644 index 0000000000000..21b413c1a2ea4 --- /dev/null +++ b/apps/oxlint/test/fixtures/tokens/files/generic_arrow.ts @@ -0,0 +1,8 @@ +const obj = { + fn: (arg: T): T => { + return arg; + }, +}; + +// A comment after the object +export { obj }; diff --git a/apps/oxlint/test/fixtures/tokens/files/jsx_element.tsx b/apps/oxlint/test/fixtures/tokens/files/jsx_element.tsx new file mode 100644 index 0000000000000..11d5f653acaaa --- /dev/null +++ b/apps/oxlint/test/fixtures/tokens/files/jsx_element.tsx @@ -0,0 +1,6 @@ +const Component = () => { + return
Hello
; +}; + +// A comment after the component +export { Component }; diff --git a/apps/oxlint/test/fixtures/tokens/output.snap.md b/apps/oxlint/test/fixtures/tokens/output.snap.md index 4c33eb5885070..2aa56b7478e51 100644 --- a/apps/oxlint/test/fixtures/tokens/output.snap.md +++ b/apps/oxlint/test/fixtures/tokens/output.snap.md @@ -3,6 +3,330 @@ # stdout ``` + x tokens-plugin(tokens): Keyword ("const") + ,-[files/generic_arrow.ts:1:1] + 1 | const obj = { + : ^^^^^ + 2 | fn: (arg: T): T => { + `---- + + x tokens-plugin(tokens): Tokens: + | Keyword loc= 1:0 - 1:5 range= 0-5 "const" + | Identifier loc= 1:6 - 1:9 range= 6-9 "obj" + | Punctuator loc= 1:10 - 1:11 range= 10-11 "=" + | Punctuator loc= 1:12 - 1:13 range= 12-13 "{" + | Identifier loc= 2:2 - 2:4 range= 16-18 "fn" + | Punctuator loc= 2:4 - 2:5 range= 18-19 ":" + | Punctuator loc= 2:6 - 2:7 range= 20-21 "<" + | Identifier loc= 2:7 - 2:8 range= 21-22 "T" + | Punctuator loc= 2:8 - 2:9 range= 22-23 ">" + | Punctuator loc= 2:9 - 2:10 range= 23-24 "(" + | Identifier loc= 2:10 - 2:13 range= 24-27 "arg" + | Punctuator loc= 2:13 - 2:14 range= 27-28 ":" + | Identifier loc= 2:15 - 2:16 range= 29-30 "T" + | Punctuator loc= 2:16 - 2:17 range= 30-31 ")" + | Punctuator loc= 2:17 - 2:18 range= 31-32 ":" + | Identifier loc= 2:19 - 2:20 range= 33-34 "T" + | Punctuator loc= 2:21 - 2:23 range= 35-37 "=>" + | Punctuator loc= 2:24 - 2:25 range= 38-39 "{" + | Keyword loc= 3:4 - 3:10 range= 44-50 "return" + | Identifier loc= 3:11 - 3:14 range= 51-54 "arg" + | Punctuator loc= 3:14 - 3:15 range= 54-55 ";" + | Punctuator loc= 4:2 - 4:3 range= 58-59 "}" + | Punctuator loc= 4:3 - 4:4 range= 59-60 "," + | Punctuator loc= 5:0 - 5:1 range= 61-62 "}" + | Punctuator loc= 5:1 - 5:2 range= 62-63 ";" + | Keyword loc= 8:0 - 8:6 range= 95-101 "export" + | Punctuator loc= 8:7 - 8:8 range= 102-103 "{" + | Identifier loc= 8:9 - 8:12 range= 104-107 "obj" + | Punctuator loc= 8:13 - 8:14 range= 108-109 "}" + | Punctuator loc= 8:14 - 8:15 range= 109-110 ";" + ,-[files/generic_arrow.ts:1:1] + 1 | ,-> const obj = { + 2 | | fn: (arg: T): T => { + 3 | | return arg; + 4 | | }, + 5 | | }; + 6 | | + 7 | | // A comment after the object + 8 | `-> export { obj }; + `---- + + x tokens-plugin(tokens): Tokens and comments: + | Keyword loc= 1:0 - 1:5 range= 0-5 "const" + | Identifier loc= 1:6 - 1:9 range= 6-9 "obj" + | Punctuator loc= 1:10 - 1:11 range= 10-11 "=" + | Punctuator loc= 1:12 - 1:13 range= 12-13 "{" + | Identifier loc= 2:2 - 2:4 range= 16-18 "fn" + | Punctuator loc= 2:4 - 2:5 range= 18-19 ":" + | Punctuator loc= 2:6 - 2:7 range= 20-21 "<" + | Identifier loc= 2:7 - 2:8 range= 21-22 "T" + | Punctuator loc= 2:8 - 2:9 range= 22-23 ">" + | Punctuator loc= 2:9 - 2:10 range= 23-24 "(" + | Identifier loc= 2:10 - 2:13 range= 24-27 "arg" + | Punctuator loc= 2:13 - 2:14 range= 27-28 ":" + | Identifier loc= 2:15 - 2:16 range= 29-30 "T" + | Punctuator loc= 2:16 - 2:17 range= 30-31 ")" + | Punctuator loc= 2:17 - 2:18 range= 31-32 ":" + | Identifier loc= 2:19 - 2:20 range= 33-34 "T" + | Punctuator loc= 2:21 - 2:23 range= 35-37 "=>" + | Punctuator loc= 2:24 - 2:25 range= 38-39 "{" + | Keyword loc= 3:4 - 3:10 range= 44-50 "return" + | Identifier loc= 3:11 - 3:14 range= 51-54 "arg" + | Punctuator loc= 3:14 - 3:15 range= 54-55 ";" + | Punctuator loc= 4:2 - 4:3 range= 58-59 "}" + | Punctuator loc= 4:3 - 4:4 range= 59-60 "," + | Punctuator loc= 5:0 - 5:1 range= 61-62 "}" + | Punctuator loc= 5:1 - 5:2 range= 62-63 ";" + | Line loc= 7:0 - 7:29 range= 65-94 " A comment after the object" + | Keyword loc= 8:0 - 8:6 range= 95-101 "export" + | Punctuator loc= 8:7 - 8:8 range= 102-103 "{" + | Identifier loc= 8:9 - 8:12 range= 104-107 "obj" + | Punctuator loc= 8:13 - 8:14 range= 108-109 "}" + | Punctuator loc= 8:14 - 8:15 range= 109-110 ";" + ,-[files/generic_arrow.ts:1:1] + 1 | ,-> const obj = { + 2 | | fn: (arg: T): T => { + 3 | | return arg; + 4 | | }, + 5 | | }; + 6 | | + 7 | | // A comment after the object + 8 | `-> export { obj }; + `---- + + x tokens-plugin(tokens): Identifier ("obj") + ,-[files/generic_arrow.ts:1:7] + 1 | const obj = { + : ^^^ + 2 | fn: (arg: T): T => { + `---- + + x tokens-plugin(tokens): Punctuator ("=") + ,-[files/generic_arrow.ts:1:11] + 1 | const obj = { + : ^ + 2 | fn: (arg: T): T => { + `---- + + x tokens-plugin(tokens): Punctuator ("{") + ,-[files/generic_arrow.ts:1:13] + 1 | const obj = { + : ^ + 2 | fn: (arg: T): T => { + `---- + + x tokens-plugin(tokens): Identifier ("fn") + ,-[files/generic_arrow.ts:2:3] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator (":") + ,-[files/generic_arrow.ts:2:5] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator ("<") + ,-[files/generic_arrow.ts:2:7] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Identifier ("T") + ,-[files/generic_arrow.ts:2:8] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator (">") + ,-[files/generic_arrow.ts:2:9] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator ("(") + ,-[files/generic_arrow.ts:2:10] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Identifier ("arg") + ,-[files/generic_arrow.ts:2:11] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^^^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator (":") + ,-[files/generic_arrow.ts:2:14] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Identifier ("T") + ,-[files/generic_arrow.ts:2:16] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator (")") + ,-[files/generic_arrow.ts:2:17] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator (":") + ,-[files/generic_arrow.ts:2:18] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Identifier ("T") + ,-[files/generic_arrow.ts:2:20] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator ("=>") + ,-[files/generic_arrow.ts:2:22] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Punctuator ("{") + ,-[files/generic_arrow.ts:2:25] + 1 | const obj = { + 2 | fn: (arg: T): T => { + : ^ + 3 | return arg; + `---- + + x tokens-plugin(tokens): Keyword ("return") + ,-[files/generic_arrow.ts:3:5] + 2 | fn: (arg: T): T => { + 3 | return arg; + : ^^^^^^ + 4 | }, + `---- + + x tokens-plugin(tokens): Identifier ("arg") + ,-[files/generic_arrow.ts:3:12] + 2 | fn: (arg: T): T => { + 3 | return arg; + : ^^^ + 4 | }, + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/generic_arrow.ts:3:15] + 2 | fn: (arg: T): T => { + 3 | return arg; + : ^ + 4 | }, + `---- + + x tokens-plugin(tokens): Punctuator ("}") + ,-[files/generic_arrow.ts:4:3] + 3 | return arg; + 4 | }, + : ^ + 5 | }; + `---- + + x tokens-plugin(tokens): Punctuator (",") + ,-[files/generic_arrow.ts:4:4] + 3 | return arg; + 4 | }, + : ^ + 5 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("}") + ,-[files/generic_arrow.ts:5:1] + 4 | }, + 5 | }; + : ^ + 6 | + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/generic_arrow.ts:5:2] + 4 | }, + 5 | }; + : ^ + 6 | + `---- + + x tokens-plugin(tokens): Line (" A comment after the object") + ,-[files/generic_arrow.ts:7:1] + 6 | + 7 | // A comment after the object + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 8 | export { obj }; + `---- + + x tokens-plugin(tokens): Keyword ("export") + ,-[files/generic_arrow.ts:8:1] + 7 | // A comment after the object + 8 | export { obj }; + : ^^^^^^ + `---- + + x tokens-plugin(tokens): Punctuator ("{") + ,-[files/generic_arrow.ts:8:8] + 7 | // A comment after the object + 8 | export { obj }; + : ^ + `---- + + x tokens-plugin(tokens): Identifier ("obj") + ,-[files/generic_arrow.ts:8:10] + 7 | // A comment after the object + 8 | export { obj }; + : ^^^ + `---- + + x tokens-plugin(tokens): Punctuator ("}") + ,-[files/generic_arrow.ts:8:14] + 7 | // A comment after the object + 8 | export { obj }; + : ^ + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/generic_arrow.ts:8:15] + 7 | // A comment after the object + 8 | export { obj }; + : ^ + `---- + x tokens-plugin(tokens): Line (" Leading comment") ,-[files/index.js:1:1] 1 | // Leading comment @@ -161,8 +485,295 @@ : ^^^^^^^^^^^^^^^^^^^ `---- -Found 0 warnings and 16 errors. -Finished in Xms on 1 file with 1 rules using X threads. + x tokens-plugin(tokens): Keyword ("const") + ,-[files/jsx_element.tsx:1:1] + 1 | const Component = () => { + : ^^^^^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Tokens: + | Keyword loc= 1:0 - 1:5 range= 0-5 "const" + | Identifier loc= 1:6 - 1:15 range= 6-15 "Component" + | Punctuator loc= 1:16 - 1:17 range= 16-17 "=" + | Punctuator loc= 1:18 - 1:19 range= 18-19 "(" + | Punctuator loc= 1:19 - 1:20 range= 19-20 ")" + | Punctuator loc= 1:21 - 1:23 range= 21-23 "=>" + | Punctuator loc= 1:24 - 1:25 range= 24-25 "{" + | Keyword loc= 2:2 - 2:8 range= 28-34 "return" + | Punctuator loc= 2:9 - 2:10 range= 35-36 "<" + | JSXIdentifier loc= 2:10 - 2:13 range= 36-39 "div" + | JSXIdentifier loc= 2:14 - 2:23 range= 40-49 "className" + | Punctuator loc= 2:23 - 2:24 range= 49-50 "=" + | JSXText loc= 2:24 - 2:30 range= 50-56 "\"test\"" + | Punctuator loc= 2:30 - 2:31 range= 56-57 ">" + | JSXText loc= 2:31 - 2:36 range= 57-62 "Hello" + | Punctuator loc= 2:36 - 2:37 range= 62-63 "<" + | Punctuator loc= 2:37 - 2:38 range= 63-64 "/" + | JSXIdentifier loc= 2:38 - 2:41 range= 64-67 "div" + | Punctuator loc= 2:41 - 2:42 range= 67-68 ">" + | Punctuator loc= 2:42 - 2:43 range= 68-69 ";" + | Punctuator loc= 3:0 - 3:1 range= 70-71 "}" + | Punctuator loc= 3:1 - 3:2 range= 71-72 ";" + | Keyword loc= 6:0 - 6:6 range= 107-113 "export" + | Punctuator loc= 6:7 - 6:8 range= 114-115 "{" + | Identifier loc= 6:9 - 6:18 range= 116-125 "Component" + | Punctuator loc= 6:19 - 6:20 range= 126-127 "}" + | Punctuator loc= 6:20 - 6:21 range= 127-128 ";" + ,-[files/jsx_element.tsx:1:1] + 1 | ,-> const Component = () => { + 2 | | return
Hello
; + 3 | | }; + 4 | | + 5 | | // A comment after the component + 6 | `-> export { Component }; + `---- + + x tokens-plugin(tokens): Tokens and comments: + | Keyword loc= 1:0 - 1:5 range= 0-5 "const" + | Identifier loc= 1:6 - 1:15 range= 6-15 "Component" + | Punctuator loc= 1:16 - 1:17 range= 16-17 "=" + | Punctuator loc= 1:18 - 1:19 range= 18-19 "(" + | Punctuator loc= 1:19 - 1:20 range= 19-20 ")" + | Punctuator loc= 1:21 - 1:23 range= 21-23 "=>" + | Punctuator loc= 1:24 - 1:25 range= 24-25 "{" + | Keyword loc= 2:2 - 2:8 range= 28-34 "return" + | Punctuator loc= 2:9 - 2:10 range= 35-36 "<" + | JSXIdentifier loc= 2:10 - 2:13 range= 36-39 "div" + | JSXIdentifier loc= 2:14 - 2:23 range= 40-49 "className" + | Punctuator loc= 2:23 - 2:24 range= 49-50 "=" + | JSXText loc= 2:24 - 2:30 range= 50-56 "\"test\"" + | Punctuator loc= 2:30 - 2:31 range= 56-57 ">" + | JSXText loc= 2:31 - 2:36 range= 57-62 "Hello" + | Punctuator loc= 2:36 - 2:37 range= 62-63 "<" + | Punctuator loc= 2:37 - 2:38 range= 63-64 "/" + | JSXIdentifier loc= 2:38 - 2:41 range= 64-67 "div" + | Punctuator loc= 2:41 - 2:42 range= 67-68 ">" + | Punctuator loc= 2:42 - 2:43 range= 68-69 ";" + | Punctuator loc= 3:0 - 3:1 range= 70-71 "}" + | Punctuator loc= 3:1 - 3:2 range= 71-72 ";" + | Line loc= 5:0 - 5:32 range= 74-106 " A comment after the component" + | Keyword loc= 6:0 - 6:6 range= 107-113 "export" + | Punctuator loc= 6:7 - 6:8 range= 114-115 "{" + | Identifier loc= 6:9 - 6:18 range= 116-125 "Component" + | Punctuator loc= 6:19 - 6:20 range= 126-127 "}" + | Punctuator loc= 6:20 - 6:21 range= 127-128 ";" + ,-[files/jsx_element.tsx:1:1] + 1 | ,-> const Component = () => { + 2 | | return
Hello
; + 3 | | }; + 4 | | + 5 | | // A comment after the component + 6 | `-> export { Component }; + `---- + + x tokens-plugin(tokens): Identifier ("Component") + ,-[files/jsx_element.tsx:1:7] + 1 | const Component = () => { + : ^^^^^^^^^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Punctuator ("=") + ,-[files/jsx_element.tsx:1:17] + 1 | const Component = () => { + : ^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Punctuator ("(") + ,-[files/jsx_element.tsx:1:19] + 1 | const Component = () => { + : ^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Punctuator (")") + ,-[files/jsx_element.tsx:1:20] + 1 | const Component = () => { + : ^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Punctuator ("=>") + ,-[files/jsx_element.tsx:1:22] + 1 | const Component = () => { + : ^^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Punctuator ("{") + ,-[files/jsx_element.tsx:1:25] + 1 | const Component = () => { + : ^ + 2 | return
Hello
; + `---- + + x tokens-plugin(tokens): Keyword ("return") + ,-[files/jsx_element.tsx:2:3] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("<") + ,-[files/jsx_element.tsx:2:10] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): JSXIdentifier ("div") + ,-[files/jsx_element.tsx:2:11] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): JSXIdentifier ("className") + ,-[files/jsx_element.tsx:2:15] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^^^^^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("=") + ,-[files/jsx_element.tsx:2:24] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): JSXText ("\"test\"") + ,-[files/jsx_element.tsx:2:25] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator (">") + ,-[files/jsx_element.tsx:2:31] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): JSXText ("Hello") + ,-[files/jsx_element.tsx:2:32] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("<") + ,-[files/jsx_element.tsx:2:37] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("/") + ,-[files/jsx_element.tsx:2:38] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): JSXIdentifier ("div") + ,-[files/jsx_element.tsx:2:39] + 1 | const Component = () => { + 2 | return
Hello
; + : ^^^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator (">") + ,-[files/jsx_element.tsx:2:42] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/jsx_element.tsx:2:43] + 1 | const Component = () => { + 2 | return
Hello
; + : ^ + 3 | }; + `---- + + x tokens-plugin(tokens): Punctuator ("}") + ,-[files/jsx_element.tsx:3:1] + 2 | return
Hello
; + 3 | }; + : ^ + 4 | + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/jsx_element.tsx:3:2] + 2 | return
Hello
; + 3 | }; + : ^ + 4 | + `---- + + x tokens-plugin(tokens): Line (" A comment after the component") + ,-[files/jsx_element.tsx:5:1] + 4 | + 5 | // A comment after the component + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | export { Component }; + `---- + + x tokens-plugin(tokens): Keyword ("export") + ,-[files/jsx_element.tsx:6:1] + 5 | // A comment after the component + 6 | export { Component }; + : ^^^^^^ + `---- + + x tokens-plugin(tokens): Punctuator ("{") + ,-[files/jsx_element.tsx:6:8] + 5 | // A comment after the component + 6 | export { Component }; + : ^ + `---- + + x tokens-plugin(tokens): Identifier ("Component") + ,-[files/jsx_element.tsx:6:10] + 5 | // A comment after the component + 6 | export { Component }; + : ^^^^^^^^^ + `---- + + x tokens-plugin(tokens): Punctuator ("}") + ,-[files/jsx_element.tsx:6:20] + 5 | // A comment after the component + 6 | export { Component }; + : ^ + `---- + + x tokens-plugin(tokens): Punctuator (";") + ,-[files/jsx_element.tsx:6:21] + 5 | // A comment after the component + 6 | export { Component }; + : ^ + `---- + +Found 0 warnings and 79 errors. +Finished in Xms on 3 files with 1 rules using X threads. ``` # stderr diff --git a/crates/oxc_ast_macros/src/generated/structs.rs b/crates/oxc_ast_macros/src/generated/structs.rs index 99e4b8e48d808..f6a9b4cd29014 100644 --- a/crates/oxc_ast_macros/src/generated/structs.rs +++ b/crates/oxc_ast_macros/src/generated/structs.rs @@ -96,7 +96,7 @@ pub static STRUCTS: phf::Map<&'static str, StructDetails> = ::phf::Map { ("TSInterfaceBody", StructDetails { field_order: None }), ("CatchParameter", StructDetails { field_order: None }), ("RawTransferData", StructDetails { field_order: None }), - ("RawTransferMetadata", StructDetails { field_order: Some(&[1, 2, 0]) }), + ("RawTransferMetadata", StructDetails { field_order: Some(&[1, 2, 3, 0]) }), ("ObjectProperty", StructDetails { field_order: Some(&[0, 3, 1, 2, 4, 5, 6]) }), ("DebuggerStatement", StructDetails { field_order: None }), ("TSModuleDeclaration", StructDetails { field_order: Some(&[0, 1, 2, 4, 5, 3]) }), @@ -136,7 +136,7 @@ pub static STRUCTS: phf::Map<&'static str, StructDetails> = ::phf::Map { ("TSTupleType", StructDetails { field_order: None }), ("TSTypeParameter", StructDetails { field_order: None }), ("ErrorLabel", StructDetails { field_order: Some(&[1, 0]) }), - ("RawTransferMetadata2", StructDetails { field_order: Some(&[1, 2, 0]) }), + ("RawTransferMetadata2", StructDetails { field_order: Some(&[1, 2, 3, 0]) }), ("ChainExpression", StructDetails { field_order: None }), ("BindingProperty", StructDetails { field_order: None }), ("NullLiteral", StructDetails { field_order: None }), diff --git a/crates/oxc_linter/src/generated/assert_layouts.rs b/crates/oxc_linter/src/generated/assert_layouts.rs index f3104ce0443de..15b83f8606282 100644 --- a/crates/oxc_linter/src/generated/assert_layouts.rs +++ b/crates/oxc_linter/src/generated/assert_layouts.rs @@ -9,21 +9,23 @@ use crate::*; #[cfg(target_pointer_width = "64")] const _: () = { - // Padding: 3 bytes + // Padding: 2 bytes assert!(size_of::() == 16); assert!(align_of::() == 8); assert!(offset_of!(RawTransferMetadata2, data_offset) == 8); assert!(offset_of!(RawTransferMetadata2, is_ts) == 12); + assert!(offset_of!(RawTransferMetadata2, is_jsx) == 13); assert!(offset_of!(RawTransferMetadata2, _padding) == 0); }; #[cfg(target_pointer_width = "32")] const _: () = if cfg!(target_family = "wasm") || align_of::() == 8 { - // Padding: 3 bytes + // Padding: 2 bytes assert!(size_of::() == 16); assert!(align_of::() == 8); assert!(offset_of!(RawTransferMetadata2, data_offset) == 8); assert!(offset_of!(RawTransferMetadata2, is_ts) == 12); + assert!(offset_of!(RawTransferMetadata2, is_jsx) == 13); assert!(offset_of!(RawTransferMetadata2, _padding) == 0); }; diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs index 03edcf6d642b1..791402e29dece 100644 --- a/crates/oxc_linter/src/lib.rs +++ b/crates/oxc_linter/src/lib.rs @@ -549,7 +549,9 @@ impl Linter { let program_offset = ptr::from_ref(program) as u32; // Write offset of `Program` in metadata at end of buffer - let metadata = RawTransferMetadata::new(program_offset); + let is_ts = program.source_type.is_typescript(); + let is_jsx = program.source_type.is_jsx(); + let metadata = RawTransferMetadata::new(program_offset, is_ts, is_jsx); let metadata_ptr = allocator.end_ptr().cast::(); // SAFETY: `Allocator` was created by `FixedSizeAllocator` which reserved space after `end_ptr` // for a `RawTransferMetadata`. `end_ptr` is aligned for `RawTransferMetadata`. @@ -682,6 +684,8 @@ pub struct RawTransferMetadata2 { pub data_offset: u32, /// `true` if AST is TypeScript. pub is_ts: bool, + /// `true` if AST is JSX. + pub is_jsx: bool, /// Padding to pad struct to size 16. pub(crate) _padding: u64, } @@ -689,7 +693,7 @@ pub struct RawTransferMetadata2 { use RawTransferMetadata2 as RawTransferMetadata; impl RawTransferMetadata { - pub fn new(data_offset: u32) -> Self { - Self { data_offset, is_ts: false, _padding: 0 } + pub fn new(data_offset: u32, is_ts: bool, is_jsx: bool) -> Self { + Self { data_offset, is_ts, is_jsx, _padding: 0 } } } diff --git a/napi/parser/src-js/generated/constants.js b/napi/parser/src-js/generated/constants.js index 14f4f407d74af..f4092171513f2 100644 --- a/napi/parser/src-js/generated/constants.js +++ b/napi/parser/src-js/generated/constants.js @@ -5,5 +5,6 @@ export const BUFFER_SIZE = 2147483616; export const BUFFER_ALIGN = 4294967296; export const DATA_POINTER_POS_32 = 536870902; export const IS_TS_FLAG_POS = 2147483612; +export const IS_JSX_FLAG_POS = 2147483613; export const PROGRAM_OFFSET = 0; export const SOURCE_LEN_OFFSET = 16; diff --git a/napi/parser/src/generated/assert_layouts.rs b/napi/parser/src/generated/assert_layouts.rs index c272146b3d0eb..f8631288b83f5 100644 --- a/napi/parser/src/generated/assert_layouts.rs +++ b/napi/parser/src/generated/assert_layouts.rs @@ -17,11 +17,12 @@ const _: () = { assert!(offset_of!(RawTransferData, module) == 152); assert!(offset_of!(RawTransferData, errors) == 256); - // Padding: 3 bytes + // Padding: 2 bytes assert!(size_of::() == 16); assert!(align_of::() == 8); assert!(offset_of!(RawTransferMetadata, data_offset) == 8); assert!(offset_of!(RawTransferMetadata, is_ts) == 12); + assert!(offset_of!(RawTransferMetadata, is_jsx) == 13); assert!(offset_of!(RawTransferMetadata, _padding) == 0); // Padding: 7 bytes @@ -75,11 +76,12 @@ const _: () = if cfg!(target_family = "wasm") || align_of::() == 8 { assert!(offset_of!(RawTransferData, module) == 104); assert!(offset_of!(RawTransferData, errors) == 172); - // Padding: 3 bytes + // Padding: 2 bytes assert!(size_of::() == 16); assert!(align_of::() == 8); assert!(offset_of!(RawTransferMetadata, data_offset) == 8); assert!(offset_of!(RawTransferMetadata, is_ts) == 12); + assert!(offset_of!(RawTransferMetadata, is_jsx) == 13); assert!(offset_of!(RawTransferMetadata, _padding) == 0); // Padding: 3 bytes diff --git a/napi/parser/src/raw_transfer_types.rs b/napi/parser/src/raw_transfer_types.rs index a58dc19590f4b..f0792ea6be493 100644 --- a/napi/parser/src/raw_transfer_types.rs +++ b/napi/parser/src/raw_transfer_types.rs @@ -36,13 +36,15 @@ pub struct RawTransferMetadata { pub data_offset: u32, /// `true` if AST is TypeScript. pub is_ts: bool, + /// This field always contains `false` in parser. It's only used in linter. + pub is_jsx: bool, /// Padding to pad struct to size 16. pub(crate) _padding: u64, } impl RawTransferMetadata { pub fn new(data_offset: u32, is_ts: bool) -> Self { - Self { data_offset, is_ts, _padding: 0 } + Self { data_offset, is_ts, is_jsx: false, _padding: 0 } } } diff --git a/tasks/ast_tools/src/generators/raw_transfer.rs b/tasks/ast_tools/src/generators/raw_transfer.rs index 6546031e12576..4bde652111675 100644 --- a/tasks/ast_tools/src/generators/raw_transfer.rs +++ b/tasks/ast_tools/src/generators/raw_transfer.rs @@ -1267,6 +1267,8 @@ struct Constants { data_pointer_pos: u32, /// Offset within buffer of `bool` indicating if AST is TS or JS is_ts_pos: u32, + /// Offset within buffer of `bool` indicating if AST is JSX + is_jsx_pos: u32, /// Offset of `Program` in buffer, relative to position of `RawTransferData` program_offset: u32, /// Offset of `u32` source text length, relative to position of `Program` @@ -1281,6 +1283,7 @@ fn generate_constants(consts: Constants) -> (String, TokenStream) { buffer_size, data_pointer_pos, is_ts_pos, + is_jsx_pos, program_offset, source_len_offset, raw_metadata_size, @@ -1294,6 +1297,7 @@ fn generate_constants(consts: Constants) -> (String, TokenStream) { export const BUFFER_ALIGN = {BLOCK_ALIGN}; export const DATA_POINTER_POS_32 = {data_pointer_pos_32}; export const IS_TS_FLAG_POS = {is_ts_pos}; + export const IS_JSX_FLAG_POS = {is_jsx_pos}; export const PROGRAM_OFFSET = {program_offset}; export const SOURCE_LEN_OFFSET = {source_len_offset}; "); @@ -1327,6 +1331,7 @@ fn get_constants(schema: &Schema) -> Constants { let mut data_offset_field = None; let mut is_ts_field = None; + let mut is_jsx_field = None; for (field1, field2) in raw_metadata_struct.fields.iter().zip(&raw_metadata2_struct.fields) { assert_eq!(field1.name(), field2.name()); assert_eq!(field1.type_id, field2.type_id); @@ -1334,11 +1339,13 @@ fn get_constants(schema: &Schema) -> Constants { match field1.name() { "data_offset" => data_offset_field = Some(field1), "is_ts" => is_ts_field = Some(field1), + "is_jsx" => is_jsx_field = Some(field1), _ => {} } } let data_offset_field = data_offset_field.unwrap(); let is_ts_field = is_ts_field.unwrap(); + let is_jsx_field = is_jsx_field.unwrap(); let raw_metadata_size = raw_metadata_struct.layout_64().size; @@ -1354,6 +1361,7 @@ fn get_constants(schema: &Schema) -> Constants { let raw_metadata_pos = buffer_size - raw_metadata_size; let data_pointer_pos = raw_metadata_pos + data_offset_field.offset_64(); let is_ts_pos = raw_metadata_pos + is_ts_field.offset_64(); + let is_jsx_pos = raw_metadata_pos + is_jsx_field.offset_64(); let program_offset = schema .type_by_name("RawTransferData") @@ -1374,6 +1382,7 @@ fn get_constants(schema: &Schema) -> Constants { buffer_size, data_pointer_pos, is_ts_pos, + is_jsx_pos, program_offset, source_len_offset, raw_metadata_size,