refactor: improve type safety (#155)

* Fix to make it type safe.

* The build is failing, fix it.
This commit is contained in:
Katsuyuki Karasawa 2024-08-28 01:19:26 +09:00 committed by GitHub
parent f79ee3482d
commit e9c8930559
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 489 additions and 133 deletions

View File

@ -8,12 +8,13 @@
"build": "astro build && pagefind --site dist",
"preview": "astro preview",
"astro": "astro",
"type-check": "tsc --noEmit --isolatedDeclarations",
"new-post": "node scripts/new-post.js",
"format": "biome format --write ./src",
"lint": "biome check --apply ./src"
},
"dependencies": {
"@astrojs/check": "^0.8.3",
"@astrojs/check": "^0.9.2",
"@astrojs/rss": "^4.0.7",
"@astrojs/sitemap": "^3.1.6",
"@astrojs/svelte": "^5.7.0",
@ -21,7 +22,7 @@
"@fontsource-variable/jetbrains-mono": "^5.0.21",
"@fontsource/roboto": "^5.0.13",
"@swup/astro": "^1.4.1",
"astro": "^4.12.2",
"astro": "^4.14.2",
"astro-compress": "^2.3.0",
"astro-icon": "1.1.0",
"colorjs.io": "^0.5.2",
@ -46,7 +47,7 @@
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@astrojs/ts-plugin": "^1.9.0",
"@astrojs/ts-plugin": "^1.10.0",
"@biomejs/biome": "1.8.3",
"@iconify-json/fa6-brands": "^1.1.21",
"@iconify-json/fa6-regular": "^1.1.21",

File diff suppressed because it is too large Load Diff

View File

@ -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 { getPostUrlBySlug } from '../utils/url-utils'
import { i18n } from '../i18n/translation'
import I18nKey from '../i18n/i18nKey'
import { UNCATEGORIZED } from '@constants/constants'
interface Props {
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(
(grouped: { [year: number]: typeof posts }, post) => {
const year = post.data.published.getFullYear()
@ -45,8 +45,8 @@ const groups: { year: number; posts: typeof posts }[] = (function () {
// convert the object to an array
const groupedPostsArray = Object.keys(groupedPosts).map(key => ({
year: parseInt(key),
posts: groupedPosts[parseInt(key)],
year: Number.parseInt(key),
posts: groupedPosts[Number.parseInt(key)],
}))
// sort years by latest first

View File

@ -1,27 +1,27 @@
---
import { getSortedPosts } from '@utils/content-utils'
import MainGridLayout from '@layouts/MainGridLayout.astro'
import ArchivePanel from '@components/ArchivePanel.astro'
import { i18n } from '@i18n/translation'
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() {
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))
return acc
}, new Set())
const allTagsArray = Array.from(allTags)
return allTagsArray.map(tag => {
return {
return allTagsArray.map(tag => ({
params: {
tag: tag,
},
}
})
}))
}
const tag = Astro.params.tag as string

View File

@ -1,25 +1,31 @@
import rss from '@astrojs/rss'
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 { getSortedPosts } from '@utils/content-utils.ts'
import sanitizeHtml from 'sanitize-html'
const parser = new MarkdownIt()
export async function GET(context: any) {
export async function GET(context: APIContext) {
const blog = await getSortedPosts()
return rss({
title: siteConfig.title,
description: siteConfig.subtitle || 'No description',
site: context.site,
items: blog.map(post => ({
site: context.site ?? 'https://fuwari.vercel.app',
items: blog.map(post => {
const body = typeof post.data.body === 'string' ? post.data.body : ''
return {
title: post.data.title,
pubDate: post.data.published,
description: post.data.description,
description: post.data.description || '',
link: `/posts/${post.slug}/`,
content: sanitizeHtml(parser.render(post.body), {
content: sanitizeHtml(parser.render(body), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
}),
})),
}
}),
customData: `<language>${siteConfig.lang}</language>`,
})
}

View File

@ -4,7 +4,7 @@ import { visit } from 'unist-util-visit'
export function parseDirectiveNode() {
return (tree, { data }) => {
visit(tree, function (node) {
visit(tree, node => {
if (
node.type === 'containerDirective' ||
node.type === 'leafDirective' ||

View File

@ -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 = {
title: string
@ -67,3 +67,18 @@ export type LIGHT_DARK_MODE =
| typeof LIGHT_MODE
| typeof DARK_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
}

View File

@ -1,16 +1,22 @@
import { getCollection } from 'astro:content'
import type { BlogPostData } from '@/types/config'
import I18nKey from '@i18n/i18nKey'
import { i18n } from '@i18n/translation'
import { getCollection } from 'astro:content'
export async function getSortedPosts() {
const allBlogPosts = await getCollection('posts', ({ data }) => {
export async function getSortedPosts(): Promise<
{ data: BlogPostData; slug: string }[]
> {
const allBlogPosts = (await getCollection('posts', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true
})
const sorted = allBlogPosts.sort((a, b) => {
})) as unknown as { data: BlogPostData; slug: string }[]
const sorted = allBlogPosts.sort(
(a: { data: { published: Date } }, b: { data: { published: Date } }) => {
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++) {
sorted[i].data.nextSlug = sorted[i - 1].slug
@ -30,12 +36,12 @@ export type 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
})
const countMap: { [key: string]: number } = {}
allBlogPosts.map(post => {
allBlogPosts.map((post: { data: { tags: string[] } }) => {
post.data.tags.map((tag: string) => {
if (!countMap[tag]) countMap[tag] = 0
countMap[tag]++
@ -56,11 +62,11 @@ export type 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
})
const count: { [key: string]: number } = {}
allBlogPosts.map(post => {
allBlogPosts.map((post: { data: { category: string | number } }) => {
if (!post.data.category) {
const ucKey = i18n(I18nKey.uncategorized)
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1

View File

@ -1,20 +1,20 @@
import type { LIGHT_DARK_MODE } from '@/types/config'
import {
AUTO_MODE,
DARK_MODE,
DEFAULT_THEME,
LIGHT_MODE,
} from '@constants/constants.ts'
import type { LIGHT_DARK_MODE } from '@/types/config'
export function getDefaultHue(): number {
const fallback = '250'
const configCarrier = document.getElementById('config-carrier')
return parseInt(configCarrier?.dataset.hue || fallback)
return Number.parseInt(configCarrier?.dataset.hue || fallback)
}
export function getHue(): number {
const stored = localStorage.getItem('hue')
return stored ? parseInt(stored) : getDefaultHue()
return stored ? Number.parseInt(stored) : getDefaultHue()
}
export function setHue(hue: number): void {

View File

@ -3,7 +3,8 @@
"compilerOptions": {
"baseUrl": ".",
"strictNullChecks": true,
"allowJs": true,
"allowJs": false,
"declaration": true,
"plugins": [
{
"name": "@astrojs/ts-plugin"