Setting the file. One moment. ECharts Option · Dreambase ECharts · DreambaseAI/skills · Skills DocsScript Validate Option
scripts/echarts-option.mjs
JavaScript·125 lines·5 KB
15
* node scripts/echarts-option.mjs xAxis.axisLabel --depth 2
16 */
17
18import { readFileSync } from "node:fs";
19import { dirname, resolve } from "node:path";
20import { fileURLToPath } from "node:url";
21
22const INDEX_PATH = resolve(dirname(fileURLToPath(import.meta.url)), "../assets/option-index.json");
23const { root } = JSON.parse(readFileSync(INDEX_PATH, "utf8"));
24
25function findChild(nodes, name) {
26 return nodes.find((n) => n.p === name);
27}
28
29function resolvePath(path) {
30 // normalize "series-sankey.links" -> ["series","sankey","links"]
31 const segs = path.replace(/^series-/, "series.").split(".").filter(Boolean);
32 let nodes = root;
33 let node = null;
34 const walked = [];
35 for (const seg of segs) {
36 node = findChild(nodes, seg);
37 if (!node) return { node: null, walked, missing: seg, siblings: nodes.map((n) => n.p) };
38 walked.push(seg);
39 nodes = node.c ?? [];
40 }
41 return { node, walked };
42}
43
44function fmt(node) {
45 let s = node.p ?? "(item)";
46 if (node.t) s += ` (${node.t}${node.arr ? "[]" : ""})`;
47 else if (node.arr) s += " (Array)";
48 if (node.d !== undefined) s += ` = ${node.d}`;
49 return s;
50}
51
52function printTree(node, depth, indent = "") {
53 console.log(indent + fmt(node));
54 if (!node.c) return;
55 if (depth <= 0) {
56 console.log(`${indent} … ${node.c.length} nested options (increase --depth to expand)`);
57 return;
58 }
59 for (const child of node.c) printTree(child, depth - 1, indent + " ");
60}
61
62function search(term, nodes = root, prefix = "", hits = []) {
63 for (const n of nodes) {
64 const name = n.p ?? "";
65 const path = prefix ? `${prefix}.${name}` : name;
66 if (name.toLowerCase().includes(term.toLowerCase())) hits.push({ path, node: n });
67 if (n.c && hits.length < 200) search(term, n.c, path, hits);
68 }
69 return hits;
70}
71
72async function fetchDesc(path) {
73 // option-parts files are keyed by top-level part: option.<part>.json
74 const segs = path.replace(/^series-/, "series.").split(".");
75 const part = segs[0] === "series" && segs[1] ? `series-${segs[1]}` : segs[0];
76 const url = `https://echarts.apache.org/en/documents/option-parts/option.${part}.json`;
77 const res = await fetch(url);
78 if (!res.ok) throw new Error(`fetch failed: ${res.status} ${url}`);
79 const doc = await res.json();
80 // keys inside a part file are relative to the part root, e.g. "nodeAlign", "links.value"
81 const key = (segs[0] === "series" && segs[1] ? segs.slice(2) : segs.slice(1)).join(".");
82 if (!key) {
83 console.log(`Documented options in ${part}:\n ${Object.keys(doc).slice(0, 80).join("\n ")}`);
84 return;
85 }
86 const entry = doc[key];
87 if (!entry?.desc) {
88 const close = Object.keys(doc).filter((k) => k.includes(key.split(".").pop())).slice(0, 15);
89 console.log(`No prose found for '${key}' in ${part}. Closest keys:\n ${close.join("\n ")}`);
90 return;
91 }
92 const text = entry.desc
93 .replace(/<pre[^>]*>([\s\S]*?)<\/pre>/g, (_, code) => `\n${code}\n`)
94 .replace(/<[^>]+>/g, "")
95 .replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'")
96 .replace(/\n{3,}/g, "\n\n")
97 .trim();
98 console.log(`# ${key}\n\n${text}`);
99}
100
101const args = process.argv.slice(2);
102if (!args.length) {
103 console.log("Usage: echarts-option.mjs <path> [--depth N] | --find <term> | --desc <path>");
104 console.log(`Top-level options:\n ${root.map((n) => n.p).join(", ")}`);
105 process.exit(2);
106}
107
108if (args[0] === "--find") {
109 const hits = search(args[1] ?? "");
110 if (!hits.length) console.log("no matches");
111 for (const h of hits.slice(0, 60)) console.log(`${h.path} ${h.node.t ? `(${h.node.t})` : ""}${h.node.d !== undefined ? ` = ${h.node.d}` : ""}`);
112 if (hits.length > 60) console.log(`… ${hits.length - 60} more matches`);
113} else if (args[0] === "--desc") {
114 await fetchDesc(args[1] ?? "");
115} else {
116 const depthIdx = args.indexOf("--depth");
117 const depth = depthIdx !== -1 ? Number(args[depthIdx + 1]) : 1;
118 const { node, walked, missing, siblings } = resolvePath(args[0]);
119 if (!node) {
120 console.error(`'${missing}' not found under '${walked.join(".") || "(root)"}'.`);
121 console.error(`Valid options there:\n ${siblings.join(", ")}`);
122 process.exit(1);
123 }
124 printTree(node, depth);
125}