From 470b7e774cc068c98b3d91ee86b0176fa8fce066 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Fri, 30 Sep 2022 13:16:05 +1000 Subject: [PATCH 1/2] Raise a more meaningful error when the explorer window is closed and user tries to complete command --- src/extension/extension.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/extension/extension.ts b/src/extension/extension.ts index 420e40f5..b589e479 100644 --- a/src/extension/extension.ts +++ b/src/extension/extension.ts @@ -1042,12 +1042,12 @@ class PetWebviewViewProvider extends PetWebviewContainer { this._update(); } - public resetPets() { - this.getWebview().postMessage({ command: 'reset-pet' }); - } - getWebview(): vscode.Webview { - return this._webviewView!.webview; + if (this._webviewView === undefined) { + throw new Error('Panel not active, make sure the pets view is visible before running this command.'); + } else { + return this._webviewView.webview; + } } } From b2db20e59ef75f0fbbc8f82f59c5a7c17a4f67fb Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Fri, 30 Sep 2022 13:48:35 +1000 Subject: [PATCH 2/2] Ban non-null bang operator unless explicitly commented. --- .eslintrc.json | 3 ++- media/main-bundle.js | 32 ++++++++++++++++++-------------- src/extension/extension.ts | 16 +++++++++------- src/panel/main.ts | 31 ++++++++++++++++--------------- src/panel/pets.ts | 12 ++++++------ src/panel/states.ts | 5 +++-- 6 files changed, 54 insertions(+), 45 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f18d7339..4bb71291 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -18,6 +18,7 @@ "semi": "off", "no-unused-vars": "error", "unused-imports/no-unused-imports": "error", - "prefer-const": "error" + "prefer-const": "error", + "@typescript-eslint/no-non-null-assertion": "warn" } } diff --git a/media/main-bundle.js b/media/main-bundle.js index f76db526..77881e84 100644 --- a/media/main-bundle.js +++ b/media/main-bundle.js @@ -316,14 +316,12 @@ function saveState() { var state = new states_1.PetPanelState(); state.petStates = new Array(); exports.allPets.pets().forEach((petItem) => { - state.petStates.push({ + state.petStates?.push({ petName: petItem.pet.name(), petColor: petItem.color, petType: petItem.type, petState: petItem.pet.getState(), - petFriend: petItem.pet.friend() - ? petItem.pet.friend().name() - : undefined, + petFriend: petItem.pet.friend()?.name() ?? undefined, elLeft: petItem.el.style.left, elBottom: petItem.el.style.bottom, }); @@ -338,16 +336,16 @@ function recoverState(basePetUri, petSize, floor) { petCounter = 1; } else { - petCounter = state.petCounter; + petCounter = state.petCounter ?? 1; } var recoveryMap = new Map(); - state.petStates.forEach((p) => { + state.petStates?.forEach((p) => { // Fixes a bug related to duck animations if (p.petType === 'rubber duck') { p.petType = 'rubber-duck'; } try { - var newPet = addPetToPanel(p.petType, basePetUri, p.petColor, petSize, parseInt(p.elLeft), parseInt(p.elBottom), floor, p.petName); + var newPet = addPetToPanel(p.petType ?? "cat" /* PetType.cat */, basePetUri, p.petColor ?? "brown" /* PetColor.brown */, petSize, parseInt(p.elLeft ?? '0'), parseInt(p.elBottom ?? '0'), floor, p.petName); exports.allPets.push(newPet); recoveryMap.set(newPet.pet, p); } @@ -357,7 +355,9 @@ function recoverState(basePetUri, petSize, floor) { }); recoveryMap.forEach((state, pet) => { // Recover previous state. - pet.recoverState(state.petState); + if (state.petState !== undefined) { + pet.recoverState(state.petState); + } // Resolve friend relationships var friend = undefined; if (state.petFriend) { @@ -383,6 +383,7 @@ function petPanelApp(basePetUri, theme, themeKind, petColor, petSize, petType) { const ballRadius = calculateBallRadius(petSize); var floor = 0; // Apply Theme backgrounds + const foregroundEl = document.getElementById('foreground'); if (theme !== "none" /* Theme.none */) { var _themeKind = ''; switch (themeKind) { @@ -398,12 +399,14 @@ function petPanelApp(basePetUri, theme, themeKind, petColor, petSize, petType) { break; } document.body.style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/background-${_themeKind}-${petSize}.png')`; - document.getElementById('foreground').style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/foreground-${_themeKind}-${petSize}.png')`; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + foregroundEl.style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/foreground-${_themeKind}-${petSize}.png')`; floor = calculateFloor(petSize, theme); // Themes have pets at a specified height from the ground } else { document.body.style.backgroundImage = ''; - document.getElementById('foreground').style.backgroundImage = ''; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + foregroundEl.style.backgroundImage = ''; } /// Bouncing ball components, credit https://stackoverflow.com/a/29982343 const gravity = 0.2, damping = 0.9, traction = 0.8; @@ -721,7 +724,7 @@ class BasePetType { recoverState(state) { // TODO : Resolve a bug where if it was swiping before, it would fail // because holdState is no longer valid. - this.currentStateEnum = state.currentStateEnum; + this.currentStateEnum = state.currentStateEnum ?? "sit-idle" /* States.sitIdle */; this.currentState = (0, states_1.resolveState)(this.currentStateEnum, this); if (!(0, states_1.isStateAboveGround)(this.currentStateEnum)) { // Reset the bottom of the sprite to the floor as the theme @@ -790,7 +793,7 @@ class BasePetType { if (this.hasFriend() && this.currentStateEnum !== "chase-friend" /* States.chaseFriend */ && this.isMoving()) { - if (this.friend().isPlaying() && + if (this.friend()?.isPlaying() && !(0, states_1.isStateAboveGround)(this.currentStateEnum)) { this.currentState = (0, states_1.resolveState)("chase-friend" /* States.chaseFriend */, this); this.currentStateEnum = "chase-friend" /* States.chaseFriend */; @@ -1355,7 +1358,7 @@ class InvalidPetException { exports.InvalidPetException = InvalidPetException; function getPetName(collection, label, count) { if (collection.has(count)) { - return collection.get(count); + return collection.get(count) ?? (label + count); } else { return label + count; @@ -1697,9 +1700,10 @@ class ChaseFriendState { this.pet = pet; } nextFrame() { - if (!this.pet.friend().isPlaying()) { + if (!this.pet.hasFriend() || !this.pet.friend()?.isPlaying()) { return FrameResult.stateCancel; // Friend is no longer playing. } + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (this.pet.left() > this.pet.friend().left()) { this.horizontalDirection = HorizontalDirection.left; this.pet.positionLeft(this.pet.left() - this.pet.speed()); diff --git a/src/extension/extension.ts b/src/extension/extension.ts index b589e479..d85e0fbe 100644 --- a/src/extension/extension.ts +++ b/src/extension/extension.ts @@ -149,7 +149,7 @@ export class PetSpecification { for (let index = 0; index < contextTypes.length; index++) { result.push( new PetSpecification( - contextColors![index], + contextColors?.[index] ?? DEFAULT_COLOR, contextTypes[index], size, ), @@ -287,7 +287,7 @@ export function activate(context: vscode.ExtensionContext) { getConfiguredSize(), ); collection.forEach((item) => { - PetPanel.currentPanel!.spawnPet(item); + PetPanel.currentPanel?.spawnPet(item); }); } } @@ -355,7 +355,7 @@ export function activate(context: vscode.ExtensionContext) { const panel = getPetPanel(); if (panel !== undefined) { panel.listPets(); - getWebview()!.onDidReceiveMessage( + getWebview()?.onDidReceiveMessage( handleRemovePetMessage, context, ); @@ -376,7 +376,7 @@ export function activate(context: vscode.ExtensionContext) { getConfiguredSize(), ); collection.forEach((item) => { - PetPanel.currentPanel!.spawnPet(item); + PetPanel.currentPanel?.spawnPet(item); }); storeCollectionAsMemento(context, collection); } else { @@ -487,7 +487,7 @@ export function activate(context: vscode.ExtensionContext) { getConfiguredSize(), ); collection.forEach((item) => { - PetPanel.currentPanel!.spawnPet(item); + PetPanel.currentPanel?.spawnPet(item); }); storeCollectionAsMemento(context, collection); } else { @@ -528,7 +528,7 @@ export function activate(context: vscode.ExtensionContext) { getConfiguredSize(), ); collection.forEach((item) => { - PetPanel.currentPanel!.spawnPet(item); + PetPanel.currentPanel?.spawnPet(item); }); storeCollectionAsMemento(context, collection); } else { @@ -1044,7 +1044,9 @@ class PetWebviewViewProvider extends PetWebviewContainer { getWebview(): vscode.Webview { if (this._webviewView === undefined) { - throw new Error('Panel not active, make sure the pets view is visible before running this command.'); + throw new Error( + 'Panel not active, make sure the pets view is visible before running this command.', + ); } else { return this._webviewView.webview; } diff --git a/src/panel/main.ts b/src/panel/main.ts index 7c511d96..260dfb6b 100644 --- a/src/panel/main.ts +++ b/src/panel/main.ts @@ -149,14 +149,12 @@ export function saveState() { state.petStates = new Array(); allPets.pets().forEach((petItem) => { - state.petStates!.push({ + state.petStates?.push({ petName: petItem.pet.name(), petColor: petItem.color, petType: petItem.type, petState: petItem.pet.getState(), - petFriend: petItem.pet.friend() - ? petItem.pet.friend().name() - : undefined, + petFriend: petItem.pet.friend()?.name() ?? undefined, elLeft: petItem.el.style.left, elBottom: petItem.el.style.bottom, }); @@ -171,11 +169,11 @@ function recoverState(basePetUri: string, petSize: PetSize, floor: number) { if (state.petCounter === undefined || isNaN(state.petCounter)) { petCounter = 1; } else { - petCounter = state.petCounter!; + petCounter = state.petCounter ?? 1; } var recoveryMap: Map = new Map(); - state.petStates!.forEach((p) => { + state.petStates?.forEach((p) => { // Fixes a bug related to duck animations if ((p.petType as string) === 'rubber duck') { (p.petType as string) = 'rubber-duck'; @@ -183,12 +181,12 @@ function recoverState(basePetUri: string, petSize: PetSize, floor: number) { try { var newPet = addPetToPanel( - p.petType!, + p.petType ?? PetType.cat, basePetUri, - p.petColor!, + p.petColor ?? PetColor.brown, petSize, - parseInt(p.elLeft!), - parseInt(p.elBottom!), + parseInt(p.elLeft ?? '0'), + parseInt(p.elBottom ?? '0'), floor, p.petName, ); @@ -202,7 +200,9 @@ function recoverState(basePetUri: string, petSize: PetSize, floor: number) { }); recoveryMap.forEach((state, pet) => { // Recover previous state. - pet.recoverState(state.petState!); + if (state.petState !== undefined) { + pet.recoverState(state.petState); + } // Resolve friend relationships var friend = undefined; @@ -240,6 +240,7 @@ export function petPanelApp( const ballRadius: number = calculateBallRadius(petSize); var floor = 0; // Apply Theme backgrounds + const foregroundEl = document.getElementById('foreground'); if (theme !== Theme.none) { var _themeKind = ''; switch (themeKind) { @@ -256,14 +257,14 @@ export function petPanelApp( } document.body.style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/background-${_themeKind}-${petSize}.png')`; - document.getElementById( - 'foreground', - )!.style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/foreground-${_themeKind}-${petSize}.png')`; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + foregroundEl!.style.backgroundImage = `url('${basePetUri}/backgrounds/${theme}/foreground-${_themeKind}-${petSize}.png')`; floor = calculateFloor(petSize, theme); // Themes have pets at a specified height from the ground } else { document.body.style.backgroundImage = ''; - document.getElementById('foreground')!.style.backgroundImage = ''; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + foregroundEl!.style.backgroundImage = ''; } /// Bouncing ball components, credit https://stackoverflow.com/a/29982343 diff --git a/src/panel/pets.ts b/src/panel/pets.ts index 6a8a13bb..e75804fa 100644 --- a/src/panel/pets.ts +++ b/src/panel/pets.ts @@ -172,7 +172,7 @@ export interface IPetType { name(): string; emoji(): string; hasFriend(): boolean; - friend(): IPetType; + friend(): IPetType | undefined; makeFriendsWith(friend: IPetType): boolean; isPlaying(): boolean; } @@ -303,7 +303,7 @@ abstract class BasePetType implements IPetType { recoverState(state: PetInstanceState) { // TODO : Resolve a bug where if it was swiping before, it would fail // because holdState is no longer valid. - this.currentStateEnum = state.currentStateEnum!; + this.currentStateEnum = state.currentStateEnum ?? States.sitIdle; this.currentState = resolveState(this.currentStateEnum, this); if (!isStateAboveGround(this.currentStateEnum)) { @@ -391,7 +391,7 @@ abstract class BasePetType implements IPetType { this.isMoving() ) { if ( - this.friend().isPlaying() && + this.friend()?.isPlaying() && !isStateAboveGround(this.currentStateEnum) ) { this.currentState = resolveState(States.chaseFriend, this); @@ -431,8 +431,8 @@ abstract class BasePetType implements IPetType { return this._friend !== undefined; } - friend(): IPetType { - return this._friend!; + friend(): IPetType | undefined { + return this._friend; } name(): string { @@ -968,7 +968,7 @@ function getPetName( count: number, ): string { if (collection.has(count)) { - return collection.get(count)!; + return collection.get(count) ?? label + count; } else { return label + count; } diff --git a/src/panel/states.ts b/src/panel/states.ts index 39f1831d..aa7210fe 100644 --- a/src/panel/states.ts +++ b/src/panel/states.ts @@ -310,10 +310,11 @@ export class ChaseFriendState implements IState { } nextFrame(): FrameResult { - if (!this.pet.friend().isPlaying()) { + if (!this.pet.hasFriend() || !this.pet.friend()?.isPlaying()) { return FrameResult.stateCancel; // Friend is no longer playing. } - if (this.pet.left() > this.pet.friend().left()) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + if (this.pet.left() > this.pet.friend()!.left()) { this.horizontalDirection = HorizontalDirection.left; this.pet.positionLeft(this.pet.left() - this.pet.speed()); } else {