Typescript support

This commit is contained in:
2020-09-26 14:49:58 +02:00
parent 57ed783083
commit dcfc3eccc2
22 changed files with 3132 additions and 1264 deletions

View File

@ -2,13 +2,18 @@ import { readFile } from 'fs'
import { promisify } from 'util'
import fm from 'front-matter'
import { parseField } from '../../markdown/parse-markdown'
import type { PostAttributes } from './_content'
export interface SinglePost {
body: string
}
export async function get(req, res, next) {
// the `slug` parameter is available because
// this file is called [slug].json.js
const { slug } = req.params
let postSource
let postSource: string
try {
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
} catch (e) {
@ -22,9 +27,9 @@ export async function get(req, res, next) {
return
}
const parsedPost = fm(postSource)
const parsedPost = fm<PostAttributes>(postSource)
const response = parseField('body')({
const response = parseField<SinglePost>('body')({
...parsedPost.attributes,
body: parsedPost.body,
})

View File

@ -64,8 +64,8 @@
<svelte:head>
<title>{post.title}</title>
<link rel="stylesheet" href="prism.css" />
<script src="prism.js">
<link rel="stylesheet" href="/prism.css" />
<script src="../../../static/prism.js" defer>
</script>
</svelte:head>

View File

@ -7,17 +7,32 @@ import marked from 'marked'
const { NODE_ENV } = process.env
export async function getBlogListing(tag) {
export interface PostAttributes {
layout: string
title: string
published: boolean
date: string
thumbnail: string
tags: string[]
}
export interface PostContent extends PostAttributes {
preview: string
slug: string
published: boolean
}
export async function getBlogListing(tag?: string) {
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
const filteredFiles = filterDevelopmentFiles(files)
const contents = await Promise.all(
filteredFiles.map(async file => {
filteredFiles.map(async (file) => {
const fileContent = await promisify(readFile)(
`_posts/blog/${file}`,
'utf-8'
)
const parsedAttributes = fm(fileContent)
const parsedAttributes = fm<PostAttributes>(fileContent)
const lineOfTextRegExp = /^(?:\w|\[).+/gm
const lines = parsedAttributes.body
@ -33,23 +48,30 @@ export async function getBlogListing(tag) {
}
})
)
const filteredContents = pipe(
const filteredContents = pipe<
PostContent[],
PostContent[],
PostContent[],
PostContent[],
PostContent[]
>(
sortBy(prop('date')),
reverse,
filter(article => article.published),
filter<typeof contents[0]>((article) => article.published),
partial(filterByTag, [tag])
)(contents)
return filteredContents
}
function filterDevelopmentFiles(files) {
function filterDevelopmentFiles(files: string[]) {
return NODE_ENV !== 'production'
? files
: files.filter(file => !file.startsWith('dev-'))
: files.filter((file) => !file.startsWith('dev-'))
}
function filterByTag(tag, contents) {
return tag ? contents.filter(content => content.tags.includes(tag)) : contents
function filterByTag(tag: string | undefined, contents: PostContent[]) {
return tag
? contents.filter((content) => content.tags.includes(tag))
: contents
}

View File

@ -1,4 +1,4 @@
<script context="module">
<script context="module" lang="typescript">
export function preload({ params, query }) {
const blogQuery = query
? '?' +
@ -14,11 +14,12 @@
}
</script>
<script>
<script lang="typescript">
import ArticleFooter from '../../components/blog/article-footer.svelte'
import type { PostContent } from './_content';
export let posts
export let query
export let posts: PostContent[]
export let query
</script>
<style>

View File

@ -25,14 +25,16 @@ export async function getFeed() {
})
const blogListing = await getBlogListing()
blogListing.forEach(post => {
blogListing.forEach((post) => {
feed.addItem({
title: post.title,
id: `https://michalvanko.dev/blog/${post.slug}`,
link: `https://michalvanko.dev/blog/${post.slug}`,
description: post.preview,
date: post.date,
image: post.thumbnail ? `https://michalvanko.dev/${post.thumbnail}` : undefined,
date: new Date(post.date),
image: post.thumbnail
? `https://michalvanko.dev/${post.thumbnail}`
: undefined,
})
})
return feed

View File

@ -1,11 +1,10 @@
import { getFeed } from './_feed'
export async function get(req, res) {
const feed = await getFeed()
const feed = await getFeed()
res.writeHead(200, {
'Content-Type': 'application/json',
})
res.end(feed.json1())
}

View File

@ -1,11 +1,10 @@
import { getFeed } from './_feed'
export async function get(req, res) {
const feed = await getFeed()
const feed = await getFeed()
res.writeHead(200, {
'Content-Type': 'application/xml',
})
res.end(feed.rss2())
}

View File

@ -4,8 +4,26 @@ import fm from 'front-matter'
import marked from 'marked'
import { parseField } from '../../markdown/parse-markdown'
export interface RecordAttributes {
name: string
description: string
displayed: boolean
}
export interface ProjectAttributes extends RecordAttributes {
image: string
}
export interface PortfolioAttributes {
title: string
work_history_prelude: string
work_history: string[]
projects: ProjectAttributes[]
education: RecordAttributes[]
}
export async function get(req, res, next) {
let pageSource
let pageSource: string
try {
pageSource = await promisify(readFile)('_pages/portfolio.md', 'utf-8')
} catch (e) {
@ -14,15 +32,15 @@ export async function get(req, res, next) {
return
}
const parsed = fm(pageSource)
const parsed = fm<PortfolioAttributes>(pageSource)
const workHistory = (parsed.attributes.work_history || []).map(
parseField('description')
)
const projects = (parsed.attributes.projects || [])
.filter(project => project.displayed)
.filter((project) => project.displayed)
.map(parseField('description'))
const education = (parsed.attributes.education || [])
.filter(education => education.displayed)
.filter((education) => education.displayed)
.map(parseField('description'))
const response = {