Skip to content

Commit 2093e06

Browse files
committed
refactor: make types more precise
1 parent 655af91 commit 2093e06

File tree

2 files changed

+64
-49
lines changed

2 files changed

+64
-49
lines changed

packages/core/src/shared/clients/codecatalystClient.ts

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ import { CodeCatalyst } from 'aws-sdk'
3030
import { ToolkitError } from '../errors'
3131
import { TokenProvider } from '../../auth/sso/sdkV2Compat'
3232
import { Uri } from 'vscode'
33-
import {
34-
GetSourceRepositoryCloneUrlsRequest,
35-
ListSourceRepositoriesItem,
36-
ListSourceRepositoriesItems,
37-
} from 'aws-sdk/clients/codecatalyst'
33+
import { GetSourceRepositoryCloneUrlsRequest } from 'aws-sdk/clients/codecatalyst'
3834
import {
3935
CodeCatalystClient as CodeCatalystSDKClient,
4036
CreateAccessTokenCommand,
@@ -62,6 +58,9 @@ import {
6258
ListProjectsCommand,
6359
ListProjectsRequest,
6460
ListProjectsResponse,
61+
ListSourceRepositoriesCommand,
62+
ListSourceRepositoriesItem,
63+
ListSourceRepositoriesResponse,
6564
ListSpacesCommand,
6665
ListSpacesRequest,
6766
ListSpacesResponse,
@@ -138,7 +137,7 @@ export interface CodeCatalystProject extends CodeCatalyst.ProjectSummary {
138137
readonly org: Pick<CodeCatalystOrg, 'name'>
139138
}
140139

141-
export interface CodeCatalystRepo extends CodeCatalyst.ListSourceRepositoriesItem {
140+
export interface CodeCatalystRepo extends ListSourceRepositoriesItem {
142141
readonly type: 'repo'
143142
readonly name: string
144143
readonly org: Pick<CodeCatalystOrg, 'name'>
@@ -552,14 +551,14 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
552551
this.callV3(ListSpacesCommand, request, true, { items: [] })
553552
const collection = pageableToCollection(requester, request, 'nextToken', 'items').filter(isDefined)
554553
// ts doesn't recognize nested assertion, so we add cast.This is safe because we assert it in the same line.
555-
return collection.map((summaries) =>
556-
(summaries.filter((s) => hasProps(s, 'name')) as Readonly<RequiredProps<SpaceSummary, 'name'>>[]).map(
557-
(s) => ({
558-
type: 'org',
559-
...s,
560-
})
561-
)
562-
)
554+
return collection.map((summaries) => summaries.filter(hasName).map(toOrg))
555+
556+
function toOrg<T extends RequiredProps<SpaceSummary, 'name'>>(s: T): CodeCatalystOrg {
557+
return {
558+
type: 'org',
559+
...s,
560+
}
561+
}
563562
}
564563

565564
/**
@@ -580,17 +579,16 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
580579
const requester: (request: ListProjectsRequest) => Promise<ListProjectsResponse> = (request) =>
581580
this.callV3(ListProjectsCommand, request, true, { items: [] })
582581

583-
const collection = pageableToCollection(requester, request, 'nextToken', 'items').filter(isDefined)
584-
// ts doesn't recognize nested assertion, so we add cast. This is safe because we assert it in the same line.
585-
return collection.map((summaries) =>
586-
(summaries.filter((s) => hasProps(s, 'name')) as Readonly<RequiredProps<ProjectSummary, 'name'>>[]).map(
587-
(s) => ({
588-
type: 'project',
589-
org: { name: request.spaceName },
590-
...s,
591-
})
592-
)
593-
)
582+
const collection = pageableToCollection(requester, request, 'nextToken', 'items')
583+
return collection.filter(isDefined).map((summaries) => summaries.filter(hasName).map(toProject))
584+
585+
function toProject<T extends RequiredProps<ProjectSummary, 'name'>>(s: T): CodeCatalystProject {
586+
return {
587+
type: 'project',
588+
org: { name: request.spaceName },
589+
...s,
590+
}
591+
}
594592
}
595593

596594
/**
@@ -604,13 +602,11 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
604602
this.callV3(ListDevEnvironmentsCommand, request, true, { items: [] })
605603
const collection = pageableToCollection(requester, initRequest, 'nextToken' as never, 'items').filter(isDefined)
606604
// ts unable to recognize nested assertion here, so we need to cast. This is safe because we assert it in the same line.
607-
return collection.map((envs) =>
608-
(
609-
envs.filter(
610-
(s) => hasProps(s, ...requiredDevEnvProps) && hasPersistentStorage(s) && hasRepositories(s)
611-
) as CodeCatalystDevEnvironmentSummary[]
612-
).map((s) => toDevEnv(proj.org.name, proj.name, s))
613-
)
605+
return collection.map((envs) => {
606+
const filteredEnvs = envs.filter(isValidEnvSummary)
607+
const mappedEnvs = filteredEnvs.map((s) => toDevEnv(proj.org.name, proj.name, s))
608+
return mappedEnvs
609+
})
614610
}
615611

616612
/**
@@ -623,7 +619,12 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
623619
thirdParty: boolean = true
624620
): AsyncCollection<CodeCatalystRepo[]> {
625621
const requester = async (request: CodeCatalyst.ListSourceRepositoriesRequest) => {
626-
const allRepositories = this.call(this.sdkClient.listSourceRepositories(request), true, { items: [] })
622+
const allRepositories: Promise<ListSourceRepositoriesResponse> = this.callV3(
623+
ListSourceRepositoriesCommand,
624+
request,
625+
true,
626+
{ items: [] }
627+
)
627628
let finalRepositories = allRepositories
628629

629630
// Filter out 3P repos
@@ -633,7 +634,7 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
633634
this,
634635
request.spaceName,
635636
request.projectName,
636-
repos.items
637+
repos.items?.filter(hasName)
637638
)
638639
return repos
639640
})
@@ -643,15 +644,16 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
643644
}
644645

645646
const collection = pageableToCollection(requester, request, 'nextToken', 'items')
646-
return collection.map(
647-
(summaries) =>
648-
summaries?.map((s) => ({
649-
type: 'repo',
650-
org: { name: request.spaceName },
651-
project: { name: request.projectName },
652-
...s,
653-
})) ?? []
654-
)
647+
return collection.filter(isDefined).map((summaries) => summaries.filter(hasName).map(toCodeCatalystRepo))
648+
649+
function toCodeCatalystRepo(s: RequiredProps<ListSourceRepositoriesItem, 'name'>): CodeCatalystRepo {
650+
return {
651+
type: 'repo',
652+
org: { name: request.spaceName },
653+
project: { name: request.projectName },
654+
...s,
655+
}
656+
}
655657
}
656658

657659
public listBranches(
@@ -768,7 +770,7 @@ class CodeCatalystClientInternal extends ClientWrapper<CodeCatalystSDKClient> {
768770

769771
const r: GetDevEnvironmentResponse = await this.callV3(GetDevEnvironmentCommand, a, false)
770772
const summary = { ...args, ...r }
771-
if (!hasProps(summary, ...requiredDevEnvProps) || !hasPersistentStorage(summary) || !hasRepositories(summary)) {
773+
if (!isValidEnvSummary(summary)) {
772774
throw new ToolkitError(`GetDevEnvironment failed due to response missing required properties`)
773775
}
774776

@@ -969,8 +971,8 @@ export async function excludeThirdPartyRepos(
969971
client: CodeCatalystClient,
970972
spaceName: CodeCatalystOrg['name'],
971973
projectName: CodeCatalystProject['name'],
972-
items?: Pick<ListSourceRepositoriesItem, 'name'>[]
973-
): Promise<ListSourceRepositoriesItems | undefined> {
974+
items?: RequiredProps<ListSourceRepositoriesItem, 'name'>[]
975+
): Promise<ListSourceRepositoriesItem[] | undefined> {
974976
if (items === undefined) {
975977
return items
976978
}
@@ -988,7 +990,7 @@ export async function excludeThirdPartyRepos(
988990
: item
989991
})
990992
)
991-
).filter((item) => item !== undefined) as CodeCatalyst.ListSourceRepositoriesItem[]
993+
).filter(isDefined)
992994
}
993995

994996
/**
@@ -1008,6 +1010,9 @@ export async function isThirdPartyRepo(
10081010
)
10091011
}
10101012

1013+
// These type guard wrappers are needed because type assertions fail
1014+
// to travel up function scope (see: https://github.com/microsoft/TypeScript/issues/9998)
1015+
10111016
function hasPersistentStorage<T extends DevEnvironmentSummary>(
10121017
s: T
10131018
): s is T & { persistentStorage: { sizeInGiB: number } } {
@@ -1019,3 +1024,11 @@ function hasRepositories<T extends DevEnvironmentSummary>(
10191024
): s is T & { repositories: RequiredProps<DevEnvironmentRepositorySummary, 'repositoryName'>[] } {
10201025
return hasProps(s, 'repositories') && s.repositories.every((r) => hasProps(r, 'repositoryName'))
10211026
}
1027+
1028+
function hasName<T extends { name: string | undefined }>(s: T): s is RequiredProps<T, 'name'> {
1029+
return hasProps(s, 'name')
1030+
}
1031+
1032+
function isValidEnvSummary(s: DevEnvironmentSummary): s is CodeCatalystDevEnvironmentSummary {
1033+
return hasProps(s, ...requiredDevEnvProps) && hasPersistentStorage(s) && hasRepositories(s)
1034+
}

packages/core/src/test/codecatalyst/codecatalystClient.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import assert from 'assert'
77
import sinon = require('sinon')
88
import { toCodeCatalystUrl } from '../../codecatalyst/utils'
99
import * as codecatalyst from '../../shared/clients/codecatalystClient'
10+
import { ListSourceRepositoriesItem } from '@aws-sdk/client-codecatalyst'
11+
import { RequiredProps } from '../../shared/utilities/tsUtils'
1012

1113
describe('codeCatalystClient', function () {
1214
it('toCodeCatalystUrl()', async function () {
@@ -66,7 +68,7 @@ describe('getFirstPartyRepos()', function () {
6668
{ name: 'code-catalyst-1' },
6769
{ name: 'not-code-catalyst-2' },
6870
{ name: 'code-catalyst-2' },
69-
])
71+
] as RequiredProps<ListSourceRepositoriesItem, 'name'>[])
7072

7173
assert.deepStrictEqual(allRepos, [{ name: 'code-catalyst-1' }, { name: 'code-catalyst-2' }])
7274
})
@@ -78,7 +80,7 @@ describe('getFirstPartyRepos()', function () {
7880
const allRepos = await codecatalyst.excludeThirdPartyRepos(codeCatalystClient, '', '', [
7981
{ name: 'aws-cdk' },
8082
{ name: 'vscode-toolkit' },
81-
])
83+
] as RequiredProps<ListSourceRepositoriesItem, 'name'>[])
8284

8385
assert.deepStrictEqual(allRepos, [])
8486
})

0 commit comments

Comments
 (0)