methanol 0.0.0 → 0.0.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.
- package/.editorconfig +19 -0
- package/.prettierrc +10 -0
- package/LICENSE +203 -0
- package/banner.txt +6 -0
- package/bin/methanol.js +24 -0
- package/index.js +22 -0
- package/package.json +42 -9
- package/src/assets.js +30 -0
- package/src/build-system.js +200 -0
- package/src/components.js +145 -0
- package/src/config.js +355 -0
- package/src/dev-server.js +559 -0
- package/src/main.js +87 -0
- package/src/mdx.js +254 -0
- package/src/node-loader.js +88 -0
- package/src/pagefind.js +99 -0
- package/src/pages.js +638 -0
- package/src/preview-server.js +58 -0
- package/src/public-assets.js +73 -0
- package/src/register-loader.js +29 -0
- package/src/rehype-plugins/link-resolve.js +89 -0
- package/src/rehype-plugins/methanol-ctx.js +89 -0
- package/src/renderer.js +25 -0
- package/src/rewind.js +117 -0
- package/src/stage-logger.js +59 -0
- package/src/state.js +159 -0
- package/src/virtual-module/inject.js +30 -0
- package/src/virtual-module/loader.js +116 -0
- package/src/virtual-module/pagefind.js +108 -0
- package/src/vite-plugins.js +173 -0
- package/themes/default/components/ThemeColorSwitch.client.jsx +95 -0
- package/themes/default/components/ThemeColorSwitch.static.jsx +23 -0
- package/themes/default/components/ThemeSearchBox.client.jsx +287 -0
- package/themes/default/components/ThemeSearchBox.static.jsx +41 -0
- package/themes/default/components/ThemeToCContainer.client.jsx +154 -0
- package/themes/default/components/ThemeToCContainer.static.jsx +61 -0
- package/themes/default/components/pre.client.jsx +84 -0
- package/themes/default/components/pre.jsx +27 -0
- package/themes/default/heading.jsx +35 -0
- package/themes/default/index.js +50 -0
- package/themes/default/page.jsx +249 -0
- package/themes/default/pages/404.mdx +8 -0
- package/themes/default/pages/index.mdx +9 -0
- package/themes/default/public/logo.png +0 -0
- package/themes/default/resources/style.css +1089 -0
package/src/mdx.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { compile, run } from '@mdx-js/mdx'
|
|
22
|
+
import * as JSXFactory from 'refui/jsx-runtime'
|
|
23
|
+
import * as JSXDevFactory from 'refui/jsx-dev-runtime'
|
|
24
|
+
import rehypeSlug from 'rehype-slug'
|
|
25
|
+
import extractToc from '@stefanprobst/rehype-extract-toc'
|
|
26
|
+
import withTocExport from '@stefanprobst/rehype-extract-toc/mdx'
|
|
27
|
+
import { HTMLRenderer } from './renderer.js'
|
|
28
|
+
import { signal, computed, read, Suspense, nextTick } from 'refui'
|
|
29
|
+
import { createPortal } from 'refui/extras'
|
|
30
|
+
import { pathToFileURL } from 'url'
|
|
31
|
+
import { existsSync } from 'fs'
|
|
32
|
+
import { resolve } from 'path'
|
|
33
|
+
import { state } from './state.js'
|
|
34
|
+
import { resolveUserMdxConfig } from './config.js'
|
|
35
|
+
import { methanolCtx } from './rehype-plugins/methanol-ctx.js'
|
|
36
|
+
import { linkResolve } from './rehype-plugins/link-resolve.js'
|
|
37
|
+
|
|
38
|
+
// Workaround for Vite: it doesn't support resolving module/virtual modules in script src in dev mode
|
|
39
|
+
const RWND_INJECT = HTMLRenderer.rawHTML`<script type="module" src="/.methanol_virtual_module/inject.js"></script>`
|
|
40
|
+
const RWND_FALLBACK = HTMLRenderer.rawHTML`<script>
|
|
41
|
+
if (!window.$$rwnd) {
|
|
42
|
+
const l = []
|
|
43
|
+
const r = function(k,i,p) {
|
|
44
|
+
l.push([k,i,p,document.currentScript])
|
|
45
|
+
}
|
|
46
|
+
r.$$loaded = l
|
|
47
|
+
window.$$rwnd = r
|
|
48
|
+
}
|
|
49
|
+
</script>`
|
|
50
|
+
|
|
51
|
+
let cachedHeadAssets = null
|
|
52
|
+
|
|
53
|
+
const resolveUserHeadAssets = () => {
|
|
54
|
+
if (cachedHeadAssets) {
|
|
55
|
+
return cachedHeadAssets
|
|
56
|
+
}
|
|
57
|
+
const assets = []
|
|
58
|
+
const pagesDir = state.PAGES_DIR
|
|
59
|
+
if (!pagesDir) return assets
|
|
60
|
+
if (existsSync(resolve(pagesDir, 'style.css'))) {
|
|
61
|
+
assets.push(HTMLRenderer.c('link', { rel: 'stylesheet', href: '/style.css' }))
|
|
62
|
+
}
|
|
63
|
+
if (existsSync(resolve(pagesDir, 'index.js'))) {
|
|
64
|
+
assets.push(HTMLRenderer.c('script', { type: 'module', src: '/index.js' }))
|
|
65
|
+
} else if (existsSync(resolve(pagesDir, 'index.ts'))) {
|
|
66
|
+
assets.push(HTMLRenderer.c('script', { type: 'module', src: '/index.ts' }))
|
|
67
|
+
}
|
|
68
|
+
if (state.CURRENT_MODE === 'production') {
|
|
69
|
+
cachedHeadAssets = assets
|
|
70
|
+
}
|
|
71
|
+
return assets
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const buildPageContext = ({ routePath, filePath, pageMeta, pagesContext }) => {
|
|
75
|
+
const page = pageMeta
|
|
76
|
+
const pagesTree = pagesContext?.getPagesTree ? pagesContext.getPagesTree(routePath) : pagesContext?.pagesTree || []
|
|
77
|
+
const language = pagesContext?.getLanguageForRoute ? pagesContext.getLanguageForRoute(routePath) : null
|
|
78
|
+
return {
|
|
79
|
+
routePath,
|
|
80
|
+
filePath,
|
|
81
|
+
page,
|
|
82
|
+
pages: pagesContext?.pages || [],
|
|
83
|
+
pagesTree,
|
|
84
|
+
pagesByRoute: pagesContext?.pagesByRoute || new Map(),
|
|
85
|
+
languages: pagesContext?.languages || [],
|
|
86
|
+
language,
|
|
87
|
+
site: pagesContext?.site || null
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const findTitleFromToc = (toc = []) => {
|
|
92
|
+
let minDepth = Infinity
|
|
93
|
+
const scanDepth = (items) => {
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
if (typeof item?.depth === 'number') {
|
|
96
|
+
minDepth = Math.min(minDepth, item.depth)
|
|
97
|
+
}
|
|
98
|
+
if (item?.children?.length) {
|
|
99
|
+
scanDepth(item.children)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
scanDepth(toc)
|
|
104
|
+
if (!Number.isFinite(minDepth)) return null
|
|
105
|
+
let result = null
|
|
106
|
+
const findFirst = (items) => {
|
|
107
|
+
for (const item of items) {
|
|
108
|
+
if (item?.depth === minDepth && item?.value) {
|
|
109
|
+
result = item.value
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
if (item?.children?.length && findFirst(item.children)) {
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
findFirst(toc)
|
|
119
|
+
return result
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let cachedMdxConfig = null
|
|
123
|
+
|
|
124
|
+
const resolveMdxConfig = async () => {
|
|
125
|
+
const userMdxConfig = await resolveUserMdxConfig()
|
|
126
|
+
if (cachedMdxConfig) {
|
|
127
|
+
return cachedMdxConfig
|
|
128
|
+
}
|
|
129
|
+
const baseMdxConfig = {
|
|
130
|
+
outputFormat: 'function-body',
|
|
131
|
+
jsxRuntime: 'automatic',
|
|
132
|
+
jsxImportSource: 'refui',
|
|
133
|
+
development: state.CURRENT_MODE !== 'production',
|
|
134
|
+
elementAttributeNameCase: 'html',
|
|
135
|
+
rehypePlugins: [rehypeSlug, extractToc, [withTocExport, { name: 'toc' }]]
|
|
136
|
+
}
|
|
137
|
+
const mdxConfig = { ...baseMdxConfig, ...userMdxConfig }
|
|
138
|
+
if (userMdxConfig.rehypePlugins.length) {
|
|
139
|
+
mdxConfig.rehypePlugins = [...baseMdxConfig.rehypePlugins, ...userMdxConfig.rehypePlugins]
|
|
140
|
+
}
|
|
141
|
+
mdxConfig.rehypePlugins.push(linkResolve)
|
|
142
|
+
mdxConfig.rehypePlugins.push(methanolCtx)
|
|
143
|
+
return (cachedMdxConfig = mdxConfig)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const compileMdx = async ({ content, filePath, ctx }) => {
|
|
147
|
+
const mdxConfig = await resolveMdxConfig()
|
|
148
|
+
const runtimeFactory = mdxConfig.development ? JSXDevFactory : JSXFactory
|
|
149
|
+
const compiled = await compile({ value: content, path: filePath }, mdxConfig)
|
|
150
|
+
|
|
151
|
+
return await run(compiled, {
|
|
152
|
+
...runtimeFactory,
|
|
153
|
+
baseUrl: pathToFileURL(filePath).href,
|
|
154
|
+
ctx,
|
|
155
|
+
rawHTML: HTMLRenderer.rawHTML
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const compilePageMdx = async (page, pagesContext) => {
|
|
160
|
+
if (!page || page.content == null || page.mdxComponent) return
|
|
161
|
+
const mdxModule = await compileMdx({
|
|
162
|
+
content: page.content,
|
|
163
|
+
filePath: page.filePath,
|
|
164
|
+
ctx: buildPageContext({
|
|
165
|
+
routePath: page.routePath,
|
|
166
|
+
filePath: page.filePath,
|
|
167
|
+
pageMeta: page,
|
|
168
|
+
pagesContext
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
page.mdxComponent = mdxModule.default
|
|
172
|
+
page.toc = mdxModule.toc
|
|
173
|
+
const shouldUseTocTitle = page.frontmatter?.title == null
|
|
174
|
+
if (shouldUseTocTitle) {
|
|
175
|
+
const nextTitle = findTitleFromToc(page.toc) || page.title
|
|
176
|
+
if (nextTitle !== page.title) {
|
|
177
|
+
page.title = nextTitle
|
|
178
|
+
if (typeof pagesContext?.refreshPagesTree === 'function') {
|
|
179
|
+
pagesContext.refreshPagesTree()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (typeof pagesContext?.setDerivedTitle === 'function') {
|
|
184
|
+
pagesContext.setDerivedTitle(
|
|
185
|
+
page.filePath,
|
|
186
|
+
shouldUseTocTitle ? page.title : null,
|
|
187
|
+
page.toc
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const renderHtml = async ({
|
|
193
|
+
routePath,
|
|
194
|
+
filePath,
|
|
195
|
+
components,
|
|
196
|
+
pagesContext,
|
|
197
|
+
pageMeta: explicitPageMeta = null
|
|
198
|
+
}) => {
|
|
199
|
+
const pageMeta =
|
|
200
|
+
explicitPageMeta ||
|
|
201
|
+
(pagesContext.getPageByRoute
|
|
202
|
+
? pagesContext.getPageByRoute(routePath, { filePath })
|
|
203
|
+
: pagesContext.pagesByRoute.get(routePath))
|
|
204
|
+
|
|
205
|
+
const ctx = buildPageContext({
|
|
206
|
+
routePath,
|
|
207
|
+
filePath,
|
|
208
|
+
pageMeta,
|
|
209
|
+
pagesContext
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
const [Head, Outlet] = createPortal()
|
|
213
|
+
const ExtraHead = () => {
|
|
214
|
+
return [RWND_INJECT, ...resolveUserHeadAssets(), Outlet(), RWND_FALLBACK]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await compilePageMdx(pageMeta, pagesContext)
|
|
218
|
+
const mdxComponent = pageMeta?.mdxComponent
|
|
219
|
+
|
|
220
|
+
const Page = ({ components: extraComponents, ...props }, ...children) =>
|
|
221
|
+
mdxComponent({
|
|
222
|
+
children,
|
|
223
|
+
...props,
|
|
224
|
+
components: {
|
|
225
|
+
...components,
|
|
226
|
+
...extraComponents,
|
|
227
|
+
head: Head,
|
|
228
|
+
Head
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
const template = state.USER_THEME.template
|
|
233
|
+
|
|
234
|
+
const renderResult = await new Promise((r) => {
|
|
235
|
+
const result = HTMLRenderer.c(
|
|
236
|
+
Suspense,
|
|
237
|
+
{
|
|
238
|
+
onLoad() {
|
|
239
|
+
nextTick(() => r(result))
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
() =>
|
|
243
|
+
template({
|
|
244
|
+
ctx,
|
|
245
|
+
Page,
|
|
246
|
+
ExtraHead,
|
|
247
|
+
HTMLRenderer,
|
|
248
|
+
components
|
|
249
|
+
})
|
|
250
|
+
)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
return HTMLRenderer.serialize(renderResult)
|
|
254
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFile } from 'node:fs/promises'
|
|
22
|
+
import { dirname, extname, join, resolve as pathResolve, relative } from 'node:path'
|
|
23
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
24
|
+
import { createRequire } from 'node:module'
|
|
25
|
+
import { transform } from 'esbuild'
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
28
|
+
const __dirname = dirname(__filename)
|
|
29
|
+
|
|
30
|
+
const projectRoot = pathResolve('.', '__virtual__.js')
|
|
31
|
+
const projectRootURL = pathToFileURL(projectRoot)
|
|
32
|
+
export const projectRequire = createRequire(projectRootURL)
|
|
33
|
+
|
|
34
|
+
const require = createRequire(import.meta.url)
|
|
35
|
+
|
|
36
|
+
const EXTS = new Set(['.jsx', '.tsx', '.ts', '.mts', '.cts'])
|
|
37
|
+
|
|
38
|
+
export async function load(url, context, nextLoad) {
|
|
39
|
+
if (url.startsWith('node:') || url.startsWith('data:')) {
|
|
40
|
+
return nextLoad(url, context, nextLoad)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const pathname = new URL(url).pathname
|
|
44
|
+
const ext = extname(pathname).toLowerCase()
|
|
45
|
+
if (!EXTS.has(ext)) {
|
|
46
|
+
return nextLoad(url, context, nextLoad)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const source = await readFile(fileURLToPath(url), 'utf-8')
|
|
50
|
+
const loader = ext === '.tsx' ? 'tsx' : ext === '.jsx' ? 'jsx' : 'ts'
|
|
51
|
+
const result = await transform(source, {
|
|
52
|
+
loader,
|
|
53
|
+
format: 'esm',
|
|
54
|
+
jsx: 'automatic',
|
|
55
|
+
jsxImportSource: 'refui',
|
|
56
|
+
sourcemap: 'inline',
|
|
57
|
+
sourcefile: fileURLToPath(url)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
format: 'module',
|
|
62
|
+
shortCircuit: true,
|
|
63
|
+
source: result.code
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const startPos = 'methanol'.length
|
|
68
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
69
|
+
if (specifier === 'refui' || specifier.startsWith('refui/')) {
|
|
70
|
+
try {
|
|
71
|
+
// Use user installed rEFui when possible
|
|
72
|
+
return await nextResolve(specifier, { ...context, parentURL: projectRootURL })
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return await nextResolve(specifier, { ...context, parentURL: import.meta.url })
|
|
75
|
+
}
|
|
76
|
+
} else if (specifier === 'methanol' || specifier.startsWith('methanol/')) {
|
|
77
|
+
// Force only one Metnanol instance
|
|
78
|
+
const filePath = require.resolve('..' + specifier.slice(startPos))
|
|
79
|
+
return {
|
|
80
|
+
__proto__: null,
|
|
81
|
+
shortCircuit: true,
|
|
82
|
+
format: 'module',
|
|
83
|
+
url: pathToFileURL(filePath).href
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
return await nextResolve(specifier, context)
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/pagefind.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { access } from 'fs/promises'
|
|
22
|
+
import { constants } from 'fs'
|
|
23
|
+
import { join } from 'path'
|
|
24
|
+
import { spawn } from 'child_process'
|
|
25
|
+
import { state } from './state.js'
|
|
26
|
+
|
|
27
|
+
const resolvePagefindBin = async () => {
|
|
28
|
+
const binName = process.platform === 'win32' ? 'pagefind.cmd' : 'pagefind'
|
|
29
|
+
const candidates = [
|
|
30
|
+
join(state.PROJECT_ROOT, 'node_modules', '.bin', binName),
|
|
31
|
+
join(state.ROOT_DIR, 'node_modules', '.bin', binName)
|
|
32
|
+
]
|
|
33
|
+
for (const candidate of candidates) {
|
|
34
|
+
try {
|
|
35
|
+
await access(candidate, constants.X_OK)
|
|
36
|
+
return candidate
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const toKebabCase = (value) =>
|
|
43
|
+
String(value)
|
|
44
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
45
|
+
.replace(/_/g, '-')
|
|
46
|
+
.toLowerCase()
|
|
47
|
+
|
|
48
|
+
const buildArgsFromOptions = (options) => {
|
|
49
|
+
if (!options) return []
|
|
50
|
+
if (Array.isArray(options)) {
|
|
51
|
+
return options.map(String)
|
|
52
|
+
}
|
|
53
|
+
if (typeof options !== 'object') return []
|
|
54
|
+
const args = []
|
|
55
|
+
for (const [rawKey, rawValue] of Object.entries(options)) {
|
|
56
|
+
if (!rawKey) continue
|
|
57
|
+
const key = String(rawKey)
|
|
58
|
+
const normalized = toKebabCase(key.replace(/^--/, ''))
|
|
59
|
+
if (normalized === 'site' || normalized === 'site-dir' || normalized === 'source') {
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
const flag = key.startsWith('--') ? key : `--${normalized}`
|
|
63
|
+
if (rawValue === true) {
|
|
64
|
+
args.push(flag)
|
|
65
|
+
} else if (rawValue === false || rawValue == null) {
|
|
66
|
+
continue
|
|
67
|
+
} else {
|
|
68
|
+
args.push(flag, String(rawValue))
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return args
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const runCommand = (command, args, options) =>
|
|
75
|
+
new Promise((resolve) => {
|
|
76
|
+
const child = spawn(command, args, {
|
|
77
|
+
stdio: 'inherit',
|
|
78
|
+
...options
|
|
79
|
+
})
|
|
80
|
+
child.on('close', (code) => resolve(code === 0))
|
|
81
|
+
child.on('error', () => resolve(false))
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
export const runPagefind = async () => {
|
|
85
|
+
const bin = await resolvePagefindBin()
|
|
86
|
+
if (!bin) {
|
|
87
|
+
console.log('Pagefind not found; skipping search indexing.')
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
console.log('Running Pagefind search indexing...')
|
|
91
|
+
const extraArgs = buildArgsFromOptions(state.PAGEFIND_BUILD_OPTIONS)
|
|
92
|
+
const ok = await runCommand(bin, ['--site', state.DIST_DIR, ...extraArgs], {
|
|
93
|
+
cwd: state.PROJECT_ROOT
|
|
94
|
+
})
|
|
95
|
+
if (!ok) {
|
|
96
|
+
console.warn('Pagefind failed to build search index.')
|
|
97
|
+
}
|
|
98
|
+
return ok
|
|
99
|
+
}
|