methanol 0.0.10 → 0.0.12

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.
@@ -0,0 +1,203 @@
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 '../register-loader.js'
22
+ import { parentPort, workerData } from 'worker_threads'
23
+ import { style } from '../logger.js'
24
+
25
+ const { mode = 'production', configPath = null, command = 'build', cli: cliOverrides = null } =
26
+ workerData || {}
27
+ let initPromise = null
28
+ let pages = []
29
+ let pagesContext = null
30
+ let components = null
31
+
32
+ const ensureInit = async () => {
33
+ if (initPromise) return initPromise
34
+ initPromise = (async () => {
35
+ const { loadUserConfig, applyConfig, resolveUserViteConfig } = await import('../config.js')
36
+ const { buildComponentRegistry } = await import('../components.js')
37
+ const { state, cli } = await import('../state.js')
38
+ if (cliOverrides) {
39
+ Object.assign(cli, cliOverrides)
40
+ }
41
+ const config = await loadUserConfig(mode, configPath)
42
+ await applyConfig(config, mode)
43
+ await resolveUserViteConfig(command)
44
+ const themeComponentsDir = state.THEME_COMPONENTS_DIR
45
+ const themeEnv = state.THEME_ENV
46
+ const themeRegistry = themeComponentsDir
47
+ ? await buildComponentRegistry({
48
+ componentsDir: themeComponentsDir,
49
+ client: themeEnv.client
50
+ })
51
+ : { components: {} }
52
+ const themeComponents = {
53
+ ...(themeRegistry.components || {}),
54
+ ...(state.USER_THEME.components || {})
55
+ }
56
+ const registry = await buildComponentRegistry()
57
+ components = {
58
+ ...themeComponents,
59
+ ...(registry.components || {})
60
+ }
61
+ })()
62
+ return initPromise
63
+ }
64
+
65
+ const rebuildPagesContext = async (excludedRoutes, excludedDirs) => {
66
+ const { createPagesContextFromPages } = await import('../pages.js')
67
+ pagesContext = createPagesContextFromPages({
68
+ pages,
69
+ excludedRoutes,
70
+ excludedDirs
71
+ })
72
+ }
73
+
74
+ const serializeError = (error) => {
75
+ if (!error) return 'Unknown error'
76
+ if (error.stack) return error.stack
77
+ if (error.message) return error.message
78
+ return String(error)
79
+ }
80
+
81
+ const logPageError = (phase, page, error) => {
82
+ const target = page?.path || page?.routePath || 'unknown file'
83
+ console.error(style.red(`\n\n[methanol] ${phase} error in ${target}`))
84
+ // Error is thrown so wo don't need to print here
85
+ // console.error(error?.stack || error)
86
+ }
87
+
88
+ const handleSetPages = async (message) => {
89
+ const { pages: nextPages, excludedRoutes = [], excludedDirs = [] } = message || {}
90
+ pages = Array.isArray(nextPages) ? nextPages : []
91
+ await rebuildPagesContext(new Set(excludedRoutes), new Set(excludedDirs))
92
+ }
93
+
94
+ const handleSyncUpdates = async (message) => {
95
+ const { updates = [], titles = null, excludedRoutes = null, excludedDirs = null } = message || {}
96
+ if (Array.isArray(titles)) {
97
+ for (let i = 0; i < titles.length; i += 1) {
98
+ const page = pages[i]
99
+ if (!page) continue
100
+ if (titles[i] !== undefined) {
101
+ page.title = titles[i]
102
+ }
103
+ }
104
+ }
105
+ for (const update of updates) {
106
+ const page = pages[update.id]
107
+ if (!page) continue
108
+ if (update.title !== undefined) page.title = update.title
109
+ if (update.toc !== undefined) page.toc = update.toc
110
+ }
111
+ await rebuildPagesContext(
112
+ excludedRoutes ? new Set(excludedRoutes) : pagesContext?.excludedRoutes || new Set(),
113
+ excludedDirs ? new Set(excludedDirs) : pagesContext?.excludedDirs || new Set()
114
+ )
115
+ }
116
+
117
+ const handleCompile = async (message) => {
118
+ const { ids = [], stage } = message || {}
119
+ const { compilePageMdx } = await import('../mdx.js')
120
+ const updates = []
121
+ let completed = 0
122
+ for (const id of ids) {
123
+ const page = pages[id]
124
+ if (!page || page.content == null || page.mdxComponent) {
125
+ completed += 1
126
+ parentPort?.postMessage({ type: 'progress', stage, completed })
127
+ continue
128
+ }
129
+ try {
130
+ await compilePageMdx(page, pagesContext, {
131
+ lazyPagesTree: true,
132
+ refreshPagesTree: false
133
+ })
134
+ updates.push({ id, title: page.title, toc: page.toc || null })
135
+ } catch (error) {
136
+ logPageError('MDX compile', page, error)
137
+ throw error
138
+ }
139
+ completed += 1
140
+ parentPort?.postMessage({ type: 'progress', stage, completed })
141
+ }
142
+ return updates
143
+ }
144
+
145
+ const handleRender = async (message) => {
146
+ const { ids = [], stage } = message || {}
147
+ const { renderHtml } = await import('../mdx.js')
148
+ const results = []
149
+ let completed = 0
150
+ for (const id of ids) {
151
+ const page = pages[id]
152
+ if (!page) {
153
+ completed += 1
154
+ parentPort?.postMessage({ type: 'progress', stage, completed })
155
+ continue
156
+ }
157
+ try {
158
+ const html = await renderHtml({
159
+ routePath: page.routePath,
160
+ path: page.path,
161
+ components,
162
+ pagesContext,
163
+ pageMeta: page
164
+ })
165
+ results.push({ id, html })
166
+ } catch (error) {
167
+ logPageError('MDX render', page, error)
168
+ throw error
169
+ }
170
+ completed += 1
171
+ parentPort?.postMessage({ type: 'progress', stage, completed })
172
+ }
173
+ return results
174
+ }
175
+
176
+ parentPort?.on('message', async (message) => {
177
+ const { type, stage } = message || {}
178
+ try {
179
+ await ensureInit()
180
+ if (type === 'setPages') {
181
+ await handleSetPages(message)
182
+ parentPort?.postMessage({ type: 'done', stage: 'setPages' })
183
+ return
184
+ }
185
+ if (type === 'sync') {
186
+ await handleSyncUpdates(message)
187
+ parentPort?.postMessage({ type: 'done', stage: 'sync' })
188
+ return
189
+ }
190
+ if (type === 'compile') {
191
+ const updates = await handleCompile(message)
192
+ parentPort?.postMessage({ type: 'done', stage, updates })
193
+ return
194
+ }
195
+ if (type === 'render') {
196
+ const results = await handleRender(message)
197
+ parentPort?.postMessage({ type: 'done', stage, results })
198
+ return
199
+ }
200
+ } catch (error) {
201
+ parentPort?.postMessage({ type: 'error', stage, error: serializeError(error) })
202
+ }
203
+ })
@@ -0,0 +1,60 @@
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 '../register-loader.js'
22
+ import { parentPort, workerData } from 'worker_threads'
23
+
24
+ const { mode = 'production', configPath = null, cli: cliOverrides = null } = workerData || {}
25
+ let initPromise = null
26
+ let compileMdxSource = null
27
+
28
+ const ensureInit = async () => {
29
+ if (initPromise) return initPromise
30
+ initPromise = (async () => {
31
+ const { loadUserConfig, applyConfig } = await import('../config.js')
32
+ const { cli } = await import('../state.js')
33
+ if (cliOverrides) {
34
+ Object.assign(cli, cliOverrides)
35
+ }
36
+ const mdx = await import('../mdx.js')
37
+ compileMdxSource = mdx.compileMdxSource
38
+ const config = await loadUserConfig(mode, configPath)
39
+ await applyConfig(config, mode)
40
+ })()
41
+ return initPromise
42
+ }
43
+
44
+ const serializeError = (error) => {
45
+ if (!error) return 'Unknown error'
46
+ if (error.stack) return error.stack
47
+ if (error.message) return error.message
48
+ return String(error)
49
+ }
50
+
51
+ parentPort?.on('message', async (message) => {
52
+ const { id, path, content, frontmatter } = message || {}
53
+ try {
54
+ await ensureInit()
55
+ const result = await compileMdxSource({ content, path, frontmatter })
56
+ parentPort?.postMessage({ id, result })
57
+ } catch (error) {
58
+ parentPort?.postMessage({ id, error: serializeError(error) })
59
+ }
60
+ })
@@ -30,10 +30,10 @@ const matchCurrentPath = onCondition(currentPath)
30
30
  const toSignal = (i) => {
31
31
  const clone = Object.assign(new NullProtoObj(), i)
32
32
 
33
- let sig = navEntryMap.get(clone.path)
33
+ let sig = navEntryMap.get(clone.routePath)
34
34
  if (!sig) {
35
35
  sig = signal(clone)
36
- navEntryMap.set(clone.path, sig)
36
+ navEntryMap.set(clone.routePath, sig)
37
37
  } else {
38
38
  sig.value = clone
39
39
  }
@@ -79,11 +79,12 @@ const NavTree = ({ nodes, depth }) => (
79
79
  <li class={isActive.choose('is-active', null)}>
80
80
  <details class="sidebar-collapsible" open={isOpen.choose(true, null)}>
81
81
  <summary class="sb-dir-header">{header}</summary>
82
- <If condition={() => children.value.length}>{() => (
83
- <ul data-depth={depth + 1}>
84
- <NavTree nodes={children} depth={depth + 1} />
85
- </ul>
86
- )}
82
+ <If condition={() => children.value.length}>
83
+ {() => (
84
+ <ul data-depth={depth + 1}>
85
+ <NavTree nodes={children} depth={depth + 1} />
86
+ </ul>
87
+ )}
87
88
  </If>
88
89
  </details>
89
90
  </li>