poveste 0.1.0
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/LICENSE +22 -0
- package/README.md +11 -0
- package/bin.mjs +4 -0
- package/client.d.ts +19 -0
- package/client.js +15 -0
- package/dist/controls.d.ts +2 -0
- package/dist/controls.d.ts.map +1 -0
- package/dist/controls.js +1 -0
- package/dist/node/alias.d.ts +3 -0
- package/dist/node/alias.d.ts.map +1 -0
- package/dist/node/alias.js +5 -0
- package/dist/node/bin.d.ts +2 -0
- package/dist/node/bin.d.ts.map +1 -0
- package/dist/node/bin.js +35 -0
- package/dist/node/build-serialize.d.ts +22 -0
- package/dist/node/build-serialize.d.ts.map +1 -0
- package/dist/node/build-serialize.js +36 -0
- package/dist/node/build.d.ts +3 -0
- package/dist/node/build.d.ts.map +1 -0
- package/dist/node/build.js +228 -0
- package/dist/node/builtin-plugins/pinceau-tokens.d.ts +7 -0
- package/dist/node/builtin-plugins/pinceau-tokens.d.ts.map +1 -0
- package/dist/node/builtin-plugins/pinceau-tokens.js +505 -0
- package/dist/node/builtin-plugins/tailwind-tokens.d.ts +6 -0
- package/dist/node/builtin-plugins/tailwind-tokens.d.ts.map +1 -0
- package/dist/node/builtin-plugins/tailwind-tokens.js +523 -0
- package/dist/node/builtin-plugins/vanilla-support/MountStory.d.ts +15 -0
- package/dist/node/builtin-plugins/vanilla-support/MountStory.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/MountStory.js +39 -0
- package/dist/node/builtin-plugins/vanilla-support/RenderStory.d.ts +39 -0
- package/dist/node/builtin-plugins/vanilla-support/RenderStory.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/RenderStory.js +129 -0
- package/dist/node/builtin-plugins/vanilla-support/client.d.ts +4 -0
- package/dist/node/builtin-plugins/vanilla-support/client.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/client.js +5 -0
- package/dist/node/builtin-plugins/vanilla-support/collect.d.ts +3 -0
- package/dist/node/builtin-plugins/vanilla-support/collect.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/collect.js +33 -0
- package/dist/node/builtin-plugins/vanilla-support/plugin.d.ts +3 -0
- package/dist/node/builtin-plugins/vanilla-support/plugin.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/plugin.js +29 -0
- package/dist/node/builtin-plugins/vanilla-support/types.d.ts +36 -0
- package/dist/node/builtin-plugins/vanilla-support/types.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/types.js +3 -0
- package/dist/node/builtin-plugins/vanilla-support/vanilla.story.d.ts +4 -0
- package/dist/node/builtin-plugins/vanilla-support/vanilla.story.d.ts.map +1 -0
- package/dist/node/builtin-plugins/vanilla-support/vanilla.story.js +55 -0
- package/dist/node/collect/index.d.ts +14 -0
- package/dist/node/collect/index.d.ts.map +1 -0
- package/dist/node/collect/index.js +129 -0
- package/dist/node/collect/run.d.ts +3 -0
- package/dist/node/collect/run.d.ts.map +1 -0
- package/dist/node/collect/run.js +7 -0
- package/dist/node/collect/worker.d.ts +14 -0
- package/dist/node/collect/worker.d.ts.map +1 -0
- package/dist/node/collect/worker.js +64 -0
- package/dist/node/colors.d.ts +287 -0
- package/dist/node/colors.d.ts.map +1 -0
- package/dist/node/colors.js +324 -0
- package/dist/node/commands/build.d.ts +5 -0
- package/dist/node/commands/build.d.ts.map +1 -0
- package/dist/node/commands/build.js +9 -0
- package/dist/node/commands/dev.d.ts +8 -0
- package/dist/node/commands/dev.d.ts.map +1 -0
- package/dist/node/commands/dev.js +52 -0
- package/dist/node/commands/preview.d.ts +5 -0
- package/dist/node/commands/preview.d.ts.map +1 -0
- package/dist/node/commands/preview.js +15 -0
- package/dist/node/config.d.ts +40 -0
- package/dist/node/config.d.ts.map +1 -0
- package/dist/node/config.js +330 -0
- package/dist/node/context.d.ts +18 -0
- package/dist/node/context.d.ts.map +1 -0
- package/dist/node/context.js +28 -0
- package/dist/node/dom/dom-keys.d.ts +5 -0
- package/dist/node/dom/dom-keys.d.ts.map +1 -0
- package/dist/node/dom/dom-keys.js +233 -0
- package/dist/node/dom/env.d.ts +5 -0
- package/dist/node/dom/env.d.ts.map +1 -0
- package/dist/node/dom/env.js +47 -0
- package/dist/node/dom/util.d.ts +11 -0
- package/dist/node/dom/util.d.ts.map +1 -0
- package/dist/node/dom/util.js +65 -0
- package/dist/node/index.d.ts +12 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +4 -0
- package/dist/node/load.d.ts +9 -0
- package/dist/node/load.d.ts.map +1 -0
- package/dist/node/load.js +42 -0
- package/dist/node/markdown.d.ts +11 -0
- package/dist/node/markdown.d.ts.map +1 -0
- package/dist/node/markdown.js +228 -0
- package/dist/node/plugin.d.ts +42 -0
- package/dist/node/plugin.d.ts.map +1 -0
- package/dist/node/plugin.js +67 -0
- package/dist/node/preview.d.ts +8 -0
- package/dist/node/preview.d.ts.map +1 -0
- package/dist/node/preview.js +41 -0
- package/dist/node/search.d.ts +17 -0
- package/dist/node/search.d.ts.map +1 -0
- package/dist/node/search.js +72 -0
- package/dist/node/server.d.ts +12 -0
- package/dist/node/server.d.ts.map +1 -0
- package/dist/node/server.js +189 -0
- package/dist/node/stories.d.ts +22 -0
- package/dist/node/stories.d.ts.map +1 -0
- package/dist/node/stories.js +125 -0
- package/dist/node/tree.d.ts +4 -0
- package/dist/node/tree.d.ts.map +1 -0
- package/dist/node/tree.js +117 -0
- package/dist/node/util/find-up.d.ts +2 -0
- package/dist/node/util/find-up.d.ts.map +1 -0
- package/dist/node/util/find-up.js +20 -0
- package/dist/node/util/fs.d.ts +2 -0
- package/dist/node/util/fs.d.ts.map +1 -0
- package/dist/node/util/fs.js +1 -0
- package/dist/node/util/log.d.ts +2 -0
- package/dist/node/util/log.d.ts.map +1 -0
- package/dist/node/util/log.js +9 -0
- package/dist/node/util/slugify.d.ts +2 -0
- package/dist/node/util/slugify.d.ts.map +1 -0
- package/dist/node/util/slugify.js +22 -0
- package/dist/node/util/vendors.d.ts +3 -0
- package/dist/node/util/vendors.d.ts.map +1 -0
- package/dist/node/util/vendors.js +22 -0
- package/dist/node/vendors/controls.d.ts +2 -0
- package/dist/node/vendors/controls.d.ts.map +1 -0
- package/dist/node/vendors/controls.js +1 -0
- package/dist/node/vendors/vue.d.ts +2 -0
- package/dist/node/vendors/vue.d.ts.map +1 -0
- package/dist/node/vendors/vue.js +1 -0
- package/dist/node/virtual/index.d.ts +38 -0
- package/dist/node/virtual/index.d.ts.map +1 -0
- package/dist/node/virtual/index.js +49 -0
- package/dist/node/virtual/markdown.d.ts +3 -0
- package/dist/node/virtual/markdown.d.ts.map +1 -0
- package/dist/node/virtual/markdown.js +19 -0
- package/dist/node/virtual/noop.d.ts +2 -0
- package/dist/node/virtual/noop.d.ts.map +1 -0
- package/dist/node/virtual/noop.js +1 -0
- package/dist/node/virtual/resolved-commands.d.ts +3 -0
- package/dist/node/virtual/resolved-commands.d.ts.map +1 -0
- package/dist/node/virtual/resolved-commands.js +32 -0
- package/dist/node/virtual/resolved-config.d.ts +3 -0
- package/dist/node/virtual/resolved-config.d.ts.map +1 -0
- package/dist/node/virtual/resolved-config.js +10 -0
- package/dist/node/virtual/resolved-generated-global-setup.d.ts +3 -0
- package/dist/node/virtual/resolved-generated-global-setup.d.ts.map +1 -0
- package/dist/node/virtual/resolved-generated-global-setup.js +23 -0
- package/dist/node/virtual/resolved-generated-setup-code.d.ts +3 -0
- package/dist/node/virtual/resolved-generated-setup-code.d.ts.map +1 -0
- package/dist/node/virtual/resolved-generated-setup-code.js +5 -0
- package/dist/node/virtual/resolved-markdown-files.d.ts +3 -0
- package/dist/node/virtual/resolved-markdown-files.d.ts.map +1 -0
- package/dist/node/virtual/resolved-markdown-files.js +17 -0
- package/dist/node/virtual/resolved-stories.d.ts +3 -0
- package/dist/node/virtual/resolved-stories.d.ts.map +1 -0
- package/dist/node/virtual/resolved-stories.js +42 -0
- package/dist/node/virtual/resolved-support-plugins-client.d.ts +3 -0
- package/dist/node/virtual/resolved-support-plugins-client.d.ts.map +1 -0
- package/dist/node/virtual/resolved-support-plugins-client.js +11 -0
- package/dist/node/virtual/resolved-support-plugins-collect.d.ts +3 -0
- package/dist/node/virtual/resolved-support-plugins-collect.d.ts.map +1 -0
- package/dist/node/virtual/resolved-support-plugins-collect.js +11 -0
- package/dist/node/virtual/resolved-theme.d.ts +3 -0
- package/dist/node/virtual/resolved-theme.d.ts.map +1 -0
- package/dist/node/virtual/resolved-theme.js +12 -0
- package/dist/node/virtual/story-source.d.ts +3 -0
- package/dist/node/virtual/story-source.d.ts.map +1 -0
- package/dist/node/virtual/story-source.js +16 -0
- package/dist/node/virtual/story.d.ts +3 -0
- package/dist/node/virtual/story.d.ts.map +1 -0
- package/dist/node/virtual/story.js +7 -0
- package/dist/node/virtual/util.d.ts +3 -0
- package/dist/node/virtual/util.d.ts.map +1 -0
- package/dist/node/virtual/util.js +4 -0
- package/dist/node/virtual/vite-plugin.d.ts +4 -0
- package/dist/node/virtual/vite-plugin.d.ts.map +1 -0
- package/dist/node/virtual/vite-plugin.js +126 -0
- package/dist/node/vite.d.ts +9 -0
- package/dist/node/vite.d.ts.map +1 -0
- package/dist/node/vite.js +337 -0
- package/index.d.ts +1 -0
- package/package.json +89 -0
- package/plugin.d.ts +3 -0
- package/plugin.js +11 -0
- package/src/controls.ts +1 -0
- package/src/node/__tests__/markdown/test1.story.md +7 -0
- package/src/node/__tests__/markdown/test2.story.md +5 -0
- package/src/node/__tests__/markdown.spec.ts +61 -0
- package/src/node/__tests__/tree.spec.ts +109 -0
- package/src/node/alias.ts +8 -0
- package/src/node/bin.ts +43 -0
- package/src/node/build-serialize.ts +62 -0
- package/src/node/build.ts +283 -0
- package/src/node/builtin-plugins/pinceau-tokens.ts +521 -0
- package/src/node/builtin-plugins/tailwind-tokens.ts +536 -0
- package/src/node/builtin-plugins/vanilla-support/MountStory.ts +49 -0
- package/src/node/builtin-plugins/vanilla-support/RenderStory.ts +164 -0
- package/src/node/builtin-plugins/vanilla-support/client.ts +6 -0
- package/src/node/builtin-plugins/vanilla-support/collect.ts +43 -0
- package/src/node/builtin-plugins/vanilla-support/plugin.ts +35 -0
- package/src/node/builtin-plugins/vanilla-support/types.ts +40 -0
- package/src/node/builtin-plugins/vanilla-support/vanilla.story.ts +63 -0
- package/src/node/collect/index.ts +160 -0
- package/src/node/collect/run.ts +9 -0
- package/src/node/collect/worker.ts +97 -0
- package/src/node/colors.ts +340 -0
- package/src/node/commands/build.ts +14 -0
- package/src/node/commands/dev.ts +67 -0
- package/src/node/commands/preview.ts +22 -0
- package/src/node/config.ts +385 -0
- package/src/node/context.ts +60 -0
- package/src/node/dom/dom-keys.ts +238 -0
- package/src/node/dom/env.ts +60 -0
- package/src/node/dom/util.ts +83 -0
- package/src/node/index.ts +12 -0
- package/src/node/load.ts +59 -0
- package/src/node/markdown.ts +267 -0
- package/src/node/plugin.ts +95 -0
- package/src/node/preview.ts +57 -0
- package/src/node/search.ts +84 -0
- package/src/node/server.ts +235 -0
- package/src/node/stories.ts +154 -0
- package/src/node/tree.ts +158 -0
- package/src/node/util/find-up.ts +24 -0
- package/src/node/util/fs.ts +1 -0
- package/src/node/util/log.ts +10 -0
- package/src/node/util/slugify.ts +26 -0
- package/src/node/util/vendors.ts +27 -0
- package/src/node/vendors/controls.ts +1 -0
- package/src/node/vendors/vue.ts +1 -0
- package/src/node/virtual/index.ts +50 -0
- package/src/node/virtual/markdown.ts +21 -0
- package/src/node/virtual/noop.ts +1 -0
- package/src/node/virtual/resolved-commands.ts +42 -0
- package/src/node/virtual/resolved-config.ts +12 -0
- package/src/node/virtual/resolved-generated-global-setup.ts +25 -0
- package/src/node/virtual/resolved-generated-setup-code.ts +7 -0
- package/src/node/virtual/resolved-markdown-files.ts +19 -0
- package/src/node/virtual/resolved-stories.ts +44 -0
- package/src/node/virtual/resolved-support-plugins-client.ts +14 -0
- package/src/node/virtual/resolved-support-plugins-collect.ts +14 -0
- package/src/node/virtual/resolved-theme.ts +14 -0
- package/src/node/virtual/story-source.ts +18 -0
- package/src/node/virtual/story.ts +9 -0
- package/src/node/virtual/util.ts +5 -0
- package/src/node/virtual/vite-plugin.ts +146 -0
- package/src/node/vite.ts +379 -0
- package/tsconfig.json +44 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JSDOM,
|
|
3
|
+
VirtualConsole,
|
|
4
|
+
} from 'jsdom'
|
|
5
|
+
import { populateGlobal } from './util.js'
|
|
6
|
+
|
|
7
|
+
export function createDomEnv() {
|
|
8
|
+
const dom = new JSDOM(
|
|
9
|
+
'<!DOCTYPE html>',
|
|
10
|
+
{
|
|
11
|
+
pretendToBeVisual: true,
|
|
12
|
+
runScripts: 'dangerously',
|
|
13
|
+
url: 'http://localhost:3000',
|
|
14
|
+
virtualConsole: console && globalThis.console ? new VirtualConsole().forwardTo(globalThis.console) : undefined,
|
|
15
|
+
includeNodeLocations: false,
|
|
16
|
+
contentType: 'text/html',
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const { keys, originals } = populateGlobal(globalThis, dom.window, { bindFunctions: true })
|
|
21
|
+
|
|
22
|
+
function destroy() {
|
|
23
|
+
keys.forEach(key => delete globalThis[key])
|
|
24
|
+
originals.forEach((v, k) => {
|
|
25
|
+
globalThis[k] = v
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
window.ResizeObserver = window.ResizeObserver || class ResizeObserver {
|
|
30
|
+
disconnect(): void { /* noop */ }
|
|
31
|
+
observe(_target: Element, _options?: ResizeObserverOptions): void { /* noop */ }
|
|
32
|
+
unobserve(_target: Element): void { /* noop */ }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
window.IntersectionObserver = window.IntersectionObserver || class IntersectionObserver {
|
|
36
|
+
root: Element
|
|
37
|
+
rootMargin: string
|
|
38
|
+
thresholds: number[]
|
|
39
|
+
disconnect(): void { /* noop */ }
|
|
40
|
+
observe = (_target: Element) => void { /* noop */ }
|
|
41
|
+
unobserve(_target: Element): void { /* noop */ }
|
|
42
|
+
takeRecords(): IntersectionObserverEntry[] { return [] }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
window.matchMedia = window.matchMedia || ((query: string) => ({
|
|
46
|
+
matches: false,
|
|
47
|
+
media: query,
|
|
48
|
+
onchange: null,
|
|
49
|
+
addListener: () => {},
|
|
50
|
+
removeListener: () => {},
|
|
51
|
+
addEventListener: () => {},
|
|
52
|
+
removeEventListener: () => {},
|
|
53
|
+
dispatchEvent: () => false,
|
|
54
|
+
}))
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
window,
|
|
58
|
+
destroy,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code from vitest https://github.com/vitest-dev/vitest/blob/98974ba4a5b95a57a98bc2077b74bc5609d6bb3a/packages/vitest/src/integrations/env/utils.ts#L1 by @antfu and @patak
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { KEYS } from './dom-keys.js'
|
|
6
|
+
|
|
7
|
+
const skipKeys = [
|
|
8
|
+
'window',
|
|
9
|
+
'self',
|
|
10
|
+
'top',
|
|
11
|
+
'parent',
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export function getWindowKeys(global: any, win: any) {
|
|
15
|
+
const keys = new Set(KEYS.concat(Object.getOwnPropertyNames(win))
|
|
16
|
+
.filter((k) => {
|
|
17
|
+
if (skipKeys.includes(k)) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
if (k in global) {
|
|
21
|
+
return KEYS.includes(k)
|
|
22
|
+
}
|
|
23
|
+
return true
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
return keys
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isClassLikeName(name: string) {
|
|
30
|
+
return name[0] === name[0].toUpperCase()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface PopulateOptions {
|
|
34
|
+
// we bind functions such as addEventListener and others
|
|
35
|
+
// because they rely on `this` in happy-dom, and in jsdom it
|
|
36
|
+
// has a priority for getting implementation from symbols
|
|
37
|
+
// (global doesn't have these symbols, but window - does)
|
|
38
|
+
bindFunctions?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function populateGlobal(global: any, win: any, options: PopulateOptions = {}) {
|
|
42
|
+
const { bindFunctions = false } = options
|
|
43
|
+
const keys = getWindowKeys(global, win)
|
|
44
|
+
|
|
45
|
+
const originals = new Map<string | symbol, any>()
|
|
46
|
+
|
|
47
|
+
const overrideObject = new Map<string | symbol, any>()
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
const boundFunction = bindFunctions
|
|
50
|
+
&& typeof win[key] === 'function'
|
|
51
|
+
&& !isClassLikeName(key)
|
|
52
|
+
&& win[key].bind(win)
|
|
53
|
+
|
|
54
|
+
if (KEYS.includes(key) && key in global) originals.set(key, global[key])
|
|
55
|
+
|
|
56
|
+
Object.defineProperty(global, key, {
|
|
57
|
+
get() {
|
|
58
|
+
if (overrideObject.has(key)) return overrideObject.get(key)
|
|
59
|
+
if (boundFunction) return boundFunction
|
|
60
|
+
return win[key]
|
|
61
|
+
},
|
|
62
|
+
set(v) {
|
|
63
|
+
overrideObject.set(key, v)
|
|
64
|
+
},
|
|
65
|
+
configurable: true,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
global.window = global
|
|
70
|
+
global.self = global
|
|
71
|
+
global.top = global
|
|
72
|
+
global.parent = global
|
|
73
|
+
|
|
74
|
+
if (global.global) global.global = global
|
|
75
|
+
|
|
76
|
+
skipKeys.forEach(k => keys.add(k))
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
keys,
|
|
80
|
+
skipKeys,
|
|
81
|
+
originals,
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/node/load.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ModuleLoader } from '@poveste/shared'
|
|
2
|
+
import type { ViteDevServer } from 'vite'
|
|
3
|
+
import { resolve } from 'pathe'
|
|
4
|
+
import pc from 'picocolors'
|
|
5
|
+
import { ViteNodeRunner } from 'vite-node/client'
|
|
6
|
+
import { ViteNodeServer } from 'vite-node/server'
|
|
7
|
+
|
|
8
|
+
export interface UseModuleLoaderOptions {
|
|
9
|
+
server: ViteDevServer
|
|
10
|
+
throws?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let _load: ModuleLoader['loadModule']
|
|
14
|
+
|
|
15
|
+
export function useModuleLoader(options: UseModuleLoaderOptions): ModuleLoader {
|
|
16
|
+
const { server } = options
|
|
17
|
+
|
|
18
|
+
const node = new ViteNodeServer(server as any)
|
|
19
|
+
|
|
20
|
+
const runner = new ViteNodeRunner({
|
|
21
|
+
root: server.config.root,
|
|
22
|
+
base: server.config.base,
|
|
23
|
+
fetchModule: async id => node.fetchModule(id),
|
|
24
|
+
resolveId: (id, importer) => node.resolveId(id, importer),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
function clearCache() {
|
|
28
|
+
server.moduleGraph.invalidateAll()
|
|
29
|
+
node.fetchCache.clear()
|
|
30
|
+
runner.moduleCache.clear()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function loadModule(file: string) {
|
|
34
|
+
try {
|
|
35
|
+
const result = await runner.executeFile(resolve(file))
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
console.error(pc.red(`Error while loading module ${file}:\n${e.frame ? `${pc.bold(e.message)}\n${e.frame}` : e.stack}`))
|
|
40
|
+
if (options.throws) {
|
|
41
|
+
throw e
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_load = loadModule
|
|
47
|
+
|
|
48
|
+
async function destroy() {
|
|
49
|
+
// Noop
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
clearCache,
|
|
54
|
+
loadModule,
|
|
55
|
+
destroy,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const loadModule: ModuleLoader['loadModule'] = (...args) => _load?.(...args)
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import type { ServerMarkdownFile } from '@poveste/shared'
|
|
2
|
+
import type { Plugin as VitePlugin } from 'vite'
|
|
3
|
+
import type { Context } from './context.js'
|
|
4
|
+
import { kebabCase } from 'change-case'
|
|
5
|
+
import chokidar from 'chokidar'
|
|
6
|
+
import fs from 'fs-extra'
|
|
7
|
+
import matter from 'gray-matter'
|
|
8
|
+
import MarkdownIt from 'markdown-it'
|
|
9
|
+
import anchor from 'markdown-it-anchor'
|
|
10
|
+
import attrs from 'markdown-it-attrs'
|
|
11
|
+
import { full as emoji } from 'markdown-it-emoji'
|
|
12
|
+
import micromatch from 'micromatch'
|
|
13
|
+
import path from 'pathe'
|
|
14
|
+
import pc from 'picocolors'
|
|
15
|
+
import { bundledLanguages, createHighlighter } from 'shiki'
|
|
16
|
+
import { addStory, notifyStoryChange, removeStory } from './stories.js'
|
|
17
|
+
import { slugify } from './util/slugify.js'
|
|
18
|
+
|
|
19
|
+
const onMarkdownListChangeHandlers: (() => unknown)[] = []
|
|
20
|
+
|
|
21
|
+
export function onMarkdownListChange(handler: () => unknown) {
|
|
22
|
+
onMarkdownListChangeHandlers.push(handler)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function notifyMarkdownListChange() {
|
|
26
|
+
for (const handler of onMarkdownListChangeHandlers) {
|
|
27
|
+
handler()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function createMarkdownRenderer(ctx: Context) {
|
|
32
|
+
const highlighter = await createHighlighter({
|
|
33
|
+
themes: ['github-dark'],
|
|
34
|
+
langs: Object.keys(bundledLanguages), // not ideal but markdown-it does not provide async highlight
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const md = new MarkdownIt({
|
|
38
|
+
highlight: (code, lang) => `<div class="htw-relative htw-not-prose __histoire-code"><div class="htw-absolute htw-top-0 htw-right-0 htw-text-xs htw-text-white/40">${lang}</div>${highlighter.codeToHtml(code, { theme: 'github-dark', lang })}</div>`,
|
|
39
|
+
linkify: true,
|
|
40
|
+
html: true,
|
|
41
|
+
breaks: false,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
md.use(anchor, {
|
|
45
|
+
slugify,
|
|
46
|
+
permalink: anchor.permalink.ariaHidden({}),
|
|
47
|
+
})
|
|
48
|
+
.use(attrs)
|
|
49
|
+
.use(emoji)
|
|
50
|
+
|
|
51
|
+
// External links
|
|
52
|
+
{
|
|
53
|
+
const defaultRender = md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
|
|
54
|
+
return self.renderToken(tokens, idx, options)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
|
58
|
+
const token = tokens[idx]
|
|
59
|
+
const hrefIndex = token.attrIndex('href')
|
|
60
|
+
const classIndex = token.attrIndex('class')
|
|
61
|
+
|
|
62
|
+
if (hrefIndex >= 0) {
|
|
63
|
+
const href = token.attrs[hrefIndex][1]
|
|
64
|
+
if (href.startsWith('.')) {
|
|
65
|
+
const queryIndex = href.indexOf('?')
|
|
66
|
+
const pathname = queryIndex >= 0 ? href.slice(0, queryIndex) : href
|
|
67
|
+
const query = queryIndex >= 0 ? href.slice(queryIndex) : ''
|
|
68
|
+
|
|
69
|
+
// File lookup
|
|
70
|
+
const file = path.resolve(path.dirname(env.file), pathname)
|
|
71
|
+
const storyFile = ctx.storyFiles.find(f => f.path === file)
|
|
72
|
+
const mdFile = ctx.markdownFiles.find(f => f.absolutePath === file)
|
|
73
|
+
if (!storyFile && !mdFile?.storyFile) {
|
|
74
|
+
throw new Error(pc.red(`[md] Cannot find story file: ${pathname} from ${env.file}`))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Add attributes
|
|
78
|
+
const newHref = `${ctx.resolvedViteConfig.base}story/${encodeURIComponent(storyFile?.id ?? mdFile.storyFile.id)}${query}`
|
|
79
|
+
token.attrSet('href', newHref)
|
|
80
|
+
token.attrSet('data-route', 'true')
|
|
81
|
+
}
|
|
82
|
+
else if (!href.startsWith('/') && !href.startsWith('#') && (classIndex < 0 || !token.attrs[classIndex][1].includes('header-anchor'))) {
|
|
83
|
+
// Add target="_blank" to external links
|
|
84
|
+
const aIndex = token.attrIndex('target')
|
|
85
|
+
|
|
86
|
+
if (aIndex < 0) {
|
|
87
|
+
token.attrPush(['target', '_blank']) // add new attribute
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
token.attrs[aIndex][1] = '_blank' // replace value of existing attr
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// pass token to default renderer.
|
|
96
|
+
return defaultRender(tokens, idx, options, env, self)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return md
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function createMarkdownRendererWithPlugins(ctx: Context) {
|
|
104
|
+
let md = await createMarkdownRenderer(ctx)
|
|
105
|
+
if (ctx.config.markdown) {
|
|
106
|
+
const result = await ctx.config.markdown(md)
|
|
107
|
+
if (result) {
|
|
108
|
+
md = result
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return md
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function createMarkdownPlugins(ctx: Context) {
|
|
115
|
+
const plugins: VitePlugin[] = []
|
|
116
|
+
const md = await createMarkdownRendererWithPlugins(ctx)
|
|
117
|
+
|
|
118
|
+
// @TODO extract
|
|
119
|
+
plugins.push({
|
|
120
|
+
name: 'histoire-vue-docs-block',
|
|
121
|
+
transform(code, id) {
|
|
122
|
+
if (!id.includes('?vue&type=docs')) return
|
|
123
|
+
if (!id.includes('lang.md')) return
|
|
124
|
+
const file = id.substring(0, id.indexOf('?vue'))
|
|
125
|
+
const html = md.render(code, {
|
|
126
|
+
file,
|
|
127
|
+
})
|
|
128
|
+
return `export default Comp => {
|
|
129
|
+
Comp.doc = ${JSON.stringify(html)}
|
|
130
|
+
}`
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
return plugins
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function createMarkdownFilesWatcher(ctx: Context) {
|
|
138
|
+
const md = await createMarkdownRendererWithPlugins(ctx)
|
|
139
|
+
|
|
140
|
+
const watcher = chokidar.watch('.', {
|
|
141
|
+
cwd: ctx.root,
|
|
142
|
+
ignored: (path, stats) => {
|
|
143
|
+
if (ctx.config.storyIgnored.some(pattern => micromatch.isMatch(path, pattern))) {
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
if (micromatch.isMatch(path, '**/*.story.md')) {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return stats?.isFile()
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Initial scan is complete.
|
|
156
|
+
*/
|
|
157
|
+
let watcherIsReady = false
|
|
158
|
+
|
|
159
|
+
function addFile(relativePath: string) {
|
|
160
|
+
const absolutePath = path.resolve(ctx.root, relativePath)
|
|
161
|
+
const dirFiles = fs.readdirSync(path.dirname(absolutePath))
|
|
162
|
+
const truncatedName = path.basename(absolutePath, '.md')
|
|
163
|
+
const isRelatedToStory = dirFiles.some(file => !file.endsWith('.md') && file.startsWith(truncatedName))
|
|
164
|
+
|
|
165
|
+
const { data: frontmatter, content } = matter(fs.readFileSync(absolutePath, 'utf8'))
|
|
166
|
+
|
|
167
|
+
let html: string | undefined
|
|
168
|
+
|
|
169
|
+
// We don't immediately render markdown during initial scanning in case
|
|
170
|
+
// markdown references other files in links (otherwise they might not
|
|
171
|
+
// be scanned yet and will throw 'not found' errors).
|
|
172
|
+
if (watcherIsReady) {
|
|
173
|
+
html = md.render(content, {
|
|
174
|
+
file: absolutePath,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const file: ServerMarkdownFile = {
|
|
179
|
+
id: kebabCase(relativePath.toLowerCase()),
|
|
180
|
+
relativePath,
|
|
181
|
+
absolutePath,
|
|
182
|
+
isRelatedToStory,
|
|
183
|
+
frontmatter,
|
|
184
|
+
content,
|
|
185
|
+
html,
|
|
186
|
+
}
|
|
187
|
+
ctx.markdownFiles.push(file)
|
|
188
|
+
|
|
189
|
+
if (!isRelatedToStory) {
|
|
190
|
+
const storyRelativePath = relativePath.replace(/\.md$/, '.js')
|
|
191
|
+
const storyFile = addStory(storyRelativePath, `export default ${JSON.stringify({
|
|
192
|
+
id: frontmatter.id,
|
|
193
|
+
title: frontmatter.title,
|
|
194
|
+
icon: frontmatter.icon ?? 'carbon:document-blank',
|
|
195
|
+
iconColor: frontmatter.iconColor,
|
|
196
|
+
group: frontmatter.group,
|
|
197
|
+
docsOnly: true,
|
|
198
|
+
variants: [],
|
|
199
|
+
})}`)
|
|
200
|
+
file.storyFile = storyFile
|
|
201
|
+
storyFile.markdownFile = file
|
|
202
|
+
notifyStoryChange(storyFile)
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
const searchPath = path.join(path.dirname(relativePath), truncatedName)
|
|
206
|
+
const storyFile = ctx.storyFiles.find(f => f.relativePath.startsWith(searchPath))
|
|
207
|
+
if (storyFile) {
|
|
208
|
+
file.storyFile = storyFile
|
|
209
|
+
storyFile.markdownFile = file
|
|
210
|
+
notifyStoryChange(storyFile)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
notifyMarkdownListChange()
|
|
215
|
+
|
|
216
|
+
return file
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function removeFile(relativePath: string) {
|
|
220
|
+
const index = ctx.markdownFiles.findIndex(file => file.relativePath === relativePath)
|
|
221
|
+
if (index !== -1) {
|
|
222
|
+
const file = ctx.markdownFiles[index]
|
|
223
|
+
if (!file.isRelatedToStory) {
|
|
224
|
+
removeStory(file.storyFile.relativePath)
|
|
225
|
+
notifyStoryChange()
|
|
226
|
+
}
|
|
227
|
+
ctx.markdownFiles.splice(index, 1)
|
|
228
|
+
notifyMarkdownListChange()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function stop() {
|
|
233
|
+
await watcher.close()
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
watcher
|
|
237
|
+
.on('add', (relativePath) => {
|
|
238
|
+
addFile(relativePath)
|
|
239
|
+
})
|
|
240
|
+
.on('unlink', (relativePath) => {
|
|
241
|
+
removeFile(relativePath)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
await new Promise((resolve) => {
|
|
245
|
+
watcher.once('ready', resolve as () => void)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
// Render markdown after initial scan is complete.
|
|
250
|
+
for (const mdFile of ctx.markdownFiles) {
|
|
251
|
+
mdFile.html = md.render(mdFile.content, {
|
|
252
|
+
file: mdFile.absolutePath,
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
watcherIsReady = true
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
stop,
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
await stop()
|
|
263
|
+
throw e
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export type MarkdownFilesWatcher = ReturnType<typeof createMarkdownFilesWatcher>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BuildEndCallback,
|
|
3
|
+
ChangeViteConfigCallback,
|
|
4
|
+
ModuleLoader,
|
|
5
|
+
Plugin,
|
|
6
|
+
PluginApiBase,
|
|
7
|
+
PluginApiBuild,
|
|
8
|
+
PluginApiDev,
|
|
9
|
+
PluginApiDevEvent,
|
|
10
|
+
PovesteConfig,
|
|
11
|
+
PreviewStoryCallback,
|
|
12
|
+
ServerStory,
|
|
13
|
+
} from '@poveste/shared'
|
|
14
|
+
import type { Context } from './context.js'
|
|
15
|
+
import chokidar from 'chokidar'
|
|
16
|
+
import fs from 'fs-extra'
|
|
17
|
+
import path from 'pathe'
|
|
18
|
+
import pc from 'picocolors'
|
|
19
|
+
import { TEMP_PATH } from './alias.js'
|
|
20
|
+
import { addStory, removeStory } from './stories.js'
|
|
21
|
+
|
|
22
|
+
export class BasePluginApi implements PluginApiBase {
|
|
23
|
+
colors = pc
|
|
24
|
+
path = path
|
|
25
|
+
fs = fs
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
protected ctx: Context,
|
|
29
|
+
protected plugin: Plugin,
|
|
30
|
+
public moduleLoader: ModuleLoader,
|
|
31
|
+
) { }
|
|
32
|
+
|
|
33
|
+
get pluginTempDir() {
|
|
34
|
+
return path.resolve(TEMP_PATH, 'plugins', this.plugin.name.replace(/:/g, '_'))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
log(...msg) {
|
|
38
|
+
console.log(this.colors.gray(`[Plugin:${this.plugin.name}]`), ...msg)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
warn(...msg) {
|
|
42
|
+
console.warn(this.colors.yellow(`[Plugin:${this.plugin.name}]`), ...msg)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
error(...msg) {
|
|
46
|
+
console.error(this.colors.red(`[Plugin:${this.plugin.name}]`), ...msg)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
addStoryFile(file: string) {
|
|
50
|
+
removeStory(file)
|
|
51
|
+
addStory(file)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getStories(): ServerStory[] {
|
|
55
|
+
return this.ctx.storyFiles.map(f => f.story).filter(Boolean)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getConfig(): PovesteConfig {
|
|
59
|
+
return this.ctx.config
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class DevPluginApi extends BasePluginApi implements PluginApiDev {
|
|
64
|
+
watcher = chokidar
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class BuildPluginApi extends BasePluginApi implements PluginApiBuild {
|
|
68
|
+
changeViteConfigCallbacks: ChangeViteConfigCallback[] = []
|
|
69
|
+
buildEndCallbacks: BuildEndCallback[] = []
|
|
70
|
+
previewStoryCallbacks: PreviewStoryCallback[] = []
|
|
71
|
+
|
|
72
|
+
changeViteConfig(cb: ChangeViteConfigCallback) {
|
|
73
|
+
this.changeViteConfigCallbacks.push(cb)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
onBuildEnd(cb: BuildEndCallback) {
|
|
77
|
+
this.buildEndCallbacks.push(cb)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
onPreviewStory(cb: PreviewStoryCallback) {
|
|
81
|
+
this.previewStoryCallbacks.push(cb)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class DevEventPluginApi extends BasePluginApi implements PluginApiDevEvent {
|
|
86
|
+
constructor(
|
|
87
|
+
ctx: Context,
|
|
88
|
+
plugin: Plugin,
|
|
89
|
+
moduleLoader: ModuleLoader,
|
|
90
|
+
public event: string,
|
|
91
|
+
public payload: any,
|
|
92
|
+
) {
|
|
93
|
+
super(ctx, plugin, moduleLoader)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Context } from './context.js'
|
|
2
|
+
import http from 'node:http'
|
|
3
|
+
import connect from 'connect'
|
|
4
|
+
import sirv from 'sirv'
|
|
5
|
+
|
|
6
|
+
interface ReturnPayload {
|
|
7
|
+
baseUrl: string
|
|
8
|
+
close: () => Promise<void>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function startPreview(port: number | null, ctx: Context): Promise<ReturnPayload> {
|
|
12
|
+
const app = connect()
|
|
13
|
+
|
|
14
|
+
app.use(
|
|
15
|
+
ctx.resolvedViteConfig.base,
|
|
16
|
+
sirv(ctx.config.outDir, {
|
|
17
|
+
dev: true,
|
|
18
|
+
etag: true,
|
|
19
|
+
single: true,
|
|
20
|
+
}),
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
let finalPort = port ?? 6006
|
|
24
|
+
|
|
25
|
+
const httpServer = http.createServer(app)
|
|
26
|
+
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
function onError(e: Error & { code?: string }) {
|
|
29
|
+
if (e.code === 'EADDRINUSE') {
|
|
30
|
+
httpServer.listen(++finalPort)
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
reject(e)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
httpServer.on('error', onError)
|
|
38
|
+
|
|
39
|
+
httpServer.listen(finalPort, () => {
|
|
40
|
+
httpServer.off('error', onError)
|
|
41
|
+
const baseUrl = `http://localhost:${finalPort}${ctx.resolvedViteConfig.base}`
|
|
42
|
+
resolve({
|
|
43
|
+
baseUrl,
|
|
44
|
+
close: () => new Promise((resolve, reject) => {
|
|
45
|
+
httpServer.close((err) => {
|
|
46
|
+
if (err) {
|
|
47
|
+
reject(err)
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
resolve()
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}),
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
}
|