このコミットが含まれているのは:
+92
-35
@@ -1,49 +1,61 @@
|
||||
import { parse } from 'yaml'
|
||||
import { parse as parseYAML } from 'yaml'
|
||||
|
||||
import type { ComponentType } from 'react'
|
||||
|
||||
type ArticleLanguage = {
|
||||
title: string
|
||||
currentEdition: string }
|
||||
type ArticleLanguage = { currentEdition: string }
|
||||
|
||||
type ArticleMeta = {
|
||||
identifier: string
|
||||
canonicalLanguage: string
|
||||
languages: Record<string, ArticleLanguage> }
|
||||
identifier: string
|
||||
languages: Record<string, ArticleLanguage> }
|
||||
|
||||
type MdxModule = { default: ComponentType }
|
||||
type MDXModule = { default: ComponentType }
|
||||
|
||||
export type HelpEditionText = {
|
||||
title: string
|
||||
body: string }
|
||||
|
||||
export type HelpSearchEntry = HelpEditionText & {
|
||||
identifier: string
|
||||
edition: string }
|
||||
|
||||
const articleFiles = import.meta.glob<string> ('../../help/*/article.yml',
|
||||
{ query: '?raw',
|
||||
import: 'default',
|
||||
eager: true })
|
||||
|
||||
const editionFiles = import.meta.glob<MDXModule> ('../../help/*/editions/*/*.mdx')
|
||||
|
||||
const rawEditionFiles = import.meta.glob<string> ('../../help/*/editions/*/*.mdx',
|
||||
{ query: '?raw',
|
||||
import: 'default' })
|
||||
|
||||
|
||||
const articleFiles = import.meta.glob<string> (
|
||||
'../../help/*/article.yml',
|
||||
{ query: '?raw', import: 'default', eager: true, })
|
||||
|
||||
const editionFiles = import.meta.glob<MdxModule> ('../../help/*/editions/*/*.mdx')
|
||||
|
||||
|
||||
const cameliseArticle = (value: {
|
||||
identifier: string
|
||||
canonical_language: string
|
||||
languages: Record<string, {
|
||||
title: string
|
||||
current_edition: string }> }): ArticleMeta => (
|
||||
{ identifier: value.identifier,
|
||||
canonicalLanguage: value.canonical_language,
|
||||
const cameliseArticle = (
|
||||
value: { identifier: string
|
||||
languages: Record<string, { ['current_edition']: string }> },
|
||||
): ArticleMeta => (
|
||||
{ identifier: value.identifier,
|
||||
languages: Object.fromEntries (
|
||||
Object.entries (value.languages).map (([language, data]) => [
|
||||
language,
|
||||
{ title: data.title,
|
||||
currentEdition: data.current_edition, }])) })
|
||||
language, { currentEdition: data['current_edition'] }])) })
|
||||
|
||||
|
||||
export const getHelpArticle = (identifier: string): ArticleMeta | undefined => {
|
||||
const path = `../../help/${identifier}/article.yml`
|
||||
const compareEditions = (a: string, b: string): number => {
|
||||
const [dateA, revisionA = '1'] = a.split ('.')
|
||||
const [dateB, revisionB = '1'] = b.split ('.')
|
||||
|
||||
return dateA.localeCompare (dateB) || Number (revisionA) - Number (revisionB)
|
||||
}
|
||||
|
||||
|
||||
export const getHelpArticle = (identifier: string): ArticleMeta | null => {
|
||||
const path = `../../help/${ identifier }/article.yml`
|
||||
const source = articleFiles[path]
|
||||
|
||||
if (!(source))
|
||||
return undefined
|
||||
return null
|
||||
|
||||
return cameliseArticle (parse (source))
|
||||
return cameliseArticle (parseYAML (source))
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +63,12 @@ export const getHelpEditions = (
|
||||
identifier: string,
|
||||
language: string,
|
||||
): string[] => {
|
||||
const prefix = `../../help/${identifier}/editions/${language}/`
|
||||
const prefix = `../../help/${ identifier }/editions/${ language }/`
|
||||
|
||||
return (Object.keys (editionFiles)
|
||||
.filter (path => path.startsWith (prefix))
|
||||
.map (path => path.slice (prefix.length, -'.mdx'.length))
|
||||
.sort ())
|
||||
.sort (compareEditions))
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +76,57 @@ export const getHelpEdition = async (
|
||||
identifier: string,
|
||||
language: string,
|
||||
edition: string,
|
||||
): Promise<ComponentType | undefined> => {
|
||||
const path = `../../help/${identifier}/editions/${language}/${edition}.mdx`
|
||||
): Promise<ComponentType | null> => {
|
||||
const path = `../../help/${ identifier }/editions/${ language }/${ edition }.mdx`
|
||||
const loader = editionFiles[path]
|
||||
|
||||
if (!(loader))
|
||||
return undefined
|
||||
return null
|
||||
|
||||
return (await loader ()).default
|
||||
}
|
||||
|
||||
|
||||
export const getHelpEditionText = async (
|
||||
identifier: string,
|
||||
language: string,
|
||||
edition: string,
|
||||
): Promise<HelpEditionText | null> => {
|
||||
const path = `../../help/${ identifier }/editions/${ language }/${ edition }.mdx`
|
||||
const loader = rawEditionFiles[path]
|
||||
|
||||
if (!(loader))
|
||||
return null
|
||||
|
||||
const mdx = (await loader ()).replace (/^\uFEFF/, '')
|
||||
const heading = mdx.match (/^# +([^\r\n]+)(?:\r?\n|$)/)
|
||||
|
||||
if (!(heading))
|
||||
throw new Error (`Help MDX の先頭に H1 がありません: ${ path }`)
|
||||
|
||||
return { title: heading[1].trim (),
|
||||
body: mdx.slice (heading[0].length) }
|
||||
}
|
||||
|
||||
|
||||
export const getHelpSearchEntries = async (
|
||||
language: string,
|
||||
): Promise<HelpSearchEntry[]> => {
|
||||
const entries = await Promise.all (
|
||||
Object.values (articleFiles).map (async source => {
|
||||
const article = cameliseArticle (parseYAML (source))
|
||||
const edition = article.languages[language]?.currentEdition
|
||||
|
||||
if (!(edition))
|
||||
return null
|
||||
|
||||
const content = await getHelpEditionText (article.identifier, language, edition)
|
||||
|
||||
if (!(content))
|
||||
throw new Error (`Help edition が見つかりません: ${ article.identifier }/${ edition }`)
|
||||
|
||||
return { identifier: article.identifier, edition, ...content }
|
||||
}))
|
||||
|
||||
return entries.filter ((entry): entry is HelpSearchEntry => entry != null)
|
||||
}
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする