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

rokucommunity / brighterscript / #12967

20 Aug 2024 04:14PM UTC coverage: 86.342%. Remained the same
#12967

push

web-flow
Merge 3c99174e3 into 353f4638c

10738 of 13227 branches covered (81.18%)

Branch coverage included in aggregate %.

87 of 97 new or added lines in 7 files covered. (89.69%)

100 existing lines in 5 files now uncovered.

12387 of 13556 relevant lines covered (91.38%)

27316.36 hits per line

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

91.95
/src/bscPlugin/codeActions/CodeActionsProcessor.ts
1
import { CodeActionKind } from 'vscode-languageserver';
1✔
2
import { codeActionUtil } from '../../CodeActionUtil';
1✔
3
import type { DiagnosticMessageType } from '../../DiagnosticMessages';
4
import { DiagnosticCodeMap } from '../../DiagnosticMessages';
1✔
5
import type { BrsFile } from '../../files/BrsFile';
6
import type { BscFile } from '../../files/BscFile';
7
import type { XmlFile } from '../../files/XmlFile';
8
import type { BsDiagnostic, OnGetCodeActionsEvent } from '../../interfaces';
9
import { ParseMode } from '../../parser/Parser';
1✔
10
import { util } from '../../util';
1✔
11
import { isBrsFile } from '../../astUtils/reflection';
1✔
12

13
export class CodeActionsProcessor {
1✔
14
    public constructor(
15
        public event: OnGetCodeActionsEvent
10✔
16
    ) {
17

18
    }
19

20
    public process() {
21
        for (const diagnostic of this.event.diagnostics) {
10✔
22
            if (diagnostic.code === DiagnosticCodeMap.cannotFindName || diagnostic.code === DiagnosticCodeMap.cannotFindFunction) {
12✔
23
                this.suggestCannotFindName(diagnostic as any);
8✔
24
            } else if (diagnostic.code === DiagnosticCodeMap.xmlComponentMissingExtendsAttribute) {
4✔
25
                this.addMissingExtends(diagnostic as any);
2✔
26
            }
27
        }
28
    }
29

30
    private suggestedImports = new Set<string>();
10✔
31

32
    /**
33
     * Generic import suggestion function. Shouldn't be called directly from the main loop, but instead called by more specific diagnostic handlers
34
     */
35
    private suggestImports(diagnostic: BsDiagnostic, key: string, files: BscFile[]) {
36
        //skip if we already have this suggestion
37
        if (this.suggestedImports.has(key) || !isBrsFile(this.event.file)) {
7!
UNCOV
38
            return;
×
39
        }
40

41
        this.suggestedImports.add(key);
7✔
42
        // eslint-disable-next-line @typescript-eslint/dot-notation
43
        const importStatements = this.event.file['_cachedLookups'].importStatements;
7✔
44
        //find the position of the first import statement, or the top of the file if there is none
45
        const insertPosition = importStatements[importStatements.length - 1]?.tokens.import?.location?.range?.start ?? util.createPosition(0, 0);
7✔
46

47
        //find all files that reference this function
48
        for (const file of files) {
7✔
49
            const destPath = util.sanitizePkgPath(file.destPath);
9✔
50
            this.event.codeActions.push(
9✔
51
                codeActionUtil.createCodeAction({
52
                    title: `import "${destPath}"`,
53
                    diagnostics: [diagnostic],
54
                    isPreferred: false,
55
                    kind: CodeActionKind.QuickFix,
56
                    changes: [{
57
                        type: 'insert',
58
                        filePath: this.event.file.srcPath,
59
                        position: insertPosition,
60
                        newText: `import "${destPath}"\n`
61
                    }]
62
                })
63
            );
64
        }
65
    }
66

67
    private suggestCannotFindName(diagnostic: DiagnosticMessageType<'cannotFindName'>) {
68
        //skip if not a BrighterScript file
69
        const file = this.event.program.getFile(diagnostic.location?.uri);
8!
70
        if (!file || (file as BrsFile).parseMode !== ParseMode.BrighterScript) {
8✔
71
            return;
1✔
72
        }
73
        const lowerName = (diagnostic.data.fullName ?? diagnostic.data.name).toLowerCase();
7!
74

75
        this.suggestImports(
7✔
76
            diagnostic,
77
            lowerName,
78
            [
79
                ...this.event.program.findFilesForFunction(lowerName),
80
                ...this.event.program.findFilesForClass(lowerName),
81
                ...this.event.program.findFilesForNamespace(lowerName),
82
                ...this.event.program.findFilesForEnum(lowerName)
83
            ]
84
        );
85
    }
86

87
    private addMissingExtends(diagnostic: DiagnosticMessageType<'xmlComponentMissingExtendsAttribute'>) {
88
        const srcPath = this.event.file.srcPath;
2✔
89
        const { componentElement } = (this.event.file as XmlFile).parser.ast;
2✔
90
        //inject new attribute after the final attribute, or after the `<component` if there are no attributes
91
        const pos = (componentElement.attributes[componentElement.attributes.length - 1] ?? componentElement.tokens.startTagName)?.location?.range.end;
2!
92
        this.event.codeActions.push(
2✔
93
            codeActionUtil.createCodeAction({
94
                title: `Extend "Group"`,
95
                diagnostics: [diagnostic],
96
                isPreferred: true,
97
                kind: CodeActionKind.QuickFix,
98
                changes: [{
99
                    type: 'insert',
100
                    filePath: srcPath,
101
                    position: pos,
102
                    newText: ' extends="Group"'
103
                }]
104
            })
105
        );
106
        this.event.codeActions.push(
2✔
107
            codeActionUtil.createCodeAction({
108
                title: `Extend "Task"`,
109
                diagnostics: [diagnostic],
110
                kind: CodeActionKind.QuickFix,
111
                changes: [{
112
                    type: 'insert',
113
                    filePath: srcPath,
114
                    position: pos,
115
                    newText: ' extends="Task"'
116
                }]
117
            })
118
        );
119
        this.event.codeActions.push(
2✔
120
            codeActionUtil.createCodeAction({
121
                title: `Extend "ContentNode"`,
122
                diagnostics: [diagnostic],
123
                kind: CodeActionKind.QuickFix,
124
                changes: [{
125
                    type: 'insert',
126
                    filePath: srcPath,
127
                    position: pos,
128
                    newText: ' extends="ContentNode"'
129
                }]
130
            })
131
        );
132
    }
133
}
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

© 2025 Coveralls, Inc