in apps-rendering/src/atoms.ts [28:366]
function parseAtom(
element: BlockElement,
atoms: Atoms,
docParser: DocParser,
): Result<string, BodyElement> {
if (element.contentAtomTypeData === undefined) {
return Result.err('The atom has no data');
}
const id = element.contentAtomTypeData.atomId;
if (id === 'interactives/2022/10/tr/default-about-the-series') {
return Result.ok({ kind: ElementKind.SpecialReportAltAtom });
}
switch (element.contentAtomTypeData.atomType) {
case 'interactive': {
const atom = atoms.interactives?.find(
(interactive) => interactive.id === id,
);
if (atom?.data.kind !== 'interactive') {
return Result.err(`No atom matched this id: ${id}`);
}
const { html, css, mainJS: js } = atom.data.interactive;
if (!html && !css && !js) {
return Result.err(`No content for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.InteractiveAtom,
html,
css,
js: fromNullable(js),
});
}
case 'guide': {
const atom = atoms.guides?.find((guide) => guide.id === id);
if (atom?.data.kind !== 'guide' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title } = atom;
const image = atom.data.guide.guideImage?.master?.file;
const credit = atom.data.guide.guideImage?.master?.credit;
const { body } = atom.data.guide.items[0];
if (!title || !body) {
return Result.err(`No title or body for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.GuideAtom,
html: body,
title,
id,
image,
credit,
});
}
case 'qanda': {
const atom = atoms.qandas?.find((qanda) => qanda.id === id);
if (atom?.data.kind !== 'qanda' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title } = atom;
const { body } = atom.data.qanda.item;
const image = atom.data.qanda.eventImage?.master?.file;
const credit = atom.data.qanda.eventImage?.master?.credit;
if (!title || !body) {
return Result.err(`No title or body for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.QandaAtom,
html: body,
title,
id,
image,
credit,
});
}
case 'profile': {
const atom = atoms.profiles?.find((profile) => profile.id === id);
if (atom?.data.kind !== 'profile' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title } = atom;
const { body } = atom.data.profile.items[0];
const image = atom.data.profile.headshot?.master?.file;
const credit = atom.data.profile.headshot?.master?.credit;
if (!title || !body) {
return Result.err(`No title or body for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.ProfileAtom,
html: body,
title,
id,
image,
credit,
});
}
case 'chart': {
const atom = atoms.charts?.find((chart) => chart.id === id);
if (atom?.data.kind !== 'chart' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title, defaultHtml } = atom;
if (!title || !defaultHtml) {
return Result.err(`No title or defaultHtml for atom: ${id}`);
}
const doc = docParser(defaultHtml);
const styles = Array.from(doc.querySelectorAll('style')).map(
(style) => style.innerHTML,
);
const inlineStyles = Array.from(
doc.querySelectorAll('[style]'),
).map((element) => (element as HTMLElement).style.cssText);
const js = Array.from(doc.querySelectorAll('script')).map(
(script) => script.innerHTML,
);
return Result.ok({
kind: ElementKind.ChartAtom,
title,
id,
html: defaultHtml + `<script>${atomScript}</script>`,
css: [...styles, ...inlineStyles],
js,
});
}
case 'timeline': {
const atom = atoms.timelines?.find(
(timeline) => timeline.id === id,
);
if (atom?.data.kind !== 'timeline' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title } = atom;
const events: TimelineEvent[] = atom.data.timeline.events.map(
(event) => ({
title: event.title,
date: formatOptionalDate(event.date) ?? '',
body: event.body,
toDate: formatOptionalDate(event.toDate),
unixDate: event.date.toNumber(),
}),
);
const description = atom.data.timeline.description;
if (!title) {
return Result.err(`No title for atom: ${id}`);
}
if (events.some((event) => event.date === '')) {
return Result.err('Invalid date in timeline atom');
}
return Result.ok({
kind: ElementKind.TimelineAtom,
title,
id,
events,
description,
});
}
case 'explainer': {
const atom = atoms.explainers?.find(
(explainer) => explainer.id === id,
);
if (atom?.data.kind !== 'explainer' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { title, body } = atom.data.explainer;
if (!title || !body) {
return Result.err(`No title or body for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.ExplainerAtom,
html: body,
title,
id,
});
}
case 'media': {
const atom = atoms.media?.find((media) => media.id === id);
if (atom?.data.kind !== 'media') {
return Result.err(`No atom matched this id: ${id}`);
}
const { posterUrl, duration, assets, activeVersion, title } =
atom.data.media;
const videoId = assets.find(
(asset) =>
asset.version.toNumber() === activeVersion?.toNumber(),
)?.id;
const caption = docParser(title);
if (!posterUrl) {
return Result.err(`No posterUrl for atom: ${id}`);
}
if (!videoId) {
return Result.err(`No videoId for atom: ${id}`);
}
return Result.ok({
kind: ElementKind.MediaAtom,
id,
posterUrl,
videoId,
title,
duration: fromNullable(duration?.toNumber()),
caption: fromNullable(caption),
});
}
case 'audio': {
const atom = atoms.audios?.find((audio) => audio.id === id);
if (atom?.data.kind !== 'audio') {
return Result.err(`No atom matched this id: ${id}`);
}
const { id: audioId, title } = atom;
const { kicker, trackUrl } = atom.data.audio;
if (!title) {
return Result.err(
`No title for audio atom with id: ${audioId}`,
);
}
return Result.ok({
kind: ElementKind.AudioAtom,
id: audioId,
trackUrl,
kicker,
title,
});
}
case 'quiz': {
const atom = atoms.quizzes?.find((quiz) => quiz.id === id);
if (atom?.data.kind !== 'quiz' || !id) {
return Result.err(`No atom matched this id: ${id}`);
}
const { content } = atom.data.quiz;
if (content.questions.length === 0) {
return Result.err(`No content for atom: ${id}`);
}
const questions = content.questions.map((question) => {
return {
text: question.questionText,
...question,
/* TODO: imageUrl & imageAlt should be set here,
by parsing question.assets[x].data */
answers: question.answers.map((answer) => {
return {
id: answer.id,
text: answer.answerText,
isCorrect: !!answer.weight,
answerBuckets: answer.bucket ?? [],
};
}),
};
});
if (atom.data.quiz.quizType === 'knowledge') {
return Result.ok({
kind: ElementKind.KnowledgeQuizAtom,
id,
questions,
resultGroups:
atom.data.quiz.content.resultGroups?.groups.map(
(group) => ({
...group,
shareText: group.share,
}),
) ?? [],
});
}
if (atom.data.quiz.quizType === 'personality') {
return Result.ok({
kind: ElementKind.PersonalityQuizAtom,
id,
questions,
resultBuckets:
atom.data.quiz.content.resultBuckets?.buckets ?? [],
});
}
return Result.err(
`Atom quizType '${atom.data.quiz.quizType}' is not supported.`,
);
}
default: {
return Result.err(
`Atom type not supported: ${element.contentAtomTypeData.atomType}`,
);
}
}
}