valaxy 0.4.0 → 0.6.1

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.
Files changed (155) hide show
  1. package/README.md +0 -4
  2. package/{src/client → client}/App.vue +0 -0
  3. package/{src/client/composables/search/index.ts → client/app/data.ts} +0 -0
  4. package/{src/client → client}/components/AppLink.vue +0 -0
  5. package/client/components/PostCard.vue +84 -0
  6. package/{src/client → client}/components/PostList.vue +0 -0
  7. package/{src/client → client}/components/README.md +0 -0
  8. package/{src/client → client}/components/ValaxyBg.vue +0 -0
  9. package/{src/client → client}/components/ValaxyCopyright.vue +0 -0
  10. package/{src/client → client}/components/ValaxyFooter.vue +1 -1
  11. package/{src/client → client}/components/ValaxyHamburger.vue +0 -0
  12. package/client/components/ValaxyMd.vue +74 -0
  13. package/{src/client → client}/components/ValaxyOverlay.vue +0 -0
  14. package/{src/client → client}/components/ValaxyPagination.vue +0 -0
  15. package/{src/client → client}/components/ValaxyRightSidebar.vue +0 -0
  16. package/{src/client → client}/components/ValaxySidebar.vue +0 -0
  17. package/{src/client → client}/components/ValaxyToc.vue +3 -3
  18. package/{src/client → client}/composables/category.ts +0 -0
  19. package/{src/client → client}/composables/comments/index.ts +0 -0
  20. package/{src/client → client}/composables/comments/twikoo.ts +0 -0
  21. package/{src/client → client}/composables/comments/waline.ts +0 -0
  22. package/{src/client → client}/composables/common.ts +0 -0
  23. package/client/composables/copy-code.ts +92 -0
  24. package/{src/client → client}/composables/dark.ts +0 -0
  25. package/client/composables/features/index.ts +0 -0
  26. package/{src/client → client}/composables/helper.ts +0 -0
  27. package/{src/client → client}/composables/index.ts +1 -1
  28. package/{src/client → client}/composables/layout.ts +0 -0
  29. package/client/composables/outline.ts +168 -0
  30. package/{src/client → client}/composables/post.ts +0 -0
  31. package/client/composables/search/index.ts +0 -0
  32. package/{src/client → client}/composables/sidebar.ts +46 -1
  33. package/{src/client → client}/composables/tag.ts +0 -0
  34. package/{src/client → client}/composables/widgets/aplayer.ts +0 -0
  35. package/{src/client → client}/composables/widgets/backToTop.ts +0 -0
  36. package/{src/client → client}/composables/widgets/codepen.ts +0 -0
  37. package/{src/client → client}/composables/widgets/index.ts +0 -0
  38. package/client/config.ts +75 -0
  39. package/{src/client → client}/index.html +0 -0
  40. package/{src/client → client}/index.ts +0 -0
  41. package/{src/client → client}/layouts/404.vue +0 -0
  42. package/{src/client → client}/layouts/README.md +0 -0
  43. package/{src/client → client}/locales/README.md +0 -0
  44. package/{src/client → client}/locales/en.yml +1 -0
  45. package/{src/client → client}/locales/zh-CN.yml +4 -3
  46. package/{src/client → client}/main.ts +4 -1
  47. package/{src/client → client}/modules/README.md +0 -0
  48. package/{src/client → client}/modules/nprogress.ts +0 -0
  49. package/{src/client → client}/modules/pinia.ts +0 -0
  50. package/{src/client → client}/modules/valaxy.ts +19 -7
  51. package/{src/client → client}/pages/README.md +0 -0
  52. package/{src/client → client}/pages/[...all].vue +0 -0
  53. package/{src/client → client}/pages/hi/[name].vue +0 -0
  54. package/{src/client → client}/pages/index.vue +0 -0
  55. package/{src/client → client}/pages/page/[page].vue +0 -0
  56. package/{src/client → client}/shims.d.ts +7 -1
  57. package/{src/client → client}/stores/app.ts +0 -0
  58. package/{src/client → client}/stores/user.ts +0 -0
  59. package/{src/client → client}/styles/common/button.scss +0 -0
  60. package/client/styles/common/code.scss +231 -0
  61. package/{src/client → client}/styles/common/custom-blocks.scss +0 -0
  62. package/{src/client → client}/styles/common/hamburger.scss +0 -0
  63. package/{src/client → client}/styles/common/markdown.scss +0 -2
  64. package/client/styles/common/scrollbar.scss +28 -0
  65. package/{src/client → client}/styles/common/sidebar.scss +0 -0
  66. package/{src/client → client}/styles/common/transition.scss +0 -0
  67. package/client/styles/css-vars.scss +62 -0
  68. package/{src/client → client}/styles/global/helper.scss +0 -0
  69. package/{src/client → client}/styles/global/i18n.scss +0 -0
  70. package/{src/client → client}/styles/global/index.scss +0 -0
  71. package/{src/client → client}/styles/global/nprogress.scss +0 -0
  72. package/{src/client → client}/styles/global/reset.scss +0 -0
  73. package/{src/client → client}/styles/index.scss +0 -0
  74. package/{src/client → client}/styles/mixins/config.scss +0 -0
  75. package/{src/client → client}/styles/mixins/index.scss +0 -0
  76. package/{src/client → client}/styles/mixins/size.scss +0 -0
  77. package/{src/client → client}/styles/mixins/variable.scss +0 -0
  78. package/{src/client → client}/styles/palette.scss +21 -2
  79. package/client/styles/third/katex.scss +3 -0
  80. package/client/styles/vars.scss +41 -0
  81. package/{src/client → client}/styles/widgets/banner.scss +0 -0
  82. package/{src/client → client}/types.ts +0 -0
  83. package/{src/client → client}/utils/helper.ts +22 -0
  84. package/{src/client → client}/utils/index.ts +0 -0
  85. package/client/utils/sidebar.ts +26 -0
  86. package/{src/client → client}/utils/time.ts +0 -0
  87. package/config/index.ts +18 -0
  88. package/dist/chunk-EAN2KU6W.mjs +1 -0
  89. package/dist/chunk-HMUGSKPK.mjs +40 -0
  90. package/dist/chunk-U5OMNIOK.js +1 -0
  91. package/dist/chunk-ZHHNO5RK.js +40 -0
  92. package/dist/{config-de04677b.d.ts → config-112ac884.d.ts} +37 -14
  93. package/dist/index.d.ts +65 -111
  94. package/dist/index.js +1 -1
  95. package/dist/index.mjs +1 -1
  96. package/dist/node/cli.js +7 -11
  97. package/dist/node/cli.mjs +7 -11
  98. package/dist/node/index.d.ts +3 -2
  99. package/dist/node/index.js +1 -1
  100. package/dist/node/index.mjs +1 -1
  101. package/{src/index.ts → index.ts} +1 -0
  102. package/{src/node → node}/build.ts +0 -0
  103. package/{src/node → node}/cli.ts +3 -2
  104. package/node/config.ts +156 -0
  105. package/{src/node → node}/index.ts +0 -0
  106. package/{src/node → node}/markdown/check.ts +0 -0
  107. package/node/markdown/highlight.ts +38 -0
  108. package/{src/node → node}/markdown/index.ts +30 -16
  109. package/{src/node → node}/markdown/markdown-it/container.ts +0 -0
  110. package/{src/node → node}/markdown/markdown-it/headings.ts +0 -0
  111. package/{src/node → node}/markdown/markdown-it/highlightLines.ts +1 -1
  112. package/{src/node → node}/markdown/markdown-it/katex.ts +0 -0
  113. package/{src/node → node}/markdown/markdown-it/parseHeader.ts +0 -0
  114. package/node/markdown/markdownToVue.ts +274 -0
  115. package/{src/node → node}/markdown/slugify.ts +0 -0
  116. package/{src/node → node}/options.ts +18 -2
  117. package/{src/node → node}/plugins/extendConfig.ts +5 -3
  118. package/node/plugins/index.ts +224 -0
  119. package/{src/node → node}/plugins/preset.ts +8 -8
  120. package/{src/node → node}/plugins/unocss.ts +0 -0
  121. package/{src/node → node}/plugins/valaxy.ts +0 -0
  122. package/{src/node → node}/rss.ts +1 -1
  123. package/{src/node → node}/server.ts +0 -0
  124. package/{src/node → node}/shims.d.ts +0 -5
  125. package/{src/node → node}/utils/cli.ts +1 -1
  126. package/node/utils/getGitTimestamp.ts +13 -0
  127. package/node/utils/index.ts +59 -0
  128. package/node/utils/net.ts +20 -0
  129. package/{src/node → node}/vite.ts +5 -1
  130. package/package.json +32 -13
  131. package/shared/index.ts +1 -0
  132. package/tsup.config.ts +7 -4
  133. package/{src/types → types}/config.ts +31 -108
  134. package/types/data.ts +31 -0
  135. package/{src/types → types}/index.ts +1 -0
  136. package/{src/types → types}/posts.ts +6 -1
  137. package/dist/chunk-6LIOFBAA.mjs +0 -1
  138. package/dist/chunk-HRARZPSA.js +0 -83
  139. package/dist/chunk-N6HD5SHF.mjs +0 -83
  140. package/dist/chunk-V3BMKLEW.js +0 -1
  141. package/src/client/components/PostCard.vue +0 -68
  142. package/src/client/components/ValaxyMd.vue +0 -71
  143. package/src/client/composables/features/index.ts +0 -1
  144. package/src/client/composables/features/katex.ts +0 -15
  145. package/src/client/composables/search/algolia.ts +0 -115
  146. package/src/client/config.ts +0 -51
  147. package/src/client/styles/common/code.scss +0 -207
  148. package/src/client/styles/common/scrollbar.scss +0 -34
  149. package/src/client/styles/css-vars.scss +0 -39
  150. package/src/client/styles/vars.scss +0 -27
  151. package/src/node/config.ts +0 -52
  152. package/src/node/markdown/highlight.ts +0 -50
  153. package/src/node/plugins/index.ts +0 -120
  154. package/src/node/plugins/markdown.ts +0 -57
  155. package/src/node/utils/index.ts +0 -26
