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

rokucommunity / vscode-brightscript-language / 35918066925

23 Sep 2026 08:45PM UTC coverage: 68.697% (+2.6%) from 66.107%
35918066925

Pull #906

github

web-flow
Merge 9efd60384 into 35d8d9931
Pull Request #906: RSG 2.0 SDK support

4616 of 7288 branches covered (63.34%)

Branch coverage included in aggregate %.

1632 of 1979 new or added lines in 27 files covered. (82.47%)

6866 of 9426 relevant lines covered (72.84%)

90.63 hits per line

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

79.88
/src/managers/JsDebugProxy/JsDebugPathTrace.ts
1
import * as vscode from 'vscode';
1✔
2
import * as path from 'path';
1✔
3
import * as fsExtra from 'fs-extra';
1✔
4

5
/**
6
 * `brightscript.debug.jsPathTrace` diagnostics for the TS/JS (Hermes) attach flow. Every bug in
7
 * that flow has been diagnosed from two complementary views: this class's DAP-level log (which
8
 * paths js-debug reported to vscode) and js-debug's own wire log (which raw CDP script urls and
9
 * sourcemap decisions produced those paths) - `getJsDebugTraceConfig()` wires up the latter.
10
 *
11
 * All logging is gated on the `jsPathTrace` setting being read FRESH on every call, not cached at
12
 * `register()` time, so toggling it mid-session (or between attach attempts of the same session)
13
 * takes effect immediately without requiring a new debug session.
14
 */
