• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lo1tuma / eslint-plugin-mocha / 14682959272

26 Apr 2025 04:15PM UTC coverage: 98.456% (-1.5%) from 100.0%
14682959272

Pull #372

github

web-flow
Merge 408a29431 into f8a1680f7
Pull Request #372: Migrate codebase to typescript

637 of 670 branches covered (95.07%)

1918 of 1971 new or added lines in 42 files covered. (97.31%)

3571 of 3627 relevant lines covered (98.46%)

1338.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.79
/source/ast/alias-references.ts
1
import { findVariable } from '@eslint-community/eslint-utils';
2✔
2
import type { Rule, Scope, SourceCode } from 'eslint';
2✔
3
import { flatMapWithArgs, mapWithArgs } from '../list.js';
2✔
4
import {
2✔
5
    type DynamicPath,
2✔
6
    extractMemberExpressionPath,
2✔
7
    getIdentifierName,
2✔
8
    isConstantPath
2✔
9
} from './member-expression.js';
2✔
10
import {
2✔
11
    type IdentifierPattern,
2✔
12
    isAssignmentProperty,
2✔
13
    isIdentifierPattern,
2✔
14
    isObjectPattern,
2✔
15
    isVariableDeclarator,
2✔
16
    type ObjectPattern,
2✔
17
    type VariableDeclarator
2✔
18
} from './node-types.js';
2✔
19
import { findParentNodeAndPathForIdentifier, type ResolvedReference } from './resolved-reference.js';
2✔
20

2✔
21
function isAliasConstAssignment(node: Rule.Node): node is VariableDeclarator {
2,608✔
22
    if (isVariableDeclarator(node) && node.parent.type === 'VariableDeclaration') {
2,608✔
23
        return node.parent.kind === 'const';
124✔
24
    }
124✔
25
    return false;
2,484✔
26
}
2,484✔
27

2✔
28
type IdentifierWithPath = { identifier: IdentifierPattern; path: DynamicPath; };
2✔
29

2✔
30
function extractIdentifiersFromObjectPattern(
62✔
31
    node: Readonly<ObjectPattern>,
62✔
32
    currentPath: DynamicPath
62✔
33
): readonly IdentifierWithPath[] {
62✔
34
    return node.properties.flatMap((property): readonly IdentifierWithPath[] => {
62✔
35
        if (!isAssignmentProperty(property)) {
66!
NEW
36
            return [];
×
NEW
37
        }
×
38
        if (property.value.type === 'Identifier') {
66✔
39
            return [{ identifier: property.value, path: [...currentPath, getIdentifierName(property.key)] }];
56✔
40
        }
56✔
41
        if (property.value.type === 'ObjectPattern') {
66✔
42
            return extractIdentifiersFromObjectPattern(property.value, [
8✔
43
                ...currentPath,
8✔
44
                getIdentifierName(property.key)
8✔
45
            ]);
8✔
46
        }
8✔
47

2✔
48
        return [];
2✔
49
    });
62✔
50
}
62✔
51

2✔
52
type IdentifierWithAssignmentPaths = {
2✔
53
    identifier: IdentifierPattern;
2✔
54
    fullPath: DynamicPath;
2✔
55
    leftHandSidePath: DynamicPath;
2✔
56
    rightHandSidePath: DynamicPath;
2✔
57
};
2✔
58

2✔
59
function getDeclaredIdentifiers(
100✔
60
    sourceCode: Readonly<SourceCode>,
100✔
61
    node: Readonly<VariableDeclarator>
100✔
62
): readonly IdentifierWithAssignmentPaths[] {
100✔
63
    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- bad typing in eslint core
100✔
64
    const path = extractMemberExpressionPath(sourceCode, node.init as Rule.Node);
100✔
65

100✔
66
    if (isIdentifierPattern(node.id)) {
100✔
67
        return [{ identifier: node.id, fullPath: path, leftHandSidePath: [], rightHandSidePath: path }];
44✔
68
    }
44✔
69

56✔
70
    if (isObjectPattern(node.id)) {
100✔
71
        const allPatternIdentifiers = extractIdentifiersFromObjectPattern(node.id, []);
54✔
72
        return allPatternIdentifiers.map((patternIdentifiers) => {
54✔
73
            return {
56✔
74
                identifier: patternIdentifiers.identifier,
56✔
75
                fullPath: [...path, ...patternIdentifiers.path],
56✔
76
                leftHandSidePath: patternIdentifiers.path,
56✔
77
                rightHandSidePath: path
56✔
78
            };
56✔
79
        });
54✔
80
    }
54✔
81

2✔
82
    return [];
2✔
83
}
2✔
84