@@ -1,12 +1,12 @@
1
1
  import * as vite from 'vite';
2
2
  import { InlineConfig } from 'vite';
3
- import { V as ValaxyConfig } from '../config-de04677b.js';
3
+ import { V as ValaxyConfig } from '../config-112ac884.js';
4
4
  import 'type-fest';
5
5
  import 'unocss/vite';
6
6
  import 'markdown-it';
7
+ import 'shiki';
7
8
  import 'markdown-it-anchor';
8
9
  import 'katex';
9
- import 'vite-plugin-md';
10
10
 
11
11
  interface ResolvedValaxyOptions {
12
12
  mode: 'dev' | 'build';
@@ -36,6 +36,7 @@ interface ResolvedValaxyOptions {
36
36
  * config file path
37
37
  */
38
38
  configFile: string;
39
+ pages: string[];
39
40
  }
40
41
  interface ValaxyServerOptions {
41
42
  onConfigReload?: (newConfig: ValaxyConfig, config: ValaxyConfig) => void;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkHRARZPSAjs = require('../chunk-HRARZPSA.js');require('../chunk-V3BMKLEW.js');exports.createServer = _chunkHRARZPSAjs.g;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkZHHNO5RKjs = require('../chunk-ZHHNO5RK.js');require('../chunk-U5OMNIOK.js');exports.createServer = _chunkZHHNO5RKjs.f;
@@ -1 +1 @@
1
- import{g as o}from"../chunk-N6HD5SHF.mjs";import"../chunk-6LIOFBAA.mjs";export{o as createServer};
1
+ import{f as o}from"../chunk-HMUGSKPK.mjs";import"../chunk-EAN2KU6W.mjs";export{o as createServer};
@@ -1,2 +1,3 @@
1
1
  export * from './client'
2
2
  export * from './types'
3
+ export * from './config'
File without changes
@@ -9,7 +9,8 @@ import openBrowser from 'open'
9
9
  import consola from 'consola'
10
10
 
11
11
  import { yellow } from 'kolorist'
12
- import { version } from '../../package.json'
12
+ import { version } from '../package.json'
13
+ import { findFreePort } from './utils/net'
13
14
  import { resolveOptions } from './options'
14
15
  import { bindShortcut, initServer, printInfo } from './utils/cli'
15
16
 
@@ -59,7 +60,7 @@ cli.command(
59
60
  if (!fs.existsSync(path.resolve(root, 'pages')))
60
61
  process.exit(0)
61
62
 
62
- const port = userPort || 4859
63
+ const port = await findFreePort(userPort || 4859)
63
64
  const options = await resolveOptions({ userRoot: root })
64
65
 
65
66
  const viteConfig: InlineConfig = {
package/node/config.ts ADDED
@@ -0,0 +1,156 @@
1
+ // import { loadConfig } from 'c12'
2
+ import fs from 'fs'
3
+ import { loadConfig } from 'unconfig'
4
+ import defu from 'defu'
5
+ import type { ValaxyConfig } from '../types'
6
+ import type { ValaxyEntryOptions } from './options'
7
+
8
+ const defaultValaxyConfig: ValaxyConfig = {
9
+ url: '/',
10
+ lang: 'en',
11
+ title: 'Valaxy Blog',
12
+ description: 'A blog generated by Valaxy.',
13
+ subtitle: 'Next Generation Static Blog Framework.',
14
+ author: {
15
+ avatar: 'https://cdn.jsdelivr.net/gh/YunYouJun/yun/images/meme/yun-good-with-bg.jpg',
16
+ email: 'me@yunyoujun.cn',
17
+ link: 'https://www.yunyoujun.cn',
18
+ name: 'YunYouJun',
19
+ status: {
20
+ emoji: '😊',
21
+ message: 'All at sea.',
22
+ },
23
+ },
24
+ favicon: '/favicon.svg',
25
+ feed: {
26
+ name: '',
27
+ favicon: 'favicon.svg',
28
+ },
29
+ social: [],
30
+
31
+ lastUpdated: true,
32
+
33
+ license: {
34
+ enabled: true,
35
+ language: '',
36
+ type: 'by-nc-sa',
37
+ },
38
+
39
+ sponsor: {
40
+ enable: true,
41
+ title: '我很可爱,请给我钱',
42
+ methods: [
43
+ {
44
+ name: '支付宝',
45
+ url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/alipay-qrcode.jpg',
46
+ color: '#00A3EE',
47
+ icon: 'i-ri-alipay-line',
48
+ },
49
+ {
50
+ name: 'QQ 支付',
51
+ url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/qqpay-qrcode.png',
52
+ color: '#12B7F5',
53
+ icon: 'i-ri-qq-line',
54
+ },
55
+ {
56
+ name: '微信支付',
57
+ url: 'https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/donate/wechatpay-qrcode.jpg',
58
+ color: '#2DC100',
59
+ icon: 'i-ri-wechat-pay-line',
60
+ },
61
+
62
+ ],
63
+ },
64
+
65
+ search: {
66
+ enable: true,
67
+ algolia: {
68
+ enable: false,
69
+ appId: '',
70
+ apiKey: '',
71
+ indexName: '',
72
+ },
73
+ },
74
+
75
+ comment: {
76
+ waline: {
77
+ enable: false,
78
+ serverURL: '',
79
+ },
80
+ twikoo: {
81
+ enable: false,
82
+ envId: 'https://twikoo.vercel.app',
83
+ },
84
+ },
85
+
86
+ features: {
87
+ katex: true,
88
+ },
89
+
90
+ theme: 'yun',
91
+ themeConfig: {
92
+ pkg: {
93
+ name: '',
94
+ version: '',
95
+ },
96
+ },
97
+
98
+ unocss: {},
99
+
100
+ // markdown: {
101
+ // excerpt: '<!-- more -->',
102
+ // },
103
+
104
+ markdownIt: {
105
+ toc: {
106
+ includeLevel: [1, 2, 3, 4],
107
+ listType: 'ol',
108
+ },
109
+ katex: {},
110
+ },
111
+ }
112
+
113
+ // for user config
114
+ export async function resolveConfig(options: ValaxyEntryOptions = {}) {
115
+ // c12 merge array twice, so i deprecated it
116
+ // const { config, configFile } = await loadConfig<ValaxyConfig>({
117
+ // name: 'valaxy',
118
+ // defaults: defaultValaxyConfig,
119
+ // })
120
+
121
+ const { config: userConfig, sources } = await loadConfig<ValaxyConfig>({
122
+ sources: [
123
+ {
124
+ files: 'valaxy.config',
125
+ extensions: ['ts', 'js', 'mjs', 'cjs', 'json'],
126
+ },
127
+ ],
128
+ merge: false,
129
+ })
130
+ const configFile = sources[0]
131
+ const config = defu(userConfig, defaultValaxyConfig)
132
+
133
+ const theme = options.theme || config.theme || 'yun'
134
+
135
+ try {
136
+ const { defaultThemeConfig } = await import(`valaxy-theme-${theme}`)
137
+ config.themeConfig = defu(config.themeConfig, defaultThemeConfig)
138
+ }
139
+ catch (e) {
140
+ console.error(`valaxy-theme-${theme} doesn't have default config`)
141
+ }
142
+
143
+ try {
144
+ const pkg = fs.readFileSync(require.resolve(`valaxy-theme-${theme}/package.json`), 'utf-8')
145
+ config.themeConfig.pkg = JSON.parse(pkg)
146
+ }
147
+ catch (e) {
148
+ console.error(`valaxy-theme-${theme} doesn't have package.json`)
149
+ }
150
+
151
+ return {
152
+ config,
153
+ configFile,
154
+ theme,
155
+ }
156
+ }
File without changes
File without changes
@@ -0,0 +1,38 @@
1
+ import { getHighlighter } from 'shiki'
2
+ import consola from 'consola'
3
+ import type { ThemeOptions } from '../markdown'
4
+
5
+ export async function highlight(theme: ThemeOptions = 'material-palenight') {
6
+ const themes = typeof theme === 'string' ? [theme] : [theme.dark, theme.light]
7
+ const highlighter = await getHighlighter({ themes })
8
+ const preRE = /^<pre.*?>/
9
+
10
+ return (str: string, lang: string) => {
11
+ lang = lang || 'text'
12
+
13
+ // https://stackoverflow.com/questions/22268952/what-is-the-difference-between-yaml-and-yml-extension
14
+ // use yaml better
15
+
16
+ // adaptive
17
+ if (lang === 'yml') {
18
+ lang = 'yaml'
19
+ consola.warn('[shiki] It is recommended to use `.yaml` instead of `.yml`.')
20
+ }
21
+
22
+ if (typeof theme === 'string') {
23
+ return highlighter
24
+ .codeToHtml(str, { lang, theme })
25
+ .replace(preRE, '<pre v-pre>')
26
+ }
27
+
28
+ const dark = highlighter
29
+ .codeToHtml(str, { lang, theme: theme.dark })
30
+ .replace(preRE, '<pre v-pre class="vp-code-dark">')
31
+
32
+ const light = highlighter
33
+ .codeToHtml(str, { lang, theme: theme.light })
34
+ .replace(preRE, '<pre v-pre class="vp-code-light">')
35
+
36
+ return dark + light
37
+ }
38
+ }
@@ -1,4 +1,6 @@
1
- import type MarkdownIt from 'markdown-it'
1
+ import MarkdownIt from 'markdown-it'
2
+
3
+ import type { Theme } from 'shiki'
2
4
 
3
5
  import Anchor from 'markdown-it-anchor'
4
6
  import Emoji from 'markdown-it-emoji'
@@ -8,23 +10,16 @@ import TaskLists from 'markdown-it-task-lists'
8
10
  import attrs from 'markdown-it-attrs'
9
11
 
10
12
  import type { KatexOptions } from 'katex'
13
+ import type { Header } from '../../types'
11
14
  import Katex from './markdown-it/katex'
12
15
  import { containerPlugin } from './markdown-it/container'
13
- // import { headingPlugin } from './markdown-it/headings'
16
+ import { headingPlugin } from './markdown-it/headings'
14
17
  import { slugify } from './slugify'
15
18
  import { parseHeader } from './markdown-it/parseHeader'
16
19
  import { highlight } from './highlight'
17
20
  import { highlightLinePlugin, preWrapperPlugin } from './markdown-it/highlightLines'
18
21
 
19
- export interface Header {
20
- level: number
21
- title: string
22
- slug: string
23
- /**
24
- * i18n
25
- */
26
- lang?: string
27
- }
22
+ export type ThemeOptions = Theme | { light: Theme; dark: Theme }
28
23
 
29
24
  export interface MarkdownParsedData {
30
25
  hoistedTags?: string[]
@@ -32,6 +27,8 @@ export interface MarkdownParsedData {
32
27
  headers?: Header[]
33
28
  }
34
29
  export interface MarkdownRenderer extends MarkdownIt {
30
+ __path: string
31
+ __relativePath: string
35
32
  __data: MarkdownParsedData
36
33
  }
37
34
 
@@ -46,12 +43,13 @@ export interface MarkdownOptions extends MarkdownIt.Options {
46
43
  [key: string]: any
47
44
  }
48
45
  katex?: KatexOptions
46
+ /**
47
+ * shiki
48
+ */
49
+ theme?: ThemeOptions
49
50
  }
50
51
 
51
- export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
52
- md.set({
53
- highlight,
54
- })
52
+ export async function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
55
53
  md
56
54
  .use(highlightLinePlugin)
57
55
  .use(preWrapperPlugin)
@@ -59,7 +57,7 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
59
57
  // conflict with {% %}
60
58
  .use(attrs)
61
59
  // generate toc in client
62
- // .use(headingPlugin, mdOptions?.toc?.includeLevel)
60
+ .use(headingPlugin, mdOptions?.toc?.includeLevel)
63
61
  // .use(lineNumberPlugin)
64
62
  // https://github.com/arve0/markdown-it-attrs
65
63
  // add classes
@@ -93,3 +91,19 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
93
91
 
94
92
  return md as MarkdownRenderer
95
93
  }
94
+
95
+ export const createMarkdownRenderer = async (
96
+ srcDir: string,
97
+ options: MarkdownOptions = {},
98
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
99
+ base = '/',
100
+ ): Promise<MarkdownRenderer> => {
101
+ const md = MarkdownIt({
102
+ html: true,
103
+ linkify: true,
104
+ highlight: await highlight(options.theme),
105
+ ...options,
106
+ }) as MarkdownRenderer
107
+ await setupMarkdownPlugins(md)
108
+ return md
109
+ }
@@ -65,7 +65,7 @@ export const preWrapperPlugin = (md: MarkdownIt) => {
65
65
  const [tokens, idx] = args
66
66
  const token = tokens[idx]
67
67
  const rawCode = fence(...args)
68
- return `<div class="language-${token.info.trim()}">${rawCode}</div>`
68
+ return `<div class="language-${token.info.trim()}"><span class="copy"></span>${rawCode}</div>`
69
69
  }
70
70
  }
71
71
 
File without changes
@@ -0,0 +1,274 @@
1
+ // copy from vitepress
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+ import c from 'picocolors'
5
+ import matter from 'gray-matter'
6
+ import LRUCache from 'lru-cache'
7
+ import _debug from 'debug'
8
+ import { getGitTimestamp, slash, transformObject } from '../utils'
9
+ import { EXTERNAL_URL_RE } from '../../shared'
10
+ import type { HeadConfig, PageData } from '../../types'
11
+ import { deeplyParseHeader } from './markdown-it/parseHeader'
12
+ import { createMarkdownRenderer } from '.'
13
+ import type { MarkdownOptions } from '.'
14
+
15
+ const debug = _debug('vitepress:md')
16
+ const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
17
+ const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g
18
+
19
+ export interface MarkdownCompileResult {
20
+ vueSrc: string
21
+ pageData: PageData
22
+ deadLinks: string[]
23
+ includes: string[]
24
+ }
25
+
26
+ const inferTitle = (frontmatter: Record<string, any>, content: string) => {
27
+ if (frontmatter.title)
28
+ return deeplyParseHeader(frontmatter.title)
29
+
30
+ const match = content.match(/^\s*#+\s+(.*)/m)
31
+
32
+ if (match)
33
+ return deeplyParseHeader(match[1].trim())
34
+
35
+ return ''
36
+ }
37
+
38
+ const getHeadMetaContent = (
39
+ head: HeadConfig[],
40
+ name: string,
41
+ ): string | undefined => {
42
+ if (!head || !head.length)
43
+ return undefined
44
+
45
+ const meta = head.find(([tag, attrs = {}]) => {
46
+ return tag === 'meta' && attrs.name === name && attrs.content
47
+ })
48
+
49
+ return meta && meta[1].content
50
+ }
51
+
52
+ const inferDescription = (frontmatter: Record<string, any>) => {
53
+ const { description, head } = frontmatter
54
+
55
+ if (description !== undefined)
56
+ return description
57
+
58
+ return (head && getHeadMetaContent(head, 'description')) || ''
59
+ }
60
+
61
+ export async function createMarkdownToVueRenderFn(
62
+ srcDir: string,
63
+ options: MarkdownOptions = {},
64
+ pages: string[],
65
+ userDefines: Record<string, any> | undefined,
66
+ isBuild = false,
67
+ base = '/',
68
+ includeLastUpdatedData = false,
69
+ ) {
70
+ const md = await createMarkdownRenderer(srcDir, options, base)
71
+
72
+ pages = pages.map(p => slash(p.replace(/\.md$/, '')))
73
+
74
+ const userDefineRegex = userDefines
75
+ ? new RegExp(
76
+ `\\b(${Object.keys(userDefines)
77
+ .map(key => key.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
78
+ .join('|')})`,
79
+ 'g',
80
+ )
81
+ : null
82
+
83
+ return async (
84
+ src: string,
85
+ file: string,
86
+ publicDir: string,
87
+ ): Promise<MarkdownCompileResult> => {
88
+ const relativePath = slash(path.relative(srcDir, file))
89
+ const dir = path.dirname(file)
90
+
91
+ const cached = cache.get(src)
92
+ if (cached) {
93
+ debug(`[cache hit] ${relativePath}`)
94
+ return cached
95
+ }
96
+
97
+ const start = Date.now()
98
+
99
+ // resolve includes
100
+ const includes: string[] = []
101
+ src = src.replace(includesRE, (_, m1) => {
102
+ const includePath = path.join(dir, m1)
103
+ const content = fs.readFileSync(includePath, 'utf-8')
104
+ includes.push(slash(includePath))
105
+ return content
106
+ })
107
+
108
+ const { content, data: frontmatter } = matter(src)
109
+
110
+ // reset state before render
111
+ md.__path = file
112
+ md.__relativePath = relativePath
113
+
114
+ let html = md.render(content)
115
+ const data = md.__data
116
+
117
+ if (isBuild) {
118
+ // avoid env variables being replaced by vite
119
+ html = html
120
+ .replace(/\bimport\.meta/g, 'import.<wbr/>meta')
121
+ .replace(/\bprocess\.env/g, 'process.<wbr/>env')
122
+
123
+ // also avoid replacing vite user defines
124
+ if (userDefineRegex) {
125
+ html = html.replace(
126
+ userDefineRegex,
127
+ _ => `${_[0]}<wbr/>${_.slice(1)}`,
128
+ )
129
+ }
130
+ }
131
+
132
+ // validate data.links
133
+ const deadLinks: string[] = []
134
+ const recordDeadLink = (url: string) => {
135
+ console.warn(
136
+ c.yellow(
137
+ `\n(!) Found dead link ${c.cyan(url)} in file ${c.white(c.dim(file))}`,
138
+ ),
139
+ )
140
+ deadLinks.push(url)
141
+ }
142
+
143
+ if (data.links) {
144
+ const dir = path.dirname(file)
145
+ for (let url of data.links) {
146
+ if (/\.(?!html|md)\w+($|\?)/i.test(url))
147
+ continue
148
+
149
+ if (url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost:')) {
150
+ recordDeadLink(url)
151
+ continue
152
+ }
153
+
154
+ url = url.replace(/[?#].*$/, '').replace(/\.(html|md)$/, '')
155
+ if (url.endsWith('/'))
156
+ url += 'index'
157
+ const resolved = decodeURIComponent(
158
+ slash(
159
+ url.startsWith('/')
160
+ ? url.slice(1)
161
+ : path.relative(srcDir, path.resolve(dir, url)),
162
+ ),
163
+ )
164
+ if (
165
+ !pages.includes(resolved)
166
+ && !fs.existsSync(path.resolve(dir, publicDir, `${resolved}.html`))
167
+ )
168
+ recordDeadLink(url)
169
+ }
170
+ }
171
+
172
+ const pageData: PageData = {
173
+ title: inferTitle(frontmatter, content),
174
+ titleTemplate: frontmatter.titleTemplate,
175
+ description: inferDescription(frontmatter),
176
+ frontmatter,
177
+ headers: data.headers || [],
178
+ relativePath,
179
+ path: path.join(srcDir, relativePath),
180
+ }
181
+
182
+ if (includeLastUpdatedData)
183
+ pageData.lastUpdated = await getGitTimestamp(file)
184
+
185
+ const pageComponent = 'ValaxyMain'
186
+
187
+ function generateSlots() {
188
+ const slots = [
189
+ 'main-header',
190
+ 'main-header-after',
191
+ 'main-nav',
192
+ 'main-content',
193
+ 'footer',
194
+ 'aside',
195
+ 'aside-custom',
196
+ ]
197
+ const slotsText = slots.map(s => `<template #${s}><slot name="${s}" /></template>`).join('')
198
+ return slotsText
199
+ }
200
+ const vueSrc
201
+ = `${genPageDataCode(data.hoistedTags || [], pageData).join('\n')
202
+ }\n<template><${pageComponent} :frontmatter="frontmatter" :data="data">
203
+ <template #main-content-md>${html}</template>
204
+ ${generateSlots()}
205
+ <slot />
206
+ </${pageComponent}></template>`
207
+
208
+ debug(`[render] ${file} in ${Date.now() - start}ms.`)
209
+
210
+ const result = {
211
+ vueSrc,
212
+ pageData,
213
+ deadLinks,
214
+ includes,
215
+ }
216
+ cache.set(src, result)
217
+ return result
218
+ }
219
+ }
220
+
221
+ const scriptRE = /<\/script>/
222
+ const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/
223
+ const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
224
+ const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/
225
+ const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
226
+ const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
227
+
228
+ function genPageDataCode(tags: string[], data: PageData) {
229
+ const code = ''
230
+
231
+ const existingScriptIndex = tags.findIndex((tag) => {
232
+ return (
233
+ scriptRE.test(tag)
234
+ && !scriptSetupRE.test(tag)
235
+ && !scriptClientRE.test(tag)
236
+ )
237
+ })
238
+
239
+ const isUsingTS = tags.findIndex(tag => scriptLangTsRE.test(tag)) > -1
240
+
241
+ const exportScript = `
242
+ export default {
243
+ name:'${data.relativePath}',
244
+ data() {
245
+ return {
246
+ frontmatter:${transformObject(data.frontmatter)},
247
+ data: ${transformObject(data)}
248
+ }
249
+ }
250
+ }`
251
+
252
+ if (existingScriptIndex > -1) {
253
+ const tagSrc = tags[existingScriptIndex]
254
+ // user has <script> tag inside markdown
255
+ // if it doesn't have export default it will error out on build
256
+ const hasDefaultExport
257
+ = defaultExportRE.test(tagSrc) || namedDefaultExportRE.test(tagSrc)
258
+ tags[existingScriptIndex] = tagSrc.replace(
259
+ scriptRE,
260
+ `${code
261
+ + (hasDefaultExport
262
+ ? ''
263
+ : `\n${exportScript}`)
264
+ }</script>`,
265
+ )
266
+ }
267
+ else {
268
+ tags.unshift(
269
+ `<script ${isUsingTS ? 'lang="ts"' : ''}>${code}\n${exportScript}</script>`,
270
+ )
271
+ }
272
+
273
+ return tags
274
+ }
File without changes