valaxy 0.6.2 → 0.7.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 (70) hide show
  1. package/client/components/PostCard.vue +26 -29
  2. package/client/config.ts +1 -1
  3. package/client/index.ts +5 -0
  4. package/client/locales/en.yml +18 -17
  5. package/client/locales/zh-CN.yml +5 -4
  6. package/client/main.ts +3 -0
  7. package/client/setup/main.ts +11 -0
  8. package/client/setups.ts +16 -0
  9. package/client/styles/common/custom-blocks.scss +7 -0
  10. package/client/styles/common/markdown.scss +0 -4
  11. package/dist/chunk-35O5DRGK.mjs +2270 -0
  12. package/dist/chunk-4VSND5ZW.mjs +1 -0
  13. package/dist/chunk-CDIW2WTI.js +1 -0
  14. package/dist/chunk-RGBLPQZ2.js +2270 -0
  15. package/dist/{index.d.ts → client/index.d.ts} +16 -160
  16. package/dist/client/index.js +1 -0
  17. package/dist/client/index.mjs +1 -0
  18. package/dist/index-a6b0a69b.d.ts +16 -0
  19. package/dist/{config-112ac884.d.ts → index-afca77df.d.ts} +223 -6
  20. package/dist/node/cli.js +13 -8
  21. package/dist/node/cli.mjs +13 -8
  22. package/dist/node/index.d.ts +13 -35
  23. package/dist/node/index.js +1 -1
  24. package/dist/node/index.mjs +1 -1
  25. package/dist/types/index.d.ts +10 -0
  26. package/dist/types/index.js +1 -0
  27. package/dist/types/index.mjs +0 -0
  28. package/package.json +27 -22
  29. package/shared/index.ts +19 -0
  30. package/config/index.ts +0 -18
  31. package/dist/chunk-23IW567G.mjs +0 -40
  32. package/dist/chunk-EAN2KU6W.mjs +0 -1
  33. package/dist/chunk-U5OMNIOK.js +0 -1
  34. package/dist/chunk-YUC5WP5Y.js +0 -40
  35. package/dist/index.js +0 -1
  36. package/dist/index.mjs +0 -1
  37. package/index.ts +0 -3
  38. package/node/build.ts +0 -31
  39. package/node/cli.ts +0 -192
  40. package/node/config.ts +0 -156
  41. package/node/index.ts +0 -1
  42. package/node/markdown/check.ts +0 -14
  43. package/node/markdown/highlight.ts +0 -38
  44. package/node/markdown/index.ts +0 -109
  45. package/node/markdown/markdown-it/container.ts +0 -61
  46. package/node/markdown/markdown-it/headings.ts +0 -32
  47. package/node/markdown/markdown-it/highlightLines.ts +0 -96
  48. package/node/markdown/markdown-it/katex.ts +0 -210
  49. package/node/markdown/markdown-it/parseHeader.ts +0 -72
  50. package/node/markdown/markdownToVue.ts +0 -275
  51. package/node/markdown/slugify.ts +0 -24
  52. package/node/options.ts +0 -108
  53. package/node/plugins/extendConfig.ts +0 -46
  54. package/node/plugins/index.ts +0 -224
  55. package/node/plugins/preset.ts +0 -186
  56. package/node/plugins/unocss.ts +0 -110
  57. package/node/plugins/valaxy.ts +0 -1
  58. package/node/rss.ts +0 -127
  59. package/node/server.ts +0 -23
  60. package/node/shims.d.ts +0 -33
  61. package/node/utils/cli.ts +0 -103
  62. package/node/utils/getGitTimestamp.ts +0 -13
  63. package/node/utils/index.ts +0 -59
  64. package/node/utils/net.ts +0 -20
  65. package/node/vite.ts +0 -52
  66. package/tsup.config.ts +0 -25
  67. package/types/config.ts +0 -217
  68. package/types/data.ts +0 -31
  69. package/types/index.ts +0 -3
  70. package/types/posts.ts +0 -122
