You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.9 KiB
121 lines
3.9 KiB
import { NormalizedOmdbData } from '../types';
|
|
import { RawOmdbData } from './types';
|
|
|
|
const identity = <T>(value: T) => value;
|
|
const stringToArray = (value: string) => value.split(', ');
|
|
const stringToNumber = (value: string) => parseInt(value, 10);
|
|
const stringToDuration = (value: string) => {
|
|
const match = /^(?<time>\d+)\smin$/.exec(value);
|
|
if (!match) {
|
|
throw new Error(`Cannot parse duration: "${value}"`);
|
|
}
|
|
|
|
// Both `groups` and `groups['time']` are guaranteed to be defined because of regex definition, but TS doesn't know that.
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
return stringToNumber(match.groups!['time']!);
|
|
};
|
|
const omdbRatingsToNormalizedRatings = (ratings: RawOmdbData['Ratings']) =>
|
|
ratings.map(({ Source, Value }) => ({ source: Source, value: Value }));
|
|
|
|
const createRequiredField = <TKey extends keyof NormalizedOmdbData, TRawValue>(
|
|
key: TKey,
|
|
value: TRawValue,
|
|
transformer: (value: TRawValue) => NormalizedOmdbData[TKey],
|
|
) => {
|
|
if (value === undefined) {
|
|
throw new Error(`Value for ${key} is not defined`);
|
|
}
|
|
|
|
if (value === 'N/A') {
|
|
throw new Error(`Value for ${key} is "N/A"`);
|
|
}
|
|
|
|
return {
|
|
[key]: transformer(value),
|
|
} as Record<TKey, NormalizedOmdbData[TKey]>;
|
|
};
|
|
|
|
const createOptionalField = <TKey extends keyof NormalizedOmdbData, TRawValue>(
|
|
key: TKey,
|
|
value: TRawValue,
|
|
transformer: (
|
|
value: Exclude<TRawValue, undefined>,
|
|
) => NormalizedOmdbData[TKey],
|
|
) => {
|
|
if (value === undefined || value === 'N/A') {
|
|
return undefined;
|
|
}
|
|
|
|
return createRequiredField(
|
|
key,
|
|
value as Exclude<TRawValue, undefined>,
|
|
transformer,
|
|
);
|
|
};
|
|
|
|
export const normalizeRawOmdbData = (
|
|
rawOmdbData: RawOmdbData,
|
|
): NormalizedOmdbData => {
|
|
const {
|
|
Actors,
|
|
Awards,
|
|
BoxOffice,
|
|
Country,
|
|
DVD,
|
|
Director,
|
|
Genre,
|
|
Language: _language,
|
|
Metascore: _metascore,
|
|
Plot,
|
|
Poster,
|
|
Production: _production,
|
|
Rated,
|
|
Ratings,
|
|
Released,
|
|
Runtime,
|
|
Title,
|
|
Type,
|
|
Website,
|
|
Writer,
|
|
Year,
|
|
imdbID,
|
|
imdbRating: _imdbRating,
|
|
imdbVotes: _imdbVotes,
|
|
totalSeasons,
|
|
...rest
|
|
} = rawOmdbData;
|
|
|
|
const restKeys = Object.keys(rest);
|
|
if (restKeys.length) {
|
|
throw new Error(
|
|
`Unexpected fields in OMDB response: ${restKeys.join(', ')}`,
|
|
);
|
|
}
|
|
|
|
return {
|
|
...createRequiredField('actors', Actors, stringToArray),
|
|
...createRequiredField('awards', Awards, identity),
|
|
...createOptionalField('boxOffice', BoxOffice, identity),
|
|
...createOptionalField('contentRating', Rated, identity),
|
|
...createRequiredField('description', Plot, identity),
|
|
...createOptionalField('directors', Director, stringToArray),
|
|
...createRequiredField('duration', Runtime, stringToDuration),
|
|
...createOptionalField('dvdReleaseDate', DVD, identity),
|
|
...createRequiredField('genres', Genre, stringToArray),
|
|
...createRequiredField('imdbId', imdbID, identity),
|
|
...createRequiredField('posterUrl', Poster, identity),
|
|
...createRequiredField('productionCountries', Country, stringToArray),
|
|
...createRequiredField('productionYear', Year, stringToNumber),
|
|
...createRequiredField(
|
|
'ratings',
|
|
Ratings,
|
|
omdbRatingsToNormalizedRatings,
|
|
),
|
|
...createRequiredField('releaseDate', Released, identity),
|
|
...createRequiredField('title', Title, identity),
|
|
...createOptionalField('totalSeasons', totalSeasons, stringToNumber),
|
|
...createRequiredField('type', Type, identity),
|
|
...createOptionalField('website', Website, identity),
|
|
...createRequiredField('writers', Writer, stringToArray),
|
|
};
|
|
};
|
|
|