@antv/dumi-theme-antv 0.6.4-beta.4 → 0.7.1

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.
@@ -111,8 +111,9 @@ var Example = function Example() {
111
111
  var demoId = example.id,
112
112
  targetExample = example.targetExample,
113
113
  targetTopic = example.targetTopic;
114
- // eg: /zh/examples/case/area/#area1
115
- var newURL = "/".concat(locale.id, "/examples/").concat(targetTopic === null || targetTopic === void 0 ? void 0 : targetTopic.id, "/").concat(targetExample === null || targetExample === void 0 ? void 0 : targetExample.id, "/#").concat(demoId);
114
+ // eg: /examples/case/area/#area1
115
+ var prefix = locale.id === 'en' ? '/en' : "";
116
+ var newURL = "".concat(prefix, "/examples/").concat(targetTopic === null || targetTopic === void 0 ? void 0 : targetTopic.id, "/").concat(targetExample === null || targetExample === void 0 ? void 0 : targetExample.id, "/#").concat(demoId);
116
117
  navigate(newURL);
117
118
  },
118
119
  exampleTopics: exampleTopics
@@ -0,0 +1,250 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/plugin/deadLinkChecker.ts
30
+ var deadLinkChecker_exports = {};
31
+ __export(deadLinkChecker_exports, {
32
+ default: () => deadLinkChecker_default
33
+ });
34
+ module.exports = __toCommonJS(deadLinkChecker_exports);
35
+ var import_chalk = __toESM(require("chalk"));
36
+ var cheerio = __toESM(require("cheerio"));
37
+ var fs = __toESM(require("fs"));
38
+ var glob = __toESM(require("glob"));
39
+ var import_lodash = __toESM(require("lodash.merge"));
40
+ var import_p_limit = __toESM(require("p-limit"));
41
+ var path = __toESM(require("path"));
42
+ var defaultConfig = {
43
+ enable: true,
44
+ distDir: "dist",
45
+ checkExternalLinks: true,
46
+ ignorePatterns: ["^#", "^mailto:", "^tel:", "^javascript:", "^data:", ".*stackoverflow\\.com.*"],
47
+ fileExtensions: [".html"],
48
+ failOnError: false,
49
+ externalLinkTimeout: 1e4,
50
+ maxConcurrentRequests: 5
51
+ };
52
+ var tempCache = {};
53
+ function processConfig(options) {
54
+ return {
55
+ ...options,
56
+ ignorePatterns: options.ignorePatterns.map(
57
+ (pattern) => typeof pattern === "string" ? new RegExp(pattern) : pattern
58
+ )
59
+ };
60
+ }
61
+ function collectLinks(htmlFiles, distDir) {
62
+ const links = [];
63
+ htmlFiles.forEach((htmlFile) => {
64
+ const filePath = path.join(distDir, htmlFile);
65
+ const content = fs.readFileSync(filePath, "utf-8");
66
+ const $ = cheerio.load(content);
67
+ $("a").each((_, element) => {
68
+ const url = $(element).attr("href");
69
+ if (!url)
70
+ return;
71
+ links.push({
72
+ url,
73
+ text: $(element).text().trim() || "[No text]",
74
+ sourceFile: htmlFile,
75
+ isExternal: url.startsWith("http://") || url.startsWith("https://")
76
+ });
77
+ });
78
+ });
79
+ return links;
80
+ }
81
+ function filterIgnoredLinks(links, ignorePatterns) {
82
+ return links.filter((link) => {
83
+ return !ignorePatterns.some((pattern) => pattern.test(link.url));
84
+ });
85
+ }
86
+ function checkInternalLinks(links, existingFiles) {
87
+ const deadLinks = [];
88
+ links.forEach((link) => {
89
+ if (!link.url.startsWith("/") || link.url.startsWith("//"))
90
+ return;
91
+ let normalizedLink = link.url.split("#")[0];
92
+ normalizedLink = normalizedLink.split("?")[0];
93
+ if (normalizedLink.endsWith("/")) {
94
+ normalizedLink += "index.html";
95
+ }
96
+ const exists = existingFiles.has(normalizedLink) || path.extname(normalizedLink) === "" && (existingFiles.has(normalizedLink + "/") || existingFiles.has(normalizedLink + "/index.html") || existingFiles.has(normalizedLink + ".html"));
97
+ if (!exists) {
98
+ deadLinks.push({
99
+ ...link,
100
+ reason: "File not found"
101
+ });
102
+ }
103
+ });
104
+ return deadLinks;
105
+ }
106
+ async function checkExternalLinks(links, config) {
107
+ const deadLinks = [];
108
+ const limit = (0, import_p_limit.default)(config.maxConcurrentRequests);
109
+ const uncachedLinks = [];
110
+ links.forEach((link) => {
111
+ if (tempCache[link.url]) {
112
+ if (!tempCache[link.url].success) {
113
+ deadLinks.push({
114
+ ...link,
115
+ reason: tempCache[link.url].reason || "未知错误"
116
+ });
117
+ }
118
+ console.log(import_chalk.default.gray(` [cached] ${link.url}`));
119
+ } else {
120
+ uncachedLinks.push(link);
121
+ }
122
+ });
123
+ const promises = uncachedLinks.map((link) => {
124
+ return limit(async () => {
125
+ try {
126
+ const controller = new AbortController();
127
+ const timeoutId = setTimeout(() => controller.abort(), config.externalLinkTimeout);
128
+ const response = await fetch(link.url);
129
+ clearTimeout(timeoutId);
130
+ if (response.status >= 400) {
131
+ tempCache[link.url] = {
132
+ success: false,
133
+ reason: `Status code ${response.status}`
134
+ };
135
+ deadLinks.push({
136
+ ...link,
137
+ reason: `Status code ${response.status}`
138
+ });
139
+ } else {
140
+ tempCache[link.url] = { success: true };
141
+ }
142
+ } catch (error) {
143
+ const reason = error instanceof Error ? error.message : String(error);
144
+ tempCache[link.url] = { success: false, reason };
145
+ deadLinks.push({
146
+ ...link,
147
+ reason
148
+ });
149
+ }
150
+ });
151
+ });
152
+ await Promise.all(promises);
153
+ return deadLinks;
154
+ }
155
+ async function runCheck(config) {
156
+ const distDir = path.resolve(process.cwd(), config.distDir);
157
+ if (!fs.existsSync(distDir)) {
158
+ return {
159
+ totalLinks: 0,
160
+ deadLinks: [],
161
+ success: false
162
+ };
163
+ }
164
+ const htmlFiles = glob.sync(`**/*+(${config.fileExtensions.join("|")})`, { cwd: distDir });
165
+ const existingFiles = /* @__PURE__ */ new Set();
166
+ glob.sync("**/*", { cwd: distDir, nodir: true }).forEach((file) => {
167
+ existingFiles.add("/" + file);
168
+ });
169
+ const allLinks = collectLinks(htmlFiles, distDir);
170
+ const linksToCheck = filterIgnoredLinks(allLinks, config.ignorePatterns);
171
+ const internalDeadLinks = checkInternalLinks(
172
+ linksToCheck.filter((link) => !link.isExternal),
173
+ existingFiles
174
+ );
175
+ const externalDeadLinks = config.checkExternalLinks ? await checkExternalLinks(
176
+ linksToCheck.filter((link) => link.isExternal),
177
+ config
178
+ ) : [];
179
+ const deadLinks = [...internalDeadLinks, ...externalDeadLinks];
180
+ return {
181
+ totalLinks: allLinks.length,
182
+ deadLinks,
183
+ success: deadLinks.length === 0
184
+ };
185
+ }
186
+ function generateReport(result) {
187
+ console.log();
188
+ if (result.deadLinks.length === 0) {
189
+ console.log(import_chalk.default.green(`✓ Check completed: All ${result.totalLinks} links are valid`));
190
+ console.log();
191
+ return;
192
+ }
193
+ const linksByFile = result.deadLinks.reduce((acc, link) => {
194
+ if (!acc[link.sourceFile]) {
195
+ acc[link.sourceFile] = [];
196
+ }
197
+ acc[link.sourceFile].push(link);
198
+ return acc;
199
+ }, {});
200
+ console.log(
201
+ import_chalk.default.yellow(
202
+ `📊 Found ${result.deadLinks.length}/${result.totalLinks} dead links in ${Object.keys(linksByFile).length} files`
203
+ )
204
+ );
205
+ Object.entries(linksByFile).forEach(([file, links]) => {
206
+ console.log();
207
+ console.log(import_chalk.default.yellow(`📄 ${file}:`));
208
+ links.forEach((link) => {
209
+ console.log(import_chalk.default.red(` ✗ ${link.url}`));
210
+ console.log(import_chalk.default.gray(` • Text: ${link.text}`));
211
+ console.log(import_chalk.default.gray(` • Reason: ${link.reason}`));
212
+ });
213
+ });
214
+ console.log();
215
+ console.log(import_chalk.default.cyan(`💡 Tip: Please fix these links and run \`npx dumi check-links\` to verify`));
216
+ console.log(import_chalk.default.cyan(`💡 Tip: Don't forget to run \`npm run build\` after fixing the links`));
217
+ console.log();
218
+ }
219
+ var deadLinkChecker_default = (api) => {
220
+ const getConfig = () => {
221
+ const themeConfig = api.config.themeConfig || {};
222
+ let userConfig = themeConfig == null ? void 0 : themeConfig.deadLinkChecker;
223
+ if (!userConfig) {
224
+ userConfig = { enable: false };
225
+ }
226
+ const config = (0, import_lodash.default)({}, defaultConfig, userConfig);
227
+ if (!config.enable) {
228
+ return processConfig({
229
+ ...config,
230
+ // 设置为空数组,使插件不执行任何检查
231
+ fileExtensions: []
232
+ });
233
+ }
234
+ return processConfig(config);
235
+ };
236
+ const checkLinks = async (onBeforeCheck) => {
237
+ const config = getConfig();
238
+ if (config.fileExtensions.length === 0) {
239
+ return;
240
+ }
241
+ onBeforeCheck == null ? void 0 : onBeforeCheck();
242
+ console.log(import_chalk.default.gray("🔍 Checking for dead links..."));
243
+ const result = await runCheck(config);
244
+ generateReport(result);
245
+ if (!result.success && config.failOnError) {
246
+ process.exit(1);
247
+ }
248
+ };
249
+ return checkLinks;
250
+ };
@@ -32,18 +32,32 @@ __export(plugin_exports, {
32
32
  default: () => plugin_default
33
33
  });
