Typescript updated to 5.0, removed pesky as const

This commit is contained in:
DrMint 2023-03-18 23:43:55 +01:00
parent bfb753bf21
commit b6882cd1e5
30 changed files with 312 additions and 342 deletions

30
package-lock.json generated
View File

@ -59,13 +59,13 @@
"eslint-config-next": "13.2.4",
"eslint-plugin-import": "^2.27.5",
"graphql": "^16.6.0",
"graphql-request": "5.2.0",
"graphql-request": "5.1.0",
"next-sitemap": "^4.0.6",
"prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.5",
"tailwindcss": "^3.2.7",
"ts-unused-exports": "^9.0.4",
"typescript": "^4.9.5"
"typescript": "^5.0.2"
}
},
"node_modules/@ampproject/remapping": {
@ -6797,9 +6797,9 @@
"dev": true
},
"node_modules/graphql-request": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz",
"integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz",
"integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==",
"dev": true,
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
@ -10261,16 +10261,16 @@
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
"node": ">=12.20"
}
},
"node_modules/ua-parser-js": {
@ -16008,9 +16008,9 @@
}
},
"graphql-request": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.2.0.tgz",
"integrity": "sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-5.1.0.tgz",
"integrity": "sha512-0OeRVYigVwIiXhNmqnPDt+JhMzsjinxHE7TVy3Lm6jUzav0guVcL0lfSbi6jVTRAxcbwgyr6yrZioSHxf9gHzw==",
"dev": true,
"requires": {
"@graphql-typed-document-node/core": "^3.1.1",
@ -18487,9 +18487,9 @@
}
},
"typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true
},
"ua-parser-js": {

View File

@ -71,13 +71,13 @@
"eslint-config-next": "13.2.4",
"eslint-plugin-import": "^2.27.5",
"graphql": "^16.6.0",
"graphql-request": "5.2.0",
"graphql-request": "5.1.0",
"next-sitemap": "^4.0.6",
"prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.5",
"tailwindcss": "^3.2.7",
"ts-unused-exports": "^9.0.4",
"typescript": "^4.9.5"
"typescript": "^5.0.2"
},
"overrides": {
"react-zoom-pan-pinch": {

View File

@ -45,10 +45,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
<div
className="grid gap-4 overflow-hidden transition-height duration-500"
style={{ maxHeight: isOpen ? `${8 * chronicles.length}rem` : 0 }}>
{filterHasAttributes(chronicles, [
"attributes.contents",
"attributes.translations",
] as const)
{filterHasAttributes(chronicles, ["attributes.contents", "attributes.translations"])
.sort((a, b) => compareDate(a.attributes.date_start, b.attributes.date_start))
.map((chronicle) => (
<div key={chronicle.id} id={`chronicle-${chronicle.attributes.slug}`}>
@ -56,14 +53,14 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
chronicle.attributes.contents.data.length === 1
? filterHasAttributes(chronicle.attributes.contents.data, [
"attributes.translations",
] as const).map((content, index) => (
]).map((content, index) => (
<TranslatedChroniclePreview
key={index}
active={chronicle.attributes.slug === currentSlug}
date={chronicle.attributes.date_start}
translations={filterHasAttributes(content.attributes.translations, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
title: prettyInlineTitle(
translation.pre_title,
translation.title,
@ -90,7 +87,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element
translations={filterHasAttributes(chronicle.attributes.translations, [
"language.data.attributes.code",
"title",
] as const).map((translation) => ({
]).map((translation) => ({
title: translation.title,
language: translation.language.data.attributes.code,
}))}

View File

@ -223,7 +223,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.descriptions, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
language: translation.language.data.attributes.code,
title: item.title,
subtitle: item.subtitle,
@ -270,7 +270,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
]).map(({ displayable_description, language, ...otherAttributes }) => ({
...otherAttributes,
description: containsHighlight(displayable_description)
? displayable_description
@ -315,7 +315,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(
]).map(
({
aliases,
summary,
@ -340,12 +340,12 @@ export const SearchPopup = (): JSX.Element => {
thumbnailRounded
thumbnailForceAspectRatio
keepInfoVisible
topChips={filterHasAttributes(item.tags?.data, ["attributes"] as const).map(
topChips={filterHasAttributes(item.tags?.data, ["attributes"]).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
)}
bottomChips={filterHasAttributes(item.categories?.data, [
"attributes",
] as const).map((category) => category.attributes.short)}
bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map(
(category) => category.attributes.short
)}
/>
))}
</div>
@ -367,7 +367,7 @@ export const SearchPopup = (): JSX.Element => {
onClick={() => setSearchOpened(false)}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({
]).map(({ excerpt, body, language, ...otherAttributes }) => ({
...otherAttributes,
description: containsHighlight(excerpt)
? excerpt
@ -449,14 +449,12 @@ export const SearchPopup = (): JSX.Element => {
href={"/"}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(
({ description, language, names: [primaryName, ...aliases] }) => ({
]).map(({ description, language, names: [primaryName, ...aliases] }) => ({
language: language.data.attributes.code,
title: primaryName,
subtitle: aliases.join("・"),
description: containsHighlight(description) ? description : undefined,
})
)}
}))}
fallback={{ title: prettySlug(item.slug) }}
thumbnail={item.thumbnail?.data?.attributes}
thumbnailAspectRatio="1/1"
@ -468,9 +466,9 @@ export const SearchPopup = (): JSX.Element => {
? [prettySlug(item.type.data.attributes.slug)]
: undefined
}
bottomChips={filterHasAttributes(item.categories, [
"attributes.short",
] as const).map((category) => category.attributes.short)}
bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map(
(category) => category.attributes.short
)}
/>
))}
</div>

View File

@ -41,7 +41,7 @@ export const SettingsPopup = (): JSX.Element => {
const router = useRouter();
const currencyOptions = filterHasAttributes(currencies, ["attributes"] as const).map(
const currencyOptions = filterHasAttributes(currencies, ["attributes"]).map(
(currentCurrency) => currentCurrency.attributes.code
);

View File

@ -94,13 +94,11 @@ export const PostPage = ({
<div>
<p className="font-headers font-bold">{"Authors"}:</p>
<div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(post.authors.data, ["id", "attributes"] as const).map(
(author) => (
{filterHasAttributes(post.authors.data, ["id", "attributes"]).map((author) => (
<Fragment key={author.id}>
<RecorderChip recorder={author.attributes} />
</Fragment>
)
)}
))}
</div>
</div>
)}

View File

@ -40,13 +40,11 @@ export const RecorderChip = ({ recorder }: Props): JSX.Element => {
{recorder.languages?.data && recorder.languages.data.length > 0 && (
<div className="flex flex-row flex-wrap gap-1">
<p>{format("language", { count: recorder.languages.data.length })}:</p>
{filterHasAttributes(recorder.languages.data, ["attributes"] as const).map(
(language) => (
{filterHasAttributes(recorder.languages.data, ["attributes"]).map((language) => (
<Fragment key={language.__typename}>
<Chip text={language.attributes.code.toUpperCase()} />
</Fragment>
)
)}
))}
</div>
)}
{recorder.pronouns && (

View File

@ -88,11 +88,9 @@ export const ThumbnailHeader = ({
<div className="flex flex-col place-items-center gap-2">
<h3 className="text-xl">{format("category", { count: categories.data.length })}</h3>
<div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(categories.data, ["attributes", "id"] as const).map(
(category) => (
{filterHasAttributes(categories.data, ["attributes", "id"]).map((category) => (
<Chip key={category.id} text={category.attributes.name} />
)
)}
))}
</div>
</div>
)}

View File

@ -41,7 +41,7 @@ export const getPostStaticProps =
[format("release_date")]: [prettyDate(post.posts.data[0].attributes.date, context.locale)],
[format("category", { count: Infinity })]: filterHasAttributes(
post.posts.data[0].attributes.categories?.data,
["attributes"] as const
["attributes"]
).map((category) => category.attributes.short),
});

View File

@ -2,12 +2,18 @@
import { createWriteStream } from "fs";
import { parse, TYPE } from "@formatjs/icu-messageformat-parser";
import { getLangui } from "./fetchLocalData";
import { filterDefined } from "helpers/asserts";
import { getLogger } from "helpers/logger";
const OUTPUT_FOLDER = `${process.cwd()}/src/graphql`;
const logger = getLogger("💽 [ICU to TS]", "server");
const isDefined = <T>(t: T): t is NonNullable<T> => t !== null && t !== undefined;
const isUndefined = <T>(t: T | null | undefined): t is null | undefined => !isDefined(t);
const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] =>
isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable<T>[]);
const icuToTypescript = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { ui_language, ...langui } = getLangui("en");

View File

@ -48,7 +48,7 @@ export const isDefinedAndNotEmpty = (string: string | null | undefined): string
export const filterDefined = <T>(t: T[] | null | undefined): NonNullable<T>[] =>
isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable<T>[]);
export const filterHasAttributes = <T, P extends PathDot<T>>(
export const filterHasAttributes = <T, const P extends PathDot<T>>(
t: T[] | null | undefined,
paths: readonly P[]
): SelectiveNonNullable<T, (typeof paths)[number]>[] =>
@ -77,3 +77,5 @@ const hasAttribute = <T>(item: T, path: string): boolean => {
}
return false;
};

View File

@ -201,7 +201,7 @@ const Revalidate = async (
});
filterHasAttributes(libraryItem.libraryItems?.data[0]?.attributes?.subitem_of?.data, [
"attributes.slug",
] as const).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`));
]).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`));
}
break;
@ -227,7 +227,7 @@ const Revalidate = async (
filterHasAttributes(content.contents?.data[0]?.attributes?.ranged_contents?.data, [
"attributes.library_item.data.attributes.slug",
] as const).forEach((ranged_content) => {
]).forEach((ranged_content) => {
const parentSlug = ranged_content.attributes.library_item.data.attributes.slug;
paths.push(`/library/${parentSlug}`);
paths.push(`/library/${parentSlug}/reader`);
@ -285,12 +285,10 @@ const Revalidate = async (
}
filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.subfolders?.data, [
"attributes.slug",
] as const).forEach((subfolder) =>
paths.push(`/contents/folder/${subfolder.attributes.slug}`)
);
]).forEach((subfolder) => paths.push(`/contents/folder/${subfolder.attributes.slug}`));
filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.contents?.data, [
"attributes.slug",
] as const).forEach((content) => paths.push(`/contents/${content.attributes.slug}`));
]).forEach((content) => paths.push(`/contents/${content.attributes.slug}`));
}
break;
}
@ -339,7 +337,7 @@ const Revalidate = async (
});
filterHasAttributes(group.weaponStoryGroup?.data?.attributes?.weapons?.data, [
"attributes.slug",
] as const).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`));
]).forEach((weapon) => paths.push(`/wiki/weapons/${weapon.attributes.slug}`));
break;
}

View File

@ -300,7 +300,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const paths: GetStaticPathsResult["paths"] = [];
if (channels.videoChannels?.data)
filterHasAttributes(channels.videoChannels.data, ["attributes"] as const).map((channel) => {
filterHasAttributes(channels.videoChannels.data, ["attributes"]).map((channel) => {
context.locales?.map((local) => {
paths.push({
params: { uid: channel.attributes.uid },

View File

@ -168,7 +168,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const videos = await sdk.getVideosSlugs();
const paths: GetStaticPathsResult["paths"] = [];
if (videos.videos?.data)
filterHasAttributes(videos.videos.data, ["attributes"] as const).map((video) => {
filterHasAttributes(videos.videos.data, ["attributes"]).map((video) => {
context.locales?.map((local) => {
paths.push({ params: { uid: video.attributes.uid }, locale: local });
});

View File

@ -47,8 +47,7 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
});
const primaryContent = chronicle.contents
? filterHasAttributes(chronicle.contents.data, ["attributes.translations"] as const)[0]
?.attributes
? filterHasAttributes(chronicle.contents.data, ["attributes.translations"])[0]?.attributes
: undefined;
const [selectedContentTranslation, ContentLanguageSwitcher, ContentLanguageSwitcherProps] =
@ -128,13 +127,13 @@ const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element =
<HorizontalLine />
<div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => (
{filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => (
<TranslatedChroniclesList
key={chapter.id}
chronicles={chapter.attributes.chronicles.data}
translations={filterHasAttributes(chapter.attributes.titles, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
title: translation.title,
language: translation.language.data.attributes.code,
}))}
@ -201,7 +200,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
[format("category", { count: Infinity })]: filterHasAttributes(
chronicle.chronicles.data[0].attributes.contents.data[0].attributes.categories
?.data,
["attributes"] as const
["attributes"]
).map((category) => category.attributes.short),
}),
};
@ -248,7 +247,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const contents = await sdk.getChroniclesSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.chronicles?.data, ["attributes"] as const).map((wikiPage) => {
filterHasAttributes(contents.chronicles?.data, ["attributes"]).map((wikiPage) => {
context.locales?.map((local) =>
paths.push({
params: { slug: wikiPage.attributes.slug },

View File

@ -34,13 +34,13 @@ const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => {
<HorizontalLine />
<div className="grid gap-16">
{filterHasAttributes(chapters, ["attributes.chronicles", "id"] as const).map((chapter) => (
{filterHasAttributes(chapters, ["attributes.chronicles", "id"]).map((chapter) => (
<TranslatedChroniclesList
key={chapter.id}
chronicles={chapter.attributes.chronicles.data}
translations={filterHasAttributes(chapter.attributes.titles, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
title: translation.title,
language: translation.language.data.attributes.code,
}))}

View File

@ -80,7 +80,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
translations: filterHasAttributes(content.folder?.data?.attributes?.titles, [
"language.data.attributes.code",
] as const).map((title) => ({
]).map((title) => ({
language: title.language.data.attributes.code,
title: title.title,
})),
@ -146,7 +146,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.transcribers.data, [
"attributes",
"id",
] as const).map((recorder) => (
]).map((recorder) => (
<Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} />
</Fragment>
@ -163,7 +163,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.translators.data, [
"attributes",
"id",
] as const).map((recorder) => (
]).map((recorder) => (
<Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} />
</Fragment>
@ -180,7 +180,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(selectedTranslation.text_set.proofreaders.data, [
"attributes",
"id",
] as const).map((recorder) => (
]).map((recorder) => (
<Fragment key={recorder.id}>
<RecorderChip recorder={recorder.attributes} />
</Fragment>
@ -209,7 +209,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
{filterHasAttributes(content.ranged_contents.data, [
"attributes.library_item.data.attributes",
"attributes.library_item.data.id",
] as const).map((rangedContent) => {
]).map((rangedContent) => {
const libraryItem = rangedContent.attributes.library_item.data;
return (
<div
@ -231,7 +231,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
}
bottomChips={filterHasAttributes(libraryItem.attributes.categories?.data, [
"attributes",
] as const).map((category) => category.attributes.short)}
]).map((category) => category.attributes.short)}
metadata={{
releaseDate: libraryItem.attributes.release_date,
price: libraryItem.attributes.price,
@ -288,7 +288,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
href={`/contents/${previousContent.attributes.slug}`}
translations={filterHasAttributes(previousContent.attributes.translations, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
pre_title: translation.pre_title,
title: translation.title,
subtitle: translation.subtitle,
@ -329,7 +329,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => {
href={`/contents/${nextContent.attributes.slug}`}
translations={filterHasAttributes(nextContent.attributes.translations, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
pre_title: translation.pre_title,
title: translation.title,
subtitle: translation.subtitle,
@ -404,7 +404,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
],
[format("category", { count: Infinity })]: filterHasAttributes(
content.contents.data[0].attributes.categories?.data,
["attributes"] as const
["attributes"]
).map((category) => category.attributes.short),
}),
};
@ -437,7 +437,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const contents = await sdk.getContentsSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(contents.contents?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => {
paths.push({
params: { slug: item.attributes.slug },

View File

@ -220,7 +220,7 @@ const Contents = (props: Props): JSX.Element => {
href={`/contents/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
]).map(({ displayable_description, language, ...otherAttributes }) => ({
...otherAttributes,
description: containsHighlight(displayable_description)
? displayable_description

View File

@ -69,7 +69,7 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
href={`/contents/folder/${folder.parent_folder.data.attributes.slug}`}
translations={filterHasAttributes(folder.parent_folder.data.attributes.titles, [
"language.data.attributes.code",
] as const).map((title) => ({
]).map((title) => ({
language: title.language.data.attributes.code,
text: title.title,
}))}
@ -86,12 +86,12 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
<Button href="/contents" icon="home" active />
) : (
<TranslatedButton
translations={filterHasAttributes(folder.titles, [
"language.data.attributes.code",
] as const).map((title) => ({
translations={filterHasAttributes(folder.titles, ["language.data.attributes.code"]).map(
(title) => ({
language: title.language.data.attributes.code,
text: title.title,
}))}
})
)}
fallback={{
text: prettySlug(folder.slug),
}}
@ -115,21 +115,19 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
"grid-cols-2 gap-4"
)
)}>
{filterHasAttributes(folder.subfolders.data, ["id", "attributes"] as const).map(
(subfolder) => (
{filterHasAttributes(folder.subfolders.data, ["id", "attributes"]).map((subfolder) => (
<TranslatedPreviewFolder
key={subfolder.id}
href={`/contents/folder/${subfolder.attributes.slug}`}
translations={filterHasAttributes(subfolder.attributes.titles, [
"language.data.attributes.code",
] as const).map((title) => ({
]).map((title) => ({
title: title.title,
language: title.language.data.attributes.code,
}))}
fallback={{ title: prettySlug(subfolder.attributes.slug) }}
/>
)
)}
))}
</div>
</div>
)}
@ -149,14 +147,13 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
"grid-cols-2 gap-4"
)
)}>
{filterHasAttributes(folder.contents.data, ["id", "attributes"] as const).map(
(item) => (
{filterHasAttributes(folder.contents.data, ["id", "attributes"]).map((item) => (
<TranslatedPreviewCard
key={item.id}
href={`/contents/${item.attributes.slug}`}
translations={filterHasAttributes(item.attributes.translations, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
pre_title: translation.pre_title,
title: translation.title,
subtitle: translation.subtitle,
@ -180,8 +177,7 @@ const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Elemen
)}
keepInfoVisible
/>
)
)}
))}
</div>
</div>
)}
@ -262,7 +258,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const contents = await sdk.getContentsFoldersSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.contentsFolders?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(contents.contentsFolders?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => {
paths.push({
params: { slug: item.attributes.slug },

View File

@ -105,7 +105,7 @@ const testingContent = (contents: Props["contents"]): Report => {
lines: [],
};
filterHasAttributes(contents.contents?.data, ["attributes"] as const).map((content) => {
filterHasAttributes(contents.contents?.data, ["attributes"]).map((content) => {
const backendUrl = sJoin(
process.env.NEXT_PUBLIC_URL_CMS,
"/admin/content-manager/collectionType/api::content.content/",

View File

@ -230,7 +230,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
{item.urls?.length ? (
<div className="flex flex-row place-items-center gap-3">
<p>{format("available_at")}</p>
{filterHasAttributes(item.urls, ["url"] as const).map((url, index) => (
{filterHasAttributes(item.urls, ["url"]).map((url, index) => (
<Fragment key={index}>
<Button href={url.url} text={prettyURL(url.url)} alwaysNewTab />
</Fragment>
@ -250,7 +250,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
<div
className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end
gap-8">
{filterHasAttributes(item.gallery.data, ["id", "attributes"] as const).map(
{filterHasAttributes(item.gallery.data, ["id", "attributes"]).map(
(galleryItem, index) => (
<Fragment key={galleryItem.id}>
<div
@ -258,7 +258,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
transition-transform hover:scale-102"
onClick={() => {
showLightBox(
filterHasAttributes(item.gallery?.data, ["attributes"] as const).map(
filterHasAttributes(item.gallery?.data, ["attributes"]).map(
(image) => image.attributes
),
index
@ -329,11 +329,9 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
{format("category", { count: item.categories.data.length })}
</h3>
<div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(item.categories.data, ["attributes"] as const).map(
(category) => (
{filterHasAttributes(item.categories.data, ["attributes"]).map((category) => (
<Chip key={category.id} text={category.attributes.name} />
)
)}
))}
</div>
</div>
)}
@ -482,8 +480,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
<div
className="grid w-full grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]
items-end gap-8">
{filterHasAttributes(item.subitems.data, ["id", "attributes"] as const).map(
(subitem) => (
{filterHasAttributes(item.subitems.data, ["id", "attributes"]).map((subitem) => (
<Fragment key={subitem.id}>
<PreviewCard
href={`/library/${subitem.attributes.slug}`}
@ -515,8 +512,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
}
/>
</Fragment>
)
)}
))}
</div>
</div>
)}
@ -530,8 +526,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
</div>
)}
<div className="max-w- grid w-full gap-4">
{filterHasAttributes(item.contents.data, ["attributes"] as const).map(
(rangedContent) => (
{filterHasAttributes(item.contents.data, ["attributes"]).map((rangedContent) => (
<ContentLine
content={
rangedContent.attributes.content?.data?.attributes
@ -549,8 +544,8 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
["attributes"]
).map((category) => category.attributes.short),
type:
rangedContent.attributes.content.data.attributes.type?.data
?.attributes?.titles?.[0]?.title ??
rangedContent.attributes.content.data.attributes.type?.data?.attributes
?.titles?.[0]?.title ??
prettySlug(
rangedContent.attributes.content.data.attributes.type?.data
?.attributes?.slug
@ -573,8 +568,7 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => {
}
condensed={!isContentPanelAtLeast3xl}
/>
)
)}
))}
</div>
</div>
)}
@ -637,7 +631,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const libraryItems = await sdk.getLibraryItemsSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => {
context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local })
);

View File

@ -537,7 +537,7 @@ const LibrarySlug = ({
id={content.attributes.slug}
translations={filterHasAttributes(
content.attributes.content?.data?.attributes?.translations,
["language.data.attributes"] as const
["language.data.attributes"]
).map((translation) => ({
language: translation.language.data.attributes.code,
title: prettyInlineTitle(
@ -596,9 +596,9 @@ export const getStaticProps: GetStaticProps = async (context) => {
filterHasAttributes(item.libraryItems.data[0].attributes.contents?.data, [
"attributes.scan_set",
] as const).forEach((content) =>
filterHasAttributes(content.attributes.scan_set, ["pages.data"] as const).forEach((scanSet) =>
filterHasAttributes(scanSet.pages.data, ["attributes"] as const)
]).forEach((content) =>
filterHasAttributes(content.attributes.scan_set, ["pages.data"]).forEach((scanSet) =>
filterHasAttributes(scanSet.pages.data, ["attributes"])
.sort((a, b) => {
if (isDefinedAndNotEmpty(a.attributes.url) && isDefinedAndNotEmpty(b.attributes.url)) {
let aName = getAssetFilename(a.attributes.url);
@ -675,7 +675,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const libraryItems = await sdk.getLibraryItemsSlugs({});
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"]).map((item) => {
context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local })
);
@ -874,14 +874,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div>
<p className="font-headers font-bold">{format("scanners")}:</p>
<div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.scanners.data, [
"id",
"attributes",
] as const).map((scanner) => (
{filterHasAttributes(selectedScan.scanners.data, ["id", "attributes"]).map(
(scanner) => (
<Fragment key={scanner.id}>
<RecorderChip recorder={scanner.attributes} />
</Fragment>
))}
)
)}
</div>
</div>
)}
@ -890,14 +889,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div>
<p className="font-headers font-bold">{format("cleaners")}:</p>
<div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.cleaners.data, [
"id",
"attributes",
] as const).map((cleaner) => (
{filterHasAttributes(selectedScan.cleaners.data, ["id", "attributes"]).map(
(cleaner) => (
<Fragment key={cleaner.id}>
<RecorderChip recorder={cleaner.attributes} />
</Fragment>
))}
)
)}
</div>
</div>
)}
@ -906,14 +904,13 @@ const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps):
<div>
<p className="font-headers font-bold">{format("typesetters")}:</p>
<div className="grid place-content-center place-items-center gap-2">
{filterHasAttributes(selectedScan.typesetters.data, [
"id",
"attributes",
] as const).map((typesetter) => (
{filterHasAttributes(selectedScan.typesetters.data, ["id", "attributes"]).map(
(typesetter) => (
<Fragment key={typesetter.id}>
<RecorderChip recorder={typesetter.attributes} />
</Fragment>
))}
)
)}
</div>
</div>
)}

View File

@ -408,7 +408,7 @@ const Library = (props: Props): JSX.Element => {
href={`/library/${item.slug}`}
translations={filterHasAttributes(item._formatted.descriptions, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
language: translation.language.data.attributes.code,
title: item.title,
subtitle: item.subtitle,

View File

@ -65,7 +65,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const posts = await sdk.getPostsSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(posts.posts?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(posts.posts?.data, ["attributes"]).map((item) => {
context.locales?.map((local) =>
paths.push({ params: { slug: item.attributes.slug }, locale: local })
);
@ -80,7 +80,7 @@ const terminalPostPage = (post: PostWithTranslations, router: NextRouter): strin
let result = "";
if (router.locales && router.locale) {
const selectedTranslation = staticSmartLanguage({
items: filterHasAttributes(post.translations, ["language.data.attributes.code"] as const),
items: filterHasAttributes(post.translations, ["language.data.attributes.code"]),
languageExtractor: (item) => item.language.data.attributes.code,
preferredLanguages: getDefaultPreferredLanguages(router.locale, router.locales),
});

View File

@ -176,7 +176,7 @@ const News = ({ ...otherProps }: Props): JSX.Element => {
href={`/news/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(({ excerpt, body, language, ...otherAttributes }) => ({
]).map(({ excerpt, body, language, ...otherAttributes }) => ({
...otherAttributes,
description: containsHighlight(excerpt)
? excerpt

View File

@ -125,11 +125,9 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
</p>
<div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(page.categories.data, ["attributes"] as const).map(
(category) => (
{filterHasAttributes(page.categories.data, ["attributes"]).map((category) => (
<Chip key={category.id} text={category.attributes.name} />
)
)}
))}
</div>
</>
)}
@ -138,7 +136,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
<>
<p className="font-headers text-xl font-bold">{format("tags")}</p>
<div className="flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(page.tags.data, ["attributes"] as const).map((tag) => (
{filterHasAttributes(page.tags.data, ["attributes"]).map((tag) => (
<Chip
key={tag.id}
text={
@ -159,8 +157,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
</div>
)}
{filterHasAttributes(page.definitions, ["translations"] as const).map(
(definition, index) => (
{filterHasAttributes(page.definitions, ["translations"]).map((definition, index) => (
<div key={index} className="mb-12">
<DefinitionCard
source={{
@ -182,13 +179,12 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
status: translation?.status,
}))}
index={index + 1}
categories={filterHasAttributes(definition.categories?.data, [
"attributes",
] as const).map((category) => category.attributes.short)}
categories={filterHasAttributes(definition.categories?.data, ["attributes"]).map(
(category) => category.attributes.short
)}
/>
</div>
)
)}
))}
{isDefined(selectedTranslation.body) && (
<div>
@ -218,13 +214,13 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
: ""
}${
page.definitions && page.definitions.length > 0
? `${filterHasAttributes(page.definitions, ["translations"] as const).map(
? `${filterHasAttributes(page.definitions, ["translations"]).map(
(definition, index) =>
`${prettyTerminalUnderlinedTitle(format("definition_x", { x: index + 1 }))}${
staticSmartLanguage({
items: filterHasAttributes(definition.translations, [
"language.data.attributes.code",
] as const),
]),
languageExtractor: (item) => item.language.data.attributes.code,
preferredLanguages: getDefaultPreferredLanguages(
router.locale ?? "en",
@ -267,12 +263,10 @@ export const getStaticProps: GetStaticProps = async (context) => {
const chipsGroups = {
[format("tags")]: filterHasAttributes(page.wikiPages.data[0].attributes.tags?.data, [
"attributes",
] as const).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
),
]).map((tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)),
[format("category", { count: Infinity })]: filterHasAttributes(
page.wikiPages.data[0].attributes.categories?.data,
["attributes"] as const
["attributes"]
).map((category) => category.attributes.short),
};
@ -313,7 +307,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const contents = await sdk.getWikiPagesSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(contents.wikiPages?.data, ["attributes"] as const).map((wikiPage) => {
filterHasAttributes(contents.wikiPages?.data, ["attributes"]).map((wikiPage) => {
context.locales?.map((local) =>
paths.push({
params: { slug: wikiPage.attributes.slug },

View File

@ -45,10 +45,7 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened);
const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]);
const ids = useMemo(
() =>
filterHasAttributes(chronologyEras, ["attributes"] as const).map(
(era) => era.attributes.slug
),
() => filterHasAttributes(chronologyEras, ["attributes"]).map((era) => era.attributes.slug),
[chronologyEras]
);
@ -60,12 +57,12 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
<HorizontalLine />
{filterHasAttributes(chronologyEras, ["attributes", "id"] as const).map((era, index) => (
{filterHasAttributes(chronologyEras, ["attributes", "id"]).map((era, index) => (
<Fragment key={era.id}>
<TranslatedNavOption
translations={filterHasAttributes(era.attributes.title, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
language: translation.language.data.attributes.code,
title: translation.title,
subtitle: `${era.attributes.starting_year}${era.attributes.ending_year}`,
@ -93,19 +90,19 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props):
className="mb-10"
/>
{filterHasAttributes(chronologyEras, ["attributes"] as const).map((era) => (
{filterHasAttributes(chronologyEras, ["attributes"]).map((era) => (
<TranslatedChronologyEra
key={era.attributes.slug}
id={era.attributes.slug}
translations={filterHasAttributes(era.attributes.title, [
"language.data.attributes.code",
] as const).map((translation) => ({
]).map((translation) => ({
language: translation.language.data.attributes.code,
title: translation.title,
description: translation.description,
}))}
fallback={{ title: prettySlug(era.attributes.slug) }}
chronologyItems={filterHasAttributes(chronologyItems, ["attributes"] as const).filter(
chronologyItems={filterHasAttributes(chronologyItems, ["attributes"]).filter(
(item) =>
item.attributes.year >= era.attributes.starting_year &&
item.attributes.year < era.attributes.ending_year
@ -157,7 +154,7 @@ const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEr
const yearGroups = (() => {
const memo: Props["chronologyItems"][] = [];
let currentYear = -Infinity;
filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => {
filterHasAttributes(chronologyItems, ["attributes"]).forEach((item) => {
if (currentYear === item.attributes.year) {
memo[memo.length - 1]?.push(item);
} else {
@ -218,7 +215,7 @@ const ChronologyYear = ({ items }: ChronologyYearProps) => (
<div
className="rounded-2xl target:my-4 target:bg-mid target:py-4"
id={generateAnchor(items[0]?.attributes?.year)}>
{filterHasAttributes(items, ["attributes.events"] as const).map((item, index) => (
{filterHasAttributes(items, ["attributes.events"]).map((item, index) => (
<ChronologyDate
key={index}
date={{
@ -284,7 +281,7 @@ export const ChronologyDate = ({ date, events }: ChronologyDateProps): JSX.Eleme
</p>
<div className="col-start-2 row-span-2 row-start-1 grid gap-4">
{filterHasAttributes(events, ["id", "translations"] as const).map((event) => (
{filterHasAttributes(events, ["id", "translations"]).map((event) => (
<ChronologyEvent
id={generateAnchor(date.year, date.month, date.day)}
key={event.id}

View File

@ -182,7 +182,7 @@ const Wiki = (props: Props): JSX.Element => {
href={`/wiki/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(
]).map(
({ aliases, summary, displayable_description, language, ...otherAttributes }) => ({
...otherAttributes,
subtitle:
@ -201,10 +201,10 @@ const Wiki = (props: Props): JSX.Element => {
thumbnailRounded
thumbnailForceAspectRatio
keepInfoVisible
topChips={filterHasAttributes(item.tags?.data, ["attributes"] as const).map(
topChips={filterHasAttributes(item.tags?.data, ["attributes"]).map(
(tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
)}
bottomChips={filterHasAttributes(item.categories?.data, ["attributes"] as const).map(
bottomChips={filterHasAttributes(item.categories?.data, ["attributes"]).map(
(category) => category.attributes.short
)}
/>

View File

@ -43,7 +43,7 @@ interface WeaponPreviewProps {
const WeaponPreview = ({ weapon }: WeaponPreviewProps): JSX.Element => (
<TranslatedPreviewCard
href={`/wiki/weapons/${weapon.slug}`}
translations={filterHasAttributes(weapon.name, ["language.data.attributes.code"] as const).map(
translations={filterHasAttributes(weapon.name, ["language.data.attributes.code"]).map(
({ name, language }) => ({
language: language.data.attributes.code,
title: name,
@ -111,7 +111,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX
<div className="grid gap-8">
{filterHasAttributes(weapon.weapon_group.data.attributes.weapons.data, [
"attributes",
] as const).map((groupWeapon) => (
]).map((groupWeapon) => (
<WeaponPreview key={groupWeapon.id} weapon={groupWeapon.attributes} />
))}
</div>
@ -140,7 +140,7 @@ const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX
<div className="grid gap-8">
<ElementsSeparator>
{filterHasAttributes(weapon.stories, ["translations"] as const).map((story, index) => (
{filterHasAttributes(weapon.stories, ["translations"]).map((story, index) => (
<WeaponStory
key={story.id}
id={intersectionIds[index]}
@ -201,7 +201,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
const sdk = getReadySdk();
const weapons = await sdk.getWeaponsSlugs();
const paths: GetStaticPathsResult["paths"] = [];
filterHasAttributes(weapons.weaponStories?.data, ["attributes"] as const).map((item) => {
filterHasAttributes(weapons.weaponStories?.data, ["attributes"]).map((item) => {
context.locales?.map((local) => {
paths.push({
params: { slug: item.attributes.slug },
@ -247,11 +247,9 @@ const WeaponStory = ({ story, storyNumber, id }: WeaponStoryProps): JSX.Element
{story.categories && story.categories.data.length > 0 && (
<div className="mb-12 flex flex-row flex-wrap place-content-center gap-2">
{filterHasAttributes(story.categories.data, ["attributes.name"] as const).map(
(category) => (
{filterHasAttributes(story.categories.data, ["attributes.name"]).map((category) => (
<Chip key={category.id} text={category.attributes.name} />
)
)}
))}
</div>
)}
@ -286,7 +284,7 @@ export const getFilteredNames = (
preferredLanguages: string[]
): string[] => {
for (const language of preferredLanguages) {
const filteredNames = filterHasAttributes(names, ["name"] as const).filter(
const filteredNames = filterHasAttributes(names, ["name"]).filter(
(name) => name.language?.data?.attributes?.code === language
);
if (filteredNames.length > 0) {

View File

@ -186,7 +186,7 @@ const Weapons = (props: Props): JSX.Element => {
href={`/wiki/weapons/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code",
] as const).map(({ description, language, names: [primaryName, ...aliases] }) => ({
]).map(({ description, language, names: [primaryName, ...aliases] }) => ({
language: language.data.attributes.code,
title: primaryName,
subtitle: aliases.join("・"),
@ -203,7 +203,7 @@ const Weapons = (props: Props): JSX.Element => {
? [prettySlug(item.type.data.attributes.slug)]
: undefined
}
bottomChips={filterHasAttributes(item.categories, ["attributes.short"] as const).map(
bottomChips={filterHasAttributes(item.categories, ["attributes.short"]).map(
(category) => category.attributes.short
)}
/>