@brillout/docpress 0.6.8 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/docpress",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "// Build vite.config.ts and +config.ts": "",
@@ -15,6 +15,7 @@
15
15
  "release:breaking-change": "release-me minor"
16
16
  },
17
17
  "dependencies": {
18
+ "@brillout/picocolors": "^1.0.10",
18
19
  "@mdx-js/mdx": "3.0.1",
19
20
  "@mdx-js/react": "3.0.1",
20
21
  "@mdx-js/rollup": "3.0.1",
@@ -75,8 +76,8 @@
75
76
  "@types/react-dom": "^17.0.6",
76
77
  "react": "^18.2.0",
77
78
  "react-dom": "^18.2.0",
78
- "typescript": "^4.9.4",
79
- "vike": "^0.4.166",
79
+ "typescript": "^5.4.3",
80
+ "vike": "^0.4.167",
80
81
  "vite": "^5.2.2"
81
82
  },
82
83
  "repository": "https://github.com/brillout/docpress",
@@ -1,20 +1,19 @@
1
- export { markdownHeadingsVitePlugin }
2
- export type { MarkdownHeading }
1
+ export { parsePageSections }
2
+ export type { PageSection }
3
3
 
4
4
  import { assert } from './utils/assert.js'
5
5
  import { determineSectionUrlHash } from './utils/determineSectionUrlHash.js'
6
6
  import os from 'os'
7
7
 
