29044867dd
This PR adds the docs app back into the tldraw monorepo. ## Deploying We'll want to update our deploy script to update the SOURCE_SHA to the newest release sha... and then deploy the docs pulling api.json files from that release. We _could_ update the docs on every push to main, but we don't have to unless something has changed. Right now there's no automated deployments from this repo. ## Side effects To make this one work, I needed to update the lock file. This might be ok (new year new lock file), and everything builds as expected, though we may want to spend some time with our scripts to be sure that things are all good. I also updated our prettier installation, which decided to add trailing commas to every generic type. Which is, I suppose, [correct behavior](https://github.com/prettier/prettier-vscode/issues/955)? But that caused diffs in every file, which is unfortunate. ### Change Type - [x] `internal` — Any other changes that don't affect the published package[^2]
134 lines
3.1 KiB
TypeScript
134 lines
3.1 KiB
TypeScript
import { Article, ArticleHeadings, GeneratedContent } from '@/types/content-types'
|
|
import GithubSlugger from 'github-slugger'
|
|
import { Database } from 'sqlite'
|
|
import sqlite3 from 'sqlite3'
|
|
|
|
export async function addContentToDb(
|
|
db: Database<sqlite3.Database, sqlite3.Statement>,
|
|
content: GeneratedContent
|
|
) {
|
|
const sectionInsert = await db.prepare(
|
|
`REPLACE INTO sections (id, idx, title, description, path, sidebar_behavior) VALUES (?, ?, ?, ?, ?, ?)`
|
|
)
|
|
|
|
const categoryInsert = await db.prepare(
|
|
`REPLACE INTO categories (id, title, description, sectionId, sectionIndex, path) VALUES (?, ?, ?, ?, ?, ?)`
|
|
)
|
|
|
|
const headingsInsert = await db.prepare(
|
|
`REPLACE INTO headings (idx, articleId, level, title, slug, isCode, path) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
)
|
|
|
|
const articleInsert = await db.prepare(
|
|
`REPLACE INTO articles (
|
|
id,
|
|
groupIndex,
|
|
categoryIndex,
|
|
sectionIndex,
|
|
groupId,
|
|
categoryId,
|
|
sectionId,
|
|
authorId,
|
|
title,
|
|
description,
|
|
hero,
|
|
status,
|
|
date,
|
|
sourceUrl,
|
|
keywords,
|
|
content,
|
|
path
|
|
) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
)
|
|
|
|
for (let i = 0; i < content.sections.length; i++) {
|
|
const section = content.sections[i]
|
|
try {
|
|
await sectionInsert.run(
|
|
section.id,
|
|
section.id === 'gen' ? 99999 : i,
|
|
section.title,
|
|
section.description,
|
|
section.path,
|
|
section.sidebar_behavior
|
|
)
|
|
|
|
for (let c = 0; c < section.categories.length; c++) {
|
|
const category = section.categories[c]
|
|
await categoryInsert.run(
|
|
category.id,
|
|
category.title,
|
|
category.description,
|
|
section.id,
|
|
c,
|
|
category.path
|
|
)
|
|
}
|
|
} catch (e: any) {
|
|
throw Error(`could not add section to db, ${section.id}: ${e.message}`)
|
|
}
|
|
}
|
|
|
|
const articles = Object.values(content.articles) as Article[]
|
|
|
|
for (let i = 0; i < articles.length; i++) {
|
|
const article = articles[i]
|
|
if (!article.id) {
|
|
throw Error(`hey, article ${article.id} has no id`)
|
|
}
|
|
|
|
await articleInsert.run(
|
|
article.id,
|
|
article.groupIndex,
|
|
article.categoryIndex,
|
|
article.sectionIndex,
|
|
article.groupId,
|
|
article.categoryId,
|
|
article.sectionId,
|
|
article.author,
|
|
article.title,
|
|
article.description,
|
|
article.hero,
|
|
article.status,
|
|
article.date,
|
|
article.sourceUrl,
|
|
article.keywords.join(', '),
|
|
article.content,
|
|
article.path
|
|
)
|
|
|
|
await db.run(`DELETE FROM headings WHERE articleId = ?`, article.id)
|
|
|
|
await Promise.all(
|
|
getHeadingLinks(article.content ?? '').map((heading, i) =>
|
|
headingsInsert.run(
|
|
i,
|
|
article.id,
|
|
heading.level,
|
|
heading.title,
|
|
heading.slug,
|
|
heading.isCode,
|
|
`${article.path}#${heading.slug}`
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
const slugs = new GithubSlugger()
|
|
|
|
const MATCH_HEADINGS = /(?:^|\n)(#{1,6})\s+(.+?)(?=\n|$)/g
|
|
function getHeadingLinks(content: string) {
|
|
let match
|
|
const headings: ArticleHeadings = []
|
|
while ((match = MATCH_HEADINGS.exec(content)) !== null) {
|
|
slugs.reset()
|
|
headings.push({
|
|
level: match[1].length,
|
|
title: match[2].replaceAll('`', ''),
|
|
slug: slugs.slug(match[2], true),
|
|
isCode: match[2].startsWith('`'),
|
|
})
|
|
}
|
|
return headings
|
|
}
|