15
export class JsDebugPathTrace {
1✔
16
    constructor(
17
        private log: (message: string) => void
32✔
18
    ) {
19
    }
20

21
    /**
22
     * Registers the DAP-tracker factory for the JS session type js-debug uses (`pwa-node`). Only
23
     * taps the Hermes child session (marked `_isBrightscriptJsSession` on its parent's
24
     * configuration by `attachJsDebugger`) - not the pwa-node process-tree sessions js-debug may
25
     * spawn for unrelated child processes.
26
     */
27
    public register(context: vscode.ExtensionContext): void {
28
        context.subscriptions.push(
32✔
29
            vscode.debug.registerDebugAdapterTrackerFactory('pwa-node', {
30
                createDebugAdapterTracker: (session) => this.createTracker(session)
7✔
31
            })
32
        );
33
    }
34

35
    /**
36
     * The js-debug `trace` config value for the attach config, or `undefined` when tracing is
37
     * disabled. `workspaceRootDir` is where the `logs/` folder is created (the workspace folder,
38
     * falling back to the bundle's rootDir when there is no open workspace folder).
39
     */
40
    public getJsDebugTraceConfig(workspaceRootDir: string): JsDebugTraceConfig | undefined {
41
        if (!this.isEnabled()) {
8✔
42
            return undefined;
7✔
43
        }
44
        try {
1✔
45
            const logDir = path.join(workspaceRootDir, 'logs');
1✔
46
            fsExtra.ensureDirSync(logDir);
1✔
47
            return {
1✔
48
                logFile: path.join(logDir, `js-debug-trace-${Date.now()}.json`)
49
            };
50
        } catch (e) {
NEW
51
            this.log(`[jsPathTrace] Failed to set up jsPathTrace logging: ${e?.message ?? e}`);
×
NEW
52
            return undefined;
×
53
        }
54
    }
55

56
    /**
57
     * Logs the derivation the attach flow used to build its debug config, plus (when tracing is
58
     * enabled) where js-debug's own wire log landed and what to grep it for. No-ops when tracing
59
     * is disabled.
60
     */
61
    public logStartupSummary(summary: JsDebugStartupSummary): void {
62
        if (!this.isEnabled()) {
9✔
63
            return;
7✔
64
        }
65
        try {
2✔
66
            const lines = [
2✔
67
                `[jsPathTrace] platform            = ${summary.platform}`,
68
                `[jsPathTrace] tsPath (pkg:stripped)= ${JSON.stringify(summary.tsPath)}`,
69
                `[jsPathTrace] remoteRoot           = ${JSON.stringify(summary.remoteRoot)}`,
70
                `[jsPathTrace] localRoot            = ${JSON.stringify(summary.localRoot)}`,
71
                `[jsPathTrace] outFiles             = ${JSON.stringify(summary.outFiles)}`
72
            ];
73
            if (summary.jsDebugTraceFile) {
2✔
74
                lines.push(
1✔
75
                    `[jsPathTrace] js-debug wire log    = ${summary.jsDebugTraceFile}`,
76
                    `[jsPathTrace]   grep it for 'setBreakpointByUrl' (expect THREE slashes: file:///${summary.remoteRoot.replace(/^\//, '')}/...)`,
77
                    `[jsPathTrace]   and for 'runtime.sourcecreate' (expect a drive-lettered absolutePath, not /examples/...)`
78
                );
79
            }
80
            this.log(lines.join('\n'));
2✔
81
        } catch (e) {
NEW
82
            this.log(`[jsPathTrace] Failed to log startup summary: ${e?.message ?? e}`);
×
83
        }
84
    }
85

86
    private isEnabled(): boolean {
87
        return vscode.workspace.getConfiguration('brightscript.debug').get<boolean>('jsPathTrace') === true;
25✔
88
    }
89

90
    private logJsPath(...parts: string[]): void {
91
        if (this.isEnabled()) {
8✔
92
            this.log(`[jsPathTrace] ${parts.join(' ')}`);
6✔
93
        }
94
    }
95

96
    private createTracker(session: vscode.DebugSession): vscode.DebugAdapterTracker | undefined {
97
        if (!session.parentSession?.configuration?._isBrightscriptJsSession) {
7✔
98
            return undefined;
2✔
99
        }
100

101
        return {
5✔
102
            onWillReceiveMessage: (message: any) => this.onWillReceiveMessage(message),
3✔
103
            onDidSendMessage: (message: any) => this.onDidSendMessage(message)
5✔
104
        };
105
    }
106

107
    /** requests vscode sends TO js-debug. A `source` request is the smoking gun for a
108
     * path-resolution failure: vscode only asks the adapter for file CONTENT when it could not
109
     * resolve the frame's path to a local file on disk. */
110
    private onWillReceiveMessage(message: any): void {
111
        if (message.type === 'request' && message.command === 'setBreakpoints') {
3✔
112
            this.logJsPath('REQ setBreakpoints ->', JSON.stringify(message.arguments?.source), `lines=${JSON.stringify(message.arguments?.lines)}`);
2!
113
        }
114
        if (message.type === 'request' && message.command === 'source') {
3✔
115
            this.logJsPath('REQ source ->', JSON.stringify(message.arguments?.source ?? message.arguments));
1!
116
        }
117
    }
118

119
    private onDidSendMessage(message: any): void {
120
        //THE answer to "did my breakpoint bind?" - an unverified breakpoint usually carries a
121
        //`message` saying why.
122
        if (message.type === 'response' && message.command === 'setBreakpoints') {
5✔
123
            this.logJsPath('RES setBreakpoints', JSON.stringify((message.body?.breakpoints ?? []).map((b: any) => ({ verified: b.verified, line: b.line, path: b.source?.path, message: b.message }))));
2!
124
        }
125
        //the paths js-debug resolved for each script/source - a driveless path here is what
126
        //makes vscode open a phantom duplicate tab
127
        if (message.type === 'event' && message.event === 'loadedSource') {
5✔
128
            const src = message.body?.source;
1!
129
            this.logJsPath(`EVT loadedSource[${message.body?.reason}]`, `name=${JSON.stringify(src?.name)}`, `path=${JSON.stringify(src?.path)}`);
1!
130
        }
131
        if (message.type === 'response' && message.command === 'source' && message.success === false) {
5✔
132
            this.logJsPath('RES source FAILED', JSON.stringify(message.message ?? message.body));
1!
133
        }
134
        //which file the stop actually landed in (and whether its path has a drive letter)
135
        if (message.type === 'response' && message.command === 'stackTrace') {
5✔
136
            const frames = message.body?.stackFrames ?? [];
1!
137
            this.logJsPath(`RES stackTrace (${frames.length} frames)`, JSON.stringify(frames.slice(0, 5).map((f: any) => ({ name: f.name, line: f.line, path: f.source?.path }))));
1!
138
        }
139
    }
140
}
141

142
// ---- types ----
143

144
export interface JsDebugTraceConfig {
145
    logFile: string;
146
}
147

148
export interface JsDebugStartupSummary {
149
    platform: string;
150
    tsPath: string;
151
    remoteRoot: string;
152
    localRoot: string;
153
    outFiles: string[];
154
    /** The path js-debug will write its own wire log to, when tracing is enabled. */
155
    jsDebugTraceFile?: string;
156
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc