dumi 2.4.53 → 2.4.54

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.
@@ -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 _a, _b, _c;
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
- (_a = node.properties).id ?? (_a.id = slugger.slug(title));
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) && ((_b = node.data) == null ? void 0 : _b[import_rehypeDemo.DEMO_PROP_VALUE_KEY])) {
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
- (_c = node.data) == null ? void 0 : _c[import_rehypeDemo.DEMO_PROP_VALUE_KEY]
164
+ (_b = node.data) == null ? void 0 : _b[import_rehypeDemo.DEMO_PROP_VALUE_KEY]
71
165
  );
72
166
  demos.forEach(({ demo, previewerProps }) => {
73
- var _a2, _b2;
167
+ var _a3, _b2;
74
168
  if (!demo.inline && previewerProps.title) {
75
169
  vFile.data.toc.push({
76
- id: slugger.slug(demo.id),
77
- depth: ((_b2 = (_a2 = vFile.data.frontmatter) == null ? void 0 : _a2.demo) == null ? void 0 : _b2.tocDepth) || 3,
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 = toString(node.children);
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.53",
3
+ "version": "2.4.54",
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
- "eslint --fix",
57
+ "utoo-lint --fix",
58
58
  "prettier --cache --write"
59
59
  ],
60
60
  "*.{ts,tsx}": [
61
- "eslint --fix",
61
+ "utoo-lint --fix",
62
62
  "prettier --cache --parser=typescript --write"
63
63
  ]
64
64
  },
@@ -148,9 +148,9 @@
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.4",
151
+ "@umijs/lint": "^4.7.28",
152
152
  "@umijs/plugins": "4.7.4",
153
- "eslint": "^8.46.0",
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",
@@ -193,7 +193,7 @@
193
193
  "format": "prettier --cache --write .",
194
194
  "lint": "npm run lint:es && npm run lint:css",
195
195
  "lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
196
- "lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
196
+ "lint:es": "utoo-lint \"{src,test}/**/*.{js,jsx,ts,tsx}\"",
197
197
  "release": "esno scripts/release.ts",
198
198
  "release:publish": "esno scripts/releasePublish.ts",
199
199
  "test": "vitest run",