@xyd-js/plugin-docs 0.1.0-build.160
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 +21 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +4605 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
- package/src/const.ts +7 -0
- package/src/declarations.d.ts +29 -0
- package/src/index.ts +386 -0
- package/src/pages/context.tsx +9 -0
- package/src/pages/layout.tsx +340 -0
- package/src/pages/metatags.ts +96 -0
- package/src/pages/page.tsx +463 -0
- package/src/presets/docs/index.ts +317 -0
- package/src/presets/docs/settings.ts +262 -0
- package/src/presets/graphql/index.ts +69 -0
- package/src/presets/openapi/index.ts +66 -0
- package/src/presets/sources/index.ts +74 -0
- package/src/presets/uniform/index.ts +832 -0
- package/src/types.ts +40 -0
- package/src/utils.ts +19 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xyd-js/plugin-docs",
|
|
3
|
+
"version": "0.1.0-build.160",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src",
|
|
15
|
+
"package.json"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"codehike": "^1.0.3",
|
|
19
|
+
"@code-hike/lighter": "^1.0.3",
|
|
20
|
+
"dotenv": "^16.4.7",
|
|
21
|
+
"@xyd-js/gql": "0.1.0-build.170",
|
|
22
|
+
"@xyd-js/uniform": "0.1.0-build.172",
|
|
23
|
+
"@xyd-js/sources": "0.1.1-build.160",
|
|
24
|
+
"@xyd-js/openapi": "0.1.0-build.168"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@react-router/dev": "^7.7.1",
|
|
28
|
+
"@react-router/node": "^7.7.1",
|
|
29
|
+
"@react-router/serve": "^7.7.1",
|
|
30
|
+
"openux-js": "0.0.0-pre.1",
|
|
31
|
+
"react": "^19.1.0",
|
|
32
|
+
"react-dom": "^19.1.0",
|
|
33
|
+
"react-router": "^7.7.1",
|
|
34
|
+
"@xyd-js/framework": "0.1.0-build.189",
|
|
35
|
+
"@xyd-js/composer": "0.1.0-build.157",
|
|
36
|
+
"@xyd-js/themes": "0.1.1-build.160",
|
|
37
|
+
"@xyd-js/components": "0.1.0-build.168",
|
|
38
|
+
"@xyd-js/core": "0.1.0-build.170",
|
|
39
|
+
"@xyd-js/content": "0.1.0-build.171"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/react-dom": "^19.1.0",
|
|
43
|
+
"@types/react": "^19.1.0",
|
|
44
|
+
"@vitejs/plugin-react": "^4.3.2",
|
|
45
|
+
"tsup": "^8.3.0",
|
|
46
|
+
"typescript": "^5.6.2",
|
|
47
|
+
"vite": "^7.0.0",
|
|
48
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
49
|
+
"rimraf": "^3.0.2"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"clean": "rimraf build",
|
|
53
|
+
"prebuild": "pnpm clean",
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"watch": "tsup --watch"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/const.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {ThemePresetName} from "@xyd-js/core";
|
|
2
|
+
|
|
3
|
+
export const THEME_CONFIG_FOLDER = ".docs/theme" // TODO: in the future shared internal const like `.xyd` and `.docs` ?
|
|
4
|
+
// TODO: SHARED
|
|
5
|
+
export const VIRTUAL_CONTENT_FOLDER = ".xyd/.cache/.content"
|
|
6
|
+
|
|
7
|
+
export const DEFAULT_THEME: ThemePresetName = "poetry"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// declarations.d.ts
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
declare module 'virtual:xyd-settings' {
|
|
5
|
+
import type {Settings} from "@xyd-js/core";
|
|
6
|
+
|
|
7
|
+
const settings: Settings;
|
|
8
|
+
export default settings;
|
|
9
|
+
export {
|
|
10
|
+
settings as Settings
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module 'virtual:xyd-theme' {
|
|
15
|
+
import {BaseTheme} from "@xyd-js/themes";
|
|
16
|
+
import {Theme as ThemeSettings} from "@xyd-js/core";
|
|
17
|
+
|
|
18
|
+
// Export a concrete theme class that extends BaseTheme
|
|
19
|
+
class ConcreteTheme extends BaseTheme {
|
|
20
|
+
constructor();
|
|
21
|
+
}
|
|
22
|
+
export default ConcreteTheme;
|
|
23
|
+
}
|
|
24
|
+
declare module 'virtual:xyd-user-components' {
|
|
25
|
+
const components: any
|
|
26
|
+
export {
|
|
27
|
+
components
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Navigation, Settings } from "@xyd-js/core";
|
|
2
|
+
import type { Plugin as VitePlugin } from "vite";
|
|
3
|
+
import { RouteConfigEntry } from "@react-router/dev/routes";
|
|
4
|
+
import type { PageURL, Sidebar, SidebarRoute } from "@xyd-js/core";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
import { docsPreset } from "./presets/docs";
|
|
9
|
+
import { graphqlPreset } from "./presets/graphql";
|
|
10
|
+
import { openapiPreset } from "./presets/openapi";
|
|
11
|
+
import { sourcesPreset } from "./presets/sources";
|
|
12
|
+
|
|
13
|
+
import type { PluginOutput, Plugin } from "./types";
|
|
14
|
+
import { ensureAndCleanupVirtualFolder } from "./presets/uniform";
|
|
15
|
+
|
|
16
|
+
export { readSettings } from "./presets/docs/settings"
|
|
17
|
+
|
|
18
|
+
export interface PluginDocsOptions {
|
|
19
|
+
disableAPIGeneration?: boolean
|
|
20
|
+
disableFSWrite?: boolean
|
|
21
|
+
appInit?: any
|
|
22
|
+
onUpdate?: (callback: (settings: Settings) => void) => void
|
|
23
|
+
doNotInstallPluginDependencies?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TODO: better plugin runner
|
|
27
|
+
// TODO: REFACTOR
|
|
28
|
+
export async function pluginDocs(options?: PluginDocsOptions): Promise<PluginOutput | null> {
|
|
29
|
+
let settings: Settings | null = null
|
|
30
|
+
const vitePlugins: VitePlugin[] = []
|
|
31
|
+
const routes: RouteConfigEntry[] = []
|
|
32
|
+
let basePath = ""
|
|
33
|
+
|
|
34
|
+
// base docs preset setup
|
|
35
|
+
{
|
|
36
|
+
const presetOptions = {
|
|
37
|
+
urlPrefix: "", // TODO: configurable,
|
|
38
|
+
appInit: options?.appInit,
|
|
39
|
+
onUpdate: options?.onUpdate
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const docs = docsPreset(undefined, presetOptions)
|
|
43
|
+
docs.preinstall = docs.preinstall || []
|
|
44
|
+
|
|
45
|
+
let preinstallMerge = {}
|
|
46
|
+
|
|
47
|
+
for (const preinstall of docs.preinstall) {
|
|
48
|
+
const resp = await preinstall()({}, {
|
|
49
|
+
routes: docs.routes
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (resp && typeof resp === 'object') {
|
|
53
|
+
preinstallMerge = {
|
|
54
|
+
...preinstallMerge,
|
|
55
|
+
...resp
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
docs.vitePlugins = docs.vitePlugins || []
|
|
61
|
+
for (const vitePlugin of docs.vitePlugins) {
|
|
62
|
+
const vitePlug = await vitePlugin()({
|
|
63
|
+
preinstall: preinstallMerge
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
vitePlugins.push(vitePlug)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if ("settings" in preinstallMerge) {
|
|
70
|
+
settings = preinstallMerge.settings as Settings
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
docs.routes = docs.routes || []
|
|
74
|
+
routes.push(...docs.routes)
|
|
75
|
+
basePath = docs.basePath
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!settings) {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await ensureAndCleanupVirtualFolder()
|
|
83
|
+
|
|
84
|
+
// graphql preset setup
|
|
85
|
+
if (!options?.disableAPIGeneration && settings?.api?.graphql) {
|
|
86
|
+
const opt = {
|
|
87
|
+
disableFSWrite: options?.disableFSWrite
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const gql = graphqlPreset(settings, opt)
|
|
91
|
+
gql.preinstall = gql.preinstall || []
|
|
92
|
+
|
|
93
|
+
let preinstallMerge = {}
|
|
94
|
+
|
|
95
|
+
for (const preinstall of gql.preinstall) {
|
|
96
|
+
const resp = await preinstall(opt)(settings, {
|
|
97
|
+
routes: gql.routes,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
if (resp && typeof resp === 'object') {
|
|
101
|
+
preinstallMerge = {
|
|
102
|
+
...preinstallMerge,
|
|
103
|
+
...resp
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
gql.vitePlugins = gql.vitePlugins || []
|
|
109
|
+
for (const vitePlugin of gql.vitePlugins) {
|
|
110
|
+
const vitePlug = await vitePlugin()({
|
|
111
|
+
preinstall: preinstallMerge
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
vitePlugins.push(vitePlug)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
gql.routes = gql.routes || []
|
|
118
|
+
routes.push(...gql.routes)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// openapi preset setup
|
|
122
|
+
if (!options?.disableAPIGeneration && settings?.api?.openapi) {
|
|
123
|
+
const opt = {
|
|
124
|
+
disableFSWrite: options?.disableFSWrite
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const oap = openapiPreset(settings, opt)
|
|
128
|
+
oap.preinstall = oap.preinstall || []
|
|
129
|
+
|
|
130
|
+
let preinstallMerge = {}
|
|
131
|
+
|
|
132
|
+
for (const preinstall of oap.preinstall) {
|
|
133
|
+
const resp = await preinstall(opt)(settings, {
|
|
134
|
+
routes: oap.routes,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
if (resp && typeof resp === 'object') {
|
|
138
|
+
preinstallMerge = {
|
|
139
|
+
...preinstallMerge,
|
|
140
|
+
...resp
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
oap.vitePlugins = oap.vitePlugins || []
|
|
146
|
+
for (const vitePlugin of oap.vitePlugins) {
|
|
147
|
+
const vitePlug = await vitePlugin()({
|
|
148
|
+
preinstall: preinstallMerge
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
vitePlugins.push(vitePlug)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
oap.routes = oap.routes || []
|
|
155
|
+
routes.push(...oap.routes)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!options?.disableAPIGeneration && settings?.api?.sources) {
|
|
159
|
+
const opt = {
|
|
160
|
+
disableFSWrite: options?.disableFSWrite
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const src = sourcesPreset(settings, opt)
|
|
164
|
+
src.preinstall = src.preinstall || []
|
|
165
|
+
|
|
166
|
+
let preinstallMerge = {}
|
|
167
|
+
|
|
168
|
+
for (const preinstall of src.preinstall) {
|
|
169
|
+
const resp = await preinstall(opt)(settings, {
|
|
170
|
+
routes: src.routes,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (resp && typeof resp === 'object') {
|
|
174
|
+
preinstallMerge = {
|
|
175
|
+
...preinstallMerge,
|
|
176
|
+
...resp
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
src.vitePlugins = src.vitePlugins || []
|
|
182
|
+
for (const vitePlugin of src.vitePlugins) {
|
|
183
|
+
const vitePlug = await vitePlugin()({
|
|
184
|
+
preinstall: preinstallMerge
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
vitePlugins.push(vitePlug)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
src.routes = src.routes || []
|
|
191
|
+
routes.push(...src.routes)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let pagePathMapping: Record<string, string> = {}
|
|
195
|
+
|
|
196
|
+
if (settings?.navigation) {
|
|
197
|
+
pagePathMapping = mapNavigationToPagePathMapping(settings?.navigation)
|
|
198
|
+
} else {
|
|
199
|
+
console.warn("No navigation found in settings")
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
sortSidebarGroups(settings?.navigation?.sidebar || [])
|
|
203
|
+
|
|
204
|
+
const indexPage = await findIndexPage()
|
|
205
|
+
|
|
206
|
+
if (indexPage) {
|
|
207
|
+
pagePathMapping["index"] = indexPage
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
vitePlugins,
|
|
212
|
+
settings,
|
|
213
|
+
routes,
|
|
214
|
+
basePath,
|
|
215
|
+
pagePathMapping,
|
|
216
|
+
hasIndexPage: !!indexPage
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async function findIndexPage(): Promise<string> {
|
|
221
|
+
if (fs.existsSync("index.md")) {
|
|
222
|
+
return "index.md"
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (fs.existsSync("index.mdx")) {
|
|
226
|
+
return "index.mdx"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return ""
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function sortSidebarGroups(sidebar: (SidebarRoute | Sidebar | string)[]) {
|
|
233
|
+
// Apply recursive sorting to all routes
|
|
234
|
+
for (const entry of sidebar) {
|
|
235
|
+
if (typeof entry === 'string') continue;
|
|
236
|
+
if (!entry.pages) continue;
|
|
237
|
+
|
|
238
|
+
// Recursively sort nested groups first
|
|
239
|
+
for (const page of entry.pages) {
|
|
240
|
+
if (typeof page === 'object' && 'pages' in page && page.pages) {
|
|
241
|
+
sortSidebarGroups([page as Sidebar]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Separate groups with order from other items
|
|
246
|
+
const groupsWithOrder: Sidebar[] = [];
|
|
247
|
+
const otherItems: (Sidebar | string)[] = [];
|
|
248
|
+
|
|
249
|
+
for (const page of entry.pages) {
|
|
250
|
+
if (typeof page === 'object' && 'group' in page && page.group && 'order' in page && page.order !== undefined) {
|
|
251
|
+
groupsWithOrder.push(page as Sidebar);
|
|
252
|
+
} else {
|
|
253
|
+
otherItems.push(page as Sidebar | string);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Sort groups with order
|
|
258
|
+
if (groupsWithOrder.length > 0) {
|
|
259
|
+
const groupMap = new Map<string, Sidebar>();
|
|
260
|
+
for (const group of groupsWithOrder) {
|
|
261
|
+
if (group.group) {
|
|
262
|
+
groupMap.set(group.group, group);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const sortedGroups: Sidebar[] = [];
|
|
267
|
+
|
|
268
|
+
// First pass: order: 0 (always on top)
|
|
269
|
+
for (const [_, group] of groupMap) {
|
|
270
|
+
if (group.order === 0) sortedGroups.push(group);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Second pass: groups without "before/after"
|
|
274
|
+
for (const [name, group] of groupMap) {
|
|
275
|
+
if (!group.order || typeof group.order === 'number') {
|
|
276
|
+
if (group.order !== 0 && group.order !== -1) {
|
|
277
|
+
sortedGroups.push(group);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Third pass: before/after
|
|
283
|
+
for (const [name, group] of groupMap) {
|
|
284
|
+
if (group.order && typeof group.order === 'object' && ('before' in group.order || 'after' in group.order)) {
|
|
285
|
+
const target = 'before' in group.order ? group.order.before : group.order.after;
|
|
286
|
+
const idx = sortedGroups.findIndex(g => g.group === target);
|
|
287
|
+
if (idx !== -1) {
|
|
288
|
+
if ('before' in group.order) {
|
|
289
|
+
sortedGroups.splice(idx, 0, group);
|
|
290
|
+
} else {
|
|
291
|
+
sortedGroups.splice(idx + 1, 0, group);
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
sortedGroups.push(group); // fallback
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Last: order: -1 (always at end)
|
|
300
|
+
for (const [_, group] of groupMap) {
|
|
301
|
+
if (group.order === -1) sortedGroups.push(group);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Replace the original pages with sorted groups + other items
|
|
305
|
+
entry.pages = [...sortedGroups, ...otherItems];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// TODO: in the future better algorithm - we should be .md/.mdx faster than checking fs here
|
|
311
|
+
function mapNavigationToPagePathMapping(navigation: Navigation) {
|
|
312
|
+
const mapping: Record<string, string> = {}
|
|
313
|
+
|
|
314
|
+
function getExistingFilePath(basePath: string): string | null {
|
|
315
|
+
const mdPath = `${basePath}.md`
|
|
316
|
+
const mdxPath = `${basePath}.mdx`
|
|
317
|
+
|
|
318
|
+
if (fs.existsSync(mdPath)) {
|
|
319
|
+
return mdPath
|
|
320
|
+
}
|
|
321
|
+
if (fs.existsSync(mdxPath)) {
|
|
322
|
+
return mdxPath
|
|
323
|
+
}
|
|
324
|
+
return null
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function processPages(pages: PageURL[]) {
|
|
328
|
+
for (const page of pages) {
|
|
329
|
+
if (typeof page === 'string') {
|
|
330
|
+
// Handle regular page
|
|
331
|
+
const existingPath = getExistingFilePath(page)
|
|
332
|
+
if (existingPath) {
|
|
333
|
+
mapping[page] = existingPath
|
|
334
|
+
}
|
|
335
|
+
} else if (typeof page === 'object' && 'virtual' in page) {
|
|
336
|
+
// Handle virtual page
|
|
337
|
+
const virtualPath = page.virtual
|
|
338
|
+
const pagePath = page.page
|
|
339
|
+
const existingPath = getExistingFilePath(virtualPath)
|
|
340
|
+
if (existingPath) {
|
|
341
|
+
mapping[pagePath] = existingPath
|
|
342
|
+
}
|
|
343
|
+
} else if (typeof page === 'object' && 'pages' in page) {
|
|
344
|
+
// Handle nested sidebar
|
|
345
|
+
processPages(page.pages || [])
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
let sidebarFlatOnly = false
|
|
351
|
+
// Process each sidebar route
|
|
352
|
+
for (const sidebar of navigation?.sidebar || []) {
|
|
353
|
+
if (typeof sidebar === 'string') {
|
|
354
|
+
sidebarFlatOnly = true
|
|
355
|
+
break
|
|
356
|
+
} else if ('pages' in sidebar && "route" in sidebar) {
|
|
357
|
+
// Handle SidebarRoute
|
|
358
|
+
for (const item of sidebar.pages) {
|
|
359
|
+
if (item?.pages) {
|
|
360
|
+
processPages(item.pages)
|
|
361
|
+
} else if (typeof item === 'string') {
|
|
362
|
+
// Handle direct string pages in SidebarRoute
|
|
363
|
+
const existingPath = getExistingFilePath(item)
|
|
364
|
+
if (existingPath) {
|
|
365
|
+
mapping[item] = existingPath
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
} else if ('pages' in sidebar) {
|
|
370
|
+
// Handle Sidebar
|
|
371
|
+
processPages(sidebar.pages || [])
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (sidebarFlatOnly) {
|
|
376
|
+
const sidebar = navigation?.sidebar as string[] || []
|
|
377
|
+
processPages(sidebar)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return mapping
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export type {
|
|
384
|
+
Plugin,
|
|
385
|
+
PluginOutput
|
|
386
|
+
}
|