@antv/infographic 0.2.7 → 0.2.9

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 (150) hide show
  1. package/dist/infographic.min.js +191 -191
  2. package/dist/infographic.min.js.map +1 -1
  3. package/esm/designs/items/BadgeCard.js +6 -1
  4. package/esm/designs/items/SimpleCircleNode.d.ts +8 -0
  5. package/esm/designs/items/SimpleCircleNode.js +14 -0
  6. package/esm/designs/items/index.d.ts +1 -0
  7. package/esm/designs/items/index.js +1 -0
  8. package/esm/designs/structures/hierarchy-mindmap.js +19 -5
  9. package/esm/designs/structures/hierarchy-tree.d.ts +2 -1
  10. package/esm/designs/structures/hierarchy-tree.js +23 -20
  11. package/esm/designs/structures/index.d.ts +1 -0
  12. package/esm/designs/structures/index.js +1 -0
  13. package/esm/designs/structures/relation-dagre-flow.d.ts +21 -0
  14. package/esm/designs/structures/relation-dagre-flow.js +497 -0
  15. package/esm/designs/utils/hierarchy-color.d.ts +1 -1
  16. package/esm/editor/plugins/edit-bar/edit-bar.js +27 -9
  17. package/esm/index.d.ts +1 -1
  18. package/esm/index.js +1 -2
  19. package/esm/jsx/global.d.ts +1 -0
  20. package/esm/jsx/types/element.d.ts +5 -1
  21. package/esm/jsx/utils/svg.js +2 -0
  22. package/esm/renderer/composites/icon.js +2 -0
  23. package/esm/renderer/composites/illus.d.ts +1 -1
  24. package/esm/renderer/composites/illus.js +9 -4
  25. package/esm/renderer/composites/text.js +4 -2
  26. package/esm/renderer/fonts/loader.js +3 -1
  27. package/esm/renderer/fonts/registry.js +1 -1
  28. package/esm/renderer/renderer.js +28 -25
  29. package/esm/resource/loader.js +3 -1
  30. package/esm/runtime/Infographic.js +1 -1
  31. package/esm/ssr/dom-shim.d.ts +4 -0
  32. package/esm/ssr/dom-shim.js +107 -0
  33. package/esm/ssr/index.d.ts +1 -0
  34. package/esm/ssr/index.js +1 -0
  35. package/esm/ssr/renderer.d.ts +2 -0
  36. package/esm/ssr/renderer.js +60 -0
  37. package/esm/syntax/index.js +57 -1
  38. package/esm/syntax/parser.js +44 -0
  39. package/esm/syntax/relations.d.ts +6 -0
  40. package/esm/syntax/relations.js +251 -0
  41. package/esm/syntax/schema.d.ts +1 -0
  42. package/esm/syntax/schema.js +12 -0
  43. package/esm/templates/built-in.js +2 -0
  44. package/esm/templates/relation-dagre-flow.d.ts +2 -0
  45. package/esm/templates/relation-dagre-flow.js +68 -0
  46. package/esm/types/data.d.ts +24 -3
  47. package/esm/utils/data.js +1 -1
  48. package/esm/utils/index.d.ts +1 -0
  49. package/esm/utils/index.js +1 -0
  50. package/esm/utils/is-browser.js +5 -9
  51. package/esm/utils/measure-text.d.ts +2 -2
  52. package/esm/utils/measure-text.js +4 -4
  53. package/esm/utils/recognizer.js +8 -5
  54. package/esm/utils/text.js +27 -19
  55. package/esm/version.d.ts +1 -0
  56. package/esm/version.js +1 -0
  57. package/lib/designs/items/BadgeCard.js +6 -1
  58. package/lib/designs/items/SimpleCircleNode.d.ts +8 -0
  59. package/lib/designs/items/SimpleCircleNode.js +18 -0
  60. package/lib/designs/items/index.d.ts +1 -0
  61. package/lib/designs/items/index.js +1 -0
  62. package/lib/designs/structures/hierarchy-mindmap.js +19 -5
  63. package/lib/designs/structures/hierarchy-tree.d.ts +2 -1
  64. package/lib/designs/structures/hierarchy-tree.js +23 -20
  65. package/lib/designs/structures/index.d.ts +1 -0
  66. package/lib/designs/structures/index.js +1 -0
  67. package/lib/designs/structures/relation-dagre-flow.d.ts +21 -0
  68. package/lib/designs/structures/relation-dagre-flow.js +501 -0
  69. package/lib/designs/utils/hierarchy-color.d.ts +1 -1
  70. package/lib/editor/plugins/edit-bar/edit-bar.js +27 -9
  71. package/lib/index.d.ts +1 -1
  72. package/lib/index.js +4 -7
  73. package/lib/jsx/global.d.ts +1 -0
  74. package/lib/jsx/types/element.d.ts +5 -1
  75. package/lib/jsx/utils/svg.js +2 -0
  76. package/lib/renderer/composites/icon.js +2 -0
  77. package/lib/renderer/composites/illus.d.ts +1 -1
  78. package/lib/renderer/composites/illus.js +8 -3
  79. package/lib/renderer/composites/text.js +4 -2
  80. package/lib/renderer/fonts/loader.js +2 -0
  81. package/lib/renderer/fonts/registry.js +6 -6
  82. package/lib/renderer/renderer.js +27 -24
  83. package/lib/resource/loader.js +3 -1
  84. package/lib/runtime/Infographic.js +1 -1
  85. package/lib/ssr/dom-shim.d.ts +4 -0
  86. package/lib/ssr/dom-shim.js +110 -0
  87. package/lib/ssr/index.d.ts +1 -0
  88. package/lib/ssr/index.js +5 -0
  89. package/lib/ssr/renderer.d.ts +2 -0
  90. package/lib/ssr/renderer.js +63 -0
  91. package/lib/syntax/index.js +57 -1
  92. package/lib/syntax/parser.js +44 -0
  93. package/lib/syntax/relations.d.ts +6 -0
  94. package/lib/syntax/relations.js +254 -0
  95. package/lib/syntax/schema.d.ts +1 -0
  96. package/lib/syntax/schema.js +13 -1
  97. package/lib/templates/built-in.js +2 -0
  98. package/lib/templates/relation-dagre-flow.d.ts +2 -0
  99. package/lib/templates/relation-dagre-flow.js +71 -0
  100. package/lib/types/data.d.ts +24 -3
  101. package/lib/utils/data.js +2 -5
  102. package/lib/utils/index.d.ts +1 -0
  103. package/lib/utils/index.js +1 -0
  104. package/lib/utils/is-browser.js +5 -9
  105. package/lib/utils/measure-text.d.ts +2 -2
  106. package/lib/utils/measure-text.js +4 -4
  107. package/lib/utils/recognizer.js +8 -5
  108. package/lib/utils/text.js +28 -23
  109. package/lib/version.d.ts +1 -0
  110. package/lib/version.js +4 -0
  111. package/package.json +21 -8
  112. package/src/designs/items/BadgeCard.tsx +9 -2
  113. package/src/designs/items/SimpleCircleNode.tsx +46 -0
  114. package/src/designs/items/index.ts +1 -0
  115. package/src/designs/structures/hierarchy-mindmap.tsx +15 -2
  116. package/src/designs/structures/hierarchy-tree.tsx +33 -31
  117. package/src/designs/structures/index.ts +1 -0
  118. package/src/designs/structures/relation-dagre-flow.tsx +782 -0
  119. package/src/designs/utils/hierarchy-color.ts +6 -1
  120. package/src/editor/plugins/edit-bar/edit-bar.ts +41 -17
  121. package/src/index.ts +1 -3
  122. package/src/jsx/global.ts +1 -0
  123. package/src/jsx/types/element.ts +15 -6
  124. package/src/jsx/utils/svg.ts +2 -0
  125. package/src/renderer/composites/icon.ts +2 -0
  126. package/src/renderer/composites/illus.ts +16 -3
  127. package/src/renderer/composites/text.ts +7 -2
  128. package/src/renderer/fonts/loader.ts +7 -1
  129. package/src/renderer/fonts/registry.ts +1 -1
  130. package/src/renderer/renderer.ts +42 -24
  131. package/src/resource/loader.ts +3 -1
  132. package/src/runtime/Infographic.tsx +1 -1
  133. package/src/ssr/dom-shim.ts +120 -0
  134. package/src/ssr/index.ts +1 -0
  135. package/src/ssr/renderer.ts +72 -0
  136. package/src/syntax/index.ts +58 -1
  137. package/src/syntax/parser.ts +49 -0
  138. package/src/syntax/relations.ts +291 -0
  139. package/src/syntax/schema.ts +16 -0
  140. package/src/templates/built-in.ts +4 -2
  141. package/src/templates/relation-dagre-flow.ts +73 -0
  142. package/src/types/data.ts +26 -3
  143. package/src/utils/data.ts +1 -1
  144. package/src/utils/index.ts +1 -0
  145. package/src/utils/is-browser.ts +3 -9
  146. package/src/utils/measure-text.ts +6 -7
  147. package/src/utils/recognizer.ts +9 -5
  148. package/src/utils/svg.ts +0 -1
  149. package/src/utils/text.ts +25 -19
  150. package/src/version.ts +1 -0
