generated from JoshuaKGoldberg/create-typescript-app
-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2cd08dc
commit f901bec
Showing
10 changed files
with
149 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Code largely based on ajafff/tsutils: | ||
// /~https://github.com/ajafff/tsutils/blob/03b4df15d14702f9c7a128ac3fae77171778d613/util/util.ts | ||
// Original license MIT: | ||
// /~https://github.com/ajafff/tsutils/blob/26b195358ec36d59f00333115aa3ffd9611ca78b/LICENSE | ||
|
||
import * as ts from "typescript"; | ||
|
||
import { forEachToken } from "./forEachToken"; | ||
|
||
/** Exclude trailing positions that would lead to scanning for trivia inside JsxText */ | ||
function canHaveTrailingTrivia(token: ts.Node): boolean { | ||
switch (token.kind) { | ||
case ts.SyntaxKind.CloseBraceToken: | ||
// after a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia | ||
return ( | ||
token.parent.kind !== ts.SyntaxKind.JsxExpression || | ||
!isJsxElementOrFragment(token.parent.parent) | ||
); | ||
case ts.SyntaxKind.GreaterThanToken: | ||
switch (token.parent.kind) { | ||
case ts.SyntaxKind.JsxOpeningElement: | ||
// if end is not equal, this is part of the type arguments list. in all other cases it would be inside the element body | ||
return token.end !== token.parent.end; | ||
case ts.SyntaxKind.JsxOpeningFragment: | ||
return false; // would be inside the fragment | ||
case ts.SyntaxKind.JsxSelfClosingElement: | ||
return ( | ||
token.end !== token.parent.end || // if end is not equal, this is part of the type arguments list | ||
!isJsxElementOrFragment(token.parent.parent) | ||
); // there's only trailing trivia if it's the end of the top element | ||
case ts.SyntaxKind.JsxClosingElement: | ||
case ts.SyntaxKind.JsxClosingFragment: | ||
// there's only trailing trivia if it's the end of the top element | ||
return !isJsxElementOrFragment(token.parent.parent.parent); | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
function isJsxElementOrFragment( | ||
node: ts.Node | ||
): node is ts.JsxElement | ts.JsxFragment { | ||
return ( | ||
node.kind === ts.SyntaxKind.JsxElement || | ||
node.kind === ts.SyntaxKind.JsxFragment | ||
); | ||
} | ||
|
||
export type ForEachCommentCallback = ( | ||
fullText: string, | ||
comment: ts.CommentRange | ||
) => void; | ||
|
||
/** Iterate over all comments owned by `node` or its children */ | ||
export function forEachComment( | ||
node: ts.Node, | ||
cb: ForEachCommentCallback, | ||
sourceFile: ts.SourceFile = node.getSourceFile() | ||
) { | ||
/* Visit all tokens and skip trivia. | ||
Comment ranges between tokens are parsed without the need of a scanner. | ||
forEachTokenWithWhitespace does intentionally not pay attention to the correct comment ownership of nodes as it always | ||
scans all trivia before each token, which could include trailing comments of the previous token. | ||
Comment onwership is done right in this function*/ | ||
const fullText = sourceFile.text; | ||
const notJsx = sourceFile.languageVariant !== ts.LanguageVariant.JSX; | ||
return forEachToken( | ||
node, | ||
(token) => { | ||
if (token.pos === token.end) return; | ||
if (token.kind !== ts.SyntaxKind.JsxText) | ||
ts.forEachLeadingCommentRange( | ||
fullText, | ||
// skip shebang at position 0 | ||
// TODO: Investigate | ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | ||
token.pos === 0 ? (ts.getShebang(fullText) || "").length : token.pos, | ||
commentCallback | ||
); | ||
if (notJsx || canHaveTrailingTrivia(token)) | ||
return ts.forEachTrailingCommentRange( | ||
fullText, | ||
token.end, | ||
commentCallback | ||
); | ||
}, | ||
sourceFile | ||
); | ||
function commentCallback(pos: number, end: number, kind: ts.CommentKind) { | ||
cb(fullText, { pos, end, kind }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Code largely based on ajafff/tsutils: | ||
// /~https://github.com/ajafff/tsutils/blob/03b4df15d14702f9c7a128ac3fae77171778d613/util/util.ts | ||
// Original license MIT: | ||
// /~https://github.com/ajafff/tsutils/blob/26b195358ec36d59f00333115aa3ffd9611ca78b/LICENSE | ||
|
||
import * as ts from "typescript"; | ||
|
||
/** | ||
* Iterate over all tokens of `node` | ||
* | ||
* @param node The node whose tokens should be visited | ||
* @param cb Is called for every token contained in `node` | ||
*/ | ||
export function forEachToken( | ||
node: ts.Node, | ||
cb: (node: ts.Node) => void, | ||
sourceFile: ts.SourceFile = node.getSourceFile() | ||
) { | ||
const queue = []; | ||
while (true) { | ||
if (ts.isTokenKind(node.kind)) { | ||
cb(node); | ||
// TODO: Investigate? | ||
// eslint-disable-next-line deprecation/deprecation | ||
} else if (node.kind !== ts.SyntaxKind.JSDocComment) { | ||
const children = node.getChildren(sourceFile); | ||
if (children.length === 1) { | ||
node = children[0]; | ||
continue; | ||
} | ||
for (let i = children.length - 1; i >= 0; --i) queue.push(children[i]); // add children in reverse order, when we pop the next element from the queue, it's the first child | ||
} | ||
if (queue.length === 0) break; | ||
node = queue.pop()!; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { describe, expect, it } from "vitest"; | ||
|
||
describe("index", () => { | ||
it("TODO", () => { | ||
expect(2 + 2).not.toBe("fish"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export * from "./greet.js"; | ||
export * from "./forEachComment.js"; | ||
export * from "./types.js"; |