From a7e5acf5391b586cdb7bb9772b9f6ce266b5b702 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Wed, 24 Aug 2022 10:59:25 -0700 Subject: [PATCH] Initial work on enabling strict nulls in azurecore (#20411) --- .../azurecore/src/azureResource/commands.ts | 8 ++++--- .../src/azureResource/messageTreeNode.ts | 4 ++-- .../src/azureResource/tree/accountTreeNode.ts | 14 ++++++------- .../src/azureResource/tree/baseTreeNodes.ts | 21 ++++++++++++------- .../tree/connectionDialogTreeProvider.ts | 12 +++++------ .../azureResource/tree/flatAccountTreeNode.ts | 6 +++--- .../azureResource/tree/flatTreeProvider.ts | 14 ++++++------- .../tree/subscriptionTreeNode.ts | 2 +- .../src/azureResource/tree/treeProvider.ts | 12 +++++------ .../azurecore/src/azureResource/treeNode.ts | 14 +++---------- extensions/azurecore/src/extension.ts | 10 ++++----- extensions/azurecore/tsconfig.json | 2 +- 12 files changed, 60 insertions(+), 59 deletions(-) diff --git a/extensions/azurecore/src/azureResource/commands.ts b/extensions/azurecore/src/azureResource/commands.ts index c1c81eb72f..151b03238f 100644 --- a/extensions/azurecore/src/azureResource/commands.ts +++ b/extensions/azurecore/src/azureResource/commands.ts @@ -31,7 +31,7 @@ export function registerAzureResourceCommands(appContext: AppContext, azureViewT } let azureAccount: AzureAccount | undefined; if (node instanceof AzureResourceAccountTreeNode) { - azureAccount = node.account as AzureAccount; + azureAccount = node.account; } else { let accounts = await azdata.accounts.getAllAccounts(); accounts = accounts.filter(a => a.key.providerId.startsWith('azure')); @@ -57,7 +57,9 @@ export function registerAzureResourceCommands(appContext: AppContext, azureViewT azureAccount = accounts.find(acct => acct.displayInfo.displayName === pickedAccount); } } - + if (!azureAccount) { + throw new Error('No Azure Account chosen'); + } const terminalService = appContext.getService(AzureResourceServiceNames.terminalService); const listOfTenants = azureAccount.properties.tenants.map(t => t.displayName); @@ -176,7 +178,7 @@ export function registerAzureResourceCommands(appContext: AppContext, azureViewT if (!node) { return; } - let connectionProfile: azdata.IConnectionProfile = undefined; + let connectionProfile: azdata.IConnectionProfile | undefined = undefined; if (node instanceof TreeNode) { const treeItem: azdata.TreeItem = await node.getTreeItem(); if (!treeItem.payload) { diff --git a/extensions/azurecore/src/azureResource/messageTreeNode.ts b/extensions/azurecore/src/azureResource/messageTreeNode.ts index acd15b9bdc..da24070dd3 100644 --- a/extensions/azurecore/src/azureResource/messageTreeNode.ts +++ b/extensions/azurecore/src/azureResource/messageTreeNode.ts @@ -12,7 +12,7 @@ import { AzureResourceItemType } from './constants'; export class AzureResourceMessageTreeNode extends TreeNode { public constructor( public readonly message: string, - parent: TreeNode + parent: TreeNode | undefined ) { super(); @@ -20,7 +20,7 @@ export class AzureResourceMessageTreeNode extends TreeNode { this._id = `message_${AzureResourceMessageTreeNode._messageNum++}`; } - public static create(message: string, parent: TreeNode): AzureResourceMessageTreeNode { + public static create(message: string, parent: TreeNode | undefined): AzureResourceMessageTreeNode { return new AzureResourceMessageTreeNode(message, parent); } diff --git a/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts b/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts index da49cc5ce2..f8561bade0 100644 --- a/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts +++ b/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts @@ -71,7 +71,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode let token: azdata.accounts.AccountSecurityToken | undefined = undefined; let errMsg = ''; try { - token = await azdata.accounts.getAccountSecurityToken(this.account, s.tenant, azdata.AzureResource.ResourceManagement); + token = await azdata.accounts.getAccountSecurityToken(this.account, s.tenant!, azdata.AzureResource.ResourceManagement); } catch (err) { errMsg = AzureResourceErrorMessageUtil.getErrorMessage(err); } @@ -84,7 +84,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode subscriptions = subscriptions.filter((_s, i) => hasTokenResults[i]); let subTreeNodes = await Promise.all(subscriptions.map(async (subscription) => { - return new AzureResourceSubscriptionTreeNode(this.account, subscription, subscription.tenant, this.appContext, this.treeChangeHandler, this); + return new AzureResourceSubscriptionTreeNode(this.account, subscription, subscription.tenant!, this.appContext, this.treeChangeHandler, this); })); return subTreeNodes.sort((a, b) => a.subscription.name.localeCompare(b.subscription.name)); } @@ -97,7 +97,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode } public async getCachedSubscriptions(): Promise { - return this.getCache(); + return this.getCache() ?? []; } public getTreeItem(): vscode.TreeItem | Promise { @@ -155,11 +155,11 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode return label; } - private _subscriptionService: IAzureResourceSubscriptionService = undefined; - private _subscriptionFilterService: IAzureResourceSubscriptionFilterService = undefined; + private _subscriptionService: IAzureResourceSubscriptionService; + private _subscriptionFilterService: IAzureResourceSubscriptionFilterService; - private _id: string = undefined; - private _label: string = undefined; + private _id: string; + private _label: string; private _totalSubscriptionCount = 0; private _selectedSubscriptionCount = 0; diff --git a/extensions/azurecore/src/azureResource/tree/baseTreeNodes.ts b/extensions/azurecore/src/azureResource/tree/baseTreeNodes.ts index 76df0955f0..9312feab4f 100644 --- a/extensions/azurecore/src/azureResource/tree/baseTreeNodes.ts +++ b/extensions/azurecore/src/azureResource/tree/baseTreeNodes.ts @@ -14,7 +14,7 @@ abstract class AzureResourceTreeNodeBase extends TreeNode { public constructor( public readonly appContext: AppContext, public readonly treeChangeHandler: IAzureResourceTreeChangeHandler, - parent: TreeNode + parent: TreeNode | undefined ) { super(); @@ -26,7 +26,7 @@ export abstract class AzureResourceContainerTreeNodeBase extends AzureResourceTr public constructor( appContext: AppContext, treeChangeHandler: IAzureResourceTreeChangeHandler, - parent: TreeNode + parent: TreeNode | undefined ) { super(appContext, treeChangeHandler, parent); @@ -46,14 +46,21 @@ export abstract class AzureResourceContainerTreeNodeBase extends AzureResourceTr } protected updateCache(cache: T): Promise { - return this._cacheService.update(this._cacheKey, cache); + return this._cacheService.update(this._cacheKey!, cache); } - protected getCache(): T { - return this._cacheService.get(this._cacheKey); + protected getCache(): T | undefined { + this.ensureCacheKey(); + return this._cacheService.get(this._cacheKey!); + } + + private ensureCacheKey(): void { + if (!this._cacheKey) { + throw new Error('A cache key must be generated first'); + } } protected _isClearingCache = true; - private _cacheService: IAzureResourceCacheService = undefined; - private _cacheKey: string = undefined; + private _cacheService: IAzureResourceCacheService; + private _cacheKey: string | undefined = undefined; } diff --git a/extensions/azurecore/src/azureResource/tree/connectionDialogTreeProvider.ts b/extensions/azurecore/src/azureResource/tree/connectionDialogTreeProvider.ts index 8645d97088..243859cec2 100644 --- a/extensions/azurecore/src/azureResource/tree/connectionDialogTreeProvider.ts +++ b/extensions/azurecore/src/azureResource/tree/connectionDialogTreeProvider.ts @@ -22,9 +22,9 @@ import { AzureAccount } from 'azurecore'; export class ConnectionDialogTreeProvider implements vscode.TreeDataProvider, IAzureResourceTreeChangeHandler { public isSystemInitialized: boolean = false; - private accounts: AzureAccount[]; - private _onDidChangeTreeData = new vscode.EventEmitter(); - private loadingAccountsPromise: Promise; + private accounts: AzureAccount[] = []; + private _onDidChangeTreeData = new vscode.EventEmitter(); + private loadingAccountsPromise: Promise | undefined; public constructor(private readonly appContext: AppContext) { azdata.accounts.onDidChangeAccounts(async (e: azdata.DidChangeAccountsParams) => { @@ -101,15 +101,15 @@ export class ConnectionDialogTreeProvider implements vscode.TreeDataProvider { + public get onDidChangeTreeData(): vscode.Event { return this._onDidChangeTreeData.event; } - public notifyNodeChanged(node: TreeNode): void { + public notifyNodeChanged(node: TreeNode | undefined): void { this._onDidChangeTreeData.fire(node); } - public async refresh(node: TreeNode, isClearingCache: boolean): Promise { + public async refresh(node: TreeNode | undefined, isClearingCache: boolean): Promise { if (isClearingCache) { if ((node instanceof AzureResourceContainerTreeNodeBase)) { node.clearCache(); diff --git a/extensions/azurecore/src/azureResource/tree/flatAccountTreeNode.ts b/extensions/azurecore/src/azureResource/tree/flatAccountTreeNode.ts index f0dc700269..df90913f72 100644 --- a/extensions/azurecore/src/azureResource/tree/flatAccountTreeNode.ts +++ b/extensions/azurecore/src/azureResource/tree/flatAccountTreeNode.ts @@ -136,7 +136,7 @@ async function getSubscriptionInfo(account: AzureAccount, subscriptionService: I class FlatAccountTreeNodeLoader { private _isLoading: boolean = false; - private _nodes: TreeNode[]; + private _nodes: TreeNode[] = []; private readonly _onNewResourcesAvailable = new vscode.EventEmitter(); public readonly onNewResourcesAvailable = this._onNewResourcesAvailable.event; private readonly _onLoadingStatusChanged = new vscode.EventEmitter(); @@ -183,7 +183,7 @@ class FlatAccountTreeNodeLoader { if (subscriptions.length !== 0) { // Filter out everything that we can't authenticate to. subscriptions = subscriptions.filter(async s => { - const token = await azdata.accounts.getAccountSecurityToken(this._account, s.tenant, azdata.AzureResource.ResourceManagement); + const token = await azdata.accounts.getAccountSecurityToken(this._account, s.tenant!, azdata.AzureResource.ResourceManagement); if (!token) { console.info(`Account does not have permissions to view subscription ${JSON.stringify(s)}.`); return false; @@ -195,7 +195,7 @@ class FlatAccountTreeNodeLoader { const resourceProviderIds = await this._resourceService.listResourceProviderIds(); for (const subscription of subscriptions) { for (const providerId of resourceProviderIds) { - const resourceTypes = await this._resourceService.getRootChildren(providerId, this._account, subscription, subscription.tenant); + const resourceTypes = await this._resourceService.getRootChildren(providerId, this._account, subscription, subscription.tenant!); for (const resourceType of resourceTypes) { const resources = await this._resourceService.getChildren(providerId, resourceType.resourceNode, true); if (resources.length > 0) { diff --git a/extensions/azurecore/src/azureResource/tree/flatTreeProvider.ts b/extensions/azurecore/src/azureResource/tree/flatTreeProvider.ts index 11396aba16..e6559f7684 100644 --- a/extensions/azurecore/src/azureResource/tree/flatTreeProvider.ts +++ b/extensions/azurecore/src/azureResource/tree/flatTreeProvider.ts @@ -24,7 +24,7 @@ export class FlatAzureResourceTreeProvider implements vscode.TreeDataProvider(); - private resourceLoader: ResourceLoader; + private resourceLoader: ResourceLoader | undefined; public constructor(private readonly appContext: AppContext) { } @@ -124,13 +124,13 @@ class ResourceLoader { for (const tenant of account.properties.tenants) { for (const subscription of await this.subscriptionService.getSubscriptions(account, [tenant.id])) { for (const providerId of await this.resourceService.listResourceProviderIds()) { - for (const group of await this.resourceService.getRootChildren(providerId, account, subscription, subscription.tenant)) { + for (const group of await this.resourceService.getRootChildren(providerId, account, subscription, subscription.tenant!)) { const children = await this.resourceService.getChildren(providerId, group.resourceNode); - if (this.resourceGroups.has(group.resourceProviderId)) { - const groupNode = this.resourceGroups.get(group.resourceProviderId); + let groupNode: AzureResourceResourceTreeNode | undefined = this.resourceGroups.get(group.resourceProviderId); + if (groupNode) { groupNode.pushItems(...children); } else { - const groupNode = new AzureResourceResourceTreeNode(group, this.appContext); + groupNode = new AzureResourceResourceTreeNode(group, this.appContext); this.resourceGroups.set(group.resourceProviderId, groupNode); groupNode.pushItems(...children); } @@ -199,14 +199,14 @@ class AzureResourceResourceTreeNode extends TreeNode { metadata: undefined, nodePath: this.generateNodePath(), nodeStatus: undefined, - nodeType: treeItem.contextValue, + nodeType: treeItem.contextValue || '', nodeSubType: undefined, iconType: treeItem.contextValue }; } public get nodePathValue(): string { - return this.resourceNodeWithProviderId.resourceNode.treeItem.id; + return this.resourceNodeWithProviderId.resourceNode.treeItem.id || ''; } } diff --git a/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts b/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts index 6d36ec12ed..62ac1128a1 100644 --- a/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts +++ b/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts @@ -87,7 +87,7 @@ export class AzureResourceSubscriptionTreeNode extends AzureResourceContainerTre return this._id; } - private _id: string = undefined; + private _id: string; private static readonly noResourcesLabel = localize('azure.resource.tree.subscriptionTreeNode.noResourcesLabel', "No Resources found."); } diff --git a/extensions/azurecore/src/azureResource/tree/treeProvider.ts b/extensions/azurecore/src/azureResource/tree/treeProvider.ts index a749acc9ff..14c08b8e4d 100644 --- a/extensions/azurecore/src/azureResource/tree/treeProvider.ts +++ b/extensions/azurecore/src/azureResource/tree/treeProvider.ts @@ -22,9 +22,9 @@ import { AzureAccount } from 'azurecore'; export class AzureResourceTreeProvider implements vscode.TreeDataProvider, IAzureResourceTreeChangeHandler { public isSystemInitialized: boolean = false; - private accounts: AzureAccount[]; - private _onDidChangeTreeData = new vscode.EventEmitter(); - private loadingAccountsPromise: Promise; + private accounts: AzureAccount[] = []; + private _onDidChangeTreeData = new vscode.EventEmitter(); + private loadingAccountsPromise: Promise | undefined; public constructor(private readonly appContext: AppContext) { azdata.accounts.onDidChangeAccounts(async (e: azdata.DidChangeAccountsParams) => { @@ -82,15 +82,15 @@ export class AzureResourceTreeProvider implements vscode.TreeDataProvider { + public get onDidChangeTreeData(): vscode.Event { return this._onDidChangeTreeData.event; } - public notifyNodeChanged(node: TreeNode): void { + public notifyNodeChanged(node: TreeNode | undefined): void { this._onDidChangeTreeData.fire(node); } - public async refresh(node: TreeNode, isClearingCache: boolean): Promise { + public async refresh(node: TreeNode | undefined, isClearingCache: boolean): Promise { if (isClearingCache) { if ((node instanceof AzureResourceContainerTreeNodeBase)) { node.clearCache(); diff --git a/extensions/azurecore/src/azureResource/treeNode.ts b/extensions/azurecore/src/azureResource/treeNode.ts index 18f13d254b..1ed289a924 100644 --- a/extensions/azurecore/src/azureResource/treeNode.ts +++ b/extensions/azurecore/src/azureResource/treeNode.ts @@ -18,13 +18,13 @@ export abstract class TreeNode { return path; } - public findNodeByPath(path: string, expandIfNeeded: boolean = false): Promise { + public findNodeByPath(path: string, expandIfNeeded: boolean = false): Promise { let condition: TreeNodePredicate = (node: TreeNode) => node.getNodeInfo().nodePath === path; let filter: TreeNodePredicate = (node: TreeNode) => path.startsWith(node.getNodeInfo().nodePath); return TreeNode.findNode(this, condition, filter, true); } - public static async findNode(node: TreeNode, condition: TreeNodePredicate, filter: TreeNodePredicate, expandIfNeeded: boolean): Promise { + public static async findNode(node: TreeNode, condition: TreeNodePredicate, filter: TreeNodePredicate, expandIfNeeded: boolean): Promise { if (!node) { return undefined; } @@ -53,13 +53,7 @@ export abstract class TreeNode { return undefined; } - public get parent(): TreeNode { - return this._parent; - } - - public set parent(node: TreeNode) { - this._parent = node; - } + public parent: TreeNode | undefined = undefined; public abstract getChildren(refreshChildren: boolean): TreeNode[] | Promise; public abstract getTreeItem(): vscode.TreeItem | Promise; @@ -70,6 +64,4 @@ export abstract class TreeNode { * The value to use for this node in the node path */ public abstract get nodePathValue(): string; - - private _parent: TreeNode = undefined; } diff --git a/extensions/azurecore/src/extension.ts b/extensions/azurecore/src/extension.ts index dcb9690348..ab4f0bcbae 100644 --- a/extensions/azurecore/src/extension.ts +++ b/extensions/azurecore/src/extension.ts @@ -56,7 +56,7 @@ let extensionContext: vscode.ExtensionContext; function getAppDataPath() { let platform = process.platform; switch (platform) { - case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming'); + case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE']!, 'AppData', 'Roaming'); case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support'); case 'linux': return process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'); default: throw new Error('Platform not supported'); @@ -79,7 +79,7 @@ export async function activate(context: vscode.ExtensionContext): Promise onDidChangeConfiguration(e), this)); + pushDisposable(vscode.workspace.onDidChangeConfiguration(e => onDidChangeConfiguration(e))); registerAzureResourceCommands(appContext, azureResourceTree, connectionDialogTree); azdata.dataprotocol.registerDataGridProvider(new AzureDataGridProvider(appContext)); vscode.commands.registerCommand('azure.dataGrid.openInAzurePortal', async (item: azdata.DataGridItem) => { @@ -280,8 +280,8 @@ async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent): Pro } } -function updatePiiLoggingLevel() { - const piiLogging: boolean = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('piiLogging'); +function updatePiiLoggingLevel(): void { + const piiLogging: boolean = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('piiLogging', false); Logger.piiLogging = piiLogging; } diff --git a/extensions/azurecore/tsconfig.json b/extensions/azurecore/tsconfig.json index 0e7adb6838..7682440684 100644 --- a/extensions/azurecore/tsconfig.json +++ b/extensions/azurecore/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../tsconfig.base.json", "compilerOptions": { "outDir": "./out", - "strict": false, + "strict": true, "noUnusedParameters": false, "typeRoots": [ "./node_modules/@types"