dishui 0.0.46 → 0.0.48

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.
Files changed (115) hide show
  1. package/dist/chart.js +35 -33
  2. package/dist/components/Chart/index.d.ts +1 -1
  3. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +1 -2
  4. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
  5. package/dist/components/pro/CodeEditor/themes.js +0 -25
  6. package/dist/components/pro/CodeEditor/themes.js.map +1 -1
  7. package/dist/components/pro/CodeEditor/types.d.ts +1 -1
  8. package/dist/components/pro/DataTable/pivotExtension.d.ts +6 -0
  9. package/dist/components/pro/DataTable/pivotExtension.js +31 -30
  10. package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
  11. package/dist/components/pro/Flow/Flow.js +500 -459
  12. package/dist/components/pro/Flow/Flow.js.map +1 -1
  13. package/dist/components/pro/Flow/FlowCanvas.js +526 -524
  14. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  15. package/dist/components/pro/Flow/canvas/GridRenderer.d.ts +3 -0
  16. package/dist/components/pro/Flow/canvas/GridRenderer.js +28 -23
  17. package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
  18. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js +18 -17
  19. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
  20. package/dist/components/pro/Flow/canvas/PixiApp.d.ts +24 -0
  21. package/dist/components/pro/Flow/canvas/PixiApp.js +60 -15
  22. package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
  23. package/dist/components/pro/Flow/constants.js +7 -7
  24. package/dist/components/pro/Flow/constants.js.map +1 -1
  25. package/dist/components/pro/Flow/context/FlowAIContext.d.ts +15 -0
  26. package/dist/components/pro/Flow/context/FlowAIContext.js +32 -0
  27. package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -0
  28. package/dist/components/pro/Flow/context/FlowUIContext.d.ts +4 -1
  29. package/dist/components/pro/Flow/context/FlowUIContext.js +58 -55
  30. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  31. package/dist/components/pro/Flow/edges/EdgeRenderer.js +22 -21
  32. package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
  33. package/dist/components/pro/Flow/hooks/useFlowImportExport.d.ts +6 -0
  34. package/dist/components/pro/Flow/hooks/useFlowImportExport.js +146 -89
  35. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  36. package/dist/components/pro/Flow/hooks/useLayoutActions.d.ts +2 -0
  37. package/dist/components/pro/Flow/hooks/useLayoutActions.js +94 -65
  38. package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
  39. package/dist/components/pro/Flow/hooks/usePdfExport.d.ts +10 -0
  40. package/dist/components/pro/Flow/hooks/usePdfExport.js +60 -0
  41. package/dist/components/pro/Flow/hooks/usePdfExport.js.map +1 -0
  42. package/dist/components/pro/Flow/hooks/usePixiApp.d.ts +6 -1
  43. package/dist/components/pro/Flow/hooks/usePixiApp.js +49 -30
  44. package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
  45. package/dist/components/pro/Flow/index.d.ts +5 -2
  46. package/dist/components/pro/Flow/lines/FreehandTool.js +21 -20
  47. package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
  48. package/dist/components/pro/Flow/lines/GeometricLineTool.js +22 -18
  49. package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
  50. package/dist/components/pro/Flow/lines/LineRenderer.js +19 -18
  51. package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
  52. package/dist/components/pro/Flow/nodes/DataNodeView.d.ts +7 -0
  53. package/dist/components/pro/Flow/nodes/DataNodeView.js +217 -0
  54. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -0
  55. package/dist/components/pro/Flow/nodes/MediaContent.js +149 -120
  56. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  57. package/dist/components/pro/Flow/nodes/MediaOverlay.js +22 -17
  58. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  59. package/dist/components/pro/Flow/nodes/NodeRenderer.js +77 -76
  60. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  61. package/dist/components/pro/Flow/nodes/aiClient.d.ts +22 -0
  62. package/dist/components/pro/Flow/nodes/aiClient.js +107 -54
  63. package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
  64. package/dist/components/pro/Flow/nodes/dataUtils.d.ts +52 -0
  65. package/dist/components/pro/Flow/nodes/dataUtils.js +270 -0
  66. package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -0
  67. package/dist/components/pro/Flow/nodes/svgIcons.js +59 -27
  68. package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
  69. package/dist/components/pro/Flow/panels/AIPanel.d.ts +2 -0
  70. package/dist/components/pro/Flow/panels/AIPanel.js +498 -0
  71. package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -0
  72. package/dist/components/pro/Flow/panels/DataInspectorSection.d.ts +11 -0
  73. package/dist/components/pro/Flow/panels/DataInspectorSection.js +436 -0
  74. package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -0
  75. package/dist/components/pro/Flow/panels/ExpandableTextarea.d.ts +16 -0
  76. package/dist/components/pro/Flow/panels/ExpandableTextarea.js +65 -0
  77. package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -0
  78. package/dist/components/pro/Flow/panels/FlowPanelGroup.js +51 -39
  79. package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
  80. package/dist/components/pro/Flow/panels/FlowToolbar.d.ts +5 -1
  81. package/dist/components/pro/Flow/panels/FlowToolbar.js +310 -233
  82. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  83. package/dist/components/pro/Flow/panels/InspectorPanel.js +358 -363
  84. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  85. package/dist/components/pro/Flow/panels/OutlinePanel.js +63 -62
  86. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  87. package/dist/components/pro/Flow/panels/ProjectTitle.d.ts +8 -0
  88. package/dist/components/pro/Flow/panels/ProjectTitle.js +49 -0
  89. package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -0
  90. package/dist/components/pro/Flow/panels/ShapePalette.js +128 -115
  91. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  92. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +13 -0
  93. package/dist/components/pro/Flow/panels/toolbarIcons.js +241 -87
  94. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  95. package/dist/components/pro/Flow/types.d.ts +77 -1
  96. package/dist/components/pro/Flow/types.js.map +1 -1
  97. package/dist/components/pro/Flow/utils/pdfExport.d.ts +20 -0
  98. package/dist/components/pro/Flow/utils/pdfExport.js +95 -0
  99. package/dist/components/pro/Flow/utils/pdfExport.js.map +1 -0
  100. package/dist/components/pro/Flow/utils/themeColor.d.ts +86 -0
  101. package/dist/components/pro/Flow/utils/themeColor.js +190 -0
  102. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -0
  103. package/dist/contexts/AppContext.d.ts +1 -1
  104. package/dist/contexts/AppContext.js +28 -29
  105. package/dist/contexts/AppContext.js.map +1 -1
  106. package/dist/dishui.css +1 -1
  107. package/dist/favicon.svg +10 -0
  108. package/dist/flow.js +59 -51
  109. package/dist/index-nostyled.d.ts +1 -1
  110. package/dist/index.d.ts +1 -1
  111. package/dist/styles/themeStyles.js +6 -11
  112. package/dist/styles/themeStyles.js.map +1 -1
  113. package/dist/utils/themes.js +3 -23
  114. package/dist/utils/themes.js.map +1 -1
  115. package/package.json +17 -18
