dumi 2.4.53 → 2.4.55
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/dist/client/pages/Demo/index.js +10 -4
- package/dist/client/theme-api/liveDemoMessage.d.ts +4 -0
- package/dist/client/theme-api/liveDemoMessage.js +19 -0
- package/dist/client/theme-api/useLiveDemo.js +3 -2
- package/dist/loaders/markdown/transformer/rehypeSlug.d.ts +5 -0
- package/dist/loaders/markdown/transformer/rehypeSlug.js +105 -9
- package/dist/loaders/markdown/transformer/remarkMeta.js +4 -1
- package/package.json +7 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useDemo, useLiveDemo, useLocation, useParams } from 'dumi';
|
|
2
2
|
import { createElement, useEffect } from 'react';
|
|
3
|
+
import { isLiveDemoMessage, isLiveDemoSource } from "../../theme-api/liveDemoMessage";
|
|
3
4
|
import { useRenderer } from "../../theme-api/useRenderer";
|
|
4
5
|
import "./index.less";
|
|
5
6
|
var DemoRenderPage = function DemoRenderPage() {
|
|
@@ -29,8 +30,13 @@ var DemoRenderPage = function DemoRenderPage() {
|
|
|
29
30
|
|
|
30
31
|
// listen message event for setSource
|
|
31
32
|
useEffect(function () {
|
|
33
|
+
var _demo$asset;
|
|
34
|
+
var dependencies = (_demo$asset = demo.asset) === null || _demo$asset === void 0 ? void 0 : _demo$asset.dependencies;
|
|
35
|
+
var entryFileName = dependencies && Object.keys(dependencies).find(function (key) {
|
|
36
|
+
return dependencies[key].type === 'FILE';
|
|
37
|
+
});
|
|
32
38
|
var handler = function handler(ev) {
|
|
33
|
-
if (ev.
|
|
39
|
+
if (isLiveDemoMessage(ev, window.parent, 'dumi.liveDemo.setSource') && isLiveDemoSource(ev.data.value, entryFileName)) {
|
|
34
40
|
setSource(ev.data.value);
|
|
35
41
|
}
|
|
36
42
|
};
|
|
@@ -38,9 +44,9 @@ var DemoRenderPage = function DemoRenderPage() {
|
|
|
38
44
|
return function () {
|
|
39
45
|
return window.removeEventListener('message', handler);
|
|
40
46
|
};
|
|
41
|
-
}, [setSource]);
|
|
47
|
+
}, [demo.asset, setSource]);
|
|
42
48
|
|
|
43
|
-
//
|
|
49
|
+
// The parent listens on this window for compilation completion.
|
|
44
50
|
useEffect(function () {
|
|
45
51
|
if (!loading && (liveDemoError || liveDemoNode)) {
|
|
46
52
|
window.postMessage({
|
|
@@ -48,7 +54,7 @@ var DemoRenderPage = function DemoRenderPage() {
|
|
|
48
54
|
value: {
|
|
49
55
|
err: liveDemoError
|
|
50
56
|
}
|
|
51
|
-
});
|
|
57
|
+
}, window.location.origin);
|
|
52
58
|
}
|
|
53
59
|
}, [liveDemoError, liveDemoNode, loading]);
|
|
54
60
|
return finalNode;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Only trust messages from the expected window on this site's origin. */
|
|
2
|
+
export declare function isLiveDemoMessage(event: MessageEvent, source: Window, type: 'dumi.liveDemo.setSource' | 'dumi.liveDemo.compileDone'): boolean;
|
|
3
|
+
export declare function isLiveDemoSource(value: unknown, entryFileName: string | undefined): value is Record<string, string>;
|
|
4
|
+
export declare function isLiveDemoCompileResult(value: unknown): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return _typeof(value) === 'object' && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** Only trust messages from the expected window on this site's origin. */
|
|
7
|
+
export function isLiveDemoMessage(event, source, type) {
|
|
8
|
+
var origin = window.location.origin;
|
|
9
|
+
return origin !== 'null' && event.origin === origin && event.source === source && isRecord(event.data) && event.data.type === type;
|
|
10
|
+
}
|
|
11
|
+
export function isLiveDemoSource(value, entryFileName) {
|
|
12
|
+
return isRecord(value) && entryFileName !== undefined && Object.prototype.hasOwnProperty.call(value, entryFileName) && typeof value[entryFileName] === 'string' && Object.values(value).every(function (source) {
|
|
13
|
+
return typeof source === 'string';
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function isLiveDemoCompileResult(value) {
|
|
17
|
+
// Preserve arbitrary compiler throw values, including errors from other realms.
|
|
18
|
+
return isRecord(value) && Object.prototype.hasOwnProperty.call(value, 'err');
|
|
19
|
+
}
|
|
@@ -13,6 +13,7 @@ import { useDemo } from 'dumi';
|
|
|
13
13
|
import throttle from 'lodash.throttle';
|
|
14
14
|
import { createElement, useCallback, useRef, useState } from 'react';
|
|
15
15
|
import DemoErrorBoundary from "./DumiDemo/DemoErrorBoundary";
|
|
16
|
+
import { isLiveDemoCompileResult, isLiveDemoMessage } from "./liveDemoMessage";
|
|
16
17
|
import { useRenderer } from "./useRenderer";
|
|
17
18
|
import { getAgnosticComponentModule } from "./utils";
|
|
18
19
|
var THROTTLE_WAIT = 500;
|
|
@@ -76,7 +77,7 @@ export var useLiveDemo = function useLiveDemo(id, opts) {
|
|
|
76
77
|
_context.next = 5;
|
|
77
78
|
return new Promise(function (resolve) {
|
|
78
79
|
var handler = function handler(ev) {
|
|
79
|
-
if (ev
|
|
80
|
+
if (isLiveDemoMessage(ev, iframeWindow, 'dumi.liveDemo.compileDone') && isLiveDemoCompileResult(ev.data.value)) {
|
|
80
81
|
iframeWindow.removeEventListener('message', handler);
|
|
81
82
|
setError(ev.data.value.err);
|
|
82
83
|
resolve();
|
|
@@ -86,7 +87,7 @@ export var useLiveDemo = function useLiveDemo(id, opts) {
|
|
|
86
87
|
iframeWindow.postMessage({
|
|
87
88
|
type: 'dumi.liveDemo.setSource',
|
|
88
89
|
value: source
|
|
89
|
-
});
|
|
90
|
+
}, window.location.origin);
|
|
90
91
|
});
|
|
91
92
|
case 5:
|
|
92
93
|
_context.next = 74;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { Root } from 'hast';
|
|
2
2
|
import type { Transformer } from 'unified';
|
|
3
3
|
export declare const HEADING_TAGS: string[];
|
|
4
|
+
/**
|
|
5
|
+
* strip the trailing custom anchor marker from plain heading text,
|
|
6
|
+
* keep text untouched if the marker is invalid
|
|
7
|
+
*/
|
|
8
|
+
export declare function stripCustomAnchorMarker(text: string): string;
|
|
4
9
|
export default function rehypeSlug(): Transformer<Root>;
|
|
@@ -30,9 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var rehypeSlug_exports = {};
|
|
31
31
|
__export(rehypeSlug_exports, {
|
|
32
32
|
HEADING_TAGS: () => HEADING_TAGS,
|
|
33
|
-
default: () => rehypeSlug
|
|
33
|
+
default: () => rehypeSlug,
|
|
34
|
+
stripCustomAnchorMarker: () => stripCustomAnchorMarker
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(rehypeSlug_exports);
|
|
37
|
+
var import_utils = require("@umijs/utils");
|
|
36
38
|
var import_github_slugger = __toESM(require("github-slugger"));
|
|
37
39
|
var import_rehypeDemo = require("./rehypeDemo");
|
|
38
40
|
var visit;
|
|
@@ -42,13 +44,91 @@ var toString;
|
|
|
42
44
|
({ toString } = await import("hast-util-to-string"));
|
|
43
45
|
})();
|
|
44
46
|
var HEADING_TAGS = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
47
|
+
var CUSTOM_ANCHOR_RE = /\s*\{#([^}]+)\}\s*$/;
|
|
48
|
+
function getCustomAnchorId(text) {
|
|
49
|
+
var _a;
|
|
50
|
+
return ((_a = text.match(CUSTOM_ANCHOR_RE)) == null ? void 0 : _a[1].trim()) || void 0;
|
|
51
|
+
}
|
|
52
|
+
function stripCustomAnchorMarker(text) {
|
|
53
|
+
return getCustomAnchorId(text) ? text.replace(CUSTOM_ANCHOR_RE, "") : text;
|
|
54
|
+
}
|
|
55
|
+
function extractCustomAnchor(node) {
|
|
56
|
+
const lastChild = node.children[node.children.length - 1];
|
|
57
|
+
if ((lastChild == null ? void 0 : lastChild.type) !== "text" || !lastChild.value.includes("{#"))
|
|
58
|
+
return;
|
|
59
|
+
const rawId = getCustomAnchorId(lastChild.value);
|
|
60
|
+
if (!rawId)
|
|
61
|
+
return;
|
|
62
|
+
lastChild.value = stripCustomAnchorMarker(lastChild.value);
|
|
63
|
+
if (!lastChild.value)
|
|
64
|
+
node.children.pop();
|
|
65
|
+
return rawId;
|
|
66
|
+
}
|
|
45
67
|
function rehypeSlug() {
|
|
46
68
|
return async (tree, vFile) => {
|
|
69
|
+
var _a;
|
|
47
70
|
const slugger = new import_github_slugger.default();
|
|
71
|
+
const customAnchors = /* @__PURE__ */ new Map();
|
|
72
|
+
const reservedIds = /* @__PURE__ */ new Set();
|
|
73
|
+
const demoIds = /* @__PURE__ */ new Set();
|
|
74
|
+
const filename = (_a = vFile.data.frontmatter) == null ? void 0 : _a.filename;
|
|
75
|
+
visit(tree, "element", (node) => {
|
|
76
|
+
var _a2, _b;
|
|
77
|
+
if (![import_rehypeDemo.DUMI_DEMO_TAG, import_rehypeDemo.DUMI_DEMO_GRID_TAG].includes(node.tagName) || !((_a2 = node.data) == null ? void 0 : _a2[import_rehypeDemo.DEMO_PROP_VALUE_KEY])) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const demos = [].concat(
|
|
81
|
+
(_b = node.data) == null ? void 0 : _b[import_rehypeDemo.DEMO_PROP_VALUE_KEY]
|
|
82
|
+
);
|
|
83
|
+
demos.forEach(({ demo }) => {
|
|
84
|
+
if (demo.inline)
|
|
85
|
+
return;
|
|
86
|
+
demoIds.add(demo.id);
|
|
87
|
+
slugger.slug(demo.id);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
const existingIds = /* @__PURE__ */ new Set();
|
|
91
|
+
const markedHeadings = [];
|
|
92
|
+
visit(tree, "element", (node) => {
|
|
93
|
+
var _a2;
|
|
94
|
+
if (!HEADING_TAGS.includes(node.tagName))
|
|
95
|
+
return;
|
|
96
|
+
const existingId = (_a2 = node.properties) == null ? void 0 : _a2.id;
|
|
97
|
+
const rawId = extractCustomAnchor(node);
|
|
98
|
+
if (rawId) {
|
|
99
|
+
markedHeadings.push({ node, rawId, existingId });
|
|
100
|
+
} else if (existingId) {
|
|
101
|
+
existingIds.add(existingId);
|
|
102
|
+
reservedIds.add(existingId);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
markedHeadings.forEach(({ node, rawId, existingId }) => {
|
|
106
|
+
let id = rawId;
|
|
107
|
+
let suffix = 1;
|
|
108
|
+
while (reservedIds.has(id) || demoIds.has(id)) {
|
|
109
|
+
id = `${rawId}-${suffix++}`;
|
|
110
|
+
}
|
|
111
|
+
if (id !== rawId) {
|
|
112
|
+
const reason = demoIds.has(rawId) ? "conflicts with demo id" : existingIds.has(rawId) ? "conflicts with an existing heading id" : "is duplicated";
|
|
113
|
+
import_utils.logger.warn(
|
|
114
|
+
`Custom anchor "${rawId}" ${reason}, fallback to "${id}" instead. at ${filename}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (existingId && existingId !== id) {
|
|
118
|
+
import_utils.logger.warn(
|
|
119
|
+
`Custom anchor "${id}" overrides the existing id "${existingId}" of heading "${toString(
|
|
120
|
+
node
|
|
121
|
+
)}". at ${filename}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
reservedIds.add(id);
|
|
125
|
+
customAnchors.set(node, id);
|
|
126
|
+
});
|
|
48
127
|
vFile.data.toc = [];
|
|
49
128
|
visit(tree, "element", (node) => {
|
|
50
|
-
var
|
|
129
|
+
var _a2, _b;
|
|
51
130
|
if (HEADING_TAGS.includes(node.tagName)) {
|
|
131
|
+
const customAnchor = customAnchors.get(node);
|
|
52
132
|
const title = toString({
|
|
53
133
|
type: "element",
|
|
54
134
|
tagName: node.tagName,
|
|
@@ -59,22 +139,37 @@ function rehypeSlug() {
|
|
|
59
139
|
}).trim();
|
|
60
140
|
const depth = Number(node.tagName.slice(1));
|
|
61
141
|
node.properties ?? (node.properties = {});
|
|
62
|
-
(
|
|
142
|
+
if (customAnchor) {
|
|
143
|
+
node.properties.id = customAnchor;
|
|
144
|
+
} else if (!node.properties.id) {
|
|
145
|
+
let id = slugger.slug(title);
|
|
146
|
+
const conflictedId = id;
|
|
147
|
+
while (reservedIds.has(id)) {
|
|
148
|
+
id = slugger.slug(title);
|
|
149
|
+
}
|
|
150
|
+
if (id !== conflictedId) {
|
|
151
|
+
import_utils.logger.warn(
|
|
152
|
+
`Heading "${title}" conflicts with the anchor "${conflictedId}", fallback to "${id}" instead. at ${filename}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
node.properties.id = id;
|
|
156
|
+
}
|
|
63
157
|
vFile.data.toc.push({
|
|
64
158
|
id: node.properties.id,
|
|
65
159
|
depth,
|
|
66
160
|
title
|
|
67
161
|
});
|
|
68
|
-
} else if ([import_rehypeDemo.DUMI_DEMO_TAG, import_rehypeDemo.DUMI_DEMO_GRID_TAG].includes(node.tagName) && ((
|
|
162
|
+
} else if ([import_rehypeDemo.DUMI_DEMO_TAG, import_rehypeDemo.DUMI_DEMO_GRID_TAG].includes(node.tagName) && ((_a2 = node.data) == null ? void 0 : _a2[import_rehypeDemo.DEMO_PROP_VALUE_KEY])) {
|
|
69
163
|
const demos = [].concat(
|
|
70
|
-
(
|
|
164
|
+
(_b = node.data) == null ? void 0 : _b[import_rehypeDemo.DEMO_PROP_VALUE_KEY]
|
|
71
165
|
);
|
|
72
166
|
demos.forEach(({ demo, previewerProps }) => {
|
|
73
|
-
var
|
|
167
|
+
var _a3, _b2;
|
|
74
168
|
if (!demo.inline && previewerProps.title) {
|
|
75
169
|
vFile.data.toc.push({
|
|
76
|
-
id
|
|
77
|
-
|
|
170
|
+
// must keep the same id as previewer rendered anchor
|
|
171
|
+
id: demo.id,
|
|
172
|
+
depth: ((_b2 = (_a3 = vFile.data.frontmatter) == null ? void 0 : _a3.demo) == null ? void 0 : _b2.tocDepth) || 3,
|
|
78
173
|
title: previewerProps.title,
|
|
79
174
|
// put debug flag to control hide/show in toc
|
|
80
175
|
...previewerProps.debug ? { _debug_demo: true } : {}
|
|
@@ -87,5 +182,6 @@ function rehypeSlug() {
|
|
|
87
182
|
}
|
|
88
183
|
// Annotate the CommonJS export names for ESM import in node:
|
|
89
184
|
0 && (module.exports = {
|
|
90
|
-
HEADING_TAGS
|
|
185
|
+
HEADING_TAGS,
|
|
186
|
+
stripCustomAnchorMarker
|
|
91
187
|
});
|
|
@@ -38,6 +38,7 @@ var import_child_process = require("child_process");
|
|
|
38
38
|
var import_fs = __toESM(require("fs"));
|
|
39
39
|
var import_js_yaml = __toESM(require("js-yaml"));
|
|
40
40
|
var import_path = __toESM(require("path"));
|
|
41
|
+
var import_rehypeSlug = require("./rehypeSlug");
|
|
41
42
|
var visit;
|
|
42
43
|
var toString;
|
|
43
44
|
(async () => {
|
|
@@ -90,7 +91,9 @@ function remarkMeta(opts) {
|
|
|
90
91
|
() => {
|
|
91
92
|
visit(tree, "heading", (node) => {
|
|
92
93
|
if (node.depth === 1) {
|
|
93
|
-
vFile.data.frontmatter.title =
|
|
94
|
+
vFile.data.frontmatter.title = (0, import_rehypeSlug.stripCustomAnchorMarker)(
|
|
95
|
+
toString(node.children)
|
|
96
|
+
);
|
|
94
97
|
}
|
|
95
98
|
});
|
|
96
99
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dumi",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.55",
|
|
4
4
|
"description": "📖 Documentation Generator of React Component",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"generator",
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"prettier --cache --write"
|
|
55
55
|
],
|
|
56
56
|
"*.{js,jsx}": [
|
|
57
|
-
"
|
|
57
|
+
"utoo-lint --fix",
|
|
58
58
|
"prettier --cache --write"
|
|
59
59
|
],
|
|
60
60
|
"*.{ts,tsx}": [
|
|
61
|
-
"
|
|
61
|
+
"utoo-lint --fix",
|
|
62
62
|
"prettier --cache --parser=typescript --write"
|
|
63
63
|
]
|
|
64
64
|
},
|
|
@@ -148,15 +148,16 @@
|
|
|
148
148
|
"@types/react-copy-to-clipboard": "^5.0.4",
|
|
149
149
|
"@types/react-dom": "^18.2.7",
|
|
150
150
|
"@typescript/native-preview": "7.0.0-dev.20260623.1",
|
|
151
|
-
"@umijs/lint": "^4.7.
|
|
151
|
+
"@umijs/lint": "^4.7.28",
|
|
152
152
|
"@umijs/plugins": "4.7.4",
|
|
153
|
-
"
|
|
153
|
+
"@utoo/lint": "^0.4.12",
|
|
154
154
|
"esno": "^4.7.0",
|
|
155
155
|
"fast-glob": "^3.3.1",
|
|
156
156
|
"father": "^4.6.23",
|
|
157
157
|
"git-repo-info": "^2.1.1",
|
|
158
158
|
"highlight-words-core": "^1.2.2",
|
|
159
159
|
"husky": "^8.0.3",
|
|
160
|
+
"jsdom": "^26.1.0",
|
|
160
161
|
"lint-staged": "^13.2.3",
|
|
161
162
|
"prettier": "^2.8.8",
|
|
162
163
|
"prettier-plugin-organize-imports": "^3.2.3",
|
|
@@ -193,7 +194,7 @@
|
|
|
193
194
|
"format": "prettier --cache --write .",
|
|
194
195
|
"lint": "npm run lint:es && npm run lint:css",
|
|
195
196
|
"lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
|
|
196
|
-
"lint:es": "
|
|
197
|
+
"lint:es": "utoo-lint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
|
|
197
198
|
"release": "esno scripts/release.ts",
|
|
198
199
|
"release:publish": "esno scripts/releasePublish.ts",
|
|
199
200
|
"test": "vitest run",
|