diff --git a/apps/oxlint/conformance/snapshot.md b/apps/oxlint/conformance/snapshot.md index 85abbb21fd611..8044513bf95a4 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 | 232 | 79.5% | -| Partially passing | 60 | 20.5% | +| Fully passing | 235 | 80.5% | +| Partially passing | 57 | 19.5% | | 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 | 32189 | 97.3% | -| Failing | 794 | 2.4% | +| Passing | 32199 | 97.3% | +| Failing | 784 | 2.4% | | Skipped | 107 | 0.3% | ## Fully Passing Rules @@ -74,6 +74,8 @@ - `keyword-spacing` (1078 tests) (9 skipped) - `line-comment-position` (38 tests) - `linebreak-style` (12 tests) +- `lines-around-comment` (199 tests) +- `lines-around-directive` (239 tests) - `lines-between-class-members` (112 tests) - `max-classes-per-file` (17 tests) - `max-depth` (25 tests) @@ -185,6 +187,7 @@ - `no-ternary` (4 tests) - `no-this-before-super` (63 tests) - `no-throw-literal` (41 tests) +- `no-trailing-spaces` (54 tests) - `no-unassigned-vars` (23 tests) - `no-undef-init` (28 tests) - `no-underscore-dangle` (116 tests) @@ -266,8 +269,6 @@ - `func-call-spacing` - 137 / 151 (90.7%) - `id-blacklist` - 120 / 131 (91.6%) - `id-denylist` - 132 / 143 (92.3%) -- `lines-around-comment` - 198 / 199 (99.5%) -- `lines-around-directive` - 231 / 239 (96.7%) - `logical-assignment-operators` - 291 / 304 (95.7%) - `no-alert` - 36 / 42 (85.7%) - `no-array-constructor` - 145 / 146 (99.3%) @@ -297,7 +298,6 @@ - `no-setter-return` - 161 / 164 (98.2%) - `no-shadow-restricted-names` - 43 / 44 (97.7%) - `no-shadow` - 300 / 308 (97.4%) -- `no-trailing-spaces` - 53 / 54 (98.1%) - `no-undef` - 54 / 94 (57.4%) - `no-undefined` - 37 / 53 (69.8%) - `no-unused-expressions` - 120 / 124 (96.8%) @@ -3045,451 +3045,6 @@ AssertionError [ERR_ASSERTION]: Should have 1 error but had 0: [] at apps/oxlint/dist/index.js -### `lines-around-comment` - -Pass: 198 / 199 (99.5%) -Fail: 1 / 199 (0.5%) -Skip: 0 / 199 (0.0%) - -#### lines-around-comment > invalid - -```js -#!foo -var a = 1; -``` - -```json -{ - "output": "#!foo\n\nvar a = 1;", - "options": [ - { - "afterHashbangComment": true - } - ], - "errors": [ - { - "messageId": "after" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 1 error but had 0: [] - -0 !== 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 - - -### `lines-around-directive` - -Pass: 231 / 239 (96.7%) -Fail: 8 / 239 (3.3%) -Skip: 0 / 239 (0.0%) - -#### lines-around-directive > valid - -```js -#!/usr/bin/env node -'use strict'; -var foo; -``` - -```json -{ - "options": [ - "never" - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline before "use strict" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - endColumn: 13, - 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 - - -#### lines-around-directive > valid - -```js -#!/usr/bin/env node -'use strict'; -'use asm'; -var foo; -``` - -```json -{ - "options": [ - "never" - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline before "use strict" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - endColumn: 13, - 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 - - -#### lines-around-directive > valid - -```js -#!/usr/bin/env node -'use strict'; - -var foo; -``` - -```json -{ - "options": [ - { - "before": "never", - "after": "always" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline before "use strict" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - endColumn: 13, - 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 - - -#### lines-around-directive > valid - -```js -#!/usr/bin/env node -'use strict'; -'use asm'; - -var foo; -``` - -```json -{ - "options": [ - { - "before": "never", - "after": "always" - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline before "use strict" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - endColumn: 13, - 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 - - -#### lines-around-directive > invalid - -```js -#!/usr/bin/env node -'use strict'; -var foo; -``` - -```json -{ - "output": "#!/usr/bin/env node\n\n'use strict';\n\nvar foo;", - "options": [ - "always" - ], - "errors": [ - { - "messageId": "expected", - "data": { - "location": "before", - "value": "use strict" - } - }, - { - "messageId": "expected", - "data": { - "location": "after", - "value": "use strict" - } - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Expected newline after "use strict" directive.', - messageId: 'expected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - 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 - - -#### lines-around-directive > invalid - -```js -#!/usr/bin/env node -'use strict'; -'use asm'; -var foo; -``` - -```json -{ - "output": "#!/usr/bin/env node\n\n'use strict';\n'use asm';\n\nvar foo;", - "options": [ - "always" - ], - "errors": [ - { - "messageId": "expected", - "data": { - "location": "before", - "value": "use strict" - } - }, - { - "messageId": "expected", - "data": { - "location": "after", - "value": "use asm" - } - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Expected newline after "use asm" directive.', - messageId: 'expected', - severity: 1, - nodeType: 'Literal', - line: 3, - column: 0, - endLine: 3, - endColumn: 10, - 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 - - -#### lines-around-directive > invalid - -```js -#!/usr/bin/env node -'use strict'; - -var foo; -``` - -```json -{ - "output": "#!/usr/bin/env node\n\n'use strict';\nvar foo;", - "options": [ - { - "before": "always", - "after": "never" - } - ], - "errors": [ - { - "messageId": "expected", - "data": { - "location": "before", - "value": "use strict" - } - }, - { - "messageId": "unexpected", - "data": { - "location": "after", - "value": "use strict" - } - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline after "use strict" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 2, - column: 0, - endLine: 2, - 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 - - -#### lines-around-directive > invalid - -```js -#!/usr/bin/env node -'use strict'; -'use asm'; - -var foo; -``` - -```json -{ - "output": "#!/usr/bin/env node\n\n'use strict';\n'use asm';\nvar foo;", - "options": [ - { - "before": "always", - "after": "never" - } - ], - "errors": [ - { - "messageId": "expected", - "data": { - "location": "before", - "value": "use strict" - } - }, - { - "messageId": "unexpected", - "data": { - "location": "after", - "value": "use asm" - } - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have 2 errors but had 1: [ - { - ruleId: 'rule-to-test/lines-around-directive', - message: 'Unexpected newline after "use asm" directive.', - messageId: 'unexpected', - severity: 1, - nodeType: 'Literal', - line: 3, - column: 0, - endLine: 3, - endColumn: 10, - 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 - - ### `logical-assignment-operators` Pass: 287 / 304 (94.4%) @@ -84241,51 +83796,6 @@ AssertionError [ERR_ASSERTION]: Should have 1 error but had 0: [] at apps/oxlint/dist/index.js -### `no-trailing-spaces` - -Pass: 53 / 54 (98.1%) -Fail: 1 / 54 (1.9%) -Skip: 0 / 54 (0.0%) - -#### no-trailing-spaces > valid - -```js -#!/usr/bin/env node -``` - -```json -{ - "options": [ - { - "ignoreComments": true - } - ] -} -``` - -AssertionError [ERR_ASSERTION]: Should have no errors but had 1: [ - { - ruleId: 'rule-to-test/no-trailing-spaces', - message: 'Trailing spaces not allowed.', - messageId: 'trailingSpace', - severity: 1, - nodeType: null, - line: 1, - column: 19, - endLine: 1, - endColumn: 20, - 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-undef` Pass: 54 / 94 (57.4%) diff --git a/apps/oxlint/src-js/generated/deserialize.js b/apps/oxlint/src-js/generated/deserialize.js index d50a3a9d04399..2fcdb22e66c42 100644 --- a/apps/oxlint/src-js/generated/deserialize.js +++ b/apps/oxlint/src-js/generated/deserialize.js @@ -61,7 +61,19 @@ function deserializeProgram(pos) { throw Error("Comments are only accessible while linting the file"); // Deserialize the comments. // Replace this getter with the comments array, so we don't deserialize twice. - let comments = deserializeVecComment(pos + 24); + let comments = deserializeVecComment(pos + 24), + { hashbang } = this; + if (hashbang !== null) { + let start, end; + comments.unshift({ + __proto__: NodeProto, + type: "Shebang", + value: hashbang.value, + start: (start = hashbang.start), + end: (end = hashbang.end), + range: [start, end], + }); + } Object.defineProperty(this, "comments", { value: comments }); return comments; }, diff --git a/apps/oxlint/src-js/plugins/types.ts b/apps/oxlint/src-js/plugins/types.ts index e1839328ab23f..1d5ca68712d81 100644 --- a/apps/oxlint/src-js/plugins/types.ts +++ b/apps/oxlint/src-js/plugins/types.ts @@ -32,7 +32,7 @@ export type NodeOrToken = Node | Token | Comment; // Comment. export interface Comment extends Span { - type: "Line" | "Block"; + type: "Line" | "Block" | "Shebang"; value: string; } diff --git a/apps/oxlint/test/fixtures/comments/files/hashbang.js b/apps/oxlint/test/fixtures/comments/files/hashbang.js new file mode 100644 index 0000000000000..e8a36edf8e9ac --- /dev/null +++ b/apps/oxlint/test/fixtures/comments/files/hashbang.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +// Line comment after hashbang +/* Block comment after hashbang */ +const topLevelVariable1 = 1; +const topLevelVariable2 = 2; + +export function topLevelFunction() {} diff --git a/apps/oxlint/test/fixtures/comments/output.snap.md b/apps/oxlint/test/fixtures/comments/output.snap.md index b1623ecb0cf71..4f85a8ce10dcf 100644 --- a/apps/oxlint/test/fixtures/comments/output.snap.md +++ b/apps/oxlint/test/fixtures/comments/output.snap.md @@ -228,6 +228,70 @@ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `---- + x test-comments(test-comments): VariableDeclaration(topLevelVariable1): + | getCommentsBefore: 3 comments + | [0] Shebang: "/usr/bin/env node" at [0, 19] + | [1] Line: " Line comment after hashbang" at [20, 50] + | [2] Block: " Block comment after hashbang " at [51, 85] + | getCommentsInside: 0 comments + | getCommentsAfter: 0 comments + | commentsExistBetween(id, init): false + ,-[files/hashbang.js:4:1] + 3 | /* Block comment after hashbang */ + 4 | const topLevelVariable1 = 1; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 5 | const topLevelVariable2 = 2; + `---- + + x test-comments(test-comments): getAllComments: 3 comments + | [0] Shebang: "/usr/bin/env node" at [0, 19] + | [1] Line: " Line comment after hashbang" at [20, 50] + | [2] Block: " Block comment after hashbang " at [51, 85] + ,-[files/hashbang.js:4:1] + 3 | /* Block comment after hashbang */ + 4 | ,-> const topLevelVariable1 = 1; + 5 | | const topLevelVariable2 = 2; + 6 | | + 7 | `-> export function topLevelFunction() {} + `---- + + x test-comments(test-comments): commentsExistBetween(topLevelVariable2, topLevelFunction): false + ,-[files/hashbang.js:5:1] + 4 | const topLevelVariable1 = 1; + 5 | const topLevelVariable2 = 2; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x test-comments(test-comments): VariableDeclaration(topLevelVariable2): + | getCommentsBefore: 0 comments + | getCommentsInside: 0 comments + | getCommentsAfter: 0 comments + | commentsExistBetween(id, init): false + ,-[files/hashbang.js:5:1] + 4 | const topLevelVariable1 = 1; + 5 | const topLevelVariable2 = 2; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x test-comments(test-comments): commentsExistBetween(topLevelFunction, topLevelVariable2): false + ,-[files/hashbang.js:7:8] + 6 | + 7 | export function topLevelFunction() {} + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x test-comments(test-comments): FunctionDeclaration(topLevelFunction): + | getCommentsBefore: 0 comments + | getCommentsInside: 0 comments + | getCommentsAfter: 0 comments + ,-[files/hashbang.js:7:8] + 6 | + 7 | export function topLevelFunction() {} + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + x test-comments(test-comments): VariableDeclaration(topLevelVariable1): | getCommentsBefore: 0 comments | getCommentsInside: 0 comments @@ -391,8 +455,8 @@ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `---- -Found 0 warnings and 26 errors. -Finished in Xms on 2 files using X threads. +Found 0 warnings and 32 errors. +Finished in Xms on 3 files using X threads. ``` # stderr diff --git a/crates/oxc_ast/src/serialize/mod.rs b/crates/oxc_ast/src/serialize/mod.rs index a2b1970cd1134..e86daaead8f40 100644 --- a/crates/oxc_ast/src/serialize/mod.rs +++ b/crates/oxc_ast/src/serialize/mod.rs @@ -138,6 +138,18 @@ impl Program<'_> { // Deserialize the comments. // Replace this getter with the comments array, so we don't deserialize twice. const comments = DESER[Vec](POS_OFFSET.comments); + // If there's a hashbang, prepend it as a `Shebang` comment + const { hashbang } = this; + if (hashbang !== null) { + let start, end; + comments.unshift({ + type: 'Shebang', + value: hashbang.value, + start: start = hashbang.start, + end: end = hashbang.end, + ...(RANGE && { range: [start, end] }), + }); + } Object.defineProperty(this, 'comments', { value: comments }); return comments; },