@@ -1,90 +1,143 @@
1
- async function* h(e, s, a) {
2
- const c = JSON.stringify({
3
- model: e.model,
4
- messages: [...e.systemPrompt ? [{
1
+ function u(t) {
2
+ const e = (t.gateway || "").trim().replace(/\/+$/, "");
3
+ if (!e) return e;
4
+ const r = t.protocol === "anthropic" ? "/messages" : "/chat/completions";
5
+ if (/\/(chat\/completions|messages|responses|completions)$/i.test(e)) return e;
6
+ if (/\/v\d+$/i.test(e)) return e + r;
7
+ try {
8
+ const n = new URL(e);
9
+ if (n.pathname === "" || n.pathname === "/") return e + "/v1" + r;
10
+ } catch {
11
+ }
12
+ return e + r;
13
+ }
14
+ async function* h(t, e, r) {
15
+ const n = JSON.stringify({
16
+ model: t.model,
17
+ messages: [...t.systemPrompt ? [{
5
18
  role: "system",
6
- content: e.systemPrompt
7
- }] : [], ...s],
19
+ content: t.systemPrompt
20
+ }] : [], ...e],
8
21
  stream: !0
9
- }), t = await fetch(e.gateway, {
22
+ }), s = await fetch(u(t), {
10
23
  method: "POST",
11
24
  headers: {
12
25
  "Content-Type": "application/json",
13
- ...e.apiKey ? { Authorization: `Bearer ${e.apiKey}` } : {},
14
- ...e.headers
26
+ ...t.apiKey ? { Authorization: `Bearer ${t.apiKey}` } : {},
27
+ ...t.headers
15
28
  },
16
- body: c,
17
- signal: a
29
+ body: n,
30
+ signal: r
18
31
  });
19
- if (!t.ok) throw new Error(`AI API error: ${t.status} ${t.statusText}`);
20
- const d = t.body?.getReader();
21
- if (!d) throw new Error("No response body");
22
- const p = new TextDecoder();
23
- let r = "";
32
+ if (!s.ok) throw new Error(`AI API error: ${s.status} ${s.statusText}`);
33
+ const c = s.body?.getReader();
34
+ if (!c) throw new Error("No response body");
35
+ const i = new TextDecoder();
36
+ let o = "";
24
37
  for (; ; ) {
25
- const { done: m, value: y } = await d.read();
26
- if (m) break;
27
- r += p.decode(y, { stream: !0 });
28
- const i = r.split(`
38
+ const { done: y, value: p } = await c.read();
39
+ if (y) break;
40
+ o += i.decode(p, { stream: !0 });
41
+ const a = o.split(`
29
42
  `);
30
- r = i.pop() || "";
31
- for (const l of i) {
32
- const o = l.trim();
33
- if (!(!o || o === "data: [DONE]" || !o.startsWith("data: ")))
43
+ o = a.pop() || "";
44
+ for (const m of a) {
45
+ const d = m.trim();
46
+ if (!(!d || d === "data: [DONE]" || !d.startsWith("data: ")))
34
47
  try {
35
- const n = JSON.parse(o.slice(6)).choices?.[0]?.delta?.content;
36
- n && (yield n);
48
+ const l = JSON.parse(d.slice(6)).choices?.[0]?.delta?.content;
49
+ l && (yield l);
37
50
  } catch {
38
51
  }
39
52
  }
40
53
  }
41
54
  }
42
- async function* u(e, s, a) {
43
- const c = JSON.stringify({
44
- model: e.model,
45
- max_tokens: 4096,
46
- ...e.systemPrompt ? { system: e.systemPrompt } : {},
47
- messages: s,
55
+ async function* f(t, e, r) {
56
+ const n = JSON.stringify({
57
+ model: t.model,
58
+ max_tokens: 8192,
59
+ ...t.systemPrompt ? { system: t.systemPrompt } : {},
60
+ messages: e,
48
61
  stream: !0
49
- }), t = await fetch(e.gateway, {
62
+ }), s = await fetch(u(t), {
50
63
  method: "POST",
51
64
  headers: {
52
65
  "Content-Type": "application/json",
53
- ...e.apiKey ? { "x-api-key": e.apiKey } : {},
66
+ ...t.apiKey ? { "x-api-key": t.apiKey } : {},
54
67
  "anthropic-version": "2023-06-01",
55
68
  "anthropic-dangerous-direct-browser-access": "true",
56
- ...e.headers
69
+ ...t.headers
57
70
  },
58
- body: c,
59
- signal: a
71
+ body: n,
72
+ signal: r
60
73
  });
61
- if (!t.ok) throw new Error(`AI API error: ${t.status} ${t.statusText}`);
62
- const d = t.body?.getReader();
63
- if (!d) throw new Error("No response body");
64
- const p = new TextDecoder();
65
- let r = "";
74
+ if (!s.ok) throw new Error(`AI API error: ${s.status} ${s.statusText}`);
75
+ const c = s.body?.getReader();
76
+ if (!c) throw new Error("No response body");
77
+ const i = new TextDecoder();
78
+ let o = "";
66
79
  for (; ; ) {
67
- const { done: m, value: y } = await d.read();
68
- if (m) break;
69
- r += p.decode(y, { stream: !0 });
70
- const i = r.split(`
80
+ const { done: y, value: p } = await c.read();
81
+ if (y) break;
82
+ o += i.decode(p, { stream: !0 });
83
+ const a = o.split(`
71
84
  `);
72
- r = i.pop() || "";
73
- for (const l of i) {
74
- const o = l.trim();
75
- if (o.startsWith("data: "))
85
+ o = a.pop() || "";
86
+ for (const m of a) {
87
+ const d = m.trim();
88
+ if (d.startsWith("data: "))
76
89
  try {
77
- const n = JSON.parse(o.slice(6));
78
- n.type === "content_block_delta" && n.delta?.text && (yield n.delta.text);
90
+ const l = JSON.parse(d.slice(6));
91
+ l.type === "content_block_delta" && l.delta?.text && (yield l.delta.text);
79
92
  } catch {
80
93
  }
81
94
  }
82
95
  }
83
96
  }
84
- function w(e, s, a) {
85
- return e.protocol === "anthropic" ? u(e, s, a) : h(e, s, a);
97
+ function w(t, e, r) {
98
+ return t.protocol === "anthropic" ? f(t, e, r) : h(t, e, r);
99
+ }
100
+ async function b(t, e, r) {
101
+ const n = r?.systemPrompt ?? t.systemPrompt, s = r?.imageDataUrl;
102
+ let c = e;
103
+ if (t.protocol === "anthropic") {
104
+ const a = [{
105
+ type: "text",
106
+ text: e
107
+ }];
108
+ if (s) {
109
+ const m = /^data:(.+?);base64,(.*)$/.exec(s);
110
+ m && a.unshift({
111
+ type: "image",
112
+ source: {
113
+ type: "base64",
114
+ media_type: m[1],
115
+ data: m[2]
116
+ }
117
+ });
118
+ }
119
+ c = a;
120
+ } else s && (c = [{
121
+ type: "text",
122
+ text: e
123
+ }, {
124
+ type: "image_url",
125
+ image_url: { url: s }
126
+ }]);
127
+ const i = n ? {
128
+ ...t,
129
+ systemPrompt: n
130
+ } : t, o = [{
131
+ role: "user",
132
+ content: c
133
+ }], y = i.protocol === "anthropic" ? f(i, o, r?.signal) : h(i, o, r?.signal);
134
+ let p = "";
135
+ for await (const a of y)
136
+ p += a, r?.onDelta?.(p);
137
+ return p;
86
138
  }
87
139
  export {
140
+ b as completeAIChatStream,
88
141
  w as streamAIChat
89
142
  };
90
143
 
@@ -1 +1 @@
1
- {"version":3,"file":"aiClient.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/aiClient.ts"],"sourcesContent":["import type { FlowAIConfig } from '../types';\n\n/**\n * Minimal streaming chat client for the Flow AI media node. Supports\n * OpenAI-compatible `/chat/completions` and Anthropic `/messages` endpoints.\n *\n * Yields incremental text deltas. Callers accumulate them to render a live,\n * streaming response. This intentionally mirrors the RichTextEditor AIRewrite\n * streaming logic but is scoped to the Flow package (no tiptap dependency).\n */\nexport interface AIChatMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\nasync function* streamOpenAI(\n config: FlowAIConfig,\n messages: AIChatMessage[],\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n messages: [\n ...(config.systemPrompt ? [{ role: 'system', content: config.systemPrompt }] : []),\n ...messages,\n ],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]' || !trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n const content = data.choices?.[0]?.delta?.content;\n if (content) yield content;\n } catch { /* skip malformed chunk */ }\n }\n }\n}\n\nasync function* streamAnthropic(\n config: FlowAIConfig,\n messages: AIChatMessage[],\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n ...(config.systemPrompt ? { system: config.systemPrompt } : {}),\n messages,\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n if (data.type === 'content_block_delta' && data.delta?.text) yield data.delta.text;\n } catch { /* skip malformed chunk */ }\n }\n }\n}\n\nexport function streamAIChat(\n config: FlowAIConfig,\n messages: AIChatMessage[],\n signal: AbortSignal,\n): AsyncIterable<string> {\n if (config.protocol === 'anthropic') return streamAnthropic(config, messages, signal);\n return streamOpenAI(config, messages, signal);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"aiClient.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/aiClient.ts"],"sourcesContent":["import type { FlowAIConfig } from '../types';\n\n/**\n * Minimal streaming chat client for the Flow AI media node. Supports\n * OpenAI-compatible `/chat/completions` and Anthropic `/messages` endpoints.\n *\n * Yields incremental text deltas. Callers accumulate them to render a live,\n * streaming response. This intentionally mirrors the RichTextEditor AIRewrite\n * streaming logic but is scoped to the Flow package (no tiptap dependency).\n */\nexport interface AIChatMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * Resolve the full request URL from a possibly-partial gateway.\n *\n * Users often paste a base URL (e.g. `https://api.moonshot.cn/v1`) instead of\n * the full endpoint, which then 404s. We append the protocol's default path\n * when the gateway doesn't already point at a completions/messages endpoint.\n */\nfunction resolveEndpoint(config: FlowAIConfig): string {\n const raw = (config.gateway || '').trim().replace(/\\/+$/, '');\n if (!raw) return raw;\n const path = config.protocol === 'anthropic' ? '/messages' : '/chat/completions';\n // Already a full endpoint.\n if (/\\/(chat\\/completions|messages|responses|completions)$/i.test(raw)) return raw;\n // Bare `/v1` (or version segment) base URL → append the default path.\n if (/\\/v\\d+$/i.test(raw)) return raw + path;\n // Host root with no path → assume `/v1` + default path.\n try {\n const u = new URL(raw);\n if (u.pathname === '' || u.pathname === '/') return raw + '/v1' + path;\n } catch { /* not a parseable URL; fall through */ }\n // Some other path was given; append the default endpoint segment.\n return raw + path;\n}\n\nasync function* streamOpenAI(\n config: FlowAIConfig,\n messages: ReadonlyArray<{ role: string; content: unknown }>,\n signal?: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n messages: [\n ...(config.systemPrompt ? [{ role: 'system', content: config.systemPrompt }] : []),\n ...messages,\n ],\n stream: true,\n });\n\n const response = await fetch(resolveEndpoint(config), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]' || !trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n const content = data.choices?.[0]?.delta?.content;\n if (content) yield content;\n } catch { /* skip malformed chunk */ }\n }\n }\n}\n\nasync function* streamAnthropic(\n config: FlowAIConfig,\n messages: ReadonlyArray<{ role: string; content: unknown }>,\n signal?: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 8192,\n ...(config.systemPrompt ? { system: config.systemPrompt } : {}),\n messages,\n stream: true,\n });\n\n const response = await fetch(resolveEndpoint(config), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n if (data.type === 'content_block_delta' && data.delta?.text) yield data.delta.text;\n } catch { /* skip malformed chunk */ }\n }\n }\n}\n\nexport function streamAIChat(\n config: FlowAIConfig,\n messages: AIChatMessage[],\n signal: AbortSignal,\n): AsyncIterable<string> {\n if (config.protocol === 'anthropic') return streamAnthropic(config, messages, signal);\n return streamOpenAI(config, messages, signal);\n}\n\n/**\n * Non-streaming completion used by the AI flow generator. Accepts an optional\n * image (data URL) for \"reconstruct this diagram\" requests. Returns the full\n * assistant text.\n */\nexport async function completeAIChat(\n config: FlowAIConfig,\n userText: string,\n options?: { imageDataUrl?: string; systemPrompt?: string; signal?: AbortSignal },\n): Promise<string> {\n const system = options?.systemPrompt ?? config.systemPrompt;\n const image = options?.imageDataUrl;\n\n if (config.protocol === 'anthropic') {\n const content: any[] = [{ type: 'text', text: userText }];\n if (image) {\n const m = /^data:(.+?);base64,(.*)$/.exec(image);\n if (m) {\n content.unshift({\n type: 'image',\n source: { type: 'base64', media_type: m[1], data: m[2] },\n });\n }\n }\n const response = await fetch(resolveEndpoint(config), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true',\n ...config.headers,\n },\n body: JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n ...(system ? { system } : {}),\n messages: [{ role: 'user', content }],\n }),\n signal: options?.signal,\n });\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const json = await response.json();\n return json.content?.map((c: any) => c.text ?? '').join('') ?? '';\n }\n\n // OpenAI-compatible (supports multimodal `image_url` content parts).\n const userContent: any = image\n ? [\n { type: 'text', text: userText },\n { type: 'image_url', image_url: { url: image } },\n ]\n : userText;\n const response = await fetch(resolveEndpoint(config), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n ...(system ? [{ role: 'system', content: system }] : []),\n { role: 'user', content: userContent },\n ],\n }),\n signal: options?.signal,\n });\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const json = await response.json();\n return json.choices?.[0]?.message?.content ?? '';\n}\n\n/**\n * Streaming variant of `completeAIChat`: same multimodal request shape\n * (optional image + system prompt override), but the reply is consumed as SSE\n * deltas. `onDelta` fires with the accumulated text after every chunk so\n * callers can render the response live. Returns the full assistant text.\n */\nexport async function completeAIChatStream(\n config: FlowAIConfig,\n userText: string,\n options?: {\n imageDataUrl?: string;\n systemPrompt?: string;\n signal?: AbortSignal;\n onDelta?: (accumulated: string) => void;\n },\n): Promise<string> {\n const system = options?.systemPrompt ?? config.systemPrompt;\n const image = options?.imageDataUrl;\n\n let content: unknown = userText;\n if (config.protocol === 'anthropic') {\n const parts: any[] = [{ type: 'text', text: userText }];\n if (image) {\n const m = /^data:(.+?);base64,(.*)$/.exec(image);\n if (m) {\n parts.unshift({\n type: 'image',\n source: { type: 'base64', media_type: m[1], data: m[2] },\n });\n }\n }\n content = parts;\n } else if (image) {\n content = [\n { type: 'text', text: userText },\n { type: 'image_url', image_url: { url: image } },\n ];\n }\n\n const effective = system ? { ...config, systemPrompt: system } : config;\n const messages = [{ role: 'user', content }];\n const stream = effective.protocol === 'anthropic'\n ? streamAnthropic(effective, messages, options?.signal)\n : streamOpenAI(effective, messages, options?.signal);\n\n let acc = '';\n for await (const delta of stream) {\n acc += delta;\n options?.onDelta?.(acc);\n }\n return acc;\n}\n"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { FlowDataColumn, FlowDataColumnType, FlowDataConfig } from '../types';
2
+ /** Result of parsing a raw table into columns + row records. */
3
+ export interface ParsedTable {
4
+ columns: FlowDataColumn[];
5
+ rows: Array<Record<string, unknown>>;
6
+ }
7
+ /**
8
+ * Parse CSV text into a matrix of string cells. Handles quoted fields,
9
+ * escaped quotes (""), and embedded newlines/commas. Auto-detects `,` or `;`
10
+ * as the delimiter from the first non-empty line.
11
+ */
12
+ export declare function parseCsv(text: string): string[][];
13
+ /** Serialize columns + rows back to CSV text (for round-tripping/exports). */
14
+ export declare function toCsv(columns: FlowDataColumn[], rows: Array<Record<string, unknown>>): string;
15
+ /**
16
+ * Parse the first worksheet of an XLSX workbook (an OOXML zip) into a string
17
+ * matrix. Uses `fflate` to unzip and DOMParser to read the sheet XML + shared
18
+ * strings. Loaded dynamically so it never enters the base bundle.
19
+ */
20
+ export declare function parseXlsx(buffer: ArrayBuffer): Promise<string[][]>;
21
+ /** Infer a column type from a sample of raw string cell values. */
22
+ export declare function inferColumnType(samples: string[]): FlowDataColumnType;
23
+ /** Coerce a raw string cell to a typed value based on the column type. */
24
+ export declare function coerceValue(raw: string, type: FlowDataColumnType): unknown;
25
+ /**
26
+ * Build a typed table from a raw string matrix. The first row is treated as the
27
+ * header. Column types are inferred from the data rows.
28
+ */
29
+ export declare function matrixToTable(matrix: string[][]): ParsedTable;
30
+ /** Parse a File (csv or xlsx) into a typed table. */
31
+ export declare function parseDataFile(file: File): Promise<ParsedTable>;
32
+ /** Default palette for chart series, mirroring the demo examples. */
33
+ export declare const DATA_CHART_PALETTE: string[];
34
+ /** Column key → display label lookup. */
35
+ export declare function labelFor(columns: FlowDataColumn[], key: string): string;
36
+ /** First non-numeric column key (a sensible default X/category field). */
37
+ export declare function firstDimension(columns: FlowDataColumn[]): string | undefined;
38
+ /** All numeric column keys (candidate measures/series). */
39
+ export declare function numericFields(columns: FlowDataColumn[]): string[];
40
+ /**
41
+ * Produce a sensible default `FlowDataConfig` for a freshly parsed table:
42
+ * table view, first numeric field charted against the first dimension.
43
+ */
44
+ export declare function makeDefaultDataConfig(parsed: ParsedTable, sourceName?: string): FlowDataConfig;
45
+ /**
46
+ * Re-parse CSV text into an existing config, preserving column keys and types
47
+ * for headers that match an existing column (by label or key). New headers get
48
+ * fresh inferred columns; chart/pivot references to removed fields are pruned.
49
+ */
50
+ export declare function applyCsvText(config: FlowDataConfig, text: string): FlowDataConfig;
51
+ /** A small starter table used when creating an empty Data node from the palette. */
52
+ export declare function makeStarterDataConfig(): FlowDataConfig;
@@ -0,0 +1,270 @@
1
+ function w(e) {
2
+ const r = e.replace(/^\uFEFF/, ""), t = A(r), n = [];
3
+ let o = "", a = [], l = !1;
4
+ for (let i = 0; i < r.length; i++) {
5
+ const c = r[i];
6
+ if (l) {
7
+ c === '"' ? r[i + 1] === '"' ? (o += '"', i++) : l = !1 : o += c;
8
+ continue;
9
+ }
10
+ c === '"' ? l = !0 : c === t ? (a.push(o), o = "") : c === `
11
+ ` ? (a.push(o), n.push(a), o = "", a = []) : c === "\r" || (o += c);
12
+ }
13
+ return (o.length > 0 || a.length > 0) && (a.push(o), n.push(a)), n.filter((i) => !(i.length === 1 && i[0].trim() === ""));
14
+ }
15
+ function A(e) {
16
+ const r = e.split(/\r?\n/, 1)[0] ?? "", t = (r.match(/,/g) ?? []).length, n = (r.match(/;/g) ?? []).length, o = (r.match(/\t/g) ?? []).length;
17
+ return o > t && o > n ? " " : n > t ? ";" : ",";
18
+ }
19
+ function D(e, r) {
20
+ const t = (a) => {
21
+ const l = a == null ? "" : String(a);
22
+ return /[",\n\r]/.test(l) ? `"${l.replace(/"/g, '""')}"` : l;
23
+ }, n = e.map((a) => t(a.label ?? a.key)).join(","), o = r.map((a) => e.map((l) => t(a[l.key])).join(",")).join(`
24
+ `);
25
+ return o ? `${n}
26
+ ${o}` : n;
27
+ }
28
+ async function T(e) {
29
+ const { unzipSync: r, strFromU8: t } = await import("fflate"), n = r(new Uint8Array(e)), o = new DOMParser(), a = (u) => {
30
+ const h = n[u];
31
+ return h ? o.parseFromString(t(h), "application/xml") : null;
32
+ }, l = [], i = a("xl/sharedStrings.xml");
33
+ if (i) for (const u of Array.from(i.getElementsByTagName("si"))) {
34
+ const h = Array.from(u.getElementsByTagName("t"));
35
+ l.push(h.map((p) => p.textContent ?? "").join(""));
36
+ }
37
+ const c = a(C(n, a));
38
+ if (!c) throw new Error("无法读取 Excel 工作表");
39
+ const m = Array.from(c.getElementsByTagName("row")), g = [];
40
+ for (const u of m) {
41
+ const h = Array.from(u.getElementsByTagName("c")), p = [];
42
+ for (const s of h) {
43
+ const f = $(s.getAttribute("r") ?? ""), y = s.getAttribute("t");
44
+ let d = "";
45
+ if (y === "s") {
46
+ const b = Number(s.getElementsByTagName("v")[0]?.textContent ?? "");
47
+ d = Number.isFinite(b) ? l[b] ?? "" : "";
48
+ } else y === "inlineStr" ? d = s.getElementsByTagName("t")[0]?.textContent ?? "" : d = s.getElementsByTagName("v")[0]?.textContent ?? "";
49
+ f >= 0 && (p[f] = d);
50
+ }
51
+ for (let s = 0; s < p.length; s++) p[s] == null && (p[s] = "");
52
+ g.push(p);
53
+ }
54
+ return g.filter((u) => u.some((h) => h.trim() !== ""));
55
+ }
56
+ function C(e, r) {
57
+ const t = r("xl/workbook.xml"), n = r("xl/_rels/workbook.xml.rels");
58
+ if (t && n) {
59
+ const o = t.getElementsByTagName("sheet")[0], a = o?.getAttribute("r:id") ?? o?.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id");
60
+ if (a) {
61
+ for (const l of Array.from(n.getElementsByTagName("Relationship"))) if (l.getAttribute("Id") === a) return `xl/${(l.getAttribute("Target") ?? "").replace(/^\//, "").replace(/^xl\//, "")}`;
62
+ }
63
+ }
64
+ return e["xl/worksheets/sheet1.xml"] ? "xl/worksheets/sheet1.xml" : Object.keys(e).find((o) => /^xl\/worksheets\/.*\.xml$/.test(o)) ?? "xl/worksheets/sheet1.xml";
65
+ }
66
+ function $(e) {
67
+ const r = e.match(/^[A-Z]+/i)?.[0];
68
+ if (!r) return -1;
69
+ let t = 0;
70
+ for (const n of r.toUpperCase()) t = t * 26 + (n.charCodeAt(0) - 64);
71
+ return t - 1;
72
+ }
73
+ function v(e, r) {
74
+ let t = e.trim().replace(/\s+/g, "_").replace(/[^\w\u4e00-\u9fa5]/g, "");
75
+ t || (t = "col");
76
+ let n = t, o = 1;
77
+ for (; r.has(n); ) n = `${t}_${o++}`;
78
+ return r.add(n), n;
79
+ }
80
+ var N = /^\d{4}[-/]\d{1,2}[-/]\d{1,2}([ T]\d{1,2}:\d{2}(:\d{2})?)?$/;
81
+ function k(e) {
82
+ const r = e.map((t) => t?.trim()).filter((t) => t);
83
+ return r.length === 0 ? "string" : r.every((t) => /^(true|false|yes|no|是|否)$/i.test(t)) ? "boolean" : r.every((t) => /^-?\d+(\.\d+)?%?$/.test(t.replace(/,/g, ""))) ? "number" : r.every((t) => N.test(t)) ? "date" : "string";
84
+ }
85
+ function F(e, r) {
86
+ const t = (e ?? "").trim();
87
+ if (t === "") return r === "number" ? null : "";
88
+ switch (r) {
89
+ case "number": {
90
+ const n = t.replace(/,/g, "").replace(/%$/, ""), o = Number(n);
91
+ return Number.isFinite(o) ? o : null;
92
+ }
93
+ case "boolean":
94
+ return /^(true|yes|是)$/i.test(t);
95
+ default:
96
+ return t;
97
+ }
98
+ }
99
+ function x(e) {
100
+ if (e.length === 0) return {
101
+ columns: [],
102
+ rows: []
103
+ };
104
+ const [r, ...t] = e, n = /* @__PURE__ */ new Set(), o = Math.max(r.length, ...t.map((l) => l.length), 0), a = [];
105
+ for (let l = 0; l < o; l++) {
106
+ const i = (r[l] ?? `列${l + 1}`).trim() || `列${l + 1}`, c = t.slice(0, 50).map((m) => m[l] ?? "");
107
+ a.push({
108
+ key: v(i, n),
109
+ label: i,
110
+ type: k(c)
111
+ });
112
+ }
113
+ return {
114
+ columns: a,
115
+ rows: t.map((l) => {
116
+ const i = {};
117
+ return a.forEach((c, m) => {
118
+ i[c.key] = F(l[m] ?? "", c.type);
119
+ }), i;
120
+ })
121
+ };
122
+ }
123
+ async function j(e) {
124
+ const r = e.name.toLowerCase();
125
+ return r.endsWith(".xlsx") || r.endsWith(".xlsm") ? x(await T(await e.arrayBuffer())) : x(w(await e.text()));
126
+ }
127
+ var R = [
128
+ "#6366f1",
129
+ "#10b981",
130
+ "#f59e0b",
131
+ "#f43f5e",
132
+ "#06b6d4",
133
+ "#8b5cf6",
134
+ "#84cc16",
135
+ "#ec4899",
136
+ "#0ea5e9",
137
+ "#f97316"
138
+ ];
139
+ function _(e, r) {
140
+ return e.find((t) => t.key === r)?.label ?? r;
141
+ }
142
+ function E(e) {
143
+ return (e.find((r) => r.type !== "number") ?? e[0])?.key;
144
+ }
145
+ function S(e) {
146
+ return e.filter((r) => r.type === "number").map((r) => r.key);
147
+ }
148
+ function B(e, r) {
149
+ const t = E(e.columns), n = S(e.columns);
150
+ return {
151
+ columns: e.columns,
152
+ rows: e.rows,
153
+ view: "table",
154
+ sourceName: r,
155
+ chart: {
156
+ type: "bar",
157
+ xField: t,
158
+ yFields: n.slice(0, 1)
159
+ },
160
+ pivot: {
161
+ enabled: !1,
162
+ rowFields: t ? [t] : [],
163
+ colFields: [],
164
+ values: n[0] ? [{
165
+ field: n[0],
166
+ aggFn: "sum"
167
+ }] : []
168
+ }
169
+ };
170
+ }
171
+ function M(e, r) {
172
+ const t = w(r);
173
+ if (t.length === 0) return {
174
+ ...e,
175
+ columns: [],
176
+ rows: [],
177
+ chart: { type: "bar" },
178
+ pivot: {
179
+ enabled: !1,
180
+ rowFields: [],
181
+ colFields: [],
182
+ values: []
183
+ }
184
+ };
185
+ const [n, ...o] = t, a = Math.max(n.length, ...o.map((s) => s.length), 0), l = /* @__PURE__ */ new Set(), i = new Map(e.columns.map((s) => [s.label ?? s.key, s])), c = new Map(e.columns.map((s) => [s.key, s])), m = [];
186
+ for (let s = 0; s < a; s++) {
187
+ const f = (n[s] ?? `列${s + 1}`).trim() || `列${s + 1}`, y = i.get(f) ?? c.get(f);
188
+ if (y)
189
+ l.add(y.key), m.push({
190
+ ...y,
191
+ label: f
192
+ });
193
+ else {
194
+ const d = o.slice(0, 50).map((b) => b[s] ?? "");
195
+ m.push({
196
+ key: v(f, l),
197
+ label: f,
198
+ type: k(d)
199
+ });
200
+ }
201
+ }
202
+ const g = o.map((s) => {
203
+ const f = {};
204
+ return m.forEach((y, d) => {
205
+ f[y.key] = F(s[d] ?? "", y.type);
206
+ }), f;
207
+ }), u = new Set(m.map((s) => s.key)), h = e.chart ? {
208
+ ...e.chart,
209
+ xField: e.chart.xField && u.has(e.chart.xField) ? e.chart.xField : E(m),
210
+ yFields: (e.chart.yFields ?? []).filter((s) => u.has(s)),
211
+ seriesColors: e.chart.seriesColors ? Object.fromEntries(Object.entries(e.chart.seriesColors).filter(([s]) => u.has(s))) : void 0
212
+ } : e.chart, p = e.pivot ? {
213
+ ...e.pivot,
214
+ rowFields: e.pivot.rowFields.filter((s) => u.has(s)),
215
+ colFields: e.pivot.colFields.filter((s) => u.has(s)),
216
+ values: e.pivot.values.filter((s) => u.has(s.field))
217
+ } : e.pivot;
218
+ return {
219
+ ...e,
220
+ columns: m,
221
+ rows: g,
222
+ chart: h,
223
+ pivot: p
224
+ };
225
+ }
226
+ function L() {
227
+ return B({
228
+ columns: [{
229
+ key: "category",
230
+ label: "类别",
231
+ type: "string"
232
+ }, {
233
+ key: "value",
234
+ label: "数值",
235
+ type: "number"
236
+ }],
237
+ rows: [
238
+ {
239
+ category: "A",
240
+ value: 30
241
+ },
242
+ {
243
+ category: "B",
244
+ value: 45
245
+ },
246
+ {
247
+ category: "C",
248
+ value: 28
249
+ }
250
+ ]
251
+ });
252
+ }
253
+ export {
254
+ R as DATA_CHART_PALETTE,
255
+ M as applyCsvText,
256
+ F as coerceValue,
257
+ E as firstDimension,
258
+ k as inferColumnType,
259
+ _ as labelFor,
260
+ B as makeDefaultDataConfig,
261
+ L as makeStarterDataConfig,
262
+ x as matrixToTable,
263
+ S as numericFields,
264
+ w as parseCsv,
265
+ j as parseDataFile,
266
+ T as parseXlsx,
267
+ D as toCsv
268
+ };
269
+
270
+ //# sourceMappingURL=dataUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataUtils.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/dataUtils.ts"],"sourcesContent":["// Data-node helpers: CSV/XLSX parsing, column type inference, and building\n// TanStack Charts definitions from parsed rows. Kept dependency-light so the\n// base `dishui/flow` bundle stays small — `fflate` (already a transitive dep of\n// markmap) is the only heavy import and only loads when an .xlsx is opened.\n\nimport type {\n FlowDataColumn,\n FlowDataColumnType,\n FlowDataConfig,\n FlowDataChartConfig,\n} from '../types';\n\n/** Result of parsing a raw table into columns + row records. */\nexport interface ParsedTable {\n columns: FlowDataColumn[];\n rows: Array<Record<string, unknown>>;\n}\n\n// ── CSV parsing ────────────────────────────────────────────────────────────\n\n/**\n * Parse CSV text into a matrix of string cells. Handles quoted fields,\n * escaped quotes (\"\"), and embedded newlines/commas. Auto-detects `,` or `;`\n * as the delimiter from the first non-empty line.\n */\nexport function parseCsv(text: string): string[][] {\n const src = text.replace(/^\\uFEFF/, ''); // strip BOM\n const delimiter = detectDelimiter(src);\n const rows: string[][] = [];\n let field = '';\n let row: string[] = [];\n let inQuotes = false;\n\n for (let i = 0; i < src.length; i++) {\n const ch = src[i];\n if (inQuotes) {\n if (ch === '\"') {\n if (src[i + 1] === '\"') {\n field += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n field += ch;\n }\n continue;\n }\n if (ch === '\"') {\n inQuotes = true;\n } else if (ch === delimiter) {\n row.push(field);\n field = '';\n } else if (ch === '\\n') {\n row.push(field);\n rows.push(row);\n field = '';\n row = [];\n } else if (ch === '\\r') {\n // ignore; handled by the following \\n (or end of input)\n } else {\n field += ch;\n }\n }\n // flush trailing field/row\n if (field.length > 0 || row.length > 0) {\n row.push(field);\n rows.push(row);\n }\n // drop fully-empty trailing rows\n return rows.filter((r) => !(r.length === 1 && r[0].trim() === ''));\n}\n\nfunction detectDelimiter(src: string): string {\n const firstLine = src.split(/\\r?\\n/, 1)[0] ?? '';\n const commas = (firstLine.match(/,/g) ?? []).length;\n const semis = (firstLine.match(/;/g) ?? []).length;\n const tabs = (firstLine.match(/\\t/g) ?? []).length;\n if (tabs > commas && tabs > semis) return '\\t';\n if (semis > commas) return ';';\n return ',';\n}\n\n/** Serialize columns + rows back to CSV text (for round-tripping/exports). */\nexport function toCsv(columns: FlowDataColumn[], rows: Array<Record<string, unknown>>): string {\n const esc = (v: unknown) => {\n const s = v == null ? '' : String(v);\n return /[\",\\n\\r]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n const header = columns.map((c) => esc(c.label ?? c.key)).join(',');\n const body = rows\n .map((r) => columns.map((c) => esc(r[c.key])).join(','))\n .join('\\n');\n return body ? `${header}\\n${body}` : header;\n}\n\n// ── XLSX parsing ─────────────────────────────────────────────────────────────\n\n/**\n * Parse the first worksheet of an XLSX workbook (an OOXML zip) into a string\n * matrix. Uses `fflate` to unzip and DOMParser to read the sheet XML + shared\n * strings. Loaded dynamically so it never enters the base bundle.\n */\nexport async function parseXlsx(buffer: ArrayBuffer): Promise<string[][]> {\n const { unzipSync, strFromU8 } = await import('fflate');\n const files = unzipSync(new Uint8Array(buffer));\n\n const parser = new DOMParser();\n const readXml = (path: string): Document | null => {\n const entry = files[path];\n if (!entry) return null;\n return parser.parseFromString(strFromU8(entry), 'application/xml');\n };\n\n // Shared strings table (cells of type \"s\" reference these by index).\n const sharedStrings: string[] = [];\n const sst = readXml('xl/sharedStrings.xml');\n if (sst) {\n for (const si of Array.from(sst.getElementsByTagName('si'))) {\n // Concatenate all <t> runs within the string item.\n const ts = Array.from(si.getElementsByTagName('t'));\n sharedStrings.push(ts.map((t) => t.textContent ?? '').join(''));\n }\n }\n\n // Resolve the first sheet's target from the workbook relationships.\n const sheetPath = resolveFirstSheetPath(files, readXml);\n const sheetDoc = readXml(sheetPath);\n if (!sheetDoc) throw new Error('无法读取 Excel 工作表');\n\n const rowsEls = Array.from(sheetDoc.getElementsByTagName('row'));\n const matrix: string[][] = [];\n for (const rowEl of rowsEls) {\n const cells = Array.from(rowEl.getElementsByTagName('c'));\n const rowArr: string[] = [];\n for (const c of cells) {\n const ref = c.getAttribute('r') ?? '';\n const colIdx = columnRefToIndex(ref);\n const type = c.getAttribute('t');\n let value = '';\n if (type === 's') {\n const idx = Number(c.getElementsByTagName('v')[0]?.textContent ?? '');\n value = Number.isFinite(idx) ? sharedStrings[idx] ?? '' : '';\n } else if (type === 'inlineStr') {\n value = c.getElementsByTagName('t')[0]?.textContent ?? '';\n } else {\n value = c.getElementsByTagName('v')[0]?.textContent ?? '';\n }\n if (colIdx >= 0) rowArr[colIdx] = value;\n }\n // normalize holes to empty strings\n for (let i = 0; i < rowArr.length; i++) if (rowArr[i] == null) rowArr[i] = '';\n matrix.push(rowArr);\n }\n return matrix.filter((r) => r.some((cell) => cell.trim() !== ''));\n}\n\nfunction resolveFirstSheetPath(\n files: Record<string, Uint8Array>,\n readXml: (path: string) => Document | null,\n): string {\n // Prefer following workbook.xml → rels; fall back to the conventional path.\n const workbook = readXml('xl/workbook.xml');\n const rels = readXml('xl/_rels/workbook.xml.rels');\n if (workbook && rels) {\n const sheet = workbook.getElementsByTagName('sheet')[0];\n const rid = sheet?.getAttribute('r:id') ?? sheet?.getAttributeNS(\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',\n 'id',\n );\n if (rid) {\n for (const rel of Array.from(rels.getElementsByTagName('Relationship'))) {\n if (rel.getAttribute('Id') === rid) {\n const target = rel.getAttribute('Target') ?? '';\n const norm = target.replace(/^\\//, '').replace(/^xl\\//, '');\n return `xl/${norm}`;\n }\n }\n }\n }\n if (files['xl/worksheets/sheet1.xml']) return 'xl/worksheets/sheet1.xml';\n // last resort: first worksheet entry found\n const first = Object.keys(files).find((p) => /^xl\\/worksheets\\/.*\\.xml$/.test(p));\n return first ?? 'xl/worksheets/sheet1.xml';\n}\n\n/** Convert an A1-style cell ref (e.g. \"C5\") to a zero-based column index. */\nfunction columnRefToIndex(ref: string): number {\n const letters = ref.match(/^[A-Z]+/i)?.[0];\n if (!letters) return -1;\n let idx = 0;\n for (const ch of letters.toUpperCase()) {\n idx = idx * 26 + (ch.charCodeAt(0) - 64);\n }\n return idx - 1;\n}\n\n// ── Matrix → table (columns + typed rows) ────────────────────────────────────\n\n/** Slugify a header label into a safe object key, deduping collisions. */\nfunction toKey(label: string, used: Set<string>): string {\n let base = label.trim().replace(/\\s+/g, '_').replace(/[^\\w\\u4e00-\\u9fa5]/g, '');\n if (!base) base = 'col';\n let key = base;\n let n = 1;\n while (used.has(key)) key = `${base}_${n++}`;\n used.add(key);\n return key;\n}\n\nconst DATE_RE = /^\\d{4}[-/]\\d{1,2}[-/]\\d{1,2}([ T]\\d{1,2}:\\d{2}(:\\d{2})?)?$/;\n\n/** Infer a column type from a sample of raw string cell values. */\nexport function inferColumnType(samples: string[]): FlowDataColumnType {\n const nonEmpty = samples.map((s) => s?.trim()).filter((s) => s);\n if (nonEmpty.length === 0) return 'string';\n const isBool = nonEmpty.every((s) => /^(true|false|yes|no|是|否)$/i.test(s));\n if (isBool) return 'boolean';\n const isNum = nonEmpty.every((s) => /^-?\\d+(\\.\\d+)?%?$/.test(s.replace(/,/g, '')));\n if (isNum) return 'number';\n const isDate = nonEmpty.every((s) => DATE_RE.test(s));\n if (isDate) return 'date';\n return 'string';\n}\n\n/** Coerce a raw string cell to a typed value based on the column type. */\nexport function coerceValue(raw: string, type: FlowDataColumnType): unknown {\n const s = (raw ?? '').trim();\n if (s === '') return type === 'number' ? null : '';\n switch (type) {\n case 'number': {\n const cleaned = s.replace(/,/g, '').replace(/%$/, '');\n const n = Number(cleaned);\n return Number.isFinite(n) ? n : null;\n }\n case 'boolean':\n return /^(true|yes|是)$/i.test(s);\n case 'date':\n case 'string':\n default:\n return s;\n }\n}\n\n/**\n * Build a typed table from a raw string matrix. The first row is treated as the\n * header. Column types are inferred from the data rows.\n */\nexport function matrixToTable(matrix: string[][]): ParsedTable {\n if (matrix.length === 0) return { columns: [], rows: [] };\n const [header, ...dataRows] = matrix;\n const used = new Set<string>();\n const colCount = Math.max(header.length, ...dataRows.map((r) => r.length), 0);\n\n const columns: FlowDataColumn[] = [];\n for (let c = 0; c < colCount; c++) {\n const label = (header[c] ?? `列${c + 1}`).trim() || `列${c + 1}`;\n const samples = dataRows.slice(0, 50).map((r) => r[c] ?? '');\n columns.push({ key: toKey(label, used), label, type: inferColumnType(samples) });\n }\n\n const rows = dataRows.map((r) => {\n const record: Record<string, unknown> = {};\n columns.forEach((col, c) => {\n record[col.key] = coerceValue(r[c] ?? '', col.type);\n });\n return record;\n });\n\n return { columns, rows };\n}\n\n/** Parse a File (csv or xlsx) into a typed table. */\nexport async function parseDataFile(file: File): Promise<ParsedTable> {\n const name = file.name.toLowerCase();\n if (name.endsWith('.xlsx') || name.endsWith('.xlsm')) {\n const buffer = await file.arrayBuffer();\n return matrixToTable(await parseXlsx(buffer));\n }\n // treat everything else as delimited text (csv/tsv/txt)\n const text = await file.text();\n return matrixToTable(parseCsv(text));\n}\n\n// ── Config helpers ───────────────────────────────────────────────────────────\n\n/** Default palette for chart series, mirroring the demo examples. */\nexport const DATA_CHART_PALETTE = [\n '#6366f1', '#10b981', '#f59e0b', '#f43f5e', '#06b6d4',\n '#8b5cf6', '#84cc16', '#ec4899', '#0ea5e9', '#f97316',\n];\n\n/** Column key → display label lookup. */\nexport function labelFor(columns: FlowDataColumn[], key: string): string {\n return columns.find((c) => c.key === key)?.label ?? key;\n}\n\n/** First non-numeric column key (a sensible default X/category field). */\nexport function firstDimension(columns: FlowDataColumn[]): string | undefined {\n return (columns.find((c) => c.type !== 'number') ?? columns[0])?.key;\n}\n\n/** All numeric column keys (candidate measures/series). */\nexport function numericFields(columns: FlowDataColumn[]): string[] {\n return columns.filter((c) => c.type === 'number').map((c) => c.key);\n}\n\n/**\n * Produce a sensible default `FlowDataConfig` for a freshly parsed table:\n * table view, first numeric field charted against the first dimension.\n */\nexport function makeDefaultDataConfig(\n parsed: ParsedTable,\n sourceName?: string,\n): FlowDataConfig {\n const x = firstDimension(parsed.columns);\n const nums = numericFields(parsed.columns);\n return {\n columns: parsed.columns,\n rows: parsed.rows,\n view: 'table',\n sourceName,\n chart: {\n type: 'bar',\n xField: x,\n yFields: nums.slice(0, 1),\n },\n pivot: {\n enabled: false,\n rowFields: x ? [x] : [],\n colFields: [],\n values: nums[0] ? [{ field: nums[0], aggFn: 'sum' }] : [],\n },\n };\n}\n\n/**\n * Re-parse CSV text into an existing config, preserving column keys and types\n * for headers that match an existing column (by label or key). New headers get\n * fresh inferred columns; chart/pivot references to removed fields are pruned.\n */\nexport function applyCsvText(config: FlowDataConfig, text: string): FlowDataConfig {\n const matrix = parseCsv(text);\n if (matrix.length === 0) {\n return { ...config, columns: [], rows: [], chart: { type: 'bar' }, pivot: { enabled: false, rowFields: [], colFields: [], values: [] } };\n }\n const [header, ...dataRows] = matrix;\n const colCount = Math.max(header.length, ...dataRows.map((r) => r.length), 0);\n const used = new Set<string>();\n const byLabel = new Map(config.columns.map((c) => [c.label ?? c.key, c]));\n const byKey = new Map(config.columns.map((c) => [c.key, c]));\n\n const columns: FlowDataColumn[] = [];\n for (let c = 0; c < colCount; c++) {\n const label = (header[c] ?? `列${c + 1}`).trim() || `列${c + 1}`;\n const existing = byLabel.get(label) ?? byKey.get(label);\n if (existing) {\n used.add(existing.key);\n columns.push({ ...existing, label });\n } else {\n const samples = dataRows.slice(0, 50).map((r) => r[c] ?? '');\n columns.push({ key: toKey(label, used), label, type: inferColumnType(samples) });\n }\n }\n\n const rows = dataRows.map((r) => {\n const record: Record<string, unknown> = {};\n columns.forEach((col, c) => {\n record[col.key] = coerceValue(r[c] ?? '', col.type);\n });\n return record;\n });\n\n const keys = new Set(columns.map((c) => c.key));\n\n const chart = config.chart\n ? {\n ...config.chart,\n xField: config.chart.xField && keys.has(config.chart.xField)\n ? config.chart.xField\n : firstDimension(columns),\n yFields: (config.chart.yFields ?? []).filter((f) => keys.has(f)),\n seriesColors: config.chart.seriesColors\n ? Object.fromEntries(Object.entries(config.chart.seriesColors).filter(([f]) => keys.has(f)))\n : undefined,\n }\n : config.chart;\n\n const pivot = config.pivot\n ? {\n ...config.pivot,\n rowFields: config.pivot.rowFields.filter((f) => keys.has(f)),\n colFields: config.pivot.colFields.filter((f) => keys.has(f)),\n values: config.pivot.values.filter((v) => keys.has(v.field)),\n }\n : config.pivot;\n\n return { ...config, columns, rows, chart, pivot };\n}\n\n/** A small starter table used when creating an empty Data node from the palette. */\nexport function makeStarterDataConfig(): FlowDataConfig {\n const columns: FlowDataColumn[] = [\n { key: 'category', label: '类别', type: 'string' },\n { key: 'value', label: '数值', type: 'number' },\n ];\n const rows = [\n { category: 'A', value: 30 },\n { category: 'B', value: 45 },\n { category: 'C', value: 28 },\n ];\n return makeDefaultDataConfig({ columns, rows });\n}\n"],"mappings":"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"}