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

rokucommunity / brighterscript / #13111

30 Sep 2024 04:35PM UTC coverage: 86.842% (-1.4%) from 88.193%
#13111

push

web-flow
Merge 25fc06528 into 3a2dc7282

11525 of 14034 branches covered (82.12%)

Branch coverage included in aggregate %.

6990 of 7581 new or added lines in 100 files covered. (92.2%)

83 existing lines in 18 files now uncovered.

12691 of 13851 relevant lines covered (91.63%)

29449.4 hits per line

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

90.91
/src/bscPlugin/transpile/XmlFilePreTranspileProcessor.ts
1
import { createSGScript } from '../../astUtils/creators';
1✔
2
import { isXmlFile } from '../../astUtils/reflection';
1✔
3
import { isSGScript } from '../../astUtils/xml';
1✔
4
import type { XmlFile } from '../../files/XmlFile';
5
import type { AfterPrepareFileEvent } from '../../interfaces';
6
import type { SGScript } from '../../parser/SGTypes';
7
import util from '../../util';
1✔
8

9
export class XmlFilePreTranspileProcessor {
1✔
10
    public constructor(
11
        private event: AfterPrepareFileEvent<XmlFile>
27✔
12
    ) {
13
    }
14

15
    public process() {
16
        if (!isXmlFile(this.event.file)) {
27!
NEW
17
            return;
×
18
        }
19

20
        //insert any missing script imports
21
        this.injectScriptImports();
27✔
22

23
        //transform any brighterscript `type` attributes to `brightscript`
24
        for (const script of this.event.file.ast?.componentElement?.scriptElements ?? []) {
27!
25
            const type = script.getAttribute('type');
52✔
26
            if (/text\/brighterscript/i.test(type?.value)) {
52✔
27
                this.event.editor.setProperty(
4✔
28
                    type,
29
                    'value',
30
                    type.value.replace(/text\/brighterscript/i, 'text/brightscript')
31
                );
32
            }
33

34
            //replace `.bs` extensions with `.brs`
35
            const uri = script.getAttribute('uri');
52✔
36
            if (/\.bs/i.test(uri?.value)) {
52✔
37
                this.event.editor.setProperty(
12✔
38
                    uri,
39
                    'value',
40
                    uri.value.replace(/\.bs/i, '.brs')
41
                );
42
            }
43
        }
44
    }
45

46
    /**
47
     * Inject any missing scripts into the xml file
48
     */
49
    private injectScriptImports() {
50
        // eslint-disable-next-line @typescript-eslint/dot-notation
51
        const extraImportScripts = this.event.file['getMissingImportsForTranspile']().map(uri => {
27✔
52
            return createSGScript({
35✔
53
                type: 'text/brightscript',
54
                uri: util.sanitizePkgPath(uri.replace(/\.bs$/, '.brs'))
55
            });
56
        });
57

58
        // eslint-disable-next-line @typescript-eslint/dot-notation
59
        const [, publishableScripts] = this.checkScriptsForPublishableImports([
27✔
60
            ...this.event.file.ast.componentElement?.scriptElements ?? [],
162!
61
            ...extraImportScripts
62
        ]);
63

64
        //force bslib to be the last script in the list
65
        const idx = publishableScripts.findIndex(x => x.uri?.endsWith('bslib.brs'));
52✔
66
        if (idx > -1) {
27!
67
            const [bslib] = publishableScripts.splice(idx, 1);
27✔
68
            publishableScripts.push(bslib);
27✔
69
        }
70

71
        const elements = this.event.file.ast.componentElement.elements;
27✔
72
        //remove any unreferenced scripts
73
        let set = new Set(publishableScripts);
27✔
74
        for (let i = elements.length - 1; i >= 0; i--) {
27✔
75
            const element = elements[i];
30✔
76
            if (isSGScript(element)) {
30✔
77
                if (set.has(element as SGScript)) {
20✔
78
                    set.delete(element as SGScript);
18✔
79
                } else {
80
                    this.event.editor.arraySplice(elements, i, 1);
2✔
81
                }
82
            }
83
        }
84

85
        //add new scripts after the LAST `<script>` tag that was created explicitly by the user, or at the top of the component if it has no scripts
86
        let lastScriptIndex = util.findLastIndex(this.event.file.ast.componentElement.elements, x => x.tokens.startTagName.text.toLowerCase() === 'script');
27✔
87
        lastScriptIndex = lastScriptIndex >= 0
27✔
88
            ? lastScriptIndex + 1
27✔
89
            : 0;
90
        for (const element of set) {
27✔
91
            this.event.editor.arraySplice(elements, lastScriptIndex++, 0, element);
34✔
92
        }
93
    }
94

95
    private checkScriptsForPublishableImports(scripts: SGScript[]): [boolean, SGScript[]] {
96
        const { program } = this.event;
27✔
97
        if (!program.options.pruneEmptyCodeFiles) {
27✔
98
            return [false, scripts];
24✔
99
        }
100
        const publishableScripts = scripts.filter(script => {
3✔
101
            const uriAttributeValue = script.uri || '';
8!
102
            const pkgMapPath = util.getPkgPathFromTarget(this.event.file.pkgPath, uriAttributeValue);
8✔
103
            let file = program.getFile(pkgMapPath);
8✔
104
            if (!file && pkgMapPath.endsWith(program.bslibPkgPath)) {
8✔
105
                return true;
3✔
106
            }
107
            if (!file && pkgMapPath.endsWith('.brs')) {
5✔
108
                file = program.getFile(pkgMapPath.replace(/\.brs$/, '.bs'));
1✔
109
            }
110
            return !(file?.canBePruned);
5!
111
        });
112
        return [publishableScripts.length !== scripts.length, publishableScripts];
3✔
113
    }
114

115
}
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