@@ -1,46 +0,0 @@
1
- import { resolve } from 'path'
2
- import type { InlineConfig, Plugin } from 'vite'
3
- import { mergeConfig } from 'vite'
4
- import type { ResolvedValaxyOptions } from '../options'
5
- import { toAtFS } from '../utils'
6
-
7
- export function createConfigPlugin(options: ResolvedValaxyOptions): Plugin {
8
- return {
9
- name: 'valaxy:config',
10
- config(config) {
11
- const injection: InlineConfig = {
12
- resolve: {
13
- alias: {
14
- '@/': `${toAtFS(options.userRoot)}/`,
15
- '~/': `${toAtFS(options.clientRoot)}/`,
16
- 'valaxy/client': `${toAtFS(options.clientRoot)}/`,
17
- 'valaxy': toAtFS(resolve(options.clientRoot, 'index.ts')),
18
- '@valaxyjs/client': `${toAtFS(options.clientRoot)}/`,
19
- '@valaxyjs/config': '/@valaxyjs/config',
20
- '@valaxyjs/context': '/@valaxyjs/context',
21
- 'valaxy/package.json': toAtFS(resolve(options.clientRoot, '../../package.json')),
22
- [`valaxy-theme-${options.theme}/`]: `${toAtFS(resolve(options.themeRoot))}/`,
23
- [`valaxy-theme-${options.theme}`]: `${toAtFS(resolve(options.themeRoot))}/index.ts`,
24
- },
25
- },
26
-
27
- optimizeDeps: {
28
- entries: [resolve(options.clientRoot, 'main.ts'), options.configFile],
29
-
30
- // must need it
31
- include: [
32
- 'vue',
33
- 'vue-router',
34
- '@vueuse/core',
35
- '@vueuse/head',
36
- 'dayjs',
37
- 'nprogress',
38
- ],
39
-
40
- exclude: ['@docsearch/js'],
41
- },
42
- }
43
- return mergeConfig(config, injection)
44
- },
45
- }
46
- }
@@ -1,224 +0,0 @@
1
- import fs from 'fs'
2
-
3
- import { join, relative } from 'path'
4
- import type { Plugin, ResolvedConfig } from 'vite'
5
- // import consola from 'consola'
6
- import { resolveConfig } from '../config'
7
- import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
8
- import { resolveImportPath, slash, toAtFS } from '../utils'
9
- import { createMarkdownToVueRenderFn } from '../markdown/markdownToVue'
10
- import type { PageDataPayload } from '../../types'
11
- import { checkMd } from '../markdown/check'
12
- import { VALAXY_CONFIG_ID } from './valaxy'
13
-
14
- /**
15
- * for /@valaxyjs/styles
16
- * @param roots
17
- * @returns
18
- */
19
- function generateStyles(roots: string[], options: ResolvedValaxyOptions) {
20
- const imports: string[] = []
21
-
22
- // katex
23
- if (options.config.features.katex) {
24
- imports.push(`import "${toAtFS(resolveImportPath('katex/dist/katex.min.css', true))}"`)
25
- imports.push(`import "${toAtFS(join(options.clientRoot, 'styles/third/katex.scss'))}"`)
26
- }
27
-
28
- for (const root of roots) {
29
- const styles: string[] = []
30
-
31
- const autoloadNames = ['index', 'css-vars']
32
- autoloadNames.forEach((name) => {
33
- styles.push(join(root, 'styles', `${name}.css`))
34
- styles.push(join(root, 'styles', `${name}.scss`))
35
- })
36
-
37
- for (const style of styles) {
38
- if (fs.existsSync(style))
39
- imports.push(`import "${toAtFS(style)}"`)
40
- }
41
- }
42
-
43
- return imports.join('\n')
44
- }
45
-
46
- function generateLocales(roots: string[]) {
47
- const imports: string[] = [
48
- 'const messages = { "zh-CN": {}, en: {} }',
49
- ]
50
- const languages = ['zh-CN', 'en']
51
-
52
- roots.forEach((root, i) => {
53
- languages.forEach((lang) => {
54
- const langYml = `${root}/locales/${lang}.yml`
55
- if (fs.existsSync(langYml) && fs.readFileSync(langYml, 'utf-8')) {
56
- const varName = lang.replace('-', '') + i
57
- imports.push(`import ${varName} from "${toAtFS(langYml)}"`)
58
- imports.push(`Object.assign(messages['${lang}'], ${varName})`)
59
- }
60
- })
61
- })
62
-
63
- imports.push('export default messages')
64
- return imports.join('\n')
65
- }
66
-
67
- export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions: ValaxyServerOptions = {}): Plugin {
68
- const valaxyPrefix = '/@valaxy'
69
-
70
- let valaxyConfig = options.config
71
-
72
- const roots = [options.clientRoot, options.themeRoot, options.userRoot]
73
-
74
- let markdownToVue: Awaited<ReturnType<typeof createMarkdownToVueRenderFn>>
75
- let hasDeadLinks = false
76
- let config: ResolvedConfig
77
-
78
- return {
79
- name: 'valaxy',
80
- enforce: 'pre',
81
-
82
- async configResolved(resolvedConfig) {
83
- config = resolvedConfig
84
- markdownToVue = await createMarkdownToVueRenderFn(
85
- options.userRoot,
86
- options.config.markdownIt,
87
- options.pages,
88
- config.define,
89
- config.command === 'build',
90
- config.base,
91
- options.config.lastUpdated,
92
- )
93
- },
94
-
95
- configureServer(server) {
96
- server.watcher.add([
97
- options.configFile,
98
- options.userRoot,
99
- options.themeRoot,
100
- ])
101
- },
102
-
103
- resolveId(id) {
104
- if (id.startsWith(valaxyPrefix))
105
- return id
106
- return null
107
- },
108
-
109
- load(id) {
110
- if (id === `/${VALAXY_CONFIG_ID}`)
111
- // stringify twice for \"
112
- return `export default ${JSON.stringify(JSON.stringify(valaxyConfig))}`
113
-
114
- if (id === '/@valaxyjs/context') {
115
- return `export default ${JSON.stringify(JSON.stringify({
116
- userRoot: options.userRoot,
117
- // clientRoot: options.clientRoot,
118
- }))}`
119
- }
120
-
121
- // generate styles
122
- if (id === '/@valaxyjs/styles')
123
- return generateStyles(roots, options)
124
-
125
- if (id === '/@valaxyjs/locales')
126
- return generateLocales(roots)
127
-
128
- if (id.startsWith(valaxyPrefix))
129
- return ''
130
- },
131
-
132
- async transform(code, id) {
133
- if (id.endsWith('.md')) {
134
- checkMd(code, id)
135
- code.replace('{%', '\{\%')
136
- code.replace('%}', '\%\}')
137
-
138
- // const scripts = [
139
- // '<script setup>',
140
- // 'import { useRoute } from "vue-router"',
141
- // 'const route = useRoute()',
142
- // `route.meta.headers = ${JSON.stringify(_md.__data)}`,
143
- // `export const data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
144
- // `frontmatter.data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
145
- // '</script>',
146
- // ]
147
-
148
- // const li = code.lastIndexOf('</script>')
149
- // code = code.slice(0, li) + scripts.join('\n') + code.slice(li + 9)
150
-
151
- // transform .md files into vueSrc so plugin-vue can handle it
152
- const { vueSrc, deadLinks, includes } = await markdownToVue(
153
- code,
154
- id,
155
- config.publicDir,
156
- )
157
- if (deadLinks.length)
158
- hasDeadLinks = true
159
-
160
- if (includes.length) {
161
- includes.forEach((i) => {
162
- this.addWatchFile(i)
163
- })
164
- }
165
-
166
- return vueSrc
167
- }
168
- },
169
-
170
- renderStart() {
171
- if (hasDeadLinks)
172
- throw new Error('One or more pages contain dead links.')
173
- },
174
-
175
- async handleHotUpdate(ctx) {
176
- // handle valaxy.config.ts hmr
177
- const { file, server, read } = ctx
178
- if (file !== options.configFile)
179
- return
180
-
181
- // send headers
182
- if (file.endsWith('.md')) {
183
- const content = await read()
184
- const { pageData, vueSrc } = await markdownToVue(
185
- content,
186
- file,
187
- join(options.userRoot, 'public'),
188
- )
189
-
190
- const path = `/${slash(relative(`${options.userRoot}/pages`, file))}`
191
- const payload: PageDataPayload = {
192
- // path: `/${slash(relative(srcDir, file))}`,
193
- path,
194
- pageData,
195
- }
196
-
197
- server.ws.send({
198
- type: 'custom',
199
- event: 'valaxy:pageData',
200
- data: payload,
201
- })
202
-
203
- // overwrite src so vue plugin can handle the HMR
204
- ctx.read = () => vueSrc
205
- }
206
-
207
- const { config } = await resolveConfig()
208
-
209
- serverOptions.onConfigReload?.(config, options.config)
210
- Object.assign(options.config, config)
211
-
212
- // if (config.base !== options.config.base)
213
- // consola.warn('[valaxy]: config.base has changed. Please restart the dev server.')
214
- valaxyConfig = config
215
-
216
- const moduleIds = [`/${VALAXY_CONFIG_ID}`, '/@valaxyjs/context']
217
- const moduleEntries = [
218
- ...Array.from(moduleIds).map(id => server.moduleGraph.getModuleById(id)),
219
- ].filter(<T>(item: T): item is NonNullable<T> => !!item)
220
-
221
- return moduleEntries
222
- },
223
- }
224
- }
@@ -1,186 +0,0 @@
1
- import fs from 'fs'
2
- import type { PluginOption } from 'vite'
3
-
4
- import consola from 'consola'
5
-
6
- import MarkdownIt from 'markdown-it'
7
- import matter from 'gray-matter'
8
-
9
- import Vue from '@vitejs/plugin-vue'
10
- import Pages from 'vite-plugin-pages'
11
- import Layouts from 'vite-plugin-vue-layouts'
12
- import Components from 'unplugin-vue-components/vite'
13
- import VueI18n from '@intlify/vite-plugin-vue-i18n'
14
- import Inspect from 'vite-plugin-inspect'
15
-
16
- import { dim, yellow } from 'kolorist'
17
- import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
18
- import { setupMarkdownPlugins } from '../markdown'
19
- // import { createMarkdownPlugin, excerpt_separator } from './markdown'
20
- import { createUnocssPlugin } from './unocss'
21
- import { createConfigPlugin } from './extendConfig'
22
- import { createValaxyPlugin } from '.'
23
-
24
- export interface ValaxyPluginOptions {
25
- components?: Parameters<typeof Components>[0]
26
- }
27
-
28
- export async function ViteValaxyPlugins(
29
- options: ResolvedValaxyOptions,
30
- serverOptions: ValaxyServerOptions = {},
31
- pluginOptions: ValaxyPluginOptions = {},
32
- ): Promise<(PluginOption | PluginOption[])[] | undefined> {
33
- const { clientRoot, themeRoot, userRoot } = options
34
-
35
- // const MarkdownPlugin = createMarkdownPlugin(options)
36
- const UnocssPlugin = await createUnocssPlugin(options)
37
-
38
- const ValaxyPlugin = createValaxyPlugin(options, serverOptions)
39
-
40
- const mdIt = new MarkdownIt({ html: true })
41
- await setupMarkdownPlugins(mdIt, options.config.markdownIt)
42
-
43
- const roots = [clientRoot, themeRoot, userRoot]
44
-
45
- const { default: ThemePlugin } = (await import(`valaxy-theme-${options.theme}`))
46
-
47
- const customElements = new Set([
48
- // katex
49
- 'annotation',
50
- 'math',
51
- 'menclose',
52
- 'mfrac',
53
- 'mglyph',
54
- 'mi',
55
- 'mlabeledtr',
56
- 'mn',
57
- 'mo',
58
- 'mover',
59
- 'mpadded',
60
- 'mphantom',
61
- 'mroot',
62
- 'mrow',
63
- 'mspace',
64
- 'msqrt',
65
- 'mstyle',
66
- 'msub',
67
- 'msubsup',
68
- 'msup',
69
- 'mtable',
70
- 'mtd',
71
- 'mtext',
72
- 'mtr',
73
- 'munder',
74
- 'munderover',
75
- 'semantics',
76
-
77
- // meting
78
- 'meting-js',
79
- ])
80
-
81
- return [
82
- Vue({
83
- include: [/\.vue$/, /\.md$/],
84
- template: {
85
- compilerOptions: {
86
- isCustomElement: (tag) => {
87
- return customElements.has(tag)
88
- },
89
- },
90
- },
91
- }),
92
-
93
- createConfigPlugin(options),
94
- ValaxyPlugin,
95
-
96
- ThemePlugin(options.config.themeConfig),
97
-
98
- // https://github.com/hannoeru/vite-plugin-pages
99
- Pages({
100
- extensions: ['vue', 'md'],
101
- dirs: roots.map(root => `${root}/pages`),
102
- /**
103
- * we need get frontmatter before route, so write it in Pages.extendRoute
104
- */
105
- extendRoute(route) {
106
- let path = route.component
107
- if (!route.meta)
108
- route.meta = {}
109
-
110
- // add default layout for home, can be overrode
111
- if (route.path === '/')
112
- route.meta.layout = 'home'
113
-
114
- roots.forEach((root) => {
115
- const pagePath = root + route.component
116
- if (fs.existsSync(pagePath))
117
- path = pagePath
118
- })
119
-
120
- const md = fs.readFileSync(path, 'utf-8')
121
- const { data, excerpt } = matter(md, { excerpt_separator: '<!-- more -->' })
122
-
123
- // warn for post frontmatter
124
- if (route.path.startsWith('/posts/')) {
125
- route.meta.layout = 'post'
126
- if (!data.date)
127
- consola.warn(`You forgot to write ${yellow('date')} for post: ${dim(`${route.component}`)}`)
128
- }
129
-
130
- route.meta = Object.assign(route.meta, {
131
- frontmatter: Object.assign({ date: new Date() }, data),
132
- excerpt: excerpt ? mdIt.render(excerpt) : '',
133
- })
134
-
135
- // set default updated
136
- if (route.meta.frontmatter.updated)
137
- route.meta.frontmatter.updated = route.meta.frontmatter.date
138
-
139
- // set layout
140
- if (data.layout)
141
- route.meta.layout = data.layout
142
-
143
- return route
144
- },
145
- }),
146
- // https://github.com/JohnCampionJr/vite-plugin-vue-layouts
147
- Layouts({
148
- layoutsDirs: roots.map(root => `${root}/layouts`),
149
- }),
150
-
151
- // https://github.com/antfu/unplugin-vue-components
152
- Components({
153
- extensions: ['vue', 'md'],
154
-
155
- // allow auto import and register components used in markdown
156
- include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
157
- exclude: [],
158
-
159
- // allow override
160
- allowOverrides: true,
161
- // override: user -> theme -> client
162
- // latter override former
163
- dirs: roots.map(root => `${root}/components`).concat(roots.map(root => `${root}/layouts`)).concat(['src/components', 'components']),
164
- dts: `${options.userRoot}/components.d.ts`,
165
-
166
- ...pluginOptions,
167
- }),
168
-
169
- // https://github.com/antfu/unocss
170
- // UnocssPlugin,
171
- UnocssPlugin,
172
-
173
- // ...MarkdownPlugin,
174
-
175
- // https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
176
- VueI18n({
177
- runtimeOnly: true,
178
- compositionOnly: true,
179
- include: roots.map(root => `${root}/locales/**`),
180
- }),
181
-
182
- // https://github.com/antfu/vite-plugin-inspect
183
- // Visit http://localhost:3333/__inspect/ to see the inspector
184
- options.mode === 'dev' && Inspect(),
185
- ]
186
- }
@@ -1,110 +0,0 @@
1
- import defu from 'defu'
2
- import type { VitePluginConfig } from 'unocss/vite'
3
- import Unocss from 'unocss/vite'
4
-
5
- import {
6
- presetAttributify,
7
- presetIcons,
8
- presetTypography,
9
- presetUno,
10
- presetWebFonts,
11
- transformerDirectives,
12
- transformerVariantGroup,
13
- } from 'unocss'
14
- import type { ValaxyConfig } from 'valaxy'
15
- import type { ThemeUserConfig } from 'valaxy-theme-yun'
16
- import type { ResolvedValaxyOptions } from '../options'
17
-
18
- export const createSafelist = async (config: ValaxyConfig<ThemeUserConfig>) => {
19
- const { generateSafelist } = await import(`valaxy-theme-${config.theme}`)
20
-
21
- const safeIcons: string[] = [
22
- 'i-ri-archive-line',
23
- 'i-ri-folder-2-line',
24
- 'i-ri-price-tag-3-line',
25
-
26
- 'i-ri-cloud-line',
27
- ]
28
-
29
- let themeSafelist: string[] = []
30
- if (typeof generateSafelist === 'function')
31
- themeSafelist = generateSafelist(config.themeConfig)
32
-
33
- const safelist = 'animate-fade-in m-auto text-left'.split(' ').concat([
34
- 'rotate-y-180',
35
- ]).concat(safeIcons).concat(themeSafelist)
36
-
37
- // generate icon safelist
38
- if (config.social.length)
39
- config.social.forEach(item => safelist.push(item.icon))
40
-
41
- // sponsor icon
42
- if (config.sponsor.methods.length)
43
- config.sponsor.methods.forEach(item => safelist.push(item.icon))
44
-
45
- return safelist
46
- }
47
-
48
- export const createUnocssConfig = async (options: ResolvedValaxyOptions) => {
49
- const unocssConfig: VitePluginConfig = {
50
- shortcuts: [
51
- ['yun-main', 'lt-md:pl-0'],
52
- ['yun-card', 'transition yun-transition shadow hover:shadow-lg'],
53
- ['btn', 'px-4 py-1 rounded inline-block bg-sky-600 text-white cursor-pointer hover:bg-sky-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
54
- ['icon-btn', 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-sky-600'],
55
- ['va-card', 'shadow hover:shadow-lg'],
56
- ],
57
- presets: [
58
- presetUno(),
59
- presetAttributify(),
60
- presetIcons({
61
- scale: 1.2,
62
- // warn: true,
63
- }),
64
- presetTypography(),
65
- // todo, add unocss config it
66
- presetWebFonts({
67
- fonts: {
68
- serif: [
69
- {
70
- name: 'Noto Serif SC',
71
- weights: [900],
72
- },
73
- ],
74
- // sans: 'DM Sans',
75
- // mono: 'DM Mono',
76
- },
77
- }),
78
- ],
79
- rules: [
80
- // more see '~/styles/global/helper.scss'
81
- ['yun-transition', {
82
- 'transition-duration': 'var(--va-transition-duration)',
83
- }],
84
- ['yun-text-light', {
85
- color: 'var(--va-c-text-light)',
86
- }],
87
- ['font-serif', {
88
- 'font-family': 'var(--va-font-serif)',
89
- }],
90
- ['font-sans', {
91
- 'font-family': 'var(--va-font-sans)',
92
- }],
93
- ['font-mono', {
94
- 'font-family': 'var(--va-font-mono)',
95
- }],
96
- ],
97
- transformers: [
98
- transformerDirectives(),
99
- transformerVariantGroup(),
100
- ],
101
- safelist: await createSafelist(options.config),
102
- }
103
-
104
- return defu(options.config.unocss, unocssConfig)
105
- }
106
-
107
- export const createUnocssPlugin = async (options: ResolvedValaxyOptions) => {
108
- const config = await createUnocssConfig(options)
109
- return Unocss(config)
110
- }
@@ -1 +0,0 @@
1
- export const VALAXY_CONFIG_ID = '@valaxyjs/config'
package/node/rss.ts DELETED
@@ -1,127 +0,0 @@
1
- import { dirname } from 'path'
2
- import { cyan, dim } from 'kolorist'
3
-
4
- import fg from 'fast-glob'
5
- import fs from 'fs-extra'
6
- import matter from 'gray-matter'
7
- import MarkdownIt from 'markdown-it'
8
- import type { Author, FeedOptions, Item } from 'feed'
9
- import { Feed } from 'feed'
10
- import consola from 'consola'
11
- import type { ResolvedValaxyOptions } from './options'
12
-
13
- const markdown = MarkdownIt({
14
- html: true,
15
- breaks: true,
16
- linkify: true,
17
- })
18
-
19
- /**
20
- * generate rss
21
- * @param options
22
- * @returns
23
- */
24
- export async function build(options: ResolvedValaxyOptions) {
25
- const { config } = options
26
-
27
- if (!config.url || config.url === '/') {
28
- consola.error('You must set "config.url" to generate rss.')
29
- return
30
- }
31
-
32
- const siteUrl = config.url.endsWith('/') ? config.url : `${config.url}/`
33
- const DOMAIN = config.url.endsWith('/') ? config.url.slice(0, -1) : config.url
34
- const author: Author = {
35
- name: options.config.author.name,
36
- email: options.config.author.email,
37
- link: options.config.author.link,
38
- }
39
-
40
- consola.info(`RSS Site Url: ${cyan(siteUrl)}`)
41
-
42
- const ccVersion = (config.license.type === 'zero') ? '1.0' : '4.0'
43
- const feedOptions: FeedOptions = {
44
- title: config.title,
45
- description: config.description,
46
- id: siteUrl || 'valaxy',
47
- link: siteUrl,
48
- copyright: `CC ${config.license.type.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${config.author.name}`,
49
- feedLinks: {
50
- json: `${siteUrl}feed.json`,
51
- atom: `${siteUrl}feed.atom`,
52
- rss: `${siteUrl}feed.xml`,
53
- },
54
- }
55
-
56
- // generate
57
- const files = await fg(`${options.userRoot}/pages/posts/**/*.md`)
58
-
59
- const posts: Item[] = []
60
- files
61
- .forEach((i) => {
62
- const raw = fs.readFileSync(i, 'utf-8')
63
- const { data, content, excerpt } = matter(raw)
64
-
65
- // not add to posts
66
- if (!data.date) {
67
- consola.warn(`Do you forget to write date for ${dim(i)}`)
68
- return false
69
- }
70
-
71
- if (data.draft) {
72
- consola.warn(`Ignore draft post: ${dim(i)}`)
73
- return false
74
- }
75
-
76
- // todo i18n
77
-
78
- // render excerpt
79
- const html = markdown.render(excerpt || content)
80
- .replace('src="/', `src="${DOMAIN}/`)
81
-
82
- if (data.image?.startsWith('/'))
83
- data.image = DOMAIN + data.image
84
-
85
- posts.push({
86
- title: '',
87
- ...data,
88
- id: (data.id || '').toString(),
89
- date: new Date(data.date),
90
- published: new Date(data.updated || data.date),
91
- content: html,
92
- author: [author],
93
- link: DOMAIN + i.replace(`${options.userRoot}/pages`, '').replace(/\.md$/, ''),
94
- })
95
- })
96
-
97
- // sort by updated
98
- posts.sort((a, b) => +new Date(b.published || b.date) - +new Date(a.published || a.date))
99
- // await writeFeed('feed', feedOptions, posts)
100
-
101
- // write
102
- feedOptions.author = author
103
- feedOptions.image = config.author.avatar.startsWith('http') ? config.author.avatar : `${DOMAIN}${config.author.avatar}`
104
- feedOptions.favicon = `${DOMAIN}/${config.feed.favicon || config.favicon}`
105
-
106
- const feed = new Feed(feedOptions)
107
- posts.forEach(item => feed.addItem(item))
108
- // items.forEach(i=> console.log(i.title, i.date))
109
-
110
- await fs.ensureDir(dirname(`./dist/${config.feed.name}`))
111
- const path = './dist'
112
-
113
- const types = ['xml', 'atom', 'json']
114
- types.forEach((type) => {
115
- let data = ''
116
- let name = `${path}/${config.feed.name || 'feed'}.${type}`
117
- if (type === 'xml') { data = feed.rss2() }
118
- else if (type === 'atom') {
119
- if (!config.feed.name)
120
- name = `${path}/atom.xml`
121
- data = feed.atom1()
122
- }
123
- else if (type === 'json') { data = feed.json1() }
124
- fs.writeFileSync(name, data, 'utf-8')
125
- consola.info(`${type}: ${name}`)
126
- })
127
- }