Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | 55x 55x 55x 77x 132x 132x 132x 87x 72x 17x 124005x 124005x 102496x 124005x 882742x 780246x 291202x 930649x 140467x 644668x 280209x 1015706x 321035x 488464x 612469x 102204x 48132x 52x 159x 108x 159x 51x 51x 51x 159x 1101x 60x 522x 522x 522x 1566x 1566x 1566x 522x 1566x 522x | import { parse, TSESTree } from '@typescript-eslint/typescript-estree';
import { readFileSync } from 'fs';
/**
* Parse a file into an AST
* Only supports TypeScript/JavaScript files (.ts, .tsx, .js, .jsx)
*/
export function parseFile(
filePath: string,
content?: string
): TSESTree.Program | null {
try {
const code = content ?? readFileSync(filePath, 'utf-8');
const isTypeScript = filePath.match(/\.tsx?$/);
return parse(code, {
jsx: filePath.match(/\.[jt]sx$/i) !== null,
loc: true,
range: true,
comment: false,
tokens: false,
// Relaxed parsing for JavaScript files
sourceType: 'module',
ecmaVersion: 'latest',
// Only use TypeScript parser features for .ts/.tsx files
filePath: isTypeScript ? filePath : undefined,
});
} catch (error) {
void error;
// Silently skip files that fail to parse (likely non-JS/TS or syntax errors)
// Non-JS/TS files should be filtered before reaching this point
return null;
}
}
/**
* Traverse AST nodes with a visitor pattern
*/
export function traverseAST(
node: TSESTree.Node,
visitor: {
enter?: (node: TSESTree.Node, parent: TSESTree.Node | null) => void;
I leave?: (node: TSESTree.Node, parent: TSESTree.Node | null) => void;
},
parent: TSESTree.Node | null = null
): void {
Iif (!node) return;
visitor.enter?.(node, parent);
// Visit children
for (const key of Object.keys(node)) {
const value = (node as any)[key];
if (Array.isArray(value)) {
for (const child of value) {
if (child && typeof child === 'object' && 'type' in child) {
traverseAST(child as TSESTree.Node, visitor, node);
}
}
} else if (value && typeof value === 'object' && 'type' in value) {
traverseAST(value as TSESTree.Node, visitor, node);
}
}
visitor.leave?.(node, parent);
}
/**
* Check if a node is within a specific type of ancestor
*/
export function hasAncestor(
node: TSESTree.Node,
ancestorTypes: string[],
ancestors: TSESTree.Node[]
): boolean {
return ancestors.some((ancestor) => ancestorTypes.includes(ancestor.type));
}
/**
* Get the name of an identifier or pattern
*/
export function getIdentifierName(node: TSESTree.Node): string | null {
if (node.type === 'Identifier') {
return node.name;
}
return null;
}
/**
* Check if a node is a loop
*/
export function isLoopStatement(node: TSESTree.Node): boolean {
return [
'ForStatement',
'ForInStatement',
'ForOfStatement',
'WhileStatement',
'DoWhileStatement',
].includes(node.type);
}
/**
* Check if a node is an arrow function or callback
*/
export function isCallback(node: TSESTree.Node): boolean {
if (node.type === 'ArrowFunctionExpression') {
return true;
}
if (node.type === 'FunctionExpression') {
return true;
}
return false;
}
/**
* Extract function/method name from various declaration types
*/
export function getFunctionName(node: TSESTree.Node): string | null {
switch (node.type) {
case 'FunctionDeclaration':
return node.id?.name ?? null;
case 'FunctionExpression':
Ereturn node.id?.name ?? null;
case 'ArrowFunctionExpression':
return null; // Arrow functions don't have names directly
case 'MethodDefinition':
Eif (node.key.type === 'Identifier') {
return node.key.name;
}
return null;
default:
return null;
}
}
/**
* Check if a variable declaration is in a destructuring pattern
*/
export function isInDestructuring(node: TSESTree.Node): boolean {
if (!node) return false;
return node.type === 'ObjectPattern' || node.type === 'ArrayPattern';
}
/**
* Get the line number from a node
*/
export function getLineNumber(node: TSESTree.Node): number {
return node.loc?.start.line ?? 0;
}
/**
* Check if a node represents a coverage metric context
*/
export function isCoverageContext(
Inode: TSESTree.Node,
ancestors: TSESTree.Node[]
): boolean {
// Check if any ancestor or the node itself references coverage-related properties
const coveragePatterns =
/coverage|summary|metrics|pct|percent|statements|branches|functions|lines/i;
I
// Check variable name
Iif (node.type === 'Identifier' && coveragePatterns.test(node.name)) {
return true;
}
//I Check if it's a property of something coverage-related
for (const ancestor of ancestors.slice(-3)) {
// Check last 3 ancestors
if (ancestor.type === 'MemberExpression') {
const memberExpr = ancestor as TSESTree.MemberExpression;
if (
memberExpr.object.type === 'Identifier' &&
coveragePatterns.test(memberExpr.object.name)
) {
return true;
}
}
if (
ancestor.type === 'ObjectPattern' ||
ancestor.type === 'ObjectExpression'
) {
// Check if parent variable has coverage-related name
const parent = ancestors[ancestors.indexOf(ancestor) - 1];
if (parent?.type === 'VariableDeclarator') {
const varDecl = parent as TSESTree.VariableDeclarator;
if (
varDecl.id.type === 'Identifier' &&
coveragePatterns.test(varDecl.id.name)
) {
return true;
}
}
}
}
return false;
}
|