astro-awesomeness 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/{lib-Edmq5pOZ.js → lib-6eq4E-OX.js} +3 -3
- package/dist/lib-6eq4E-OX.js.map +1 -0
- package/package.json +9 -9
- package/src/lib/category-index.ts +2 -2
- package/src/lib/get-related-posts.test.ts +1 -2
- package/dist/lib-Edmq5pOZ.js.map +0 -1
package/dist/index.js
CHANGED
package/dist/lib/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as uniqueTags, c as getRelatedPosts, d as createPostUrl, f as slugify, i as tagUrl, l as formatDate, m as cn, n as DEFAULT_TAG_BASE, o as requireEnv, p as categoryLabel, r as tagLabel, s as readingTime, u as createCategoryIndex } from "../lib-
|
|
1
|
+
import { a as uniqueTags, c as getRelatedPosts, d as createPostUrl, f as slugify, i as tagUrl, l as formatDate, m as cn, n as DEFAULT_TAG_BASE, o as requireEnv, p as categoryLabel, r as tagLabel, s as readingTime, u as createCategoryIndex } from "../lib-6eq4E-OX.js";
|
|
2
2
|
|
|
3
3
|
export { DEFAULT_TAG_BASE, categoryLabel, cn, createCategoryIndex, createPostUrl, formatDate, getRelatedPosts, readingTime, requireEnv, slugify, tagLabel, tagUrl, uniqueTags };
|
|
@@ -84,14 +84,14 @@ const createCategoryIndex = (categorySlugMap, defaultCategory, posts) => {
|
|
|
84
84
|
const { category } = postParams(post);
|
|
85
85
|
const names = post.data.categories;
|
|
86
86
|
for (const name of names) register(categorySlug(name), name);
|
|
87
|
-
const first = names
|
|
87
|
+
const first = names.at(0);
|
|
88
88
|
if (first !== void 0 && !names.some((name) => categorySlug(name) === category)) register(category, first);
|
|
89
89
|
}
|
|
90
90
|
const categoryName = (slug) => {
|
|
91
91
|
const names = [...namesBySlug.get(slug) ?? []];
|
|
92
92
|
const native = names.find((name) => slugify(categoryLabel(name)) === slug);
|
|
93
93
|
const mapped = names.find((name) => categorySlug(name) === slug);
|
|
94
|
-
const name = native ?? mapped ?? names
|
|
94
|
+
const name = native ?? mapped ?? names.at(0);
|
|
95
95
|
return name === void 0 ? humanize(slug) : categoryLabel(name);
|
|
96
96
|
};
|
|
97
97
|
const postCategory = (post) => {
|
|
@@ -228,4 +228,4 @@ var lib_exports = /* @__PURE__ */ __exportAll({
|
|
|
228
228
|
|
|
229
229
|
//#endregion
|
|
230
230
|
export { uniqueTags as a, getRelatedPosts as c, createPostUrl as d, slugify as f, tagUrl as i, formatDate as l, cn$1 as m, DEFAULT_TAG_BASE as n, requireEnv as o, categoryLabel as p, tagLabel as r, readingTime as s, lib_exports as t, createCategoryIndex as u };
|
|
231
|
-
//# sourceMappingURL=lib-
|
|
231
|
+
//# sourceMappingURL=lib-6eq4E-OX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib-6eq4E-OX.js","names":[],"sources":["../src/lib/category-label.ts","../src/lib/slugify.ts","../src/lib/post-url.ts","../src/lib/category-index.ts","../src/lib/format-date.ts","../src/lib/get-related-posts.ts","../src/lib/reading-time.ts","../src/lib/require-env.ts","../src/lib/tag-url.ts","../src/lib/index.ts"],"sourcesContent":["const NAMED_ENTITIES = {\n amp: \"&\",\n apos: \"'\",\n gt: \">\",\n hellip: \"\\u2026\",\n ldquo: \"\\u201c\",\n lsquo: \"\\u2018\",\n lt: \"<\",\n nbsp: \"\\u00a0\",\n ndash: \"\\u2013\",\n quot: '\"',\n rdquo: \"\\u201d\",\n rsquo: \"\\u2019\",\n} as const;\n\nconst MAX_CODE_POINT = 1_114_111;\nconst EM_DASH = 8212;\nconst HEX_RADIX = 16;\nconst ENTITY_PATTERN = /&(?:#(?<decimal>\\d+)|#x(?<hex>[\\dA-F]+)|(?<named>[A-Z]+));/giv;\n\nconst isNamedEntity = (key: string): key is keyof typeof NAMED_ENTITIES =>\n Object.hasOwn(NAMED_ENTITIES, key);\n\nconst fromCodePoint = (codePoint: number, entity: string): string =>\n Number.isInteger(codePoint) && codePoint <= MAX_CODE_POINT && codePoint !== EM_DASH\n ? String.fromCodePoint(codePoint)\n : entity;\n\nconst decodeEntity = (entity: string, decimal?: string, hex?: string, named?: string): string => {\n if (decimal !== undefined) {\n return fromCodePoint(Number(decimal), entity);\n }\n if (hex !== undefined) {\n return fromCodePoint(Number.parseInt(hex, HEX_RADIX), entity);\n }\n if (named === undefined) {\n return entity;\n }\n const key = named.toLowerCase();\n if (!isNamedEntity(key)) {\n return entity;\n }\n return NAMED_ENTITIES[key];\n};\n\nconst categoryLabel = (name: string): string => name.replaceAll(ENTITY_PATTERN, decodeEntity);\n\nexport { categoryLabel };\n","const slugify = (input: string) =>\n input\n .normalize(\"NFD\")\n .replaceAll(/[̀-ͯ]/gv, \"\")\n .toLowerCase()\n .replaceAll(/[^a-z0-9\\s\\-]/gv, \"\")\n .trim()\n .replaceAll(/[\\s\\-]+/gv, \"-\")\n .replaceAll(/^-+|-+$/gv, \"\");\n\nexport { slugify };\n","import { slugify } from \"./slugify\";\n\ntype PostLike = {\n data: {\n categories?: Array<string>;\n seo?: { canonical_url?: string };\n };\n id: string;\n};\n\ntype PostParams = { category: string; slug: string };\n\ntype PostUrlBuilder = {\n postParams: (post: PostLike) => PostParams;\n postUrl: (post: PostLike) => string;\n};\n\nconst createPostUrl = (\n categorySlugMap: Record<string, string>,\n defaultCategory: string,\n): PostUrlBuilder => {\n const postParams = (post: PostLike): PostParams => {\n const canonical = post.data.seo?.canonical_url;\n if (canonical !== undefined && canonical !== \"\") {\n try {\n const segments = new URL(canonical).pathname.split(\"/\").filter(Boolean);\n const category = segments.at(-2);\n const slug = segments.at(-1);\n if (category !== undefined && slug !== undefined) {\n return { category, slug };\n }\n } catch {\n // Malformed canonical_url; fall through to category-derived logic.\n }\n }\n const first = post.data.categories?.at(0);\n const category =\n first !== undefined && first !== \"\"\n ? (categorySlugMap[first] ?? slugify(first))\n : defaultCategory;\n return { category, slug: post.id };\n };\n\n const postUrl = (post: PostLike): string => {\n const { category, slug } = postParams(post);\n return `/${category}/${slug}/`;\n };\n\n return { postParams, postUrl };\n};\n\nexport type { PostLike, PostParams, PostUrlBuilder };\nexport { createPostUrl };\n","import { byPubDateDesc } from \"../content/index\";\nimport { categoryLabel } from \"./category-label\";\nimport type { PostLike } from \"./post-url\";\nimport { createPostUrl } from \"./post-url\";\nimport { slugify } from \"./slugify\";\n\ntype CategoryPostLike = PostLike & { data: { categories: Array<string>; pubDate: Date } };\n\ntype CategoryBucket<P> = { name: string; posts: Array<P>; slug: string };\n\ntype PostCategory = { name: string; slug: string };\n\ntype GroupOptions = {\n includeSecondaryCategories?: boolean;\n};\n\nconst humanize = (slug: string): string => {\n const words = slug.replaceAll(\"-\", \" \");\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\nconst createCategoryIndex = <P extends CategoryPostLike>(\n categorySlugMap: Record<string, string>,\n defaultCategory: string,\n posts: Array<P>,\n) => {\n const { postParams } = createPostUrl(categorySlugMap, defaultCategory);\n const categorySlug = (name: string) => categorySlugMap[name] ?? slugify(name);\n\n const namesBySlug = new Map<string, Set<string>>();\n const register = (slug: string, name: string) => {\n namesBySlug.set(slug, (namesBySlug.get(slug) ?? new Set()).add(name));\n };\n for (const post of posts) {\n const { category } = postParams(post);\n const names = post.data.categories;\n for (const name of names) {\n register(categorySlug(name), name);\n }\n const first = names.at(0);\n if (first !== undefined && !names.some((name) => categorySlug(name) === category)) {\n register(category, first);\n }\n }\n\n const categoryName = (slug: string): string => {\n const names = [...(namesBySlug.get(slug) ?? [])];\n const native = names.find((name) => slugify(categoryLabel(name)) === slug);\n const mapped = names.find((name) => categorySlug(name) === slug);\n const name = native ?? mapped ?? names.at(0);\n return name === undefined ? humanize(slug) : categoryLabel(name);\n };\n\n const postCategory = (post: PostLike): PostCategory => {\n const { category } = postParams(post);\n return { name: categoryName(category), slug: category };\n };\n\n const groupByCategory = ({ includeSecondaryCategories = false }: GroupOptions = {}): Array<\n CategoryBucket<P>\n > => {\n const postsBySlug = new Map<string, Array<P>>();\n const add = (slug: string, post: P) => {\n const bucket = postsBySlug.get(slug);\n if (bucket) {\n bucket.push(post);\n } else {\n postsBySlug.set(slug, [post]);\n }\n };\n\n for (const post of posts) {\n const { category } = postParams(post);\n add(category, post);\n if (!includeSecondaryCategories) {\n continue;\n }\n for (const name of post.data.categories) {\n const slug = categorySlug(name);\n if (slug !== category) {\n add(slug, post);\n }\n }\n }\n\n return [...postsBySlug].map(([slug, bucketPosts]) => ({\n name: categoryName(slug),\n posts: bucketPosts.toSorted(byPubDateDesc),\n slug,\n }));\n };\n\n return { categoryName, groupByCategory, postCategory };\n};\n\nexport type { CategoryBucket, CategoryPostLike, PostCategory };\nexport { createCategoryIndex };\n","const defaultOptions: Intl.DateTimeFormatOptions = {\n day: \"numeric\",\n month: \"long\",\n timeZone: \"UTC\",\n year: \"numeric\",\n};\n\nconst formatterCache = new Map<string, Intl.DateTimeFormat>();\n\nconst getFormatter = (key: string, locale: string, options: Intl.DateTimeFormatOptions) => {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n formatter = new Intl.DateTimeFormat(locale, options);\n formatterCache.set(key, formatter);\n }\n return formatter;\n};\n\nconst formatDate = (date: Date, locale: string = \"en-US\", options?: Intl.DateTimeFormatOptions) => {\n if (!options) {\n return getFormatter(locale, locale, defaultOptions).format(date);\n }\n const merged = { ...defaultOptions, ...options };\n return getFormatter(`${locale}:${JSON.stringify(merged)}`, locale, merged).format(date);\n};\n\nexport { formatDate };\n","type HasTags = { data: { tags: Array<string> }; id: string };\n\nconst getRelatedPosts = <T extends HasTags>(current: T, all: Array<T>, n: number) => {\n const currentTagSet = new Set(current.data.tags);\n const scored: Array<{ post: T; score: number }> = [];\n\n for (const post of all) {\n if (post.id === current.id) {\n continue;\n }\n let score = 0;\n for (const tag of post.data.tags) {\n if (currentTagSet.has(tag)) {\n score++;\n }\n }\n scored.push({ post, score });\n }\n\n return scored\n .toSorted((x, y) => y.score - x.score)\n .slice(0, n)\n .map(({ post }) => post);\n};\n\nexport { getRelatedPosts };\n","const WORDS_PER_MINUTE = 200;\n\nconst readingTime = (input: string) => {\n const stripped = input\n .replaceAll(/<[^>]*>/gv, \"\")\n .replaceAll(/[#*_`>\\-]/gv, \" \")\n .replaceAll(/\\s+/gv, \" \")\n .trim();\n const words = stripped.length === 0 ? 0 : stripped.split(\" \").length;\n const minutes = Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));\n return { minutes, words };\n};\n\nexport { readingTime };\n","const requireEnv = (name: string): string => {\n const value = process.env[name];\n if (value === undefined || value === \"\") {\n throw new Error(`Missing required env var: ${name}`);\n }\n return value;\n};\n\nexport { requireEnv };\n","import { slugify } from \"./slugify\";\n\nconst DEFAULT_TAG_BASE = \"/tag\";\n\nconst tagUrl = (tag: string, base: string = DEFAULT_TAG_BASE): string =>\n `${base.replace(/\\/+$/v, \"\")}/${slugify(tag)}/`;\n\nconst tagLabel = (tag: string): string => tag.replace(/^#/v, \"\");\n\nconst uniqueTags = (tags: Array<string>): Array<string> => {\n const seen = new Set<string>();\n return tags.filter((tag) => {\n const slug = slugify(tag);\n if (seen.has(slug)) {\n return false;\n }\n seen.add(slug);\n return true;\n });\n};\n\nexport { DEFAULT_TAG_BASE, tagLabel, tagUrl, uniqueTags };\n","export { cn } from \"./cn\";\nexport type { CategoryBucket, CategoryPostLike, PostCategory } from \"./category-index\";\nexport { createCategoryIndex } from \"./category-index\";\nexport { categoryLabel } from \"./category-label\";\nexport { formatDate } from \"./format-date\";\nexport { getRelatedPosts } from \"./get-related-posts\";\nexport type { PostLike, PostParams, PostUrlBuilder } from \"./post-url\";\nexport { createPostUrl } from \"./post-url\";\nexport { readingTime } from \"./reading-time\";\nexport { requireEnv } from \"./require-env\";\nexport { slugify } from \"./slugify\";\nexport { DEFAULT_TAG_BASE, tagLabel, tagUrl, uniqueTags } from \"./tag-url\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-awesomeness",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Astro 6/7 blog theme with shadcn primitives and a Tailwind v4 preset.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -54,21 +54,21 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@base-ui/react": "^1.8.0",
|
|
56
56
|
"class-variance-authority": "^0.7.1",
|
|
57
|
-
"cn": "^0.
|
|
58
|
-
"lucide-react": "^1.
|
|
57
|
+
"cn": "^0.4.0",
|
|
58
|
+
"lucide-react": "^1.48.0",
|
|
59
59
|
"shadcn": "^4.21.0",
|
|
60
60
|
"tw-animate-css": "^1.4.0",
|
|
61
|
-
"zod": "^4.6.
|
|
61
|
+
"zod": "^4.6.5"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@tailwindcss/postcss": "^4.3.
|
|
65
|
-
"@types/node": "^26.
|
|
64
|
+
"@tailwindcss/postcss": "^4.3.3",
|
|
65
|
+
"@types/node": "^26.6.2",
|
|
66
66
|
"@types/react": "^19.3.0",
|
|
67
67
|
"@types/react-dom": "^19.3.0",
|
|
68
|
-
"@vitest/coverage-v8": "^5.0.
|
|
69
|
-
"tailwindcss": "^4.3.
|
|
68
|
+
"@vitest/coverage-v8": "^5.0.1",
|
|
69
|
+
"tailwindcss": "^4.3.3",
|
|
70
70
|
"typescript": "^7.0.2",
|
|
71
|
-
"vitest": "^5.0.
|
|
71
|
+
"vitest": "^5.0.1",
|
|
72
72
|
"@repo/config-vitest": "0.0.0",
|
|
73
73
|
"@repo/typescript-config": "0.0.0"
|
|
74
74
|
},
|
|
@@ -37,7 +37,7 @@ const createCategoryIndex = <P extends CategoryPostLike>(
|
|
|
37
37
|
for (const name of names) {
|
|
38
38
|
register(categorySlug(name), name);
|
|
39
39
|
}
|
|
40
|
-
const first = names
|
|
40
|
+
const first = names.at(0);
|
|
41
41
|
if (first !== undefined && !names.some((name) => categorySlug(name) === category)) {
|
|
42
42
|
register(category, first);
|
|
43
43
|
}
|
|
@@ -47,7 +47,7 @@ const createCategoryIndex = <P extends CategoryPostLike>(
|
|
|
47
47
|
const names = [...(namesBySlug.get(slug) ?? [])];
|
|
48
48
|
const native = names.find((name) => slugify(categoryLabel(name)) === slug);
|
|
49
49
|
const mapped = names.find((name) => categorySlug(name) === slug);
|
|
50
|
-
const name = native ?? mapped ?? names
|
|
50
|
+
const name = native ?? mapped ?? names.at(0);
|
|
51
51
|
return name === undefined ? humanize(slug) : categoryLabel(name);
|
|
52
52
|
};
|
|
53
53
|
|
|
@@ -20,8 +20,7 @@ describe("getRelatedPosts", () => {
|
|
|
20
20
|
});
|
|
21
21
|
it("limits to n", () => {
|
|
22
22
|
const related = getRelatedPosts(a, [a, b, c, d], 1);
|
|
23
|
-
expect(related).
|
|
24
|
-
expect(related[0].id).toBe("d");
|
|
23
|
+
expect(related.map((p) => p.id)).toEqual(["d"]);
|
|
25
24
|
});
|
|
26
25
|
it("falls back to other posts when no overlap exists", () => {
|
|
27
26
|
const lonely: TestPost = { data: { tags: ["nothing"] }, id: "lonely" };
|
package/dist/lib-Edmq5pOZ.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lib-Edmq5pOZ.js","names":[],"sources":["../src/lib/category-label.ts","../src/lib/slugify.ts","../src/lib/post-url.ts","../src/lib/category-index.ts","../src/lib/format-date.ts","../src/lib/get-related-posts.ts","../src/lib/reading-time.ts","../src/lib/require-env.ts","../src/lib/tag-url.ts","../src/lib/index.ts"],"sourcesContent":["const NAMED_ENTITIES = {\n amp: \"&\",\n apos: \"'\",\n gt: \">\",\n hellip: \"\\u2026\",\n ldquo: \"\\u201c\",\n lsquo: \"\\u2018\",\n lt: \"<\",\n nbsp: \"\\u00a0\",\n ndash: \"\\u2013\",\n quot: '\"',\n rdquo: \"\\u201d\",\n rsquo: \"\\u2019\",\n} as const;\n\nconst MAX_CODE_POINT = 1_114_111;\nconst EM_DASH = 8212;\nconst HEX_RADIX = 16;\nconst ENTITY_PATTERN = /&(?:#(?<decimal>\\d+)|#x(?<hex>[\\dA-F]+)|(?<named>[A-Z]+));/giv;\n\nconst isNamedEntity = (key: string): key is keyof typeof NAMED_ENTITIES =>\n Object.hasOwn(NAMED_ENTITIES, key);\n\nconst fromCodePoint = (codePoint: number, entity: string): string =>\n Number.isInteger(codePoint) && codePoint <= MAX_CODE_POINT && codePoint !== EM_DASH\n ? String.fromCodePoint(codePoint)\n : entity;\n\nconst decodeEntity = (entity: string, decimal?: string, hex?: string, named?: string): string => {\n if (decimal !== undefined) {\n return fromCodePoint(Number(decimal), entity);\n }\n if (hex !== undefined) {\n return fromCodePoint(Number.parseInt(hex, HEX_RADIX), entity);\n }\n if (named === undefined) {\n return entity;\n }\n const key = named.toLowerCase();\n if (!isNamedEntity(key)) {\n return entity;\n }\n return NAMED_ENTITIES[key];\n};\n\nconst categoryLabel = (name: string): string => name.replaceAll(ENTITY_PATTERN, decodeEntity);\n\nexport { categoryLabel };\n","const slugify = (input: string) =>\n input\n .normalize(\"NFD\")\n .replaceAll(/[̀-ͯ]/gv, \"\")\n .toLowerCase()\n .replaceAll(/[^a-z0-9\\s\\-]/gv, \"\")\n .trim()\n .replaceAll(/[\\s\\-]+/gv, \"-\")\n .replaceAll(/^-+|-+$/gv, \"\");\n\nexport { slugify };\n","import { slugify } from \"./slugify\";\n\ntype PostLike = {\n data: {\n categories?: Array<string>;\n seo?: { canonical_url?: string };\n };\n id: string;\n};\n\ntype PostParams = { category: string; slug: string };\n\ntype PostUrlBuilder = {\n postParams: (post: PostLike) => PostParams;\n postUrl: (post: PostLike) => string;\n};\n\nconst createPostUrl = (\n categorySlugMap: Record<string, string>,\n defaultCategory: string,\n): PostUrlBuilder => {\n const postParams = (post: PostLike): PostParams => {\n const canonical = post.data.seo?.canonical_url;\n if (canonical !== undefined && canonical !== \"\") {\n try {\n const segments = new URL(canonical).pathname.split(\"/\").filter(Boolean);\n const category = segments.at(-2);\n const slug = segments.at(-1);\n if (category !== undefined && slug !== undefined) {\n return { category, slug };\n }\n } catch {\n // Malformed canonical_url; fall through to category-derived logic.\n }\n }\n const first = post.data.categories?.at(0);\n const category =\n first !== undefined && first !== \"\"\n ? (categorySlugMap[first] ?? slugify(first))\n : defaultCategory;\n return { category, slug: post.id };\n };\n\n const postUrl = (post: PostLike): string => {\n const { category, slug } = postParams(post);\n return `/${category}/${slug}/`;\n };\n\n return { postParams, postUrl };\n};\n\nexport type { PostLike, PostParams, PostUrlBuilder };\nexport { createPostUrl };\n","import { byPubDateDesc } from \"../content/index\";\nimport { categoryLabel } from \"./category-label\";\nimport type { PostLike } from \"./post-url\";\nimport { createPostUrl } from \"./post-url\";\nimport { slugify } from \"./slugify\";\n\ntype CategoryPostLike = PostLike & { data: { categories: Array<string>; pubDate: Date } };\n\ntype CategoryBucket<P> = { name: string; posts: Array<P>; slug: string };\n\ntype PostCategory = { name: string; slug: string };\n\ntype GroupOptions = {\n includeSecondaryCategories?: boolean;\n};\n\nconst humanize = (slug: string): string => {\n const words = slug.replaceAll(\"-\", \" \");\n return words.charAt(0).toUpperCase() + words.slice(1);\n};\n\nconst createCategoryIndex = <P extends CategoryPostLike>(\n categorySlugMap: Record<string, string>,\n defaultCategory: string,\n posts: Array<P>,\n) => {\n const { postParams } = createPostUrl(categorySlugMap, defaultCategory);\n const categorySlug = (name: string) => categorySlugMap[name] ?? slugify(name);\n\n const namesBySlug = new Map<string, Set<string>>();\n const register = (slug: string, name: string) => {\n namesBySlug.set(slug, (namesBySlug.get(slug) ?? new Set()).add(name));\n };\n for (const post of posts) {\n const { category } = postParams(post);\n const names = post.data.categories;\n for (const name of names) {\n register(categorySlug(name), name);\n }\n const first = names[0];\n if (first !== undefined && !names.some((name) => categorySlug(name) === category)) {\n register(category, first);\n }\n }\n\n const categoryName = (slug: string): string => {\n const names = [...(namesBySlug.get(slug) ?? [])];\n const native = names.find((name) => slugify(categoryLabel(name)) === slug);\n const mapped = names.find((name) => categorySlug(name) === slug);\n const name = native ?? mapped ?? names[0];\n return name === undefined ? humanize(slug) : categoryLabel(name);\n };\n\n const postCategory = (post: PostLike): PostCategory => {\n const { category } = postParams(post);\n return { name: categoryName(category), slug: category };\n };\n\n const groupByCategory = ({ includeSecondaryCategories = false }: GroupOptions = {}): Array<\n CategoryBucket<P>\n > => {\n const postsBySlug = new Map<string, Array<P>>();\n const add = (slug: string, post: P) => {\n const bucket = postsBySlug.get(slug);\n if (bucket) {\n bucket.push(post);\n } else {\n postsBySlug.set(slug, [post]);\n }\n };\n\n for (const post of posts) {\n const { category } = postParams(post);\n add(category, post);\n if (!includeSecondaryCategories) {\n continue;\n }\n for (const name of post.data.categories) {\n const slug = categorySlug(name);\n if (slug !== category) {\n add(slug, post);\n }\n }\n }\n\n return [...postsBySlug].map(([slug, bucketPosts]) => ({\n name: categoryName(slug),\n posts: bucketPosts.toSorted(byPubDateDesc),\n slug,\n }));\n };\n\n return { categoryName, groupByCategory, postCategory };\n};\n\nexport type { CategoryBucket, CategoryPostLike, PostCategory };\nexport { createCategoryIndex };\n","const defaultOptions: Intl.DateTimeFormatOptions = {\n day: \"numeric\",\n month: \"long\",\n timeZone: \"UTC\",\n year: \"numeric\",\n};\n\nconst formatterCache = new Map<string, Intl.DateTimeFormat>();\n\nconst getFormatter = (key: string, locale: string, options: Intl.DateTimeFormatOptions) => {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n formatter = new Intl.DateTimeFormat(locale, options);\n formatterCache.set(key, formatter);\n }\n return formatter;\n};\n\nconst formatDate = (date: Date, locale: string = \"en-US\", options?: Intl.DateTimeFormatOptions) => {\n if (!options) {\n return getFormatter(locale, locale, defaultOptions).format(date);\n }\n const merged = { ...defaultOptions, ...options };\n return getFormatter(`${locale}:${JSON.stringify(merged)}`, locale, merged).format(date);\n};\n\nexport { formatDate };\n","type HasTags = { data: { tags: Array<string> }; id: string };\n\nconst getRelatedPosts = <T extends HasTags>(current: T, all: Array<T>, n: number) => {\n const currentTagSet = new Set(current.data.tags);\n const scored: Array<{ post: T; score: number }> = [];\n\n for (const post of all) {\n if (post.id === current.id) {\n continue;\n }\n let score = 0;\n for (const tag of post.data.tags) {\n if (currentTagSet.has(tag)) {\n score++;\n }\n }\n scored.push({ post, score });\n }\n\n return scored\n .toSorted((x, y) => y.score - x.score)\n .slice(0, n)\n .map(({ post }) => post);\n};\n\nexport { getRelatedPosts };\n","const WORDS_PER_MINUTE = 200;\n\nconst readingTime = (input: string) => {\n const stripped = input\n .replaceAll(/<[^>]*>/gv, \"\")\n .replaceAll(/[#*_`>\\-]/gv, \" \")\n .replaceAll(/\\s+/gv, \" \")\n .trim();\n const words = stripped.length === 0 ? 0 : stripped.split(\" \").length;\n const minutes = Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));\n return { minutes, words };\n};\n\nexport { readingTime };\n","const requireEnv = (name: string): string => {\n const value = process.env[name];\n if (value === undefined || value === \"\") {\n throw new Error(`Missing required env var: ${name}`);\n }\n return value;\n};\n\nexport { requireEnv };\n","import { slugify } from \"./slugify\";\n\nconst DEFAULT_TAG_BASE = \"/tag\";\n\nconst tagUrl = (tag: string, base: string = DEFAULT_TAG_BASE): string =>\n `${base.replace(/\\/+$/v, \"\")}/${slugify(tag)}/`;\n\nconst tagLabel = (tag: string): string => tag.replace(/^#/v, \"\");\n\nconst uniqueTags = (tags: Array<string>): Array<string> => {\n const seen = new Set<string>();\n return tags.filter((tag) => {\n const slug = slugify(tag);\n if (seen.has(slug)) {\n return false;\n }\n seen.add(slug);\n return true;\n });\n};\n\nexport { DEFAULT_TAG_BASE, tagLabel, tagUrl, uniqueTags };\n","export { cn } from \"./cn\";\nexport type { CategoryBucket, CategoryPostLike, PostCategory } from \"./category-index\";\nexport { createCategoryIndex } from \"./category-index\";\nexport { categoryLabel } from \"./category-label\";\nexport { formatDate } from \"./format-date\";\nexport { getRelatedPosts } from \"./get-related-posts\";\nexport type { PostLike, PostParams, PostUrlBuilder } from \"./post-url\";\nexport { createPostUrl } from \"./post-url\";\nexport { readingTime } from \"./reading-time\";\nexport { requireEnv } from \"./require-env\";\nexport { slugify } from \"./slugify\";\nexport { DEFAULT_TAG_BASE, tagLabel, tagUrl, uniqueTags } from \"./tag-url\";\n"],"mappings":"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"}
|