wt-huatu 1.3.4

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 (110) hide show
  1. package/Readme.md +223 -0
  2. package/component/HuatuComponentCache.js +89 -0
  3. package/component/HuatuComponentDef.js +249 -0
  4. package/component/HuatuComponentPlacement.js +172 -0
  5. package/component/HuatuComponentPort.js +58 -0
  6. package/component/IHuatuComponent.js +2 -0
  7. package/for-node/node-cli-funcs.js +36 -0
  8. package/geometry/AngDeg.js +68 -0
  9. package/geometry/Angle.js +77 -0
  10. package/geometry/Bezier.js +623 -0
  11. package/geometry/Circle.js +143 -0
  12. package/geometry/Ellipse.js +546 -0
  13. package/geometry/EllipticalArc.js +337 -0
  14. package/geometry/IGeometry.js +1 -0
  15. package/geometry/Intersection.js +601 -0
  16. package/geometry/Line.js +136 -0
  17. package/geometry/LineSeg.js +179 -0
  18. package/geometry/Point.js +88 -0
  19. package/geometry/PolyLine.js +97 -0
  20. package/geometry/Polygon.js +122 -0
  21. package/geometry/Rect.js +149 -0
  22. package/geometry/Ring.js +91 -0
  23. package/geometry/SegmentModel.js +206 -0
  24. package/geometry/Triangle.js +168 -0
  25. package/geometry/Vector.js +92 -0
  26. package/huatu/Huatu.js +4279 -0
  27. package/huatu/HuatuAngleMark.js +400 -0
  28. package/huatu/HuatuBlock.js +26 -0
  29. package/huatu/HuatuClipPath.js +29 -0
  30. package/huatu/HuatuCompDrawing.js +77 -0
  31. package/huatu/HuatuDimMark.js +579 -0
  32. package/huatu/HuatuDrawing.js +185 -0
  33. package/huatu/HuatuDrawingGroup.js +52 -0
  34. package/huatu/HuatuJob.js +347 -0
  35. package/huatu/HuatuLabel.js +311 -0
  36. package/huatu/HuatuLabelStyle.js +190 -0
  37. package/huatu/HuatuLayer.js +10 -0
  38. package/huatu/HuatuMarker.js +209 -0
  39. package/huatu/HuatuParser.js +435 -0
  40. package/huatu/HuatuPath.js +131 -0
  41. package/huatu/HuatuPathSeries.js +51 -0
  42. package/huatu/HuatuPattern.js +54 -0
  43. package/huatu/HuatuPoint.js +20 -0
  44. package/huatu/HuatuPointSeries.js +67 -0
  45. package/huatu/HuatuStyle.js +394 -0
  46. package/huatu/HuatuSymbol.js +81 -0
  47. package/huatu/HuatuSymbolArray.js +235 -0
  48. package/huatu/HuatuTransform.js +113 -0
  49. package/huatu/HuatuVar.js +17 -0
  50. package/huatu/HuatuYml.js +271 -0
  51. package/huatu/IHuatu.js +2 -0
  52. package/huatu/IHuatuYml.js +1 -0
  53. package/huatu/IndentParsingStack.js +82 -0
  54. package/index.d.ts +1747 -0
  55. package/index.js +247 -0
  56. package/math/Complex.js +72 -0
  57. package/math/Matrix.js +31 -0
  58. package/math/NumberRange.js +38 -0
  59. package/math/VarFuncs.js +24 -0
  60. package/math/WtMath.js +217 -0
  61. package/package.json +34 -0
  62. package/path/PathBezier2.js +75 -0
  63. package/path/PathBezier3.js +89 -0
  64. package/path/PathCircle.js +82 -0
  65. package/path/PathConfig.js +81 -0
  66. package/path/PathContinuousSegmentedPath.js +390 -0
  67. package/path/PathEllipse.js +99 -0
  68. package/path/PathEllipticalArc.js +111 -0
  69. package/path/PathGeneric.js +59 -0
  70. package/path/PathLine.js +75 -0
  71. package/path/PathLines.js +46 -0
  72. package/path/PathPolygon.js +142 -0
  73. package/path/PathPolyline.js +266 -0
  74. package/path/PathRect.js +125 -0
  75. package/path/PathRing.js +51 -0
  76. package/path/PathSegmentedPath.js +199 -0
  77. package/path/PathTriangle.js +90 -0
  78. package/presets/marker.js +37 -0
  79. package/presets/pattern.js +85 -0
  80. package/shape/SvgShapeArrowHead.js +92 -0
  81. package/shape/SvgShapeCircle.js +26 -0
  82. package/shape/SvgShapeCross.js +43 -0
  83. package/shape/SvgShapeEllipse.js +28 -0
  84. package/shape/SvgShapeGeneric.js +50 -0
  85. package/shape/SvgShapeHeart.js +40 -0
  86. package/shape/SvgShapeIsoscelesTriangle.js +52 -0
  87. package/shape/SvgShapePolygon.js +39 -0
  88. package/shape/SvgShapeRect.js +26 -0
  89. package/shape/SvgShapeRhombus.js +27 -0
  90. package/shape/SvgShapeStar.js +103 -0
  91. package/svg/ISvg.js +1 -0
  92. package/svg/SvgBBox.js +149 -0
  93. package/svg/SvgConstants.js +14 -0
  94. package/svg/SvgGradient.js +97 -0
  95. package/svg/SvgMarker.js +221 -0
  96. package/svg/SvgPattern.js +228 -0
  97. package/svg/SvgPoint.js +33 -0
  98. package/svg/SvgPointSet.js +41 -0
  99. package/templates/lines.js +35 -0
  100. package/tools/gen-id.js +2 -0
  101. package/tools/html.js +2 -0
  102. package/tools/katex.js +75 -0
  103. package/tools/rand-str.js +122 -0
  104. package/tools/regex.js +15 -0
  105. package/tools/utils.js +438 -0
  106. package/tools/webColor.js +700 -0
  107. package/wire/HuatuNet.js +22 -0
  108. package/wire/HuatuWire.js +415 -0
  109. package/wire/HuatuWireDrawing.js +17 -0
  110. package/wire/IHuatuWire.js +1 -0
