refactor: improve type safety (#155)
* Fix to make it type safe. * The build is failing, fix it.
This commit is contained in:
parent
f79ee3482d
commit
e9c8930559
|
@ -8,12 +8,13 @@
|
||||||
"build": "astro build && pagefind --site dist",
|
"build": "astro build && pagefind --site dist",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
|
"type-check": "tsc --noEmit --isolatedDeclarations",
|
||||||
"new-post": "node scripts/new-post.js",
|
"new-post": "node scripts/new-post.js",
|
||||||
"format": "biome format --write ./src",
|
"format": "biome format --write ./src",
|
||||||
"lint": "biome check --apply ./src"
|
"lint": "biome check --apply ./src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.8.3",
|
"@astrojs/check": "^0.9.2",
|
||||||
"@astrojs/rss": "^4.0.7",
|
"@astrojs/rss": "^4.0.7",
|
||||||
"@astrojs/sitemap": "^3.1.6",
|
"@astrojs/sitemap": "^3.1.6",
|
||||||
"@astrojs/svelte": "^5.7.0",
|
"@astrojs/svelte": "^5.7.0",
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
"@fontsource-variable/jetbrains-mono": "^5.0.21",
|
"@fontsource-variable/jetbrains-mono": "^5.0.21",
|
||||||
"@fontsource/roboto": "^5.0.13",
|
"@fontsource/roboto": "^5.0.13",
|
||||||
"@swup/astro": "^1.4.1",
|
"@swup/astro": "^1.4.1",
|
||||||
"astro": "^4.12.2",
|
"astro": "^4.14.2",
|
||||||
"astro-compress": "^2.3.0",
|
"astro-compress": "^2.3.0",
|
||||||
"astro-icon": "1.1.0",
|
"astro-icon": "1.1.0",
|
||||||
"colorjs.io": "^0.5.2",
|
"colorjs.io": "^0.5.2",
|
||||||
|
@ -46,7 +47,7 @@
|
||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/ts-plugin": "^1.9.0",
|
"@astrojs/ts-plugin": "^1.10.0",
|
||||||
"@biomejs/biome": "1.8.3",
|
"@biomejs/biome": "1.8.3",
|
||||||
"@iconify-json/fa6-brands": "^1.1.21",
|
"@iconify-json/fa6-brands": "^1.1.21",
|
||||||
"@iconify-json/fa6-regular": "^1.1.21",
|
"@iconify-json/fa6-regular": "^1.1.21",
|
||||||
|
|
483
pnpm-lock.yaml
483
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
|
import { UNCATEGORIZED } from '@constants/constants'
|
||||||
|
import I18nKey from '../i18n/i18nKey'
|
||||||
|
import { i18n } from '../i18n/translation'
|
||||||
import { getSortedPosts } from '../utils/content-utils'
|
import { getSortedPosts } from '../utils/content-utils'
|
||||||
import { getPostUrlBySlug } from '../utils/url-utils'
|
import { getPostUrlBySlug } from '../utils/url-utils'
|
||||||
import { i18n } from '../i18n/translation'
|
|
||||||
import I18nKey from '../i18n/i18nKey'
|
|
||||||
import { UNCATEGORIZED } from '@constants/constants'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
keyword?: string
|
keyword?: string
|
||||||
|
@ -30,7 +30,7 @@ if (Array.isArray(categories) && categories.length > 0) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const groups: { year: number; posts: typeof posts }[] = (function () {
|
const groups: { year: number; posts: typeof posts }[] = (() => {
|
||||||
const groupedPosts = posts.reduce(
|
const groupedPosts = posts.reduce(
|
||||||
(grouped: { [year: number]: typeof posts }, post) => {
|
(grouped: { [year: number]: typeof posts }, post) => {
|
||||||
const year = post.data.published.getFullYear()
|
const year = post.data.published.getFullYear()
|
||||||
|
@ -45,8 +45,8 @@ const groups: { year: number; posts: typeof posts }[] = (function () {
|
||||||
|
|
||||||
// convert the object to an array
|
// convert the object to an array
|
||||||
const groupedPostsArray = Object.keys(groupedPosts).map(key => ({
|
const groupedPostsArray = Object.keys(groupedPosts).map(key => ({
|
||||||
year: parseInt(key),
|
year: Number.parseInt(key),
|
||||||
posts: groupedPosts[parseInt(key)],
|
posts: groupedPosts[Number.parseInt(key)],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// sort years by latest first
|
// sort years by latest first
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
---
|
---
|
||||||
import { getSortedPosts } from '@utils/content-utils'
|
|
||||||
import MainGridLayout from '@layouts/MainGridLayout.astro'
|
|
||||||
import ArchivePanel from '@components/ArchivePanel.astro'
|
import ArchivePanel from '@components/ArchivePanel.astro'
|
||||||
import { i18n } from '@i18n/translation'
|
|
||||||
import I18nKey from '@i18n/i18nKey'
|
import I18nKey from '@i18n/i18nKey'
|
||||||
|
import { i18n } from '@i18n/translation'
|
||||||
|
import MainGridLayout from '@layouts/MainGridLayout.astro'
|
||||||
|
import { getSortedPosts } from '@utils/content-utils'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
let posts = await getSortedPosts()
|
const posts = await getSortedPosts()
|
||||||
|
|
||||||
const allTags = posts.reduce((acc, post) => {
|
// タグを集めるための Set の型を指定
|
||||||
|
const allTags = posts.reduce<Set<string>>((acc, post) => {
|
||||||
|
// biome-ignore lint/complexity/noForEach: <explanation>
|
||||||
post.data.tags.forEach(tag => acc.add(tag))
|
post.data.tags.forEach(tag => acc.add(tag))
|
||||||
return acc
|
return acc
|
||||||
}, new Set())
|
}, new Set())
|
||||||
|
|
||||||
const allTagsArray = Array.from(allTags)
|
const allTagsArray = Array.from(allTags)
|
||||||
|
|
||||||
return allTagsArray.map(tag => {
|
return allTagsArray.map(tag => ({
|
||||||
return {
|
params: {
|
||||||
params: {
|
tag: tag,
|
||||||
tag: tag,
|
},
|
||||||
},
|
}))
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag = Astro.params.tag as string
|
const tag = Astro.params.tag as string
|
||||||
|
@ -29,4 +29,4 @@ const tag = Astro.params.tag as string
|
||||||
|
|
||||||
<MainGridLayout title={i18n(I18nKey.archive)} description={i18n(I18nKey.archive)}>
|
<MainGridLayout title={i18n(I18nKey.archive)} description={i18n(I18nKey.archive)}>
|
||||||
<ArchivePanel tags={[tag]}></ArchivePanel>
|
<ArchivePanel tags={[tag]}></ArchivePanel>
|
||||||
</MainGridLayout>
|
</MainGridLayout>
|
|
@ -1,25 +1,31 @@
|
||||||
import rss from '@astrojs/rss'
|
|
||||||
import { siteConfig } from '@/config'
|
import { siteConfig } from '@/config'
|
||||||
import sanitizeHtml from 'sanitize-html'
|
import rss from '@astrojs/rss'
|
||||||
|
import { getSortedPosts } from '@utils/content-utils'
|
||||||
|
import type { APIContext } from 'astro'
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
import { getSortedPosts } from '@utils/content-utils.ts'
|
import sanitizeHtml from 'sanitize-html'
|
||||||
|
|
||||||
const parser = new MarkdownIt()
|
const parser = new MarkdownIt()
|
||||||
|
|
||||||
export async function GET(context: any) {
|
export async function GET(context: APIContext) {
|
||||||
const blog = await getSortedPosts()
|
const blog = await getSortedPosts()
|
||||||
|
|
||||||
return rss({
|
return rss({
|
||||||
title: siteConfig.title,
|
title: siteConfig.title,
|
||||||
description: siteConfig.subtitle || 'No description',
|
description: siteConfig.subtitle || 'No description',
|
||||||
site: context.site,
|
site: context.site ?? 'https://fuwari.vercel.app',
|
||||||
items: blog.map(post => ({
|
items: blog.map(post => {
|
||||||
title: post.data.title,
|
const body = typeof post.data.body === 'string' ? post.data.body : ''
|
||||||
pubDate: post.data.published,
|
return {
|
||||||
description: post.data.description,
|
title: post.data.title,
|
||||||
link: `/posts/${post.slug}/`,
|
pubDate: post.data.published,
|
||||||
content: sanitizeHtml(parser.render(post.body), {
|
description: post.data.description || '',
|
||||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
link: `/posts/${post.slug}/`,
|
||||||
}),
|
content: sanitizeHtml(parser.render(body), {
|
||||||
})),
|
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}),
|
||||||
customData: `<language>${siteConfig.lang}</language>`,
|
customData: `<language>${siteConfig.lang}</language>`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { visit } from 'unist-util-visit'
|
||||||
|
|
||||||
export function parseDirectiveNode() {
|
export function parseDirectiveNode() {
|
||||||
return (tree, { data }) => {
|
return (tree, { data }) => {
|
||||||
visit(tree, function (node) {
|
visit(tree, node => {
|
||||||
if (
|
if (
|
||||||
node.type === 'containerDirective' ||
|
node.type === 'containerDirective' ||
|
||||||
node.type === 'leafDirective' ||
|
node.type === 'leafDirective' ||
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { LIGHT_MODE, DARK_MODE, AUTO_MODE } from '@constants/constants'
|
import type { AUTO_MODE, DARK_MODE, LIGHT_MODE } from '@constants/constants'
|
||||||
|
|
||||||
export type SiteConfig = {
|
export type SiteConfig = {
|
||||||
title: string
|
title: string
|
||||||
|
@ -67,3 +67,18 @@ export type LIGHT_DARK_MODE =
|
||||||
| typeof LIGHT_MODE
|
| typeof LIGHT_MODE
|
||||||
| typeof DARK_MODE
|
| typeof DARK_MODE
|
||||||
| typeof AUTO_MODE
|
| typeof AUTO_MODE
|
||||||
|
|
||||||
|
export type BlogPostData = {
|
||||||
|
body: string
|
||||||
|
title: string
|
||||||
|
published: Date
|
||||||
|
description: string
|
||||||
|
tags: string[]
|
||||||
|
draft?: boolean
|
||||||
|
image?: string
|
||||||
|
category?: string
|
||||||
|
prevTitle?: string
|
||||||
|
prevSlug?: string
|
||||||
|
nextTitle?: string
|
||||||
|
nextSlug?: string
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
|
import { getCollection } from 'astro:content'
|
||||||
|
import type { BlogPostData } from '@/types/config'
|
||||||
import I18nKey from '@i18n/i18nKey'
|
import I18nKey from '@i18n/i18nKey'
|
||||||
import { i18n } from '@i18n/translation'
|
import { i18n } from '@i18n/translation'
|
||||||
import { getCollection } from 'astro:content'
|
|
||||||
|
|
||||||
export async function getSortedPosts() {
|
export async function getSortedPosts(): Promise<
|
||||||
const allBlogPosts = await getCollection('posts', ({ data }) => {
|
{ data: BlogPostData; slug: string }[]
|
||||||
|
> {
|
||||||
|
const allBlogPosts = (await getCollection('posts', ({ data }) => {
|
||||||
return import.meta.env.PROD ? data.draft !== true : true
|
return import.meta.env.PROD ? data.draft !== true : true
|
||||||
})
|
})) as unknown as { data: BlogPostData; slug: string }[]
|
||||||
const sorted = allBlogPosts.sort((a, b) => {
|
|
||||||
const dateA = new Date(a.data.published)
|
const sorted = allBlogPosts.sort(
|
||||||
const dateB = new Date(b.data.published)
|
(a: { data: { published: Date } }, b: { data: { published: Date } }) => {
|
||||||
return dateA > dateB ? -1 : 1
|
const dateA = new Date(a.data.published)
|
||||||
})
|
const dateB = new Date(b.data.published)
|
||||||
|
return dateA > dateB ? -1 : 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
for (let i = 1; i < sorted.length; i++) {
|
for (let i = 1; i < sorted.length; i++) {
|
||||||
sorted[i].data.nextSlug = sorted[i - 1].slug
|
sorted[i].data.nextSlug = sorted[i - 1].slug
|
||||||
|
@ -30,12 +36,12 @@ export type Tag = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTagList(): Promise<Tag[]> {
|
export async function getTagList(): Promise<Tag[]> {
|
||||||
const allBlogPosts = await getCollection('posts', ({ data }) => {
|
const allBlogPosts = await getCollection<'posts'>('posts', ({ data }) => {
|
||||||
return import.meta.env.PROD ? data.draft !== true : true
|
return import.meta.env.PROD ? data.draft !== true : true
|
||||||
})
|
})
|
||||||
|
|
||||||
const countMap: { [key: string]: number } = {}
|
const countMap: { [key: string]: number } = {}
|
||||||
allBlogPosts.map(post => {
|
allBlogPosts.map((post: { data: { tags: string[] } }) => {
|
||||||
post.data.tags.map((tag: string) => {
|
post.data.tags.map((tag: string) => {
|
||||||
if (!countMap[tag]) countMap[tag] = 0
|
if (!countMap[tag]) countMap[tag] = 0
|
||||||
countMap[tag]++
|
countMap[tag]++
|
||||||
|
@ -56,11 +62,11 @@ export type Category = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCategoryList(): Promise<Category[]> {
|
export async function getCategoryList(): Promise<Category[]> {
|
||||||
const allBlogPosts = await getCollection('posts', ({ data }) => {
|
const allBlogPosts = await getCollection<'posts'>('posts', ({ data }) => {
|
||||||
return import.meta.env.PROD ? data.draft !== true : true
|
return import.meta.env.PROD ? data.draft !== true : true
|
||||||
})
|
})
|
||||||
const count: { [key: string]: number } = {}
|
const count: { [key: string]: number } = {}
|
||||||
allBlogPosts.map(post => {
|
allBlogPosts.map((post: { data: { category: string | number } }) => {
|
||||||
if (!post.data.category) {
|
if (!post.data.category) {
|
||||||
const ucKey = i18n(I18nKey.uncategorized)
|
const ucKey = i18n(I18nKey.uncategorized)
|
||||||
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1
|
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
|
import type { LIGHT_DARK_MODE } from '@/types/config'
|
||||||
import {
|
import {
|
||||||
AUTO_MODE,
|
AUTO_MODE,
|
||||||
DARK_MODE,
|
DARK_MODE,
|
||||||
DEFAULT_THEME,
|
DEFAULT_THEME,
|
||||||
LIGHT_MODE,
|
LIGHT_MODE,
|
||||||
} from '@constants/constants.ts'
|
} from '@constants/constants.ts'
|
||||||
import type { LIGHT_DARK_MODE } from '@/types/config'
|
|
||||||
|
|
||||||
export function getDefaultHue(): number {
|
export function getDefaultHue(): number {
|
||||||
const fallback = '250'
|
const fallback = '250'
|
||||||
const configCarrier = document.getElementById('config-carrier')
|
const configCarrier = document.getElementById('config-carrier')
|
||||||
return parseInt(configCarrier?.dataset.hue || fallback)
|
return Number.parseInt(configCarrier?.dataset.hue || fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHue(): number {
|
export function getHue(): number {
|
||||||
const stored = localStorage.getItem('hue')
|
const stored = localStorage.getItem('hue')
|
||||||
return stored ? parseInt(stored) : getDefaultHue()
|
return stored ? Number.parseInt(stored) : getDefaultHue()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setHue(hue: number): void {
|
export function setHue(hue: number): void {
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"allowJs": true,
|
"allowJs": false,
|
||||||
|
"declaration": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "@astrojs/ts-plugin"
|
"name": "@astrojs/ts-plugin"
|
||||||
|
|
Loading…
Reference in New Issue