Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 20 additions & 66 deletions apps/oxlint/src-js/plugins/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { ast, initAst, sourceText } from "./source_code.ts";
import { firstTokenAtOrAfter } from "./tokens_methods.ts";
import { debugAssertIsNonNull } from "../utils/asserts.ts";

import type { Comment, Node, NodeOrToken } from "./types.ts";
Expand Down Expand Up @@ -44,29 +45,20 @@ export function getCommentsBefore(nodeOrToken: NodeOrToken): Comment[] {
debugAssertIsNonNull(ast);
debugAssertIsNonNull(sourceText);

const { comments } = ast,
commentsLength = comments.length;
const { comments } = ast;

let targetStart = nodeOrToken.range[0]; // start

let sliceStart = commentsLength;
let sliceEnd = 0;

// Binary search for the comment immediately before `nodeOrToken`.
for (let lo = 0, hi = commentsLength; lo < hi; ) {
const mid = (lo + hi) >> 1;
if (comments[mid].end <= targetStart) {
sliceEnd = lo = mid + 1;
} else {
hi = mid;
}
}
// Binary search for first comment at or past `nodeOrToken`'s start.
// Comments before this index are candidates to be included in returned array.
const sliceEnd = firstTokenAtOrAfter(comments, targetStart, 0);

let sliceStart = comments.length;
for (let i = sliceEnd - 1; i >= 0; i--) {
const comment = comments[i];
const gap = sourceText.slice(comment.end, targetStart);
// Ensure that there is nothing except whitespace between the end of the
// current comment and the start of the next as we iterate backwards.
// current comment and the start of the next one as we iterate backwards
if (WHITESPACE_ONLY_REGEXP.test(gap)) {
sliceStart = i;
targetStart = comment.start;
Expand Down Expand Up @@ -101,27 +93,19 @@ export function getCommentsAfter(nodeOrToken: NodeOrToken): Comment[] {
debugAssertIsNonNull(ast);
debugAssertIsNonNull(sourceText);

const { comments } = ast,
commentsLength = comments.length;
const { comments } = ast;

let targetEnd = nodeOrToken.range[1]; // end

let sliceStart = commentsLength;
let sliceEnd = 0;

// Binary search for the comment immediately after `nodeOrToken`.
for (let lo = 0, hi = commentsLength; lo < hi; ) {
const mid = (lo + hi) >> 1;
if (comments[mid].start < targetEnd) {
lo = mid + 1;
} else {
sliceStart = hi = mid;
}
}
// Binary search for first comment at or past `nodeOrToken`'s end.
// Comments from this index onwards are candidates to be included in returned array.
const sliceStart = firstTokenAtOrAfter(comments, targetEnd, 0);

const commentsLength = comments.length;
let sliceEnd = 0;
for (let i = sliceStart; i < commentsLength; i++) {
// Ensure that there is nothing except whitespace between the
// end of the previous comment and the start of the current.
// end of the previous comment and the start of the current one
const comment = comments[i];
const gap = sourceText.slice(targetEnd, comment.start);
if (WHITESPACE_ONLY_REGEXP.test(gap)) {
Expand All @@ -144,36 +128,17 @@ export function getCommentsInside(node: Node): Comment[] {
if (ast === null) initAst();
debugAssertIsNonNull(ast);

const { comments } = ast,
commentsLength = comments.length;

let sliceStart = commentsLength;
let sliceEnd: number | undefined = undefined;
const { comments } = ast;

const { range } = node,
rangeStart = range[0],
rangeEnd = range[1];

// Binary search for first comment within `node`'s range.
for (let lo = 0, hi = commentsLength; lo < hi; ) {
const mid = (lo + hi) >> 1;
if (comments[mid].start < rangeStart) {
lo = mid + 1;
} else {
sliceStart = hi = mid;
}
}

// Binary search for first comment within `node`'s range
const sliceStart = firstTokenAtOrAfter(comments, rangeStart, 0);
// Binary search for first comment outside `node`'s range.
// Its index is used as `sliceEnd`, which is exclusive of the slice.
for (let lo = sliceStart, hi = commentsLength; lo < hi; ) {
const mid = (lo + hi) >> 1;
if (comments[mid].start < rangeEnd) {
lo = mid + 1;
} else {
sliceEnd = hi = mid;
}
}
const sliceEnd = firstTokenAtOrAfter(comments, rangeEnd, sliceStart);

return comments.slice(sliceStart, sliceEnd);
}
Expand All @@ -193,22 +158,11 @@ export function commentsExistBetween(

// Find the first comment after `nodeOrToken1` ends.
const { comments } = ast,
commentsLength = comments.length,
betweenRangeStart = nodeOrToken1.range[1];
let firstCommentBetween = -1;

for (let lo = 0, hi = commentsLength; lo < hi; ) {
const mid = (lo + hi) >> 1;
if (comments[mid].start < betweenRangeStart) {
lo = mid + 1;
} else {
firstCommentBetween = hi = mid;
}
}
const firstCommentBetween = firstTokenAtOrAfter(comments, betweenRangeStart, 0);
// Check if it ends before `nodeOrToken2` starts.
return (
0 <= firstCommentBetween &&
firstCommentBetween < commentsLength &&
firstCommentBetween < comments.length &&
comments[firstCommentBetween].end <= nodeOrToken2.range[0]
);
}
Expand Down
6 changes: 5 additions & 1 deletion apps/oxlint/src-js/plugins/tokens_methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,11 @@ export function isSpaceBetweenTokens(first: NodeOrToken, second: NodeOrToken): b
* @param startIndex - Starting index for the search
* @returns Index of first token with `start >= offset`
*/
function firstTokenAtOrAfter(tokens: TokenOrComment[], offset: number, startIndex: number): number {
export function firstTokenAtOrAfter(
tokens: TokenOrComment[],
offset: number,
startIndex: number,
): number {
for (let endIndex = tokens.length; startIndex < endIndex; ) {
const mid = (startIndex + endIndex) >> 1;
if (tokens[mid].start < offset) {
Expand Down
Loading