8
- type MarkdownHeading = {
9
- title: string
10
- headingId: string | null
11
- headingLevel: number
12
- titleAddendum?: string
8
+ type PageSection = {
9
+ pageSectionTitle: string
10
+ pageSectionId: string | null
11
+ pageSectionLevel: number
13
12
  }
14
13
 
15
- function markdownHeadingsVitePlugin() {
14
+ function parsePageSections() {
16
15
  return {
17
- name: 'mdx-headings',
16
+ name: '@brillout/docpress:parsePageSections',
18
17
  enforce: 'pre',
19
18
  transform: async (code: string, id: string) => {
20
19
  if (!id.endsWith('+Page.mdx')) {
@@ -27,7 +26,7 @@ function markdownHeadingsVitePlugin() {
27
26
  }
28
27
 
29
28
  function transform(code: string) {
30
- const headings: MarkdownHeading[] = []
29
+ const pageSections: PageSection[] = []
31
30
  let isCodeBlock = false
32
31
  let codeNew = code
33
32
  .split('\n')
@@ -46,52 +45,49 @@ function transform(code: string) {
46
45
  }
47
46
 
48
47
  if (line.startsWith('#')) {
49
- const { headingId, headingLevel, title, headingHtml } = parseMarkdownHeading(line)
50
- headings.push({ headingId, headingLevel, title })
48
+ const { pageSectionId, pageSectionLevel, pageSectionTitle, headingHtml } = parsePageSection(line)
49
+ pageSections.push({ pageSectionId, pageSectionLevel, pageSectionTitle })
51
50
  return headingHtml
52
51
  }
53
52
 
54
53
  return line
55
54
  })
56
55
  .join('\n')
57
- const headingsExportCode = `export const headings = [${headings
58
- .map((heading) => JSON.stringify(heading))
56
+ const exportCode = `export const pageSectionsExport = [${pageSections
57
+ .map((pageSection) => JSON.stringify(pageSection))
59
58
  .join(', ')}];`
60
- codeNew += `\n\n${headingsExportCode}\n`
59
+ codeNew += `\n\n${exportCode}\n`
61
60
  return codeNew
62
61
  }
63
62
 
64
- function parseMarkdownHeading(line: string): MarkdownHeading & { headingHtml: string } {
63
+ function parsePageSection(line: string): PageSection & { headingHtml: string } {
65
64
  const [lineBegin, ...lineWords] = line.split(' ')
66
65
  assert(lineBegin.split('#').join('') === '', { line, lineWords })
67
- const headingLevel = lineBegin.length
66
+ const pageSectionLevel = lineBegin.length
68
67
 
69
68
  const titleMdx = lineWords.join(' ')
70
69
  assert(!titleMdx.startsWith(' '), { line, lineWords })
71
70
  assert(titleMdx, { line, lineWords })
72
71
 
73
- const headingMdx = {
74
- title: titleMdx,
75
- anchor: titleMdx,
76
- }
72
+ let pageSectionTitle = titleMdx
73
+ let anchor = titleMdx
77
74
  {
78
- // Support custom anchor like: `## title{#custom-anchor}`
75
+ // Support custom anchor: `## Some Title{#custom-anchor}`
79
76
  const customAnchor = /(?<={#).*(?=})/g.exec(titleMdx)?.[0]
80
77
  if (customAnchor) {
81
- headingMdx.anchor = customAnchor
82
- headingMdx.title = titleMdx.replace(/{#.*}/g, '')
78
+ anchor = customAnchor
79
+ pageSectionTitle = titleMdx.replace(/{#.*}/g, '')
83
80
  }
84
81
  }
85
- const headingId = determineSectionUrlHash(headingMdx.anchor)
86
- const title = headingMdx.title
82
+ const pageSectionId = determineSectionUrlHash(anchor)
87
83
 
88
- const titleParsed = parseTitle(title)
89
- assert(headingId === null || headingId.length > 0)
90
- const headingAttrId = headingId === null ? '' : ` id="${headingId}"`
91
- const headingHtml = `<h${headingLevel}${headingAttrId}>${titleParsed}</h${headingLevel}>`
84
+ const titleParsed = parseTitle(pageSectionTitle)
85
+ assert(pageSectionId === null || pageSectionId.length > 0)
86
+ const headingId = pageSectionId === null ? '' : ` id="${pageSectionId}"`
87
+ const headingHtml = `<h${pageSectionLevel}${headingId}>${titleParsed}</h${pageSectionLevel}>`
92
88
 
93
- const heading = { headingLevel, title, headingId, headingHtml }
94
- return heading
89
+ const pageSection = { pageSectionLevel, pageSectionTitle, pageSectionId, headingHtml }
90
+ return pageSection
95
91
  }
96
92
 
97
93
  function parseTitle(titleMarkdown: string): string {
package/parseTitle.ts CHANGED
@@ -1,91 +1,8 @@
1
1
  export { parseTitle }
2
- export { getHeadingsWithProcessedTitle }
2
+ export { withEmoji }
3
3
 
4
4
  import React from 'react'
5
- import type { HeadingDefinition, HeadingDetachedDefinition, Heading, HeadingDetached } from './types/Heading'
6
- import { assert, Emoji, EmojiName } from './utils/server'
7
-
8
- function getHeadingsWithProcessedTitle(config: {
9
- headings: HeadingDefinition[]
10
- headingsDetached: HeadingDetachedDefinition[]
11
- }): {
12
- headingsProcessed: Heading[]
13
- headingsDetachedProcessed: HeadingDetached[]
14
- } {
15
- const headingsWithoutBreadcrumb: Omit<Heading, 'headingsBreadcrumb'>[] = config.headings.map(
16
- (heading: HeadingDefinition) => {
17
- const titleProcessed: JSX.Element = parseTitle(heading.title)
18
-
19
- const titleInNav = heading.titleInNav || heading.title
20
- let titleInNavProcessed: JSX.Element
21
- titleInNavProcessed = parseTitle(titleInNav)
22
- if ('titleEmoji' in heading) {
23
- assert(heading.titleEmoji)
24
- titleInNavProcessed = withEmoji(heading.titleEmoji, titleInNavProcessed)
25
- }
26
-
27
- const headingProcessed: Omit<Heading, 'headingsBreadcrumb'> = {
28
- ...heading,
29
- title: titleProcessed,
30
- titleInNav: titleInNavProcessed,
31
- }
32
- return headingProcessed
33
- },
34
- )
35
-
36
- const headingsProcessed: Heading[] = []
37
- headingsWithoutBreadcrumb.forEach((heading) => {
38
- const headingsBreadcrumb = getHeadingsBreadcrumb(heading, headingsProcessed)
39
- headingsProcessed.push({
40
- ...heading,
41
- headingsBreadcrumb,
42
- })
43
- })
44
-
45
- const headingsDetachedProcessed = config.headingsDetached.map((headingsDetached) => {
46
- const { url, title } = headingsDetached
47
- assert(
48
- headingsProcessed.find((heading) => heading.url === url) === undefined,
49
- `remove ${headingsDetached.url} from headingsDetached`,
50
- )
51
- const titleProcessed = typeof title === 'string' ? parseTitle(title) : title
52
- return {
53
- ...headingsDetached,
54
- level: 2 as const,
55
- title: titleProcessed,
56
- titleInNav: titleProcessed,
57
- headingsBreadcrumb: null,
58
- }
59
- })
60
-
61
- assertHeadingsUrl([...headingsProcessed, ...headingsDetachedProcessed])
62
- return { headingsProcessed, headingsDetachedProcessed }
63
- }
64
-
65
- function getHeadingsBreadcrumb(heading: Omit<Heading, 'headingsBreadcrumb'>, headings: Heading[]) {
66
- const headingsBreadcrumb: Heading[] = []
67
- let levelCurrent = heading.level
68
- headings
69
- .slice()
70
- .reverse()
71
- .forEach((parentCandidate) => {
72
- const isParent = parentCandidate.level < levelCurrent
73
- if (isParent) {
74
- levelCurrent = parentCandidate.level
75
- headingsBreadcrumb.push(parentCandidate)
76
- }
77
- })
78
- return headingsBreadcrumb
79
- }
80
-
81
- function assertHeadingsUrl(headings: { url?: null | string }[]) {
82
- headings.forEach((heading) => {
83
- if (heading.url) {
84
- const { url } = heading
85
- assert(url.startsWith('/'))
86
- }
87
- })
88
- }
5
+ import { Emoji, EmojiName } from './utils/server'
89
6
 
90
7
  function parseTitle(title: string): JSX.Element {
91
8
  type Part = { nodeType: 'text' | 'code'; content: string }
@@ -34,11 +34,15 @@ async function onRenderHtml(pageContextOriginal: PageContextOriginal) {
34
34
  <head>
35
35
  <meta charset="UTF-8" />
36
36
  <link rel="icon" href="${pageContextResolved.meta.faviconUrl}" />
37
- <title>${pageContextResolved.meta.title}</title>
37
+ <title>${pageContextResolved.documentTitle}</title>
38
38
  ${descriptionTag}
39
39
  <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
40
40
  ${docSearchCSS}
41
- ${getOpenGraphTags(pageContextOriginal.urlPathname, pageContextResolved.meta)}
41
+ ${getOpenGraphTags(
42
+ pageContextOriginal.urlPathname,
43
+ pageContextResolved.documentTitle,
44
+ pageContextResolved.meta,
45
+ )}
42
46
  </head>
43
47
  <body>
44
48
  <div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
@@ -49,9 +53,10 @@ async function onRenderHtml(pageContextOriginal: PageContextOriginal) {
49
53
 
50
54
  function getOpenGraphTags(
51
55
  url: string,
52
- meta: { title: string; tagline: string; websiteUrl: string; twitterHandle: string; bannerUrl?: string },
56
+ documentTitle: string,
57
+ meta: { tagline: string; websiteUrl: string; twitterHandle: string; bannerUrl?: string },
53
58
  ) {
54
- const { title, tagline, websiteUrl, twitterHandle, bannerUrl } = meta
59
+ const { tagline, websiteUrl, twitterHandle, bannerUrl } = meta
55
60
 
56
61
  assert(url.startsWith('/'))
57
62
  if (!bannerUrl) return ''
@@ -59,7 +64,7 @@ function getOpenGraphTags(
59
64
  // See view-source:https://vitejs.dev/
60
65
  return escapeInject`
61
66
  <meta property="og:type" content="website">
62
- <meta property="og:title" content="${title}">
67
+ <meta property="og:title" content="${documentTitle}">
63
68
  <meta property="og:image" content="${bannerUrl}">
64
69
  <meta property="og:url" content="${websiteUrl}">
65
70
  <meta property="og:description" content="${tagline}">
package/types/Heading.ts CHANGED
@@ -1,49 +1,51 @@
1
- export { Heading }
2
- export { HeadingDetached }
1
+ export { HeadingResolved }
2
+ export { HeadingDetachedResolved }
3
3
  export { HeadingDetachedDefinition }
4
4
  export { HeadingDefinition }
5
5
 
6
6
  import type { EmojiName } from '../utils/server'
7
7
 
8
- type Heading = Omit<HeadingDefinition, 'title' | 'titleInNav'> & {
8
+ type HeadingResolved = {
9
+ url?: null | string
10
+ level: number
9
11
  title: JSX.Element
10
12
  titleInNav: JSX.Element
11
- headingsBreadcrumb: (Heading | HeadingDetached)[]
13
+ linkBreadcrumb: JSX.Element[]
12
14
  sectionTitles?: string[]
13
- }
14
- type HeadingDetached = Omit<Heading, 'level' | 'headingsBreadcrumb'> & {
15
+ } & Tmp
16
+
17
+ type HeadingDetachedResolved = Omit<HeadingResolved, 'level' | 'linkBreadcrumb'> & {
15
18
  level: 2
16
- headingsBreadcrumb: null
19
+ linkBreadcrumb: null
17
20
  }
21
+
18
22
  type HeadingDetachedDefinition = {
19
23
  url: string
20
24
  title: string | JSX.Element
21
25
  sectionTitles?: string[]
22
26
  }
23
- type HeadingDefinition = HeadingBase &
24
- (
25
- | ({ level: 1; titleEmoji: EmojiName } & HeadingAbstract)
26
- | ({ level: 4 } & HeadingAbstract)
27
- | {
28
- level: 2
29
- sectionTitles?: string[]
30
- url: null | string
31
- }
32
- | {
33
- level: 3
34
- url: null | string
35
- }
36
- )
37
- type HeadingBase = {
38
- title: string
39
- level: number
27
+
28
+ type HeadingDefinition = {
40
29
  url?: null | string
41
- titleDocument?: string
30
+ title: string
42
31
  titleInNav?: string
43
- // titleSize?: string
44
- }
45
- type HeadingAbstract = {
32
+ } & HeadingDefinitionLevel &
33
+ Tmp
34
+ type IsCategory = {
46
35
  url?: undefined
47
36
  titleDocument?: undefined
48
37
  titleInNav?: undefined
49
38
  }
39
+ type HeadingDefinitionLevel =
40
+ | ({ level: 1; titleEmoji: EmojiName } & IsCategory)
41
+ | ({ level: 4 } & IsCategory)
42
+ | {
43
+ level: 2
44
+ sectionTitles?: string[]
45
+ url: null | string
46
+ }
47
+
48
+ type Tmp = {
49
+ // TODO: remove? Both Vike and Telefunc set it to the same value than docpress.config.js#projectInfo.projectName
50
+ titleDocument?: string
51
+ }
package/types.d.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  declare module '*.mdx' {
4
4
  const value: () => JSX.Element
5
5
  export default value
6
- export const headings: { level: number; title: string; id: string; titleAddendum?: string }[]
6
+ export const headings: { level: number; title: string; id: string }[]
7
7
  }
package/vite.config.ts CHANGED
@@ -2,7 +2,7 @@ import mdx from '@mdx-js/rollup'
2
2
  import react from '@vitejs/plugin-react-swc'
3
3
  import vike from 'vike/plugin'
4
4
  import { UserConfig } from 'vite'
5
- import { markdownHeadingsVitePlugin } from './markdownHeadingsVitePlugin.js'
5
+ import { parsePageSections } from './parsePageSections.js'
6
6
  import rehypePrettyCode from 'rehype-pretty-code'
7
7
  import remarkGfm from 'remark-gfm'
8
8
  import { transformerNotationDiff } from '@shikijs/transformers'
@@ -15,7 +15,7 @@ const remarkPlugins = [remarkGfm]
15
15
  const config: UserConfig = {
16
16
  root,
17
17
  plugins: [
18
- markdownHeadingsVitePlugin(),
18
+ parsePageSections(),
19
19
  mdx({ rehypePlugins, remarkPlugins }),
20
20
  // @vitejs/plugin-react-swc needs to be added *after* the mdx plugins
21
21
  react(),
@@ -1,13 +0,0 @@
1
- export { markdownHeadingsVitePlugin };
2
- export type { MarkdownHeading };
3
- type MarkdownHeading = {
4
- title: string;
5
- headingId: string | null;
6
- headingLevel: number;
7
- titleAddendum?: string;
8
- };
9
- declare function markdownHeadingsVitePlugin(): {
10
- name: string;
11
- enforce: string;
12
- transform: (code: string, id: string) => Promise<string | undefined>;
13
- };