@@ -1,4 +1,4 @@
1
1
  import { type ResourceConfig } from '../../resource';
2
2
  import type { IllusElement, ItemDatum } from '../../types';
3
- export declare function renderIllus(svg: SVGSVGElement, node: SVGElement, value: string | ResourceConfig | undefined, datum?: ItemDatum): IllusElement | null;
3
+ export declare function renderIllus(svg: SVGSVGElement, node: SVGElement, value: string | ResourceConfig | undefined, datum?: ItemDatum, attrs?: Record<string, any>): IllusElement | null;
4
4
  export declare function renderItemIllus(svg: SVGSVGElement, node: SVGElement, datum: ItemDatum): SVGGElement | null;
@@ -4,25 +4,30 @@ exports.renderIllus = renderIllus;
4
4
  exports.renderItemIllus = renderItemIllus;
5
5
  const resource_1 = require("../../resource");
6
6
  const utils_1 = require("../../utils");
7
- function renderIllus(svg, node, value, datum) {
7
+ function renderIllus(svg, node, value, datum, attrs = {}) {
8
8
  if (!value)
9
9
  return null;
10
10
  const config = (0, resource_1.parseResourceConfig)(value);
11
11
  if (!config)
12
12
  return null;
13
13
  const id = (0, resource_1.getResourceId)(config);
14
+ if (attrs && Object.keys(attrs).length > 0) {
15
+ (0, utils_1.setAttributes)(node, attrs);
16
+ }
14
17
  const clipPathId = createClipPath(svg, node, id);
15
18
  (0, resource_1.loadResource)(svg, 'illus', config, datum);
16
19
  const { data, color } = config;
17
20
  return createIllusElement(id, {
18
21
  ...parseIllusBounds(node),
19
- 'clip-path': `url(#${clipPathId})`,
20
22
  ...(color ? { color } : {}),
23
+ ...attrs,
24
+ 'clip-path': `url(#${clipPathId})`,
21
25
  }, data);
22
26
  }
23
27
  function renderItemIllus(svg, node, datum) {
24
28
  const value = datum.illus;
25
- return renderIllus(svg, node, value, datum);
29
+ const attrs = datum.attributes?.illus;
30
+ return renderIllus(svg, node, value, datum, attrs);
26
31
  }
27
32
  function createClipPath(svg, node, id) {
28
33
  const clipPathId = `clip-${id}-${(0, utils_1.uuid)()}`;
@@ -24,8 +24,10 @@ function renderItemText(type, node, options) {
24
24
  return null;
25
25
  const { data, themeConfig } = options;
26
26
  const indexes = (0, utils_1.getItemIndexes)(node.dataset.indexes || '0');
27
- const text = String((0, lodash_es_1.get)((0, utils_1.getDatumByIndexes)(data, indexes), type, ''));
28
- const attrs = Object.assign({}, themeConfig.base?.text, themeConfig.item?.[type]);
27
+ const datum = (0, utils_1.getDatumByIndexes)(data, indexes);
28
+ const text = String((0, lodash_es_1.get)(datum, type, ''));
29
+ const dataAttrs = datum?.attributes?.[type];
30
+ const attrs = Object.assign({}, themeConfig.base?.text, themeConfig.item?.[type], dataAttrs);
29
31
  const staticAttrs = (0, utils_2.parseDynamicAttributes)(textShape, attrs);
30
32
  return renderText(node, node.textContent || text, staticAttrs);
31
33
  }
@@ -118,6 +118,8 @@ function loadFont(svg, font) {
118
118
  }
119
119
  }
120
120
  function loadFonts(svg) {
121
+ if (utils_1.isNode)
122
+ return;
121
123
  const fonts = (0, registry_1.getFonts)();
122
124
  fonts.forEach((font) => loadFont(svg, font.fontFamily));
123
125
  }
@@ -6,13 +6,13 @@ exports.getFonts = getFonts;
6
6
  exports.setDefaultFont = setDefaultFont;
7
7
  exports.registerFont = registerFont;
8
8
  exports.unregisterFont = unregisterFont;
9
- const utils_1 = require("../../utils");
9
+ const font_1 = require("../../utils/font");
10
10
  const FONT_REGISTRY = new Map();
11
11
  exports.DEFAULT_FONT = 'Alibaba PuHuiTi';
12
12
  function getFont(font) {
13
- const families = (0, utils_1.splitFontFamily)(font);
13
+ const families = (0, font_1.splitFontFamily)(font);
14
14
  for (const family of families) {
15
- const fontObj = FONT_REGISTRY.get((0, utils_1.decodeFontFamily)(family));
15
+ const fontObj = FONT_REGISTRY.get((0, font_1.decodeFontFamily)(family));
16
16
  if (fontObj)
17
17
  return fontObj;
18
18
  }
@@ -22,7 +22,7 @@ function getFonts() {
22
22
  return Array.from(FONT_REGISTRY.values());
23
23
  }
24
24
  function setDefaultFont(font) {
25
- exports.DEFAULT_FONT = (0, utils_1.encodeFontFamily)(font);
25
+ exports.DEFAULT_FONT = (0, font_1.encodeFontFamily)(font);
26
26
  }
27
27
  /**
28
28
  * 注册自定义字体
@@ -44,13 +44,13 @@ function setDefaultFont(font) {
44
44
  function registerFont(font) {
45
45
  const f = { ...font };
46
46
  FONT_REGISTRY.set(f.fontFamily, f);
47
- f.fontFamily = (0, utils_1.encodeFontFamily)(f.fontFamily);
47
+ f.fontFamily = (0, font_1.encodeFontFamily)(f.fontFamily);
48
48
  return f;
49
49
  }
50
50
  function unregisterFont(font) {
51
51
  const fontObj = getFont(font);
52
52
  if (!fontObj)
53
53
  return null;
54
- FONT_REGISTRY.delete((0, utils_1.decodeFontFamily)(fontObj.fontFamily));
54
+ FONT_REGISTRY.delete((0, font_1.decodeFontFamily)(fontObj.fontFamily));
55
55
  return fontObj;
56
56
  }
@@ -33,30 +33,33 @@ class Renderer {
33
33
  const postRender = () => {
34
34
  setView(this.template, this.options);
35
35
  (0, fonts_1.loadFonts)(this.template);
36
- svg.style.visibility = '';
36
+ svg.style.removeProperty('visibility');
37
37
  };
38
- const observer = new MutationObserver((mutations) => {
39
- mutations.forEach((mutation) => {
40
- mutation.addedNodes.forEach((node) => {
41
- if (node === svg || node.contains(svg)) {
42
- // post render
43
- postRender();
44
- // disconnect observer
45
- observer.disconnect();
46
- }
38
+ if (utils_1.isNode) {
39
+ postRender();
40
+ }
41
+ else {
42
+ const observer = new MutationObserver((mutations) => {
43
+ mutations.forEach((mutation) => {
44
+ mutation.addedNodes.forEach((node) => {
45
+ if (node === svg || node.contains(svg)) {
46
+ postRender();
47
+ observer.disconnect();
48
+ }
49
+ });
47
50
  });
48
51
  });
49
- });
50
- try {
51
- observer.observe(document, {
52
- childList: true,
53
- subtree: true,
54
- });
55
- }
56
- catch (error) {
57
- // Fallback for micro-app environments that proxy document.
58
- postRender();
59
- console.error(error);
52
+ try {
53
+ observer.observe(document, {
54
+ childList: true,
55
+ subtree: true,
56
+ });
57
+ }
58
+ catch (error) {
59
+ // Fallback for micro-app environments that proxy document.
60
+ postRender();
61
+ console.error(error);
62
+ }
60
63
  }
61
64
  this.rendered = true;
62
65
  return svg;
@@ -75,15 +78,15 @@ function fill(svg, options) {
75
78
  elements.forEach((element) => {
76
79
  const id = element.id || '';
77
80
  if ((0, utils_1.isTitle)(element)) {
78
- const modified = (0, composites_1.renderText)(element, data.title || '', Object.assign({}, themeConfig.base?.text, themeConfig.title));
81
+ const modified = (0, composites_1.renderText)(element, data.title || '', Object.assign({}, themeConfig.base?.text, themeConfig.title, data.attributes?.title));
79
82
  return upsert(element, modified);
80
83
  }
81
84
  if ((0, utils_1.isDesc)(element)) {
82
- const modified = (0, composites_1.renderText)(element, data.desc || '', Object.assign({}, themeConfig.base?.text, themeConfig.desc));
85
+ const modified = (0, composites_1.renderText)(element, data.desc || '', Object.assign({}, themeConfig.base?.text, themeConfig.desc, data.attributes?.desc));
83
86
  return upsert(element, modified);
84
87
  }
85
88
  if ((0, utils_1.isIllus)(element)) {
86
- const modified = (0, composites_1.renderIllus)(svg, element, data.illus?.[id]);
89
+ const modified = (0, composites_1.renderIllus)(svg, element, data.illus?.[id], undefined, data.attributes?.illus);
87
90
  return upsert(element, modified);
88
91
  }
89
92
  if ((0, utils_1.isShapesGroup)(element)) {
@@ -94,7 +94,9 @@ Object.defineProperty(exports, "getSvgLoadPromises", { enumerable: true, get: fu
94
94
  Object.defineProperty(exports, "waitForSvgLoads", { enumerable: true, get: function () { return load_tracker_2.waitForSvgLoads; } });
95
95
  function getFallbackQuery(cfg, scene, datum) {
96
96
  const defaultQuery = scene === 'illus' ? 'illustration' : 'icon';
97
- const datumQuery = normalizeQuery(datum?.label) || normalizeQuery(datum?.desc);
97
+ const datumQuery = normalizeQuery(cfg.data) ||
98
+ normalizeQuery(datum?.label) ||
99
+ normalizeQuery(datum?.desc);
98
100
  if (datumQuery)
99
101
  return datumQuery;
100
102
  const data = normalizeQuery(cfg.data);
@@ -30,7 +30,7 @@ class Infographic {
30
30
  setOptions(options, mode = 'replace', isInitial = false) {
31
31
  const { options: parsedOptions, errors, warnings, } = parseSyntaxOptions(options);
32
32
  if (isInitial) {
33
- this.initialOptions = (0, utils_2.cloneOptions)(parsedOptions);
33
+ this.initialOptions = parsedOptions;
34
34
  }
35
35
  const base = mode === 'replace'
36
36
  ? (0, utils_2.mergeOptions)((0, utils_2.cloneOptions)(this.initialOptions || {}), parsedOptions)
@@ -0,0 +1,4 @@
1
+ export declare function setupDOM(): {
2
+ window: Window;
3
+ document: Document;
4
+ };
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupDOM = setupDOM;
4
+ const linkedom_1 = require("linkedom");
5
+ function setupDOM() {
6
+ const { document, window } = (0, linkedom_1.parseHTML)('<!DOCTYPE html><html><body><div id="container"></div></body></html>');
7
+ Object.assign(globalThis, {
8
+ window,
9
+ document,
10
+ DOMParser: linkedom_1.DOMParser,
11
+ });
12
+ const classes = [
13
+ 'HTMLElement',
14
+ 'HTMLDivElement',
15
+ 'HTMLSpanElement',
16
+ 'HTMLImageElement',
17
+ 'HTMLCanvasElement',
18
+ 'HTMLInputElement',
19
+ 'HTMLButtonElement',
20
+ 'Element',
21
+ 'Node',
22
+ 'Text',
23
+ 'Comment',
24
+ 'DocumentFragment',
25
+ 'Document',
26
+ 'XMLSerializer',
27
+ 'MutationObserver',
28
+ // SVG
29
+ 'SVGElement',
30
+ 'SVGSVGElement',
31
+ 'SVGGraphicsElement',
32
+ 'SVGGElement',
33
+ 'SVGPathElement',
34
+ 'SVGRectElement',
35
+ 'SVGCircleElement',
36
+ 'SVGTextElement',
37
+ 'SVGLineElement',
38
+ 'SVGPolygonElement',
39
+ 'SVGPolylineElement',
40
+ 'SVGEllipseElement',
41
+ 'SVGImageElement',
42
+ 'SVGDefsElement',
43
+ 'SVGUseElement',
44
+ 'SVGClipPathElement',
45
+ 'SVGLinearGradientElement',
46
+ 'SVGRadialGradientElement',
47
+ 'SVGStopElement',
48
+ 'SVGPatternElement',
49
+ 'SVGMaskElement',
50
+ 'SVGForeignObjectElement',
51
+ 'Image',
52
+ ];
53
+ classes.forEach((name) => {
54
+ if (window[name])
55
+ globalThis[name] = window[name];
56
+ });
57
+ if (!document.fonts) {
58
+ const fontSet = new Set();
59
+ Object.defineProperty(document, 'fonts', {
60
+ value: {
61
+ add: (font) => fontSet.add(font),
62
+ delete: (font) => fontSet.delete(font),
63
+ has: (font) => fontSet.has(font),
64
+ clear: () => fontSet.clear(),
65
+ forEach: (callback) => fontSet.forEach(callback),
66
+ entries: () => fontSet.entries(),
67
+ keys: () => fontSet.keys(),
68
+ values: () => fontSet.values(),
69
+ [Symbol.iterator]: () => fontSet[Symbol.iterator](),
70
+ get size() {
71
+ return fontSet.size;
72
+ },
73
+ get ready() {
74
+ return Promise.resolve(this);
75
+ },
76
+ check: () => true,
77
+ load: () => Promise.resolve([]),
78
+ get status() {
79
+ return 'loaded';
80
+ },
81
+ onloading: null,
82
+ onloadingdone: null,
83
+ onloadingerror: null,
84
+ addEventListener: () => { },
85
+ removeEventListener: () => { },
86
+ dispatchEvent: () => true,
87
+ },
88
+ configurable: true,
89
+ });
90
+ }
91
+ const rafIds = new Map();
92
+ let nextRafId = 0;
93
+ globalThis.requestAnimationFrame = (cb) => {
94
+ const id = ++nextRafId;
95
+ const immediate = setImmediate(() => {
96
+ rafIds.delete(id);
97
+ cb(performance.now());
98
+ });
99
+ rafIds.set(id, immediate);
100
+ return id;
101
+ };
102
+ globalThis.cancelAnimationFrame = (id) => {
103
+ const immediate = rafIds.get(id);
104
+ if (immediate) {
105
+ clearImmediate(immediate);
106
+ rafIds.delete(id);
107
+ }
108
+ };
109
+ return { window, document };
110
+ }
@@ -0,0 +1 @@
1
+ export { renderToString } from './renderer';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderToString = void 0;
4
+ var renderer_1 = require("./renderer");
5
+ Object.defineProperty(exports, "renderToString", { enumerable: true, get: function () { return renderer_1.renderToString; } });
@@ -0,0 +1,2 @@
1
+ import type { InfographicOptions } from '../options';
2
+ export declare function renderToString(options: string | Partial<InfographicOptions>, init?: Partial<InfographicOptions>): Promise<string>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderToString = renderToString;
4
+ const exporter_1 = require("../exporter");
5
+ const renderer_1 = require("../renderer");
6
+ const runtime_1 = require("../runtime");
7
+ const utils_1 = require("../utils");
8
+ const dom_shim_1 = require("./dom-shim");
9
+ async function renderToString(options, init) {
10
+ const { document } = (0, dom_shim_1.setupDOM)();
11
+ const container = document.getElementById('container');
12
+ let infographic;
13
+ let timeoutId;
14
+ try {
15
+ infographic = new runtime_1.Infographic({
16
+ ...init,
17
+ container,
18
+ editable: false,
19
+ });
20
+ const renderPromise = new Promise((resolve, reject) => {
21
+ infographic.on('loaded', async ({ node }) => {
22
+ try {
23
+ const svg = await (0, exporter_1.exportToSVG)(node, { embedResources: true });
24
+ resolve(svg.outerHTML);
25
+ }
26
+ catch (e) {
27
+ reject(e);
28
+ }
29
+ });
30
+ });
31
+ const timeoutPromise = new Promise((_, reject) => {
32
+ timeoutId = setTimeout(() => {
33
+ reject(new Error('SSR render timeout'));
34
+ }, 10000);
35
+ });
36
+ infographic.render(options);
37
+ const svg = await Promise.race([renderPromise, timeoutPromise]);
38
+ return injectXMLStylesheet(svg);
39
+ }
40
+ finally {
41
+ clearTimeout(timeoutId);
42
+ if (infographic) {
43
+ infographic.destroy();
44
+ }
45
+ }
46
+ }
47
+ function injectXMLStylesheet(svg) {
48
+ const matched = svg.matchAll(/font-family="([\S ]+?)"/g);
49
+ const fonts = Array.from(matched, (match) => match[1]);
50
+ const set = new Set();
51
+ fonts.forEach((font) => {
52
+ const decoded = (0, utils_1.decodeFontFamily)(font);
53
+ decoded.split(',').forEach((f) => set.add(f.trim()));
54
+ });
55
+ const urls = Array.from(set)
56
+ .map((font) => (0, renderer_1.getFontURLs)(font))
57
+ .flat();
58
+ if (urls.length === 0)
59
+ return svg;
60
+ return `<?xml version="1.0" encoding="UTF-8"?>
61
+ ${urls.map((url) => `<?xml-stylesheet href="${url}" type="text/css"?>`).join('\n')}
62
+ ${svg}`;
63
+ }
@@ -3,7 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseSyntax = parseSyntax;
4
4
  const mapper_1 = require("./mapper");
5
5
  const parser_1 = require("./parser");
6
+ const relations_1 = require("./relations");
6
7
  const schema_1 = require("./schema");
8
+ function normalizeItems(items) {
9
+ const seen = new Set();
10
+ const normalized = [];
11
+ for (let index = items.length - 1; index >= 0; index -= 1) {
12
+ const item = items[index];
13
+ const id = item.id ?? item.label;
14
+ if (!id) {
15
+ normalized.push(item);
16
+ continue;
17
+ }
18
+ if (seen.has(id))
19
+ continue;
20
+ seen.add(id);
21
+ if (!item.id)
22
+ item.id = id;
23
+ normalized.push(item);
24
+ }
25
+ return normalized.reverse();
26
+ }
7
27
  function resolveTemplate(node, errors) {
8
28
  if (!node)
9
29
  return undefined;
@@ -67,9 +87,45 @@ function parseSyntax(input) {
67
87
  }
68
88
  const dataNode = mergedEntries.data;
69
89
  if (dataNode) {
70
- const data = (0, mapper_1.mapWithSchema)(dataNode, schema_1.DataSchema, 'data', errors);
90
+ let relationsNode;
91
+ let dataNodeForMapping = dataNode;
92
+ if (dataNode.kind === 'object') {
93
+ const { relations, ...rest } = dataNode.entries;
94
+ relationsNode = relations;
95
+ dataNodeForMapping = { ...dataNode, entries: rest };
96
+ }
97
+ const data = (0, mapper_1.mapWithSchema)(dataNodeForMapping, schema_1.DataSchema, 'data', errors);
71
98
  if (data)
72
99
  options.data = data;
100
+ if (relationsNode) {
101
+ const parsed = (0, relations_1.parseRelationsNode)(relationsNode, errors, 'data.relations');
102
+ if (parsed.relations.length > 0 || parsed.items.length > 0) {
103
+ const current = (options.data ?? {});
104
+ const existingItems = Array.isArray(current.items)
105
+ ? current.items
106
+ : [];
107
+ const normalizedItems = normalizeItems(existingItems);
108
+ const itemMap = new Map();
109
+ normalizedItems.forEach((item) => {
110
+ if (item.id)
111
+ itemMap.set(item.id, item);
112
+ });
113
+ parsed.items.forEach((item) => {
114
+ const existing = itemMap.get(item.id);
115
+ if (existing) {
116
+ if (!existing.label && item.label)
117
+ existing.label = item.label;
118
+ }
119
+ else {
120
+ normalizedItems.push(item);
121
+ itemMap.set(item.id, item);
122
+ }
123
+ });
124
+ current.items = normalizedItems;
125
+ current.relations = parsed.relations;
126
+ options.data = current;
127
+ }
128
+ }
73
129
  }
74
130
  const themeNode = mergedEntries.theme;
75
131
  if (themeNode) {
@@ -27,6 +27,9 @@ function getIndentInfo(line) {
27
27
  function stripComments(content) {
28
28
  return content.trimEnd();
29
29
  }
30
+ function looksLikeRelationExpression(text) {
31
+ return /[<>=o.x-]{2,}/.test(text);
32
+ }
30
33
  function parseKeyValue(raw) {
31
34
  const text = raw.trim();
32
35
  if (!text)
@@ -109,6 +112,47 @@ function parseSyntaxToAst(input) {
109
112
  });
110
113
  return;
111
114
  }
115
+ if (parentFrame.key === 'relations' &&
116
+ !trimmed.startsWith('-') &&
117
+ looksLikeRelationExpression(trimmed)) {
118
+ if (parentNode.kind !== 'array') {
119
+ if (parentNode.kind === 'object' &&
120
+ Object.keys(parentNode.entries).length === 0 &&
121
+ parentNode.value === undefined &&
122
+ parentFrame.parent &&
123
+ parentFrame.key) {
124
+ const arrayNode = createArrayNode(parentNode.line);
125
+ if (parentFrame.parent.kind === 'object') {
126
+ parentFrame.parent.entries[parentFrame.key] = arrayNode;
127
+ }
128
+ else if (parentFrame.parent.kind === 'array') {
129
+ const indexInParent = parentFrame.parent.items.indexOf(parentNode);
130
+ if (indexInParent >= 0)
131
+ parentFrame.parent.items[indexInParent] = arrayNode;
132
+ }
133
+ parentFrame.node = arrayNode;
134
+ parentNode = arrayNode;
135
+ }
136
+ else {
137
+ errors.push({
138
+ path: '',
139
+ line: lineNumber,
140
+ code: 'bad_list',
141
+ message: 'List item is not under an array container.',
142
+ raw: trimmed,
143
+ });
144
+ return;
145
+ }
146
+ }
147
+ const itemNode = createObjectNode(lineNumber, trimmed);
148
+ parentNode.items.push(itemNode);
149
+ stack.push({
150
+ indent,
151
+ node: itemNode,
152
+ parent: parentNode,
153
+ });
154
+ return;
155
+ }
112
156
  const parsed = parseKeyValue(trimmed);
113
157
  if (!parsed) {
114
158
  errors.push({
@@ -0,0 +1,6 @@
1
+ import type { ItemDatum, RelationDatum } from '../types';
2
+ import type { SyntaxError, SyntaxNode } from './types';
3
+ export declare function parseRelationsNode(node: SyntaxNode, errors: SyntaxError[], path: string): {
4
+ relations: RelationDatum[];
5
+ items: ItemDatum[];
6
+ };