Move all sets to new static generation routine
This commit is contained in:
parent
f0d9ea28b6
commit
c4b1e349e1
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -13,6 +13,8 @@
|
|||||||
"Consolas",
|
"Consolas",
|
||||||
"CredentialsSignin",
|
"CredentialsSignin",
|
||||||
"datetime",
|
"datetime",
|
||||||
|
"depluralize",
|
||||||
|
"depluralizes",
|
||||||
"Eterna",
|
"Eterna",
|
||||||
"exif",
|
"exif",
|
||||||
"exifr",
|
"exifr",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { parameterize } from '@/utility/string';
|
import { parameterize, depluralize } from '@/utility/string';
|
||||||
|
|
||||||
describe('String', () => {
|
describe('String', () => {
|
||||||
it('parameterizes', () => {
|
it('parameterizes', () => {
|
||||||
@ -10,4 +10,11 @@ describe('String', () => {
|
|||||||
expect(parameterize('"person\'s tag"')).toBe('persons-tag');
|
expect(parameterize('"person\'s tag"')).toBe('persons-tag');
|
||||||
expect(parameterize('宿宿宿宿')).toBe('宿宿宿宿');
|
expect(parameterize('宿宿宿宿')).toBe('宿宿宿宿');
|
||||||
});
|
});
|
||||||
|
it('depluralizes', () => {
|
||||||
|
expect(depluralize('lenses')).toBe('lens');
|
||||||
|
expect(depluralize('cameras')).toBe('camera');
|
||||||
|
expect(depluralize('tags')).toBe('tag');
|
||||||
|
expect(depluralize('recipes')).toBe('recipe');
|
||||||
|
expect(depluralize('films')).toBe('film');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,20 +9,23 @@ import { FilmSimulation } from '@/simulation';
|
|||||||
import { getIBMPlexMono } from '@/app/font';
|
import { getIBMPlexMono } from '@/app/font';
|
||||||
import { ImageResponse } from 'next/og';
|
import { ImageResponse } from 'next/og';
|
||||||
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
|
||||||
import { getUniqueFilmSimulations } from '@/photo/db/query';
|
import { getUniqueFilmSimulations } from '@/photo/db/query';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
export let generateStaticParams:
|
export let generateStaticParams:
|
||||||
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
|
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('films', 'image')) {
|
if (shouldGenerateStaticParamsForCategory('films', 'image')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const simulations = await getUniqueFilmSimulations();
|
staticallyGenerateCategory(
|
||||||
return simulations
|
'films',
|
||||||
.map(({ simulation }) => ({ simulation }))
|
'image',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueFilmSimulations,
|
||||||
};
|
simulations => simulations.map(({ simulation }) => ({ simulation })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
|
|||||||
@ -7,8 +7,10 @@ import { Metadata } from 'next/types';
|
|||||||
import { cache } from 'react';
|
import { cache } from 'react';
|
||||||
import { PATH_ROOT } from '@/app/paths';
|
import { PATH_ROOT } from '@/app/paths';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
const getPhotosFilmSimulationDataCachedCached =
|
const getPhotosFilmSimulationDataCachedCached =
|
||||||
cache(getPhotosFilmSimulationDataCached);
|
cache(getPhotosFilmSimulationDataCached);
|
||||||
@ -17,12 +19,13 @@ export let generateStaticParams:
|
|||||||
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
|
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('films', 'page')) {
|
if (shouldGenerateStaticParamsForCategory('films', 'page')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const simulations = await getUniqueFilmSimulations();
|
staticallyGenerateCategory(
|
||||||
return simulations
|
'films',
|
||||||
.map(({ simulation }) => ({ simulation }))
|
'page',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueFilmSimulations,
|
||||||
};
|
simulations => simulations.map(({ simulation }) => ({ simulation })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FilmSimulationProps {
|
interface FilmSimulationProps {
|
||||||
|
|||||||
@ -9,20 +9,24 @@ import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
|||||||
import FocalLengthImageResponse from
|
import FocalLengthImageResponse from
|
||||||
'@/image-response/FocalLengthImageResponse';
|
'@/image-response/FocalLengthImageResponse';
|
||||||
import { formatFocalLength, getFocalLengthFromString } from '@/focal';
|
import { formatFocalLength, getFocalLengthFromString } from '@/focal';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
|
||||||
import { getUniqueFocalLengths } from '@/photo/db/query';
|
import { getUniqueFocalLengths } from '@/photo/db/query';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
export let generateStaticParams:
|
export let generateStaticParams:
|
||||||
(() => Promise<{ focal: string }[]>) | undefined = undefined;
|
(() => Promise<{ focal: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'image')) {
|
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'image')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const focalLengths= await getUniqueFocalLengths();
|
staticallyGenerateCategory(
|
||||||
return focalLengths
|
'focal-lengths',
|
||||||
.map(({ focal }) => ({ focal: formatFocalLength(focal)! }))
|
'image',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueFocalLengths,
|
||||||
};
|
focalLengths => focalLengths
|
||||||
|
.map(({ focal }) => ({ focal: formatFocalLength(focal)! })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
|
|||||||
@ -7,8 +7,10 @@ import { PATH_ROOT } from '@/app/paths';
|
|||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { cache } from 'react';
|
import { cache } from 'react';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
const getPhotosFocalDataCachedCached = cache((focal: number) =>
|
const getPhotosFocalDataCachedCached = cache((focal: number) =>
|
||||||
getPhotosFocalLengthDataCached({
|
getPhotosFocalLengthDataCached({
|
||||||
@ -20,12 +22,14 @@ export let generateStaticParams:
|
|||||||
(() => Promise<{ focal: string }[]>) | undefined = undefined;
|
(() => Promise<{ focal: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'page')) {
|
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'page')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const focalLengths = await getUniqueFocalLengths();
|
staticallyGenerateCategory(
|
||||||
return focalLengths
|
'focal-lengths',
|
||||||
.map(({ focal }) => ({ focal: focal.toString() }))
|
'page',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueFocalLengths,
|
||||||
};
|
focalLengths => focalLengths
|
||||||
|
.map(({ focal }) => ({ focal: focal.toString() })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FocalLengthProps {
|
interface FocalLengthProps {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
import { getIBMPlexMono } from '@/app/font';
|
import { getIBMPlexMono } from '@/app/font';
|
||||||
import { ImageResponse } from 'next/og';
|
import { ImageResponse } from 'next/og';
|
||||||
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
|
||||||
import { getUniqueLenses } from '@/photo/db/query';
|
import { getUniqueLenses } from '@/photo/db/query';
|
||||||
import {
|
import {
|
||||||
getLensFromParams,
|
getLensFromParams,
|
||||||
@ -15,17 +14,22 @@ import {
|
|||||||
safelyGenerateLensStaticParams,
|
safelyGenerateLensStaticParams,
|
||||||
} from '@/lens';
|
} from '@/lens';
|
||||||
import LensImageResponse from '@/image-response/LensImageResponse';
|
import LensImageResponse from '@/image-response/LensImageResponse';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
export let generateStaticParams:
|
export let generateStaticParams:
|
||||||
(() => Promise<Lens[]>) | undefined = undefined;
|
(() => Promise<Lens[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('lenses', 'image')) {
|
if (shouldGenerateStaticParamsForCategory('lenses', 'image')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const lenses = await getUniqueLenses();
|
staticallyGenerateCategory(
|
||||||
return safelyGenerateLensStaticParams(lenses)
|
'lenses',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
'image',
|
||||||
};
|
getUniqueLenses,
|
||||||
|
safelyGenerateLensStaticParams,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
|
|||||||
@ -11,8 +11,10 @@ import {
|
|||||||
LensProps,
|
LensProps,
|
||||||
safelyGenerateLensStaticParams,
|
safelyGenerateLensStaticParams,
|
||||||
} from '@/lens';
|
} from '@/lens';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
import {
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
const getPhotosLensDataCachedCached = cache((
|
const getPhotosLensDataCachedCached = cache((
|
||||||
make: string | undefined,
|
make: string | undefined,
|
||||||
@ -27,11 +29,13 @@ export let generateStaticParams:
|
|||||||
(() => Promise<Lens[]>) | undefined = undefined;
|
(() => Promise<Lens[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('lenses', 'page')) {
|
if (shouldGenerateStaticParamsForCategory('lenses', 'page')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const lenses = await getUniqueLenses();
|
staticallyGenerateCategory(
|
||||||
return safelyGenerateLensStaticParams(lenses)
|
'lenses',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
'page',
|
||||||
};
|
getUniqueLenses,
|
||||||
|
safelyGenerateLensStaticParams,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
|
|||||||
@ -6,21 +6,24 @@ import {
|
|||||||
import { getIBMPlexMono } from '@/app/font';
|
import { getIBMPlexMono } from '@/app/font';
|
||||||
import { ImageResponse } from 'next/og';
|
import { ImageResponse } from 'next/og';
|
||||||
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
|
||||||
import { getUniqueRecipes } from '@/photo/db/query';
|
import { getUniqueRecipes } from '@/photo/db/query';
|
||||||
import RecipeImageResponse from '@/image-response/RecipeImageResponse';
|
import RecipeImageResponse from '@/image-response/RecipeImageResponse';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
export let generateStaticParams:
|
export let generateStaticParams:
|
||||||
(() => Promise<{ recipe: string }[]>) | undefined = undefined;
|
(() => Promise<{ recipe: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('recipes', 'image')) {
|
if (shouldGenerateStaticParamsForCategory('recipes', 'image')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const recipes = await getUniqueRecipes();
|
staticallyGenerateCategory(
|
||||||
return recipes
|
'recipes',
|
||||||
.map(({ recipe }) => ({ recipe }))
|
'image',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueRecipes,
|
||||||
};
|
recipes => recipes.map(({ recipe }) => ({ recipe })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
|
|||||||
@ -7,8 +7,10 @@ import { cache } from 'react';
|
|||||||
import { generateMetaForRecipe } from '@/recipe';
|
import { generateMetaForRecipe } from '@/recipe';
|
||||||
import RecipeOverview from '@/recipe/RecipeOverview';
|
import RecipeOverview from '@/recipe/RecipeOverview';
|
||||||
import { getPhotosRecipeDataCached } from '@/recipe/data';
|
import { getPhotosRecipeDataCached } from '@/recipe/data';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
const getPhotosRecipeDataCachedCached = cache(getPhotosRecipeDataCached);
|
const getPhotosRecipeDataCachedCached = cache(getPhotosRecipeDataCached);
|
||||||
|
|
||||||
@ -16,12 +18,13 @@ export let generateStaticParams:
|
|||||||
(() => Promise<{ recipe: string }[]>) | undefined = undefined;
|
(() => Promise<{ recipe: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('recipes', 'page')) {
|
if (shouldGenerateStaticParamsForCategory('recipes', 'page')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const recipes = await getUniqueRecipes();
|
staticallyGenerateCategory(
|
||||||
return recipes
|
'recipes',
|
||||||
.map(({ recipe }) => ({ recipe }))
|
'page',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueRecipes,
|
||||||
};
|
recipes => recipes.map(({ recipe }) => ({ recipe })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RecipeProps {
|
interface RecipeProps {
|
||||||
|
|||||||
@ -7,20 +7,23 @@ import TagImageResponse from '@/image-response/TagImageResponse';
|
|||||||
import { getIBMPlexMono } from '@/app/font';
|
import { getIBMPlexMono } from '@/app/font';
|
||||||
import { ImageResponse } from 'next/og';
|
import { ImageResponse } from 'next/og';
|
||||||
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
|
||||||
import { getUniqueTags } from '@/photo/db/query';
|
import { getUniqueTags } from '@/photo/db/query';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
export let generateStaticParams:
|
export let generateStaticParams:
|
||||||
(() => Promise<{ tag: string }[]>) | undefined = undefined;
|
(() => Promise<{ tag: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('tags', 'image')) {
|
if (shouldGenerateStaticParamsForCategory('tags', 'image')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const tags = await getUniqueTags();
|
staticallyGenerateCategory(
|
||||||
return tags
|
'tags',
|
||||||
.map(({ tag }) => ({ tag }))
|
'image',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueTags,
|
||||||
};
|
tags => tags.map(({ tag }) => ({ tag })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
|
|||||||
@ -7,8 +7,10 @@ import { getPhotosTagDataCached } from '@/tag/data';
|
|||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { cache } from 'react';
|
import { cache } from 'react';
|
||||||
import { shouldGenerateStaticParamsForCategory } from '@/category/server';
|
import {
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
shouldGenerateStaticParamsForCategory,
|
||||||
|
staticallyGenerateCategory,
|
||||||
|
} from '@/category/server';
|
||||||
|
|
||||||
const getPhotosTagDataCachedCached = cache((tag: string) =>
|
const getPhotosTagDataCachedCached = cache((tag: string) =>
|
||||||
getPhotosTagDataCached({ tag, limit: INFINITE_SCROLL_GRID_INITIAL}));
|
getPhotosTagDataCached({ tag, limit: INFINITE_SCROLL_GRID_INITIAL}));
|
||||||
@ -17,12 +19,13 @@ export let generateStaticParams:
|
|||||||
(() => Promise<{ tag: string }[]>) | undefined = undefined;
|
(() => Promise<{ tag: string }[]>) | undefined = undefined;
|
||||||
|
|
||||||
if (shouldGenerateStaticParamsForCategory('tags', 'page')) {
|
if (shouldGenerateStaticParamsForCategory('tags', 'page')) {
|
||||||
generateStaticParams = async () => {
|
generateStaticParams = () =>
|
||||||
const tags = await getUniqueTags();
|
staticallyGenerateCategory(
|
||||||
return tags
|
'tags',
|
||||||
.map(({ tag }) => ({ tag }))
|
'page',
|
||||||
.slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
getUniqueTags,
|
||||||
};
|
tags => tags.map(({ tag }) => ({ tag })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TagProps {
|
interface TagProps {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES,
|
STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES,
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
|
||||||
import { pluralize } from '@/utility/string';
|
import { depluralize, pluralize } from '@/utility/string';
|
||||||
|
|
||||||
type StaticOutput = 'page' | 'image';
|
type StaticOutput = 'page' | 'image';
|
||||||
|
|
||||||
@ -30,9 +30,8 @@ export const staticallyGenerateCategory = async <T, K>(
|
|||||||
const data = (await getData()).slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
const data = (await getData()).slice(0, GENERATE_STATIC_PARAMS_LIMIT);
|
||||||
|
|
||||||
if (IS_BUILDING) {
|
if (IS_BUILDING) {
|
||||||
console.log(
|
const meta = pluralize(data.length, `${depluralize(key)} ${type}`);
|
||||||
`Statically generating ${key} (${pluralize(data.length, type)})`,
|
console.log(`Statically generating ${meta}`);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatData(data);
|
return formatData(data);
|
||||||
|
|||||||
@ -47,6 +47,12 @@ export const pluralize = (
|
|||||||
) =>
|
) =>
|
||||||
`${count} ${count === 1 ? singular : plural ?? `${singular}s`}`;
|
`${count} ${count === 1 ? singular : plural ?? `${singular}s`}`;
|
||||||
|
|
||||||
|
export const depluralize = (string: string) =>
|
||||||
|
// Handle plurals like "lenses"
|
||||||
|
/ses$/i.test(string)
|
||||||
|
? string.replace(/es$/i, '')
|
||||||
|
: string.replace(/s$/i, '');
|
||||||
|
|
||||||
export const formatCountDescriptive = (
|
export const formatCountDescriptive = (
|
||||||
count: number,
|
count: number,
|
||||||
verb = 'found',
|
verb = 'found',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user