Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
"natural-orderby": "^2.0.3",
"replace-in-file": "^6.3.2",
"replace-last": "^1.2.6",
"roku-deploy": "^3.7.1",
"roku-deploy": "^3.8.0",
"semver": "^7.3.5",
"serialize-error": "^8.1.0",
"smart-buffer": "^4.2.0",
Expand Down
23 changes: 12 additions & 11 deletions src/debugSession/BrightScriptDebugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fsExtra from 'fs-extra';
import { orderBy } from 'natural-orderby';
import * as path from 'path';
import * as request from 'request';
import { rokuDeploy } from 'roku-deploy';
import { rokuDeploy, CompileError } from 'roku-deploy';
import type { RokuDeploy, RokuDeployOptions } from 'roku-deploy';
import {
BreakpointEvent,
Expand Down Expand Up @@ -330,9 +330,9 @@ export class BrightScriptDebugSession extends BaseDebugSession {

await this.connectAndPublish();

this.sendEvent(new ChannelPublishedEvent({
launchConfiguration: this.launchConfiguration
}));
this.sendEvent(new ChannelPublishedEvent(
this.launchConfiguration
));

//tell the adapter adapter that the channel has been launched.
await this.rokuAdapter.activate();
Expand All @@ -356,16 +356,14 @@ export class BrightScriptDebugSession extends BaseDebugSession {
}
} catch (e) {
//if the message is anything other than compile errors, we want to display the error
//TODO: look into the reason why we are getting the 'Invalid response code: 400' on compile errors
if (e.message !== 'compileErrors' && e.message !== 'Invalid response code: 400') {
//TODO make the debugger stop!
if (!(e instanceof CompileError)) {
util.log('Encountered an issue during the publish process');
util.log((e as Error).message);
this.sendErrorResponse(response, -1, (e as Error).message);
} else {
//request adapter to send errors (even empty) before ending the session
await this.rokuAdapter.sendErrors();
}

//send any compile errors to the client
await this.rokuAdapter.sendErrors();
this.logger.error('Error. Shutting down.', e);
this.shutdown();
return;
Expand Down Expand Up @@ -399,7 +397,10 @@ export class BrightScriptDebugSession extends BaseDebugSession {

let packageIsPublished = false;
//publish the package to the target Roku
const publishPromise = this.rokuDeploy.publish(this.launchConfiguration as any as RokuDeployOptions).then(() => {
const publishPromise = this.rokuDeploy.publish({
...this.launchConfiguration,
failOnCompileError: true
} as any as RokuDeployOptions).then(() => {
packageIsPublished = true;
});

Expand Down
26 changes: 26 additions & 0 deletions src/debugSession/Events.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { expect } from 'chai';
import { isCompileFailureEvent, CompileFailureEvent, isLogOutputEvent, LogOutputEvent, isDebugServerLogOutputEvent, DebugServerLogOutputEvent, isRendezvousEvent, RendezvousEvent, isChanperfEvent, ChanperfEvent, isLaunchStartEvent, LaunchStartEvent, isPopupMessageEvent, PopupMessageEvent, isChannelPublishedEvent, ChannelPublishedEvent } from './Events';

describe('Events', () => {
it('is* methods work properly', () => {
//match
expect(isCompileFailureEvent(new CompileFailureEvent(null))).to.be.true;
expect(isLogOutputEvent(new LogOutputEvent(null))).to.be.true;
expect(isDebugServerLogOutputEvent(new DebugServerLogOutputEvent(null))).to.be.true;
expect(isRendezvousEvent(new RendezvousEvent(null))).to.be.true;
expect(isChanperfEvent(new ChanperfEvent(null))).to.be.true;
expect(isLaunchStartEvent(new LaunchStartEvent(null))).to.be.true;
expect(isPopupMessageEvent(new PopupMessageEvent(null, 'error'))).to.be.true;
expect(isChannelPublishedEvent(new ChannelPublishedEvent(null))).to.be.true;

//not match
expect(isCompileFailureEvent(null)).to.be.false;
expect(isLogOutputEvent(null)).to.be.false;
expect(isDebugServerLogOutputEvent(null)).to.be.false;
expect(isRendezvousEvent(null)).to.be.false;
expect(isChanperfEvent(null)).to.be.false;
expect(isLaunchStartEvent(null)).to.be.false;
expect(isPopupMessageEvent(null)).to.be.false;
expect(isChannelPublishedEvent(null)).to.be.false;
});
});
181 changes: 122 additions & 59 deletions src/debugSession/Events.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,171 @@
/* eslint-disable @typescript-eslint/no-useless-constructor */
import type { DebugProtocol } from 'vscode-debugprotocol';
import type { BrightScriptDebugCompileError } from '../CompileErrorProcessor';
import type { LaunchConfiguration } from '../LaunchConfiguration';
import type { ChanperfData } from '../ChanperfTracker';
import type { RendezvousHistory } from '../RendezvousTracker';

export class CompileFailureEvent implements DebugProtocol.Event {
constructor(compileError: BrightScriptDebugCompileError[]) {
this.body = compileError;
export class CustomEvent<T> implements DebugProtocol.Event {
public constructor(body: T) {
this.body = body;
this.event = this.constructor.name;
}

public body: any;
/**
* The body (payload) of the event.
*/
public body: T;
/**
* The name of the event. This name is how the client identifies the type of event and how to handle it
*/
public event: string;
/**
* The type of ProtocolMessage. Hardcoded to 'event' for all custom events
*/
public type = 'event';
public seq: number;
public type: string;
}

export class LogOutputEvent implements DebugProtocol.Event {
constructor(lines: string) {
this.body = lines;
this.event = 'BSLogOutputEvent';
/**
* Emitted when compile errors were encountered during the current debug session,
* usually during the initial sideload process as the Roku is compiling the app.
*/
export class CompileFailureEvent extends CustomEvent<{ compileErrors: BrightScriptDebugCompileError[] }> {
constructor(compileErrors: BrightScriptDebugCompileError[]) {
super({ compileErrors });
}
}

public body: any;
public event: string;
public seq: number;
public type: string;
/**
* Is the object a `CompileFailureEvent`
*/
export function isCompileFailureEvent(event: any): event is CompileFailureEvent {
return !!event && event.event === CompileFailureEvent.name;
}

/**
* A line of log ouptut from the Roku device
*/
export class LogOutputEvent extends CustomEvent<{ line: string }> {
constructor(line: string) {
super({ line });
}
}

export class DebugServerLogOutputEvent extends LogOutputEvent {
constructor(lines: string) {
super(lines);
this.event = 'BSDebugServerLogOutputEvent';
/**
* Is the object a `LogOutputEvent`
*/
export function isLogOutputEvent(event: any): event is LogOutputEvent {
return !!event && event.event === LogOutputEvent.name;
}

/**
* Log output from the debug server. These are logs emitted from NodeJS from the various RokuCommunity tools
*/
export class DebugServerLogOutputEvent extends CustomEvent<{ line: string }> {
constructor(line: string) {
super({ line });
}
}

export class RendezvousEvent implements DebugProtocol.Event {
/**
* Is the object a `DebugServerLogOutputEvent`
*/
export function isDebugServerLogOutputEvent(event: any): event is DebugServerLogOutputEvent {
return !!event && event.event === DebugServerLogOutputEvent.name;
}

/**
* Emitted when a rendezvous has occurred. Contains the full history of rendezvous since the start of the current debug session
*/
export class RendezvousEvent extends CustomEvent<RendezvousHistory> {
constructor(output: RendezvousHistory) {
this.body = output;
this.event = 'BSRendezvousEvent';
super(output);
}
}

public body: RendezvousHistory;
public event: string;
public seq: number;
public type: string;
/**
* Is the object a `RendezvousEvent`
*/
export function isRendezvousEvent(event: any): event is RendezvousEvent {
return !!event && event.event === RendezvousEvent.name;
}

export class ChanperfEvent implements DebugProtocol.Event {
/**
* Emitted anytime the debug session receives chanperf data.
*/
export class ChanperfEvent extends CustomEvent<ChanperfData> {
constructor(output: ChanperfData) {
this.body = output;
this.event = 'BSChanperfEvent';
super(output);
}
}

public body: ChanperfData;
public event: string;
public seq: number;
public type: string;
/**
* Is the object a `ChanperfEvent`
*/
export function isChanperfEvent(event: any): event is ChanperfEvent {
return !!event && event.event === ChanperfEvent.name;
}

export class LaunchStartEvent implements DebugProtocol.Event {
constructor(args: LaunchConfiguration) {
this.body = args;
this.event = 'BSLaunchStartEvent';

/**
* Emitted when the launch sequence first starts. This is right after the debug session receives the `launch` request,
* which happens before any zipping, sideloading, etc.
*/
export class LaunchStartEvent extends CustomEvent<LaunchConfiguration> {
constructor(launchConfiguration: LaunchConfiguration) {
super(launchConfiguration);
}
}

public body: any;
public event: string;
public seq: number;
public type: string;
/**
* Is the object a `LaunchStartEvent`
*/
export function isLaunchStartEvent(event: any): event is LaunchStartEvent {
return !!event && event.event === LaunchStartEvent.name;
}

export class PopupMessageEvent implements DebugProtocol.Event {
/**
* This event indicates that the client should show a popup message with the supplied information
*/
export class PopupMessageEvent extends CustomEvent<{ message: string; severity: 'error' | 'info' | 'warn' }> {
constructor(message: string, severity: 'error' | 'info' | 'warn') {
this.body = { message, severity };
this.event = 'BSPopupMessageEvent';
super({ message, severity });
}
}

public body: any;
public event: string;
public seq: number;
public type: string;
/**
* Is the object a `PopupMessageEvent`
*/
export function isPopupMessageEvent(event: any): event is PopupMessageEvent {
return !!event && event.event === PopupMessageEvent.name;
}

export class ChannelPublishedEvent implements DebugProtocol.Event {
/**
* Emitted once the channel has been sideloaded to the channel and the session is ready to start actually debugging.
*/
export class ChannelPublishedEvent extends CustomEvent<{ launchConfiguration: LaunchConfiguration }> {
constructor(
body: {
launchConfiguration: LaunchConfiguration;
}
launchConfiguration: LaunchConfiguration
) {
this.body = body ?? {};
this.event = 'BSChannelPublishedEvent';
super({ launchConfiguration });
}

public body: any;
public event: string;
public seq: number;
public type: string;
}

/**
* Is the object a `ChannelPublishedEvent`
*/
export function isChannelPublishedEvent(event: any): event is ChannelPublishedEvent {
return !!event && event.event === ChannelPublishedEvent.name;
}

export enum StoppedEventReason {
step = 'step',
breakpoint = 'breakpoint',
exception = 'exception',
pause = 'pause',
entry = 'entry'
entry = 'entry',
goto = 'goto',
functionBreakpoint = 'function breakpoint',
dataBreakpoint = 'data breakpoint',
instructionBreakpoint = 'instruction breakpoint'
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './managers/BreakpointManager';
export * from './LaunchConfiguration';
export * from './debugProtocol/Debugger';
export * from './debugSession/BrightScriptDebugSession';
export * from './debugSession/Events';
export * from './ComponentLibraryServer';
export * from './CompileErrorProcessor';
export * from './debugProtocol/Constants';
Expand Down