2024-12-04 14:17:00 +01:00

146 lines
5.3 KiB
TypeScript

import { NDKEvent } from '@nostr-dev-kit/ndk'
import { Event } from 'nostr-tools'
import { ModDetails, ModFormState } from '../types'
import { getTagValue, getTagValues } from './nostr'
/**
* Extracts and normalizes mod data from an event.
*
* This function extracts specific tag values from an event and maps them to properties
* of a `PageData` object. It handles default values and type conversions as needed.
*
* @param event - The event object from which to extract data.
* @returns A `Partial<PageData>` object containing extracted data.
*/
export const extractModData = (event: Event | NDKEvent): ModDetails => {
// Helper function to safely get the first value of a tag or return a default value
const getFirstTagValue = (tagIdentifier: string, defaultValue = '') => {
const tagValue = getTagValue(event, tagIdentifier)
return tagValue ? tagValue[0] : defaultValue
}
// Helper function to safely parse integer values from tags
const getIntTagValue = (tagIdentifier: string, defaultValue: number = -1) => {
const tagValue = getTagValue(event, tagIdentifier)
return tagValue ? parseInt(tagValue[0], 10) : defaultValue
}
return {
id: event.id,
dTag: getFirstTagValue('d'),
aTag: getFirstTagValue('a'),
rTag: getFirstTagValue('r'),
author: event.pubkey,
edited_at: event.created_at!,
body: event.content,
published_at: getIntTagValue('published_at'),
game: getFirstTagValue('game'),
title: getFirstTagValue('title'),
featuredImageUrl: getFirstTagValue('featuredImageUrl'),
summary: getFirstTagValue('summary'),
nsfw: getFirstTagValue('nsfw') === 'true',
repost: getFirstTagValue('repost') === 'true',
originalAuthor: getFirstTagValue('originalAuthor'),
screenshotsUrls: getTagValue(event, 'screenshotsUrls') || [],
tags: getTagValue(event, 'tags') || [],
LTags: (getTagValues(event, 'L') || []).map((t) =>
t.replace('com.degmods:', '')
),
lTags: (getTagValues(event, 'l') || []).map((t) =>
t.replace('com.degmods:', '')
),
downloadUrls: (getTagValue(event, 'downloadUrls') || []).map((item) =>
JSON.parse(item)
)
}
}
/**
* Constructs a list of `ModDetails` objects from an array of events.
*
* This function filters out events that do not contain all required data,
* extracts the necessary information from the valid events, and constructs
* `ModDetails` objects.
*
* @param events - The array of event objects to be processed.
* @returns An array of `ModDetails` objects constructed from valid events.
*/
export const constructModListFromEvents = (
events: Event[] | NDKEvent[]
): ModDetails[] => {
// Filter and extract mod details from events
const modDetailsList: ModDetails[] = events
.filter(isModDataComplete) // Filter out incomplete events
.map((event) => extractModData(event)) // Extract data and construct ModDetails
return modDetailsList
}
/**
* Checks if the provided event contains all the required data for constructing a `ModDetails` object.
*
* This function verifies that the event has the necessary tags and values to construct a `ModDetails` object.
*
* @param event - The event object to be checked.
* @returns `true` if the event contains all required data; `false` otherwise.
*/
export const isModDataComplete = (event: Event | NDKEvent): boolean => {
// Helper function to check if a tag value is present and not empty
const hasTagValue = (tagIdentifier: string): boolean => {
const value = getTagValue(event, tagIdentifier)
return !!value && value.length > 0 && value[0].trim() !== ''
}
// Check if all required fields are present
return (
hasTagValue('d') &&
hasTagValue('a') &&
hasTagValue('t') &&
hasTagValue('published_at') &&
hasTagValue('game') &&
hasTagValue('title') &&
hasTagValue('featuredImageUrl') &&
hasTagValue('summary') &&
hasTagValue('nsfw') &&
getTagValue(event, 'screenshotsUrls') !== null &&
getTagValue(event, 'tags') !== null &&
getTagValue(event, 'downloadUrls') !== null
)
}
/**
* Initializes the form state with values from existing mod data or defaults.
*
* @param existingModData - An optional object containing existing mod details. If provided, its values will be used to populate the form state.
* @returns The initial state for the form, with values from existingModData if available, otherwise default values.
*/
export const initializeFormState = (
existingModData?: ModDetails
): ModFormState => ({
dTag: existingModData?.dTag || '',
aTag: existingModData?.aTag || '',
rTag: existingModData?.rTag || window.location.host,
game: existingModData?.game || '',
title: existingModData?.title || '',
body: existingModData?.body || '',
featuredImageUrl: existingModData?.featuredImageUrl || '',
summary: existingModData?.summary || '',
nsfw: existingModData?.nsfw || false,
repost: existingModData?.repost || false,
originalAuthor: existingModData?.originalAuthor || undefined,
screenshotsUrls: existingModData?.screenshotsUrls || [''],
tags: existingModData?.tags.join(',') || '',
lTags: existingModData?.lTags || [],
LTags: existingModData?.LTags || [],
downloadUrls: existingModData?.downloadUrls || [
{
url: '',
hash: '',
signatureKey: '',
malwareScanLink: '',
modVersion: '',
customNote: ''
}
]
})