34
34
  module.exports = __toCommonJS(plugin_exports);
35
+ var import_chalk = __toESM(require("chalk"));
35
36
  var import_plugin_utils = require("dumi/plugin-utils");
36
37
  var path = __toESM(require("path"));
37
38
  var import_antVReactTechStack = require("./antVReactTechStack");
39
+ var import_deadLinkChecker = __toESM(require("./deadLinkChecker"));
38
40
  var import_examples = require("./examples");
39
41
  var import_rehypeObservable = __toESM(require("./rehypeObservable"));
40
42
  var import_remarkFeedback = __toESM(require("./remarkFeedback"));
43
+ var import_sitemapGenerator = __toESM(require("./sitemapGenerator"));
41
44
  var PAGES_DIR = (0, import_plugin_utils.winPath)(path.join(__dirname, "../pages"));
42
45
  var MOCK_META = { frontmatter: { title: "mock-meta" }, texts: [], toc: [] };
43
46
  var plugin_default = (api) => {
44
47
  api.describe({ key: `dumi-theme:${require("../../package.json").name}` });
45
48
  api.modifyDefaultConfig((memo) => {
46
49
  memo.resolve.codeBlockMode = "passive";
50
+ memo.chainWebpack = (memo2) => {
51
+ memo2.module.rule("less").test(/\.less$/).use("style-loader").loader("style-loader").before("css-loader").end().use("css-loader").loader("css-loader").options({
52
+ importLoaders: 1,
53
+ modules: { auto: true }
54
+ // 启用 CSS Modules(可选)
55
+ }).end().use("less-loader").loader("less-loader").options({
56
+ javascriptEnabled: true
57
+ });
58
+ return memo2;
59
+ };
60
+ memo.exportStatic = {};
47
61
  memo.exportStatic.extraRoutePaths = (0, import_examples.getExamplePaths)();
48
62
  memo.mfsu = false;
49
63
  memo.jsMinifier = "terser";
@@ -161,4 +175,15 @@ export default function ThemeAntVContextWrapper() {
161
175
  });
162
176
  api.addTmpGenerateWatcherPaths(() => [path.resolve(process.cwd(), "examples")]);
163
177
  api.registerTechStack(() => new import_antVReactTechStack.AntVReactTechStack());
178
+ const checkLinks = (0, import_deadLinkChecker.default)(api);
179
+ api.registerCommand({
180
+ name: "check-links",
181
+ fn: async () => await checkLinks()
182
+ });
183
+ api.onBuildHtmlComplete(async () => {
184
+ await checkLinks(() => {
185
+ console.log(import_chalk.default.green("🚀 Build completed."));
186
+ });
187
+ (0, import_sitemapGenerator.default)(api);
188
+ });
164
189
  };
@@ -0,0 +1,103 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/plugin/sitemapGenerator.ts
30
+ var sitemapGenerator_exports = {};
31
+ __export(sitemapGenerator_exports, {
32
+ default: () => generateSitemap
33
+ });
34
+ module.exports = __toCommonJS(sitemapGenerator_exports);
35
+ var import_chalk = __toESM(require("chalk"));
36
+ var import_fs = __toESM(require("fs"));
37
+ var import_lodash = require("lodash");
38
+ var import_moment = __toESM(require("moment"));
39
+ var import_path = __toESM(require("path"));
40
+ var import_xmlbuilder = __toESM(require("xmlbuilder"));
41
+ var defaultConfig = {
42
+ enable: true,
43
+ outputDir: "dist",
44
+ filename: "sitemap.xml"
45
+ };
46
+ var currentDateTime = (0, import_moment.default)().format("YYYY-MM-DDTHH:mm:ss+00:00");
47
+ function generateUrls(config) {
48
+ const urls = [];
49
+ function walkDir(currentPath) {
50
+ const files = import_fs.default.readdirSync(currentPath);
51
+ files.forEach((file) => {
52
+ const fullPath = import_path.default.join(currentPath, file);
53
+ const stat = import_fs.default.statSync(fullPath);
54
+ if (stat.isDirectory()) {
55
+ walkDir(fullPath);
56
+ } else if (stat.isFile() && import_path.default.extname(file) === ".html") {
57
+ const relativePath = import_path.default.relative(config.outputDir, fullPath);
58
+ let url = `${config.siteUrl}/${relativePath.replace(/\\/g, "/")}`;
59
+ if (url.endsWith("/index.html") && !url.match(/\/:(\w+)/) && !url.includes("/zh/")) {
60
+ url = url.replace(/\/index\.html$/, "");
61
+ urls.push(url);
62
+ }
63
+ }
64
+ });
65
+ }
66
+ walkDir(config.outputDir);
67
+ return urls;
68
+ }
69
+ function writeSitemap(config, urls) {
70
+ const root = import_xmlbuilder.default.create("urlset", {
71
+ version: "1.0",
72
+ encoding: "utf-8"
73
+ }).att("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9").att("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").att(
74
+ "xsi:schemaLocation",
75
+ "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
76
+ );
77
+ root.comment(` Created By G6 Sitemap Generator, Generated at: ${currentDateTime} `);
78
+ urls.forEach((url) => {
79
+ const loc = url.replace(/\/index\.html$/, "");
80
+ const depth = url.split("/").length - 3;
81
+ const priority = Math.max(0.5, 1 - depth * 0.1).toFixed(2);
82
+ root.ele("url").ele("loc", loc).up().ele("lastmod", currentDateTime).up().ele("priority", priority);
83
+ });
84
+ const sitemapContent = root.end({ pretty: true });
85
+ import_fs.default.writeFileSync(import_path.default.join(config.outputDir, config.filename), sitemapContent);
86
+ console.log(import_chalk.default.green(`✅ Sitemap generated including ${urls.length} urls. `));
87
+ }
88
+ function generateSitemap(api) {
89
+ const getConfig = () => {
90
+ const themeConfig = api.config.themeConfig || {};
91
+ let userConfig = themeConfig == null ? void 0 : themeConfig.sitemap;
92
+ if (!userConfig) {
93
+ userConfig = { enable: false };
94
+ }
95
+ return (0, import_lodash.merge)({ siteUrl: themeConfig.siteUrl }, defaultConfig, userConfig);
96
+ };
97
+ const config = getConfig();
98
+ if (!config.enable) {
99
+ return;
100
+ }
101
+ const urls = generateUrls(config);
102
+ writeSitemap(config, urls);
103
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antv/dumi-theme-antv",
3
- "version": "0.6.4-beta.4",
3
+ "version": "0.7.1",
4
4
  "description": "AntV website theme based on dumi2.",
5
5
  "keywords": [
6
6
  "dumi",
@@ -52,6 +52,8 @@
52
52
  "@petercatai/assistant": "^2.0.24",
53
53
  "@stackblitz/sdk": "^1.11.0",
54
54
  "antd": "^4.24.16",
55
+ "chalk": "^4.1.2",
56
+ "cheerio": "^1.0.0-rc.12",
55
57
  "classnames": "^2.5.1",
56
58
  "codesandbox": "^2.2.3",
57
59
  "d3-dsv": "^3.0.1",
@@ -64,8 +66,10 @@
64
66
  "insert-css": "^2.0.0",
65
67
  "leancloud-storage": "^4.15.2",
66
68
  "lodash-es": "^4.17.21",
69
+ "lodash.merge": "^4.6.2",
67
70
  "monaco-editor": "^0.25.2",
68
71
  "nprogress": "^0.2.0",
72
+ "p-limit": "^3.1.0",
69
73
  "parse-github-url": "^1.0.3",
70
74
  "rc-drawer": "^4.4.3",
71
75
  "rc-footer": "^0.6.8",
@@ -92,7 +96,8 @@
92
96
  "unist-util-visit": "^4.1.2",
93
97
  "uri-parse": "^1.0.0",
94
98
  "valtio": "^1.13.2",
95
- "video-react": "^0.16.0"
99
+ "video-react": "^0.16.0",
100
+ "xmlbuilder": "^15.1.1"
96
101
  },
97
102
  "devDependencies": {
98
103
  "@commitlint/cli": "^17.8.1",
@@ -110,17 +115,19 @@
110
115
  "@types/react-slick": "^0.23.13",
111
116
  "@types/styled-components": "^5.1.34",
112
117
  "@umijs/lint": "^4.3.34",
118
+ "css-loader": "^7.1.2",
113
119
  "dumi": "^2.4.13",
114
120
  "eslint": "^8.57.1",
115
121
  "father": "^4.5.1",
116
122
  "father-plugin-dumi-theme": "1.0.0-rc.1",
117
123
  "husky": "^8.0.3",
118
- "less": "^4.2.1",
124
+ "less": "^4.2.2",
119
125
  "less-loader": "^12.2.0",
120
126
  "lint-staged": "^13.3.0",
121
127
  "prettier": "^2.8.8",
122
128
  "prettier-plugin-organize-imports": "^3.2.4",
123
129
  "prettier-plugin-packagejson": "^2.5.3",
130
+ "style-loader": "^4.0.0",
124
131
  "stylelint": "^14.16.1"
125
132
  },
126
133
  "peerDependencies": {
@@ -129,8 +136,7 @@
129
136
  "react-dom": ">=16.9.0"
130
137
  },
131
138
  "publishConfig": {
132
- "access": "public",
133
- "tag": "beta"
139
+ "access": "public"
134
140
  },
135
141
  "authors": [
136
142
  "dumi",