@@ -0,0 +1,235 @@
1
+ import { HuatuDrawing } from "./HuatuDrawing.js";
2
+ import Vector from "../geometry/Vector.js";
3
+ import { AngDeg } from "../geometry/AngDeg.js";
4
+ import { HuatuDrawingGroup } from "./HuatuDrawingGroup.js";
5
+ export class HuatuSymbolArray extends HuatuDrawingGroup {
6
+ static METHODS = ["line", "2d", "polar"];
7
+ symbol;
8
+ arrayMethod = "line";
9
+ startPoint; // Start point will not be used by Polar arraying method
10
+ deltaX = 0;
11
+ deltaY = 0;
12
+ /**
13
+ * This count will be shared when Array specified as Polar or Line type
14
+ * If specified as 2D, then countX and countY will work.
15
+ */
16
+ count = 1;
17
+ countX = 1;
18
+ countY = 1;
19
+ center;
20
+ startDeg;
21
+ deltaDeg;
22
+ alignCenter;
23
+ transforms = [];
24
+ constructor(name, symbol, desc) {
25
+ super(name, desc);
26
+ // Symbol array will not accept any transforming
27
+ this.acceptTransform = false;
28
+ this.symbol = symbol;
29
+ }
30
+ /**
31
+ * Resolve the Linear generation of the Symbol Array
32
+ * @param count The Count to place the symbol
33
+ * @param dx Interval in X-axis
34
+ * @param dy Interval in Y-axis
35
+ * @param scale Scale factor of the Symbol, could be a number, or a func like Si = f(i) where i is the growing index
36
+ */
37
+ configLine(startPoint, count, dx, dy, scale, rotDeg) {
38
+ this.startPoint = startPoint;
39
+ // Clear element buffer at first
40
+ this.elements = [];
41
+ this.arrayMethod = "line";
42
+ count = Math.floor(count);
43
+ this.count = count >= 1 ? count : 1;
44
+ this.deltaX = dx ?? 0;
45
+ this.deltaY = dy ?? 0;
46
+ if (scale && typeof scale === "number") {
47
+ scale = scale > 0 ? scale : undefined; // non-positive scale will be discarded
48
+ }
49
+ for (let i = 0; i < this.count; i++) {
50
+ const transform = {
51
+ x: this.startPoint.x + i * this.deltaX,
52
+ y: this.startPoint.y + i * this.deltaY
53
+ };
54
+ if (scale) {
55
+ if (typeof scale === "function") {
56
+ try {
57
+ let newScale = scale(i);
58
+ if (newScale && newScale > 0)
59
+ transform.scale = newScale;
60
+ }
61
+ catch (error) {
62
+ // Nothing to do
63
+ }
64
+ }
65
+ else {
66
+ transform.scale = scale;
67
+ }
68
+ }
69
+ if (rotDeg)
70
+ transform.rotDeg = rotDeg;
71
+ this.transforms.push(transform);
72
+ this.addElement(new HuatuDrawing(this.symbol, undefined, transform, this.alignCenter));
73
+ }
74
+ }
75
+ /**
76
+ * Resolve the 2D generation of the Symbol Array
77
+ * @param countX The count in X-axis
78
+ * @param countY The Count in Y-axis
79
+ * @param dx Interval in X-axis
80
+ * @param dy Interval in Y-axis
81
+ * @param scale Scale factor of the symbol, it could be a number or a func like Sxy = f(ix, iy), where ix and iy
82
+ * is the growing index in X- and Y-axis
83
+ */
84
+ config2D(startPoint, countX, countY, dx, dy, scale, rotDeg) {
85
+ this.startPoint = startPoint;
86
+ // Clear element buffer at first
87
+ this.elements = [];
88
+ this.arrayMethod = "2d";
89
+ countX = Math.floor(countX);
90
+ countY = Math.floor(countY);
91
+ this.countX = countX >= 1 ? countX : 1;
92
+ this.countY = countY >= 1 ? countY : 1;
93
+ this.deltaX = dx ?? 0;
94
+ this.deltaY = dy ?? 0;
95
+ this.count = this.countX * this.countY;
96
+ if (scale && typeof scale === "number") {
97
+ scale = scale > 0 ? scale : undefined; // non-positive scale will be discarded
98
+ }
99
+ for (let iX = 0; iX < this.countX; iX++) {
100
+ for (let iY = 0; iY < this.countY; iY++) {
101
+ const transform = {
102
+ x: this.startPoint.x + iX * this.deltaX,
103
+ y: this.startPoint.y + iY * this.deltaY,
104
+ };
105
+ if (scale) {
106
+ if (typeof scale === "function") {
107
+ try {
108
+ let newScale = scale(iX, iY);
109
+ if (newScale && newScale > 0)
110
+ transform.scale = newScale;
111
+ }
112
+ catch (error) {
113
+ // Nothing to do
114
+ }
115
+ }
116
+ else {
117
+ transform.scale = scale;
118
+ }
119
+ }
120
+ if (rotDeg)
121
+ transform.rotDeg = rotDeg;
122
+ this.transforms.push(transform);
123
+ this.addElement(new HuatuDrawing(this.symbol, undefined, transform, this.alignCenter));
124
+ }
125
+ }
126
+ }
127
+ /**
128
+ * Resolve the polar method of arraying
129
+ * @param count How many symbols should be arrayed
130
+ * @param center The center to make the Array, i.e. the center of rotating
131
+ * @param radius How far should be the symbol located from the center, it could be a function of rotating of Angle,
132
+ * e.g. R = f(theta), here, the unit of theta is Radian(not degree), to make it convenient to import
133
+ * existing math curves which does this way
134
+ * @param scale How large will the symbol be scaled to, it could be a function of radius
135
+ * @param startDeg The start rotating angle, in degree
136
+ * @param deltaDeg The Interval of the rotating angle
137
+ * @param symbolNotRotate A switch to make sure if the symbol should stay not rotated
138
+ */
139
+ configPolar(count, center, radius, scale, // The Scale parameter, if could be the function of Radius
140
+ startDeg, deltaDeg, symbolNotRotate) {
141
+ // Clear element buffer at first
142
+ this.elements = [];
143
+ count = Math.floor(count);
144
+ this.count = count >= 1 ? count : 1;
145
+ this.center = center;
146
+ this.startDeg = startDeg ?? 0;
147
+ this.deltaDeg = deltaDeg ?? 30;
148
+ let constantRadius;
149
+ if (typeof radius === "number") {
150
+ constantRadius = Math.abs(radius);
151
+ }
152
+ if (scale && typeof scale === "number") {
153
+ scale = scale > 0 ? scale : undefined; // non-positive scale will be discarded
154
+ }
155
+ for (let i = 0; i < this.count; i++) {
156
+ const deg = this.startDeg + i * this.deltaDeg;
157
+ const ang = AngDeg.deg2Ang(deg); // Here is the conversion, please notice
158
+ // Default radius will be zero, i.e. if no radius specified, all the symbols will be placed at 'Center'
159
+ let r = 0;
160
+ if (constantRadius)
161
+ r = constantRadius;
162
+ else if (typeof radius === "function") {
163
+ try {
164
+ r = radius(ang); // Use the angle in Radian
165
+ }
166
+ catch (error) {
167
+ // Nothing to do
168
+ }
169
+ }
170
+ const loc = Vector.fromPoint(this.center).moveByLenAndAng(r, ang);
171
+ const transform = {
172
+ x: loc.x,
173
+ y: loc.y
174
+ };
175
+ if (!symbolNotRotate) {
176
+ transform.rotDeg = deg;
177
+ }
178
+ if (scale) {
179
+ if (typeof scale === "function") {
180
+ try {
181
+ let newScale = scale(r); // Scale is a func of Radius, please note
182
+ if (newScale && newScale > 0)
183
+ transform.scale = newScale;
184
+ }
185
+ catch (error) {
186
+ // Nothing to do
187
+ }
188
+ }
189
+ else {
190
+ transform.scale = scale;
191
+ }
192
+ }
193
+ this.transforms.push(transform);
194
+ this.addElement(new HuatuDrawing(this.symbol, undefined, transform, this.alignCenter));
195
+ }
196
+ }
197
+ static optsSymbolArray = {
198
+ keys: [
199
+ ["symbol", "sym"],
200
+ ["startPoint", "start", "from"],
201
+ ["desc"],
202
+ ["method", "arrayMethod"],
203
+ ["deltaX", "dx"],
204
+ ["deltaY", "dy"],
205
+ ["count"],
206
+ ["countX"],
207
+ ["countY"],
208
+ ["center", "centerPoint", "at"],
209
+ ["rotDeg", "rot", "rotate"],
210
+ ["alignCenter"],
211
+ ["radius", "r"],
212
+ ["scale"],
213
+ ["notRotate", "noRotate", "noRot"],
214
+ ["startDeg", "initialDeg", "iniDeg"],
215
+ ["deltaDeg", "degDelta", "degD", "dDeg"],
216
+ ],
217
+ ints: [
218
+ "count",
219
+ "countX",
220
+ "countY",
221
+ ],
222
+ numbers: [],
223
+ booleans: [
224
+ "alignCenter",
225
+ "notRotate", "noRotate", "noRot"
226
+ ],
227
+ allowAppend: [],
228
+ qualifiers: {
229
+ "method": HuatuSymbolArray.METHODS,
230
+ },
231
+ blindGuess: {
232
+ "method": HuatuSymbolArray.METHODS,
233
+ }
234
+ };
235
+ }
@@ -0,0 +1,113 @@
1
+ import { SvgPoint } from "../svg/SvgPoint.js";
2
+ import { WtMath } from "../math/WtMath.js";
3
+ export class HuatuTransform {
4
+ x;
5
+ y;
6
+ rotCx;
7
+ rotCy;
8
+ rotDeg;
9
+ scale;
10
+ constructor(x, y, rotCx, rotCy, rotDeg, scale) {
11
+ this.x = x;
12
+ this.y = y;
13
+ this.rotCx = rotCx;
14
+ this.rotCy = rotCy;
15
+ this.rotDeg = rotDeg;
16
+ this.scale = scale;
17
+ }
18
+ static addMove(arr, move) {
19
+ if (!WtMath.isZero(move.x) || !WtMath.isZero(move.y)) {
20
+ arr.push(`translate(${SvgPoint.toCoors(move)})`);
21
+ }
22
+ }
23
+ static addRotate(arr, rotDeg, rotCenter) {
24
+ if (!WtMath.isZero(rotDeg)) {
25
+ const vals = [rotDeg];
26
+ if (rotCenter) {
27
+ vals.push(rotCenter.x, rotCenter.y);
28
+ }
29
+ const valStrs = vals.map(x => `${x}`).join(",");
30
+ arr.push(`rotate(${valStrs})`);
31
+ }
32
+ }
33
+ static addScale(arr, scale, scaleCenter) {
34
+ if (!WtMath.isEqual(scale, 1)) {
35
+ if (scaleCenter) {
36
+ const dx = scaleCenter.x * (1 - scale), dy = scaleCenter.y * (1 - scale);
37
+ arr.push(`translate(${dx},${dy})`);
38
+ }
39
+ arr.push(`scale(${scale})`);
40
+ }
41
+ }
42
+ static buildTransformAttrsForBlockAndPath(transform) {
43
+ if (!transform)
44
+ return [];
45
+ const move = (transform.x || transform.y)
46
+ ? new SvgPoint(transform.x ?? 0, transform.y ?? 0)
47
+ : undefined;
48
+ const attrs = [];
49
+ if (transform.rotDeg) {
50
+ const rotCenter = new SvgPoint(0, 0);
51
+ if (transform.rotCx)
52
+ rotCenter.x = transform.rotCx;
53
+ if (transform.rotCy)
54
+ rotCenter.y = transform.rotCy;
55
+ const scale = HuatuTransform.judgeScale(transform);
56
+ // Rotate at
57
+ HuatuTransform.addRotate(attrs, transform.rotDeg, rotCenter);
58
+ // Scale at
59
+ HuatuTransform.addScale(attrs, scale, rotCenter);
60
+ }
61
+ else {
62
+ if (transform.scale) {
63
+ const scale = HuatuTransform.judgeScale(transform);
64
+ let scaleCenter = (transform.rotCx || transform.rotCy)
65
+ ? new SvgPoint(transform.rotCx ?? 0, transform.rotCy ?? 0)
66
+ : undefined;
67
+ HuatuTransform.addScale(attrs, scale, scaleCenter);
68
+ }
69
+ }
70
+ // First move action will be placed as last
71
+ if (move) {
72
+ HuatuTransform.addMove(attrs, move);
73
+ }
74
+ return attrs;
75
+ }
76
+ static buildTransformStrForBlockAndPath(transform) {
77
+ if (!transform)
78
+ return "";
79
+ const attrs = HuatuTransform.buildTransformAttrsForBlockAndPath(transform);
80
+ if (attrs.length < 1)
81
+ return "";
82
+ return `transform="${attrs.join(" ")}"`;
83
+ }
84
+ static buildTransformAttrsForSymbol(transform) {
85
+ if (!transform)
86
+ return [];
87
+ const move = (transform.x || transform.y)
88
+ ? new SvgPoint(transform.x ?? 0, transform.y ?? 0)
89
+ : undefined;
90
+ const attrs = [];
91
+ if (transform.rotDeg) {
92
+ // If the rotation center is not given, then use the point of move
93
+ // If both not given, then leave no translate action
94
+ const rotCenter = transform.rotCx || transform.rotCy
95
+ ? new SvgPoint(transform.rotCx ?? 0, transform.rotCy ?? 0)
96
+ : move;
97
+ if (rotCenter)
98
+ HuatuTransform.addMove(attrs, rotCenter);
99
+ HuatuTransform.addRotate(attrs, transform.rotDeg);
100
+ }
101
+ else if (move) {
102
+ HuatuTransform.addMove(attrs, move);
103
+ }
104
+ return attrs;
105
+ }
106
+ static judgeScale(transform) {
107
+ if (!transform)
108
+ return 1;
109
+ if (!transform.scale || transform.scale <= 0)
110
+ return 1;
111
+ return transform.scale;
112
+ }
113
+ }
@@ -0,0 +1,17 @@
1
+ export class HuatuVar {
2
+ name;
3
+ value;
4
+ howGet;
5
+ constructor(name, value, howGet) {
6
+ this.howGet = howGet ?? "direct";
7
+ this.name = name;
8
+ this.value = value;
9
+ }
10
+ /**
11
+ * Return the value of the variable, return 0 if not set.
12
+ * @returns the value of this variable
13
+ */
14
+ getValue() {
15
+ return this.value ?? 0;
16
+ }
17
+ }
@@ -0,0 +1,271 @@
1
+ import { IndentParsingStack } from "./IndentParsingStack.js";
2
+ export class HuatuYml {
3
+ static parseYml(yml) {
4
+ // Prepare error handling
5
+ let hasError = false;
6
+ // Prepare the result
7
+ const res = {
8
+ succeeded: false,
9
+ errorMessages: []
10
+ };
11
+ // The regex to match a "Real" comment, conditions are:
12
+ // - The Comment part starts with a '#' sign
13
+ // - The # sign is not followed by a ':', because this will escape the '#' char to be used in label text
14
+ // - The # sign is not followed by 3/6/8 color (hex) codes(a-z, 0-9), because this will build some color
15
+ const YML_COMMENT_REGEX = /#(?!(:|([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})\b))(.*)$/ig;
16
+ const REGEX_MATCH_LIST = /^(\s*)-(\s.*|$)/i;
17
+ const REGEX_MATCH_KEY_VALUE = /^(\s*)(\$?[a-z][a-z0-9_]*)\s*:\s?(.*)$/i;
18
+ const parseKeyVal = (line) => {
19
+ const match = REGEX_MATCH_KEY_VALUE.exec(line);
20
+ if (match) {
21
+ return {
22
+ indentLevel: Math.floor(match[1].length / 2),
23
+ key: match[2],
24
+ value: match[3].trim(),
25
+ };
26
+ }
27
+ else {
28
+ let indentLevel = Math.floor(/\s*/.exec(line)[0].length / 2);
29
+ return {
30
+ indentLevel: indentLevel,
31
+ key: undefined,
32
+ value: line.trim(), // If line is not empty, then prepend a space
33
+ };
34
+ }
35
+ };
36
+ // Process the input
37
+ const ymlLines = yml.replace(/\r/ig, "").split('\n');
38
+ const lines = ymlLines
39
+ .map((l, i) => {
40
+ const lClean = l.replace(/#:/g, "_^;_;^_") // Backup the '#' char
41
+ .replace(YML_COMMENT_REGEX, "") // Remove comment
42
+ .replace(/_\^;_;\^_/g, "#") // Restore # char
43
+ .trimEnd() // Remove trailing spaces
44
+ .replace(/\t/g, " "); // Replace tab key to two spaces
45
+ return lClean
46
+ ? {
47
+ value: lClean,
48
+ lineNumber: i + 1
49
+ }
50
+ : undefined;
51
+ })
52
+ .filter(l => !!l)
53
+ .map(l => {
54
+ let lineInfo;
55
+ const tryAsList = l.value.match(REGEX_MATCH_LIST);
56
+ if (tryAsList) {
57
+ const res = parseKeyVal(tryAsList[2].trim());
58
+ lineInfo = {
59
+ lineNumber: l.lineNumber,
60
+ indentLevel: Math.floor(tryAsList[1].length / 2),
61
+ isListItem: true,
62
+ key: res.key,
63
+ value: res.value.trim(),
64
+ isPureValue: false,
65
+ };
66
+ }
67
+ else {
68
+ const res = parseKeyVal(l.value);
69
+ lineInfo = {
70
+ lineNumber: l.lineNumber,
71
+ indentLevel: res.indentLevel,
72
+ isListItem: false,
73
+ key: res.key,
74
+ value: res.value,
75
+ isPureValue: !res.key
76
+ };
77
+ }
78
+ return lineInfo;
79
+ })
80
+ .filter(l => !!l);
81
+ // If has error, then skip the steps following
82
+ if (hasError)
83
+ return res;
84
+ if (lines.length < 1) {
85
+ hasError = true;
86
+ res.errorMessages.push({
87
+ lineNumber: 0,
88
+ message: 'No valid line ever input!'
89
+ });
90
+ }
91
+ else if (lines[0].isPureValue) {
92
+ hasError = true;
93
+ res.errorMessages.push({
94
+ lineNumber: lines[0].lineNumber,
95
+ message: "First line mustn't be pure value line!"
96
+ });
97
+ }
98
+ if (hasError)
99
+ return res;
100
+ // Append pure-value lines into previous
101
+ const realLines = [lines[0]]; // Initialize with the first line
102
+ for (let i = 1; i < lines.length; i++) {
103
+ const line = lines[i];
104
+ if (line.isPureValue && !line.isListItem) {
105
+ if (line.value) {
106
+ const lastLine = realLines[realLines.length - 1];
107
+ if (line.indentLevel > lastLine.indentLevel) {
108
+ lastLine.value = lastLine.value ? `${lastLine.value} ${line.value}` : line.value;
109
+ }
110
+ else {
111
+ hasError = true;
112
+ res.errorMessages.push({
113
+ lineNumber: line.lineNumber,
114
+ message: "Continuing text should have more indent than its parent."
115
+ });
116
+ return res;
117
+ }
118
+ }
119
+ }
120
+ else {
121
+ realLines.push(line);
122
+ }
123
+ }
124
+ // Parse the YML lines into Object
125
+ const indentLevelMin = Math.min(...realLines.map(l => l.indentLevel));
126
+ const indentLevelMax = Math.max(...realLines.map(l => l.indentLevel));
127
+ const indentLevelCount = indentLevelMax - indentLevelMin + 1 + 1;
128
+ realLines.forEach(l => {
129
+ l.indentLevel -= indentLevelMin;
130
+ });
131
+ const stacks = [];
132
+ for (let i = 0; i < indentLevelCount; i++) {
133
+ stacks.push(new IndentParsingStack());
134
+ }
135
+ /**
136
+ * This function is used to make the object composed by following sub-stacks
137
+ * for the current stack that is going to close current open item.
138
+ */
139
+ const buildObjOnClose = (indentLevel) => {
140
+ let objOnClose = undefined;
141
+ for (let j = indentLevelCount - 1; j > indentLevel; j--) {
142
+ if (stacks[j].inUse) {
143
+ stacks[j].close(objOnClose);
144
+ objOnClose = stacks[j].buildObj();
145
+ stacks[j].stop();
146
+ }
147
+ }
148
+ return objOnClose;
149
+ };
150
+ for (let i = 0; i < realLines.length; i++) {
151
+ const line = realLines[i];
152
+ const stack = stacks[line.indentLevel];
153
+ // Check if the line has invalid indent, i.e. over-indented, or less-indented
154
+ let indentError = "";
155
+ if (line.indentLevel > 0) {
156
+ for (let j = line.indentLevel - 1; j >= 0; j--) {
157
+ if (stacks[j].inUse && !stacks[j].isOpen) {
158
+ indentError = "Over Indented";
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ if (!stack.inUse) {
164
+ for (let j = line.indentLevel + 1; j < indentLevelCount; j++) {
165
+ if (stacks[j].inUse) {
166
+ indentError = "Less Indented";
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ if (indentError) {
172
+ hasError = true;
173
+ res.errorMessages.push({
174
+ lineNumber: line.lineNumber,
175
+ message: indentError,
176
+ });
177
+ return res;
178
+ }
179
+ if (stack.inUse) {
180
+ // Check if coming item has a different item type, list or not
181
+ if ((stack.isList && !line.isListItem) || (!stack.isList && line.isListItem)) {
182
+ hasError = true;
183
+ res.errorMessages.push({
184
+ lineNumber: line.lineNumber,
185
+ message: "You cannot mix list and/or dictionary definitions."
186
+ });
187
+ return res;
188
+ }
189
+ if (stack.isOpen) { // Let's close all the sub and sub level stacks
190
+ stack.close(buildObjOnClose(line.indentLevel));
191
+ }
192
+ // Push current item into the stack
193
+ if (line.isListItem) {
194
+ if (line.key) {
195
+ stack.open(); // Make it open
196
+ const stackNext = stacks[line.indentLevel + 1];
197
+ stackNext.start(false, line.key, line.value); // Make next-level stack in use
198
+ }
199
+ else {
200
+ if (line.value)
201
+ stack.add("", line.value);
202
+ else
203
+ stack.open();
204
+ }
205
+ }
206
+ else {
207
+ if (line.key) {
208
+ const addRes = stack.add(line.key, line.value);
209
+ if (addRes) {
210
+ hasError = true;
211
+ res.errorMessages.push({
212
+ lineNumber: line.lineNumber,
213
+ message: addRes,
214
+ });
215
+ return res;
216
+ }
217
+ }
218
+ }
219
+ }
220
+ else { // Start the stack
221
+ if (line.isListItem) {
222
+ if (line.key) {
223
+ stack.start(true);
224
+ const stackNext = stacks[line.indentLevel + 1];
225
+ stackNext.start(false, line.key, line.value); // Leave the key and value to next-level stack
226
+ }
227
+ else {
228
+ stack.start(true, undefined, line.value); // If no key, then add into list if value presented
229
+ }
230
+ }
231
+ else {
232
+ stack.start(false, line.key, line.value);
233
+ }
234
+ }
235
+ }
236
+ // Close the root stack
237
+ stacks[0].close(buildObjOnClose(0));
238
+ res.rootObj = stacks[0].buildObj();
239
+ res.succeeded = true;
240
+ return res;
241
+ }
242
+ /**
243
+ * A tool function to copy the source object to a new one. With the option of accepted key list and
244
+ * string replacing function.
245
+ * @param srcObj The Object to be processed
246
+ * @param acceptedRootKeys A list of which keys are accepted, if not presented, all keys will be accepted
247
+ * @param replaceFunc A function to replace string occurrences
248
+ * @returns The copied/processed object
249
+ */
250
+ static copyObj(srcObj, acceptedRootKeys, replaceFunc) {
251
+ const resObj = {};
252
+ for (let k in srcObj) {
253
+ if (acceptedRootKeys && !acceptedRootKeys.includes(k))
254
+ continue;
255
+ const v = srcObj[k];
256
+ if (typeof v === "string") {
257
+ resObj[k] = replaceFunc ? replaceFunc(v) : v;
258
+ }
259
+ else if (Array.isArray(v)) {
260
+ resObj[k] = [
261
+ ...v.filter(x => typeof x === "string")
262
+ .map(x => replaceFunc ? replaceFunc(x) : x)
263
+ ];
264
+ }
265
+ else if (typeof v === "object") {
266
+ resObj[k] = HuatuYml.copyObj(v, undefined, replaceFunc);
267
+ }
268
+ }
269
+ return resObj;
270
+ }
271
+ }
@@ -0,0 +1,2 @@
1
+ /** This file holds all the data structures designed for WT Huatu, all the modelling will be placed here. */
2
+ export {};
@@ -0,0 +1 @@
1
+ export {};