import type {
JsonRecord,
TrelloBoardSummary,
TrelloCardSummary,
TrelloCommentSummary,
TrelloLabelSummary,
TrelloListSummary,
TrelloMemberSummary,
TrelloOrganizationSummary,
} from './types.ts'
export const MEMBER_FIELDS = 'id,username,fullName,url,initials'
export const ORG_FIELDS = 'id,name,displayName,url'
export const BOARD_FIELDS = 'id,name,desc,closed,url,shortUrl,shortLink,idOrganization,dateLastActivity'
export const LIST_FIELDS = 'id,name,closed,idBoard,pos'
export const CARD_FIELDS =
'id,name,desc,closed,idList,idBoard,url,shortUrl,due,dueComplete,pos,labels,idMembers,dateLastActivity'
function asString(value: unknown): string | null {
return typeof value === 'string' ? value : null
}
function asBoolean(value: unknown): boolean | null {
return typeof value === 'boolean' ? value : null
}
function asNumber(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? value : null
}
export function memberSummary(
member: Record<string, unknown> | null | undefined,
): TrelloMemberSummary | null {
if (typeof member?.id !== 'string') return null
return {
id: member.id,
username: asString(member.username),
fullName: asString(member.fullName),
url: asString(member.url),
initials: asString(member.initials),
}
}
export function organizationSummary(
org: Record<string, unknown> | null | undefined,
): TrelloOrganizationSummary | null {
if (typeof org?.id !== 'string') return null
return {
id: org.id,
name: asString(org.name),
displayName: asString(org.displayName),
url: asString(org.url),
}
}
export function boardSummary(
board: Record<string, unknown> | null | undefined,
): TrelloBoardSummary | null {
if (typeof board?.id !== 'string' || typeof board.name !== 'string') return null
return {
id: board.id,
name: board.name,
desc: asString(board.desc),
closed: asBoolean(board.closed),
url: asString(board.url),
shortUrl: asString(board.shortUrl),
shortLink: asString(board.shortLink),
idOrganization: asString(board.idOrganization),
dateLastActivity: asString(board.dateLastActivity),
}
}
export function listSummary(
list: Record<string, unknown> | null | undefined,
): TrelloListSummary | null {
if (typeof list?.id !== 'string' || typeof list.name !== 'string') return null
return {
id: list.id,
name: list.name,
closed: asBoolean(list.closed),
idBoard: asString(list.idBoard),
pos: asNumber(list.pos),
}
}
export function labelSummary(
label: Record<string, unknown> | null | undefined,
): TrelloLabelSummary | null {
if (typeof label?.id !== 'string') return null
return {
id: label.id,
name: asString(label.name),
color: asString(label.color),
}
}
export function cardSummary(
card: Record<string, unknown> | null | undefined,
): TrelloCardSummary | null {
if (typeof card?.id !== 'string' || typeof card.name !== 'string') return null
const labels = Array.isArray(card.labels)
? card.labels
.map((item) => (item && typeof item === 'object' ? labelSummary(item as JsonRecord) : null))
.filter((item): item is TrelloLabelSummary => item !== null)
: []
const idMembers = Array.isArray(card.idMembers)
? card.idMembers.filter((item): item is string => typeof item === 'string')
: []
return {
id: card.id,
name: card.name,
desc: asString(card.desc),
closed: asBoolean(card.closed),
idList: asString(card.idList),
idBoard: asString(card.idBoard),
url: asString(card.url),
shortUrl: asString(card.shortUrl),
due: asString(card.due),
dueComplete: asBoolean(card.dueComplete),
pos: asNumber(card.pos),
idMembers,
labels,
dateLastActivity: asString(card.dateLastActivity),
}
}
export function commentSummary(
action: Record<string, unknown> | null | undefined,
): TrelloCommentSummary | null {
if (typeof action?.id !== 'string') return null
const data = action.data && typeof action.data === 'object' ? (action.data as JsonRecord) : {}
const card =
data.card && typeof data.card === 'object' ? (data.card as { id?: unknown }) : null
const creator =
action.memberCreator && typeof action.memberCreator === 'object'
? memberSummary(action.memberCreator as JsonRecord)
: null
return {
id: action.id,
text: asString(data.text),
date: asString(action.date),
cardId: typeof card?.id === 'string' ? card.id : null,
memberCreator: creator,
}
}
export function requireMapped<T>(
value: T | null,
action: string,
): T {
if (!value) throw new Error(`${action}: Trello returned no matching record.`)
return value
}
export function mapMany<T>(
items: unknown,
mapper: (item: Record<string, unknown>) => T | null,
): Array<T> {
if (!Array.isArray(items)) return []
return items
.filter((item): item is Record<string, unknown> => Boolean(item && typeof item === 'object'))
.map(mapper)
.filter((item): item is T => item !== null)
}