2✔
85
// eslint-disable-next-line complexity -- no good idea how to refactor
2✔
86
function extendPath(
94✔
87
    parentReference: Readonly<ResolvedReference>,
94✔
88
    originalPath: DynamicPath,
94✔
89
    identifierPath: DynamicPath
94✔
90
): DynamicPath {
94✔
91
    const extendedPath = [...parentReference.resolvedPath, ...originalPath, ...identifierPath.slice(1)];
94✔
92
    if (
94✔
93
        isConstantPath(identifierPath) && identifierPath.length === 1 && identifierPath.at(0)?.endsWith('()') === true
94✔
94
    ) {
94✔
95
        const lastElement = extendedPath.at(-1);
32✔
96
        if (lastElement !== undefined) {
32✔
97
            extendedPath[extendedPath.length - 1] = typeof lastElement === 'string'
32✔
98
                ? `${lastElement}()`
32✔
99
                : lastElement;
32!
100
        }
32✔
101
    }
32✔
102
    return extendedPath;
94✔
103
}
94✔
104

2✔
105
function aliasReferenceToResolvedReference(
94✔
106
    reference: Readonly<Scope.Reference>,
94✔
107
    sourceCode: Readonly<SourceCode>,
94✔
108
    parentReference: Readonly<ResolvedReference>,
94✔
109
    originalPath: DynamicPath
94✔
110
): Readonly<ResolvedReference> {
94✔
111
    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- bad typings in eslint core
94✔
112
    const { node, path } = findParentNodeAndPathForIdentifier(sourceCode, reference.identifier as Rule.Node);
94✔
113
    return { node, path, resolvedPath: extendPath(parentReference, originalPath, path) };
94✔
114
}
94✔
115

2✔
116
function isNonInitReference(reference: Readonly<Scope.Reference>): boolean {
194✔
117
    return !reference.init;
194✔
118
}
194✔
119

2✔
120
// eslint-disable-next-line max-statements -- no good idea how to split this function
2✔
121
function resolveAliasReferencesRecursively(
2,608✔
122
    reference: Readonly<ResolvedReference>,
2,608✔
123
    sourceCode: Readonly<SourceCode>
2,608✔
124
): readonly ResolvedReference[] {
2,608✔
125
    const { node } = reference;
2,608✔
126
    const result = [reference];
2,608✔
127

2,608✔
128
    if (isAliasConstAssignment(node)) {
2,608✔
129
        const declaratedIdentifiers = getDeclaredIdentifiers(sourceCode, node);
100✔
130

100✔
131
        for (const { identifier, leftHandSidePath: identifierPath } of declaratedIdentifiers) {
100✔
132
            const aliasedVariable = findVariable(sourceCode.getScope(node), identifier.name);
100✔
133

100✔
134
            if (aliasedVariable !== null) {
100✔
135
                const aliasReferencesWithoutInit = aliasedVariable.references.filter(isNonInitReference);
100✔
136
                const aliasedResolvedReferences = mapWithArgs(
100✔
137
                    aliasReferencesWithoutInit,
100✔
138
                    aliasReferenceToResolvedReference,
100✔
139
                    sourceCode,
100✔
140
                    reference,
100✔
141
                    identifierPath
100✔
142
                );
100✔
143

100✔
144
                result.push(
100✔
145
                    ...flatMapWithArgs(aliasedResolvedReferences, resolveAliasReferencesRecursively, sourceCode)
100✔
146
                );
100✔
147
            }
100✔
148
        }
100✔
149
    }
100✔
150

2,608✔
151
    return result;
2,608✔
152
}
2,608✔
153

2✔
154
function hasConstantResolvedPath(resolvedReference: Readonly<ResolvedReference>): boolean {
2,608✔
155
    return isConstantPath(resolvedReference.resolvedPath);
2,608✔
156
}
2,608✔
157

2✔
158
export function resolveAliasedReferences(
2✔
159
    sourceCode: Readonly<SourceCode>,
1,874✔
160
    originalResolvedReferences: readonly ResolvedReference[]
1,874✔
161
): readonly ResolvedReference[] {
1,874✔
162
    return flatMapWithArgs(originalResolvedReferences, resolveAliasReferencesRecursively, sourceCode).filter(
1,874✔
163
        hasConstantResolvedPath
1,874✔
164
    );
1,874✔
165
}
1,874✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc