-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathast-utils.ts
95 lines (73 loc) · 2.9 KB
/
ast-utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESLint, TSESTree } from "@typescript-eslint/utils";
import { createRequire } from "node:module"
import { MaybeTypeCast, TSTypeCastExpression } from './types'
const require = createRequire(import.meta.url)
const eslintRequire = createRequire(require.resolve("eslint"))
export const espreeParser = eslintRequire.resolve('espree');
// We'll only verify nodes with these parent types
const STATEMENT_LIST_PARENTS = new Set([
AST_NODE_TYPES.Program,
AST_NODE_TYPES.BlockStatement,
AST_NODE_TYPES.SwitchCase,
AST_NODE_TYPES.SwitchStatement,
]);
export const isValidParent = (parentType: AST_NODE_TYPES): boolean => {
return STATEMENT_LIST_PARENTS.has(parentType)
}
export const isTokenASemicolon = (token: TSESTree.Token): boolean =>
token.value === ';' && token.type === AST_TOKEN_TYPES.Punctuator
/**
* Gets the actual last token.
*
* If a semicolon is semicolon-less style's semicolon, this ignores it.
* For example:
*
* foo()
* ;[1, 2, 3].forEach(bar)
*/
export const getActualLastToken = (sourceCode: TSESLint.SourceCode, node: TSESTree.Node): TSESTree.Token => {
const semiToken = sourceCode.getLastToken(node)!;
const prevToken = sourceCode.getTokenBefore(semiToken)!;
const nextToken = sourceCode.getTokenAfter(semiToken)
const isSemicolonLessStyle = Boolean(
prevToken &&
nextToken &&
prevToken.range[0] >= node.range[0] &&
isTokenASemicolon(semiToken) &&
semiToken.loc.start.line !== prevToken.loc.end.line &&
semiToken.loc.end.line === nextToken.loc.start.line,
);
return isSemicolonLessStyle ? prevToken : semiToken;
}
export const getPaddingLineSequences = (prevNode: TSESTree.Node, nextNode: TSESTree.Node, sourceCode: TSESLint.SourceCode) => {
const pairs: TSESTree.Token[][] = []
const includeComments = true
let prevToken = getActualLastToken(sourceCode, prevNode)
if ((nextNode.loc.start.line - prevNode.loc.end.line) >= 2) {
do {
const token = sourceCode.getTokenAfter(prevToken, { includeComments }) as TSESTree.Token
if ((token.loc.start.line - prevToken.loc.end.line) >= 2) {
pairs.push([prevToken, token])
}
prevToken = token
} while (prevToken.range[0] < nextNode.range[0])
}
return pairs
}
export const areTokensOnSameLine = (
left: TSESTree.Node | TSESTree.Token,
right: TSESTree.Node | TSESTree.Token,
): boolean => left.loc.end.line === right.loc.start.line;
const isTypeCastExpression = <Expression extends TSESTree.Expression>(
node: MaybeTypeCast<Expression>
): node is TSTypeCastExpression<Expression> =>
node.type === AST_NODE_TYPES.TSAsExpression ||
node.type === AST_NODE_TYPES.TSTypeAssertion;
export const followTypeAssertionChain = <
Expression extends TSESTree.Expression
>(
expression: MaybeTypeCast<Expression>
): Expression =>
isTypeCastExpression(expression)
? followTypeAssertionChain(expression.expression)
: expression;