kipphi 2.0.0 → 2.1.0

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.
package/jumparray.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  import { NodeType } from "./util";
2
+ import Env from "./env";
2
3
 
3
4
  // type EndBeats = number;
4
- const MIN_LENGTH = 128
5
- const MAX_LENGTH = 1024
6
- const MINOR_PARTS = 16;
7
5
  /// #declaration:global
8
6
 
9
7
  type EndNextFn<T extends TwoDirectionNodeLike> = (node: T) => [endBeats: number, next: T];
@@ -23,6 +21,7 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
23
21
  averageBeats: number;
24
22
  effectiveBeats: number;
25
23
  goPrev: (node: T) => T;
24
+ readonly MINOR_SCALE_COUNT: number = Env.JUMPARRAY_MINOR_SCALE_COUNT;
26
25
 
27
26
  /**
28
27
  *
@@ -46,7 +45,7 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
46
45
  this.header = head;
47
46
  this.tailer = tail;
48
47
  // const originalListLength = this.listLength
49
- const listLength: number = Math.max(MIN_LENGTH, Math.min(originalListLength * 4, MAX_LENGTH));
48
+ const listLength: number = Math.max(Env.JUMPARRAY_MIN_LENGTH, Math.min(originalListLength * 4, Env.JUMPARRAY_MAX_LENGTH));
50
49
  const averageBeats: number = Math.pow(2, Math.ceil(Math.log2(effectiveBeats / listLength)));
51
50
  const exactLength: number = Math.ceil(effectiveBeats / averageBeats);
52
51
  // console.log(exactLength, listLength, averageBeats, exactLength)
@@ -91,6 +90,7 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
91
90
  updateRange(firstNode: T, lastNode: T) {
92
91
  const {endNextFn, effectiveBeats, resolveLastNode} = this;
93
92
  lastNode = resolveLastNode(lastNode);
93
+ const MINOR_PARTS = this.MINOR_SCALE_COUNT;
94
94
  // console.log(firstNode, lastNode)
95
95
  /**
96
96
  *
@@ -125,16 +125,13 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
125
125
  if (Array.isArray(jumpArray[jumpIndex])) {
126
126
  fillMinor(previousEndTime, endTime)
127
127
  } else {
128
- try {
129
- // console.log(jumpIndex, currentNode)
130
128
  jumpArray[jumpIndex] = currentNode;
131
- } catch (E) {console.log(jumpIndex, jumpArray);debugger}
132
129
  }
133
130
  jumpIndex++;
134
131
  }
135
132
  const currentJumpBeats: number = jumpIndex * averageBeats // 放错了
136
133
  if (endTime > currentJumpBeats) {
137
- let minor = jumpArray[jumpIndex];
134
+ const minor = jumpArray[jumpIndex];
138
135
  if (!Array.isArray(minor)) {
139
136
  jumpArray[jumpIndex] = new Array(MINOR_PARTS);
140
137
  }
@@ -175,8 +172,9 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
175
172
  const jumpAverageBeats = this.averageBeats;
176
173
  const jumpPos = Math.floor(beats / jumpAverageBeats);
177
174
  const rest = beats - jumpPos * jumpAverageBeats;
175
+ const MINOR_PARTS = this.MINOR_SCALE_COUNT;
178
176
  for (let i = jumpPos; i >= 0; i--) {
179
- let canBeNodeOrArray: T | T[] = this.array[i];
177
+ const canBeNodeOrArray: T | T[] = this.array[i];
180
178
  if (Array.isArray(canBeNodeOrArray)) {
181
179
  const minorIndex = Math.floor(rest / (jumpAverageBeats / MINOR_PARTS)) - 1;
182
180
  for (let j = minorIndex; j >= 0; j--) {
@@ -202,11 +200,12 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
202
200
  if (beats >= this.effectiveBeats) {
203
201
  return this.tailer;
204
202
  }
203
+ const MINOR_PARTS = this.MINOR_SCALE_COUNT;
205
204
  const jumpAverageBeats = this.averageBeats;
206
205
  const jumpPos = Math.floor(beats / jumpAverageBeats);
207
206
  const rest = beats - jumpPos * jumpAverageBeats;
208
207
  const nextFn = this.nextFn;
209
- let canBeNodeOrArray: T | T[] = this.array[jumpPos]
208
+ const canBeNodeOrArray: T | T[] = this.array[jumpPos]
210
209
  let node: T = Array.isArray(canBeNodeOrArray)
211
210
  ? canBeNodeOrArray[Math.floor(rest / (jumpAverageBeats / MINOR_PARTS))]
212
211
  : canBeNodeOrArray;
@@ -216,7 +215,7 @@ export class JumpArray<T extends TwoDirectionNodeLike> {
216
215
  // console.log(this, node, jumpPos, beats)
217
216
  if (!node) {
218
217
  console.warn("No node:", node, beats)
219
- debugger
218
+ throw new Error();
220
219
  }
221
220
  let next: T | false;
222
221
  // console.log(this)
package/line.ts ADDED
@@ -0,0 +1,246 @@
1
+ import { Chart, JudgeLineGroup, BasicEventName, UIName } from "../chart";
2
+ import { ExtendedEventTypeName, RGB } from "../chartTypes";
3
+ import { EventNodeSequence } from "../event";
4
+ import { JudgeLine, ExtendedLayer } from "../judgeline";
5
+ import { Operation } from "./basic";
6
+
7
+
8
+
9
+ // 有点怪异,感觉破坏了纯净性。不管了(
10
+ enum JudgeLinesEditorLayoutType {
11
+ ordered = 0b001,
12
+ tree = 0b010,
13
+ grouped = 0b100
14
+ }
15
+
16
+
17
+ export class JudgeLineInheritanceChangeOperation extends Operation {
18
+ originalValue: JudgeLine | null;
19
+ updatesEditor = true;
20
+ static REFLOWS = JudgeLinesEditorLayoutType.tree;
21
+ reflows = JudgeLineInheritanceChangeOperation.REFLOWS;
22
+ constructor(public chart: Chart, public judgeLine: JudgeLine, public value: JudgeLine | null) {
23
+ super();
24
+ this.originalValue = judgeLine.father;
25
+ // 这里只会让它静默失败,外面调用的时候能够在判断一次并抛错误才是最好的
26
+ if (JudgeLine.checkinterdependency(judgeLine, value)) {
27
+ this.ineffective = true;
28
+ }
29
+ }
30
+ do() {
31
+ const line = this.judgeLine;
32
+ line.father = this.value;
33
+ if (this.originalValue) {
34
+ this.originalValue.children.delete(line);
35
+ } else {
36
+ const index = this.chart.orphanLines.indexOf(line);
37
+ if (index >= 0) // Impossible to be false, theoretically
38
+ this.chart.orphanLines.splice(index, 1)
39
+ }
40
+ if (this.value) {
41
+ this.value.children.add(line);
42
+ } else {
43
+ this.chart.orphanLines.push(line);
44
+ }
45
+ }
46
+ undo() {
47
+ const line = this.judgeLine;
48
+ line.father = this.originalValue;
49
+ if (this.originalValue) {
50
+ this.originalValue.children.add(line);
51
+ } else {
52
+ this.chart.orphanLines.push(line);
53
+ }
54
+ if (this.value) {
55
+ this.value.children.delete(line);
56
+ } else {
57
+ const index = this.chart.orphanLines.indexOf(line);
58
+ if (index >= 0) // Impossible to be false, theoretically
59
+ this.chart.orphanLines.splice(index, 1)
60
+ }
61
+ }
62
+ }
63
+
64
+ export class JudgeLineRenameOperation extends Operation {
65
+ updatesEditor = true;
66
+ originalValue: string;
67
+ constructor(public judgeLine: JudgeLine, public value: string) {
68
+ super();
69
+ this.originalValue = judgeLine.name;
70
+ }
71
+ do() {
72
+ this.judgeLine.name = this.value;
73
+ }
74
+ undo() {
75
+ this.judgeLine.name = this.originalValue;
76
+ }
77
+ }
78
+
79
+ type JudgeLinePropName = "name" | "rotatesWithFather" | "anchor" | "texture" | "cover" | "zOrder";
80
+
81
+ export class JudgeLinePropChangeOperation<T extends JudgeLinePropName> extends Operation {
82
+ updatesEditor = true;
83
+ originalValue: JudgeLine[T];
84
+ constructor(public judgeLine: JudgeLine, public field: T, public value: JudgeLine[T]) {
85
+ super();
86
+ this.originalValue = judgeLine[field];
87
+ }
88
+ do() {
89
+ this.judgeLine[this.field] = this.value;
90
+ }
91
+ undo() {
92
+ this.judgeLine[this.field] = this.originalValue;
93
+ }
94
+ }
95
+
96
+ export class JudgeLineRegroupOperation extends Operation {
97
+ updatesEditor = true;
98
+ reflows = JudgeLinesEditorLayoutType.grouped;
99
+ originalValue: JudgeLineGroup;
100
+ constructor(public judgeLine: JudgeLine, public value: JudgeLineGroup) {
101
+ super();
102
+ this.originalValue = judgeLine.group;
103
+ }
104
+ do() {
105
+ this.judgeLine.group = this.value;
106
+ this.value.add(this.judgeLine);
107
+ this.originalValue.remove(this.judgeLine);
108
+ }
109
+ undo() {
110
+ this.judgeLine.group = this.originalValue;
111
+ this.originalValue.add(this.judgeLine);
112
+ this.value.remove(this.judgeLine);
113
+ }
114
+ }
115
+
116
+ export class JudgeLineCreateOperation extends Operation {
117
+ reflows = JudgeLinesEditorLayoutType.grouped | JudgeLinesEditorLayoutType.tree | JudgeLinesEditorLayoutType.ordered;
118
+ // 之前把=写成了:半天不知道咋错了
119
+ constructor(public chart: Chart, public judgeLine: JudgeLine) {
120
+ super();
121
+ }
122
+ do() {
123
+ const id = this.chart.judgeLines.length;
124
+ this.judgeLine.id = id;
125
+ this.chart.judgeLines.push(this.judgeLine);
126
+ this.chart.orphanLines.push(this.judgeLine);
127
+ this.chart.judgeLineGroups[0].add(this.judgeLine);
128
+ }
129
+ undo() {
130
+ this.chart.judgeLineGroups[0].remove(this.judgeLine);
131
+ this.chart.judgeLines.splice(this.chart.judgeLines.indexOf(this.judgeLine), 1);
132
+ this.chart.orphanLines.splice(this.chart.orphanLines.indexOf(this.judgeLine), 1);
133
+ }
134
+ }
135
+
136
+ export class JudgeLineDeleteOperation extends Operation {
137
+ readonly originalGroup: JudgeLineGroup;
138
+ constructor(public chart: Chart, public judgeLine: JudgeLine) {
139
+ super();
140
+ if (!this.chart.judgeLines.includes(this.judgeLine)) {
141
+ this.ineffective = true;
142
+ }
143
+ this.originalGroup = judgeLine.group;
144
+ }
145
+ do() {
146
+ this.chart.judgeLines.splice(this.chart.judgeLines.indexOf(this.judgeLine), 1);
147
+ if (this.chart.orphanLines.includes(this.judgeLine)) {
148
+ this.chart.orphanLines.splice(this.chart.orphanLines.indexOf(this.judgeLine), 1);
149
+ }
150
+ this.originalGroup.remove(this.judgeLine);
151
+ }
152
+ undo() {
153
+ this.chart.judgeLines.push(this.judgeLine);
154
+ this.chart.orphanLines.push(this.judgeLine);
155
+ this.originalGroup.add(this.judgeLine);
156
+ }
157
+ }
158
+
159
+
160
+
161
+ export class JudgeLineENSChangeOperation extends Operation {
162
+ originalValue: EventNodeSequence;
163
+ constructor(public judgeLine: JudgeLine, public layerId: number, public typeStr: BasicEventName, public value: EventNodeSequence) {
164
+ super();
165
+ this.originalValue = judgeLine.eventLayers[layerId][typeStr];
166
+ }
167
+ do() {
168
+ this.judgeLine.eventLayers[this.layerId][this.typeStr] = this.value;
169
+ }
170
+ undo() {
171
+ this.judgeLine.eventLayers[this.layerId][this.typeStr] = this.originalValue;
172
+ }
173
+ }
174
+
175
+
176
+ export type ENSOfTypeName<T extends ExtendedEventTypeName> = {
177
+ "scaleX": EventNodeSequence<number>,
178
+ "scaleY": EventNodeSequence<number>
179
+ "text": EventNodeSequence<string>,
180
+ "color": EventNodeSequence<RGB>
181
+ }[T]
182
+ export class JudgeLineExtendENSChangeOperation<T extends ExtendedEventTypeName> extends Operation {
183
+ originalValue: ENSOfTypeName<T>;
184
+ constructor(public judgeLine: JudgeLine, public typeStr: T, public value: ENSOfTypeName<T> | null) {
185
+ super();
186
+ this.originalValue = judgeLine.extendedLayer[typeStr satisfies keyof ExtendedLayer] as ENSOfTypeName<T>;
187
+ }
188
+ do() {
189
+ this.judgeLine.extendedLayer[this.typeStr] = this.value
190
+ }
191
+ undo() {
192
+ this.judgeLine.extendedLayer[this.typeStr] = this.originalValue
193
+ }
194
+
195
+ }
196
+
197
+ export class UIAttachOperation extends Operation {
198
+ updatesEditor = true;
199
+ constructor(public chart: Chart, public judgeLine: JudgeLine, public ui: UIName) {
200
+ super();
201
+ }
202
+ do() {
203
+ this.chart.attachUIToLine(this.ui, this.judgeLine);
204
+ }
205
+ undo() {
206
+ this.chart.detachUI(this.ui);
207
+ }
208
+ }
209
+
210
+ export class UIDetachOperation extends Operation {
211
+ updatesEditor = true;
212
+ judgeLine: JudgeLine;
213
+ constructor(public chart: Chart, public ui: UIName) {
214
+ super();
215
+ if (chart[`${ui}Attach` satisfies keyof Chart]) {
216
+ this.judgeLine = chart[`${ui}Attach` satisfies keyof Chart];
217
+ } else {
218
+ this.ineffective = true;
219
+ }
220
+ }
221
+ do() {
222
+ this.chart.detachUI(this.ui);
223
+ }
224
+ undo() {
225
+ this.chart.attachUIToLine(this.ui, this.judgeLine);
226
+ }
227
+ }
228
+
229
+ export class JudgeLineDetachAllUIOperation extends Operation {
230
+ updatesEditor = true;
231
+ uinames: UIName[];
232
+ constructor(public chart: Chart, public judgeLine: JudgeLine) {
233
+ super();
234
+ this.uinames = chart.queryJudgeLineUI(this.judgeLine);
235
+ }
236
+ do() {
237
+ for (const ui of this.uinames) {
238
+ this.chart.detachUI(ui);
239
+ }
240
+ }
241
+ undo() {
242
+ for (const ui of this.uinames) {
243
+ this.chart.attachUIToLine(ui, this.judgeLine);
244
+ }
245
+ }
246
+ }
package/macro.ts ADDED
@@ -0,0 +1,215 @@
1
+ import type { Chart } from "./chart";
2
+ import type { EventValueESType, MacroData, MacroEvaluatorBodyData, MacroLink, MacroTimeBodyData, MacroValueBodyData, RGB, TimeT } from "./chartTypes";
3
+ import { err, ERROR_IDS, KPAError } from "./env";
4
+ import { MacroEvaluator } from "./evaluator";
5
+ import type { EventNode, EventStartNode } from "./event";
6
+ import type { JudgeLine } from "./judgeline";
7
+ import { Note } from "./note";
8
+
9
+
10
+ const getLine = (node: EventStartNode<EventValueESType>, chart: Chart) => {
11
+ const canBeId = node.parentSeq.id.match(/#(\d+)/);
12
+ if (!canBeId) {
13
+ return null;
14
+ }
15
+ return chart.judgeLines[parseInt(canBeId[1])]
16
+ }
17
+
18
+
19
+ // 添加表达式宏,通过@表示。如@line.id表示判定线ID,会在构造函数中被替换为实际值
20
+ export const EVENT_MACROS = {
21
+ "line.id": (node: EventStartNode<EventValueESType>, chart: Chart) => getLine(node, chart)?.id,
22
+ "line.name": (node: EventStartNode<EventValueESType>, chart: Chart) => getLine(node, chart)?.name,
23
+ "line.group": (node: EventStartNode<EventValueESType>, chart: Chart) => getLine(node, chart)?.group,
24
+ "node.time": (node: EventStartNode<EventValueESType>) => node.time,
25
+ "node.value": (node: EventStartNode<EventValueESType>) => node.value,
26
+ "seq.id": (node: EventStartNode<EventValueESType>) => node.parentSeq.id,
27
+ "seq.type": (node: EventStartNode<EventValueESType>) => node.parentSeq.type
28
+ }
29
+
30
+ export type Macroable = number | string | TimeT | RGB | boolean;
31
+ export type Macroee = EventNode<EventValueESType> | Note;
32
+
33
+ export abstract class Macro<T extends Macroable, C extends Macroee, P extends Macroee> {
34
+ public readonly consumers: Map<C, number> = new Map();
35
+ /**
36
+ * **原形节点**
37
+ *
38
+ * 作为参数,向其他节点派生数值。
39
+ *
40
+ * 需要parametric为true。
41
+ *
42
+ * 如:若节点A存在于这个数组,下标为1:
43
+ *
44
+ * 节点B设有数值宏,即这个宏,宏表达式: @proto.value + 2。
45
+ *
46
+ * 那么评估B的宏时可以调用节点A的数值。
47
+ *
48
+ * 在转储时,是节点存储宏的ID,而不是宏去找节点,因为节点并没有全谱面编号系统。
49
+ */
50
+ public readonly protoNodes: P[] = [];
51
+ /**
52
+ *
53
+ * @param macro
54
+ * @param id
55
+ * @param parametric 是否为参数宏,即是否可以把一个节点作为参数。
56
+ */
57
+ constructor(public macro: string, public id: string, public readonly parametric: boolean) {
58
+ }
59
+ abstract eval(consumer: C, chart: Chart): T;
60
+ }
61
+
62
+ export abstract class EventMacro<T extends Macroable> extends Macro<T, EventNode<EventValueESType>, EventNode<EventValueESType>> {
63
+ eval(node: EventNode<EventValueESType>, chart: Chart): T {
64
+ let jsExpr = this.parametric ? this.macro.replace(/@proto\.(value|time)/, (k) => {
65
+ return JSON.stringify(this.protoNodes[this.consumers.get(node)!][k]) + " "
66
+ }): this.macro;
67
+ jsExpr = this.macro.replace(/@([a-z]+\.[a-z])/, (k) => {
68
+ return JSON.stringify(EVENT_MACROS[k](node, chart)) + " "
69
+ });
70
+ return new Function("return " + jsExpr)() as T;
71
+ }
72
+ checkSyntax(): KPAError<ERROR_IDS.PROTO_PRESENT_IN_NONPARAMETRIC | ERROR_IDS.UNKNOWN_MACRO_EXPRESSION | ERROR_IDS.JAVASCRIPT_SYNTAX_ERROR> | null {
73
+ let jsExpr: string;
74
+ if (this.parametric) {
75
+ jsExpr = this.macro.replace(/@proto\.(value|time)/, (k) => {
76
+ return '"aaa" '
77
+ });
78
+ } else {
79
+ if (/@proto/.test(this.macro)) {
80
+ return err.PROTO_PRESENT_IN_NONPARAMETRIC(this.id);
81
+ }
82
+ }
83
+ try {
84
+ jsExpr = this.macro.replace(/@([a-z]+\.[a-z])/, (k) => {
85
+ if (!(k in EVENT_MACROS)) {
86
+ throw err.UNKNOWN_MACRO_EXPRESSION(k, this.id);
87
+ }
88
+ return '"aaa" '
89
+ });
90
+ } catch (e) {
91
+ if (e instanceof KPAError) {
92
+ return e;
93
+ } else {
94
+ throw e;
95
+ }
96
+ }
97
+ try {
98
+ new Function("return " + jsExpr); // 仅检查语法,不执行
99
+ } catch (e) {
100
+ return err.JAVASCRIPT_SYNTAX_ERROR(e, this.id);
101
+ }
102
+ }
103
+ bindNode(node: EventNode<EventValueESType>, macroData: MacroData, pos?: string) {
104
+ if (this.parametric) {
105
+ if (typeof macroData === "string") {
106
+ throw err.PARAMETRIC_MACRO_REQUIRES_PROTO_KEY(pos)
107
+ }
108
+ this.consumers.set(node, macroData[1]);
109
+ } else {
110
+ if (Array.isArray(macroData)) {
111
+ throw err.MACRO_NOT_PARAMETRIC(this.id, pos);
112
+ }
113
+ this.consumers.set(node, -1);
114
+ }
115
+ }
116
+ linkProtoNode(node: EventNode<EventValueESType>, id: number): void {
117
+ this.protoNodes[id] = node;
118
+ node.linkedMacros.add(this);
119
+ }
120
+ dumpContent(): MacroValueBodyData {
121
+ return {
122
+ id: this.id,
123
+ macro: this.macro,
124
+ parametric: this.parametric ? true : undefined
125
+ }
126
+ }
127
+ /**
128
+ * 为单个节点导出宏名称和参数(若有)
129
+ * @param node
130
+ * @example
131
+ * return {
132
+ * start: node.value,
133
+ * end: node.next.value,
134
+ * macroStart: node.valueMacro.dumpForNode(node),
135
+ * macroEnd: node.valueMacro.dumpForNode(node.next),
136
+ * ...
137
+ * } satisfies EvenDataKPA2
138
+ *
139
+ */
140
+ dumpForNode(node: EventNode<EventValueESType>): MacroData {
141
+ if (this.parametric) {
142
+ return [this.id, this.consumers.get(node)!]
143
+ } else {
144
+ return this.id
145
+ }
146
+ }
147
+ abstract dumpLinkForNode(node: EventNode<EventValueESType>): MacroLink;
148
+ }
149
+
150
+ export class EventMacroValue extends EventMacro<EventValueESType> {
151
+ dumpLinkForNode(node: EventNode<EventValueESType>): MacroLink {
152
+ return [`value:${this.id}`, this.protoNodes.indexOf(node)];
153
+ }
154
+ }
155
+
156
+ export class EventMacroTime extends EventMacro<TimeT> {
157
+ dumpLinkForNode(node: EventNode<EventValueESType>): MacroLink {
158
+ return [`time:${this.id}`, this.protoNodes.indexOf(node)];
159
+ }
160
+ }
161
+
162
+ export class MacroLib {
163
+ timeMacros: Map<string, EventMacroTime> = new Map();
164
+ valueMacros: Map<string, EventMacroValue> = new Map();
165
+ macroEvaluators: Map<string, MacroEvaluator<EventValueESType>> = new Map();
166
+ dumpTimeMacros(): MacroTimeBodyData[] {
167
+ const arr: MacroTimeBodyData[] = [];
168
+ for (const [_, macro] of this.timeMacros) {
169
+ arr.push(macro.dumpContent());
170
+ }
171
+ return arr;
172
+ }
173
+ readTimeMacros(data: MacroTimeBodyData[]) {
174
+ const len = data.length;
175
+ for (let i = 0; i < len; i++) {
176
+ const datum = data[i];
177
+ const macro = new EventMacroTime(datum.macro, datum.id, datum.parametric);
178
+ this.timeMacros.set(datum.id, macro);
179
+ }
180
+ }
181
+
182
+ dumpValueMacros(): MacroValueBodyData[] {
183
+ const arr: MacroValueBodyData[] = [];
184
+ for (const [_, macro] of this.valueMacros) {
185
+ arr.push(macro.dumpContent());
186
+ }
187
+ return arr;
188
+ }
189
+ readValueMacros(data: MacroValueBodyData[]) {
190
+ const len = data.length;
191
+ for (let i = 0; i < len; i++) {
192
+ const datum = data[i];
193
+ const macro = new EventMacroValue(datum.macro, datum.id, datum.parametric);
194
+ this.valueMacros.set(datum.id, macro);
195
+ }
196
+ }
197
+
198
+ dumpMacroEvaluators(): MacroEvaluatorBodyData[] {
199
+ const arr: MacroEvaluatorBodyData[] = [];
200
+ for (const [_, ev] of this.macroEvaluators) {
201
+ arr.push({
202
+ id: ev.id,
203
+ macro: ev.expression
204
+ })
205
+ }
206
+ return arr;
207
+ }
208
+ readMacroEvaluators(data: MacroEvaluatorBodyData[]): void {
209
+ const len = data.length;
210
+ for (let i = 0; i < len; i++) {
211
+ const datum = data[i];
212
+ this.macroEvaluators.set(datum.id, new MacroEvaluator(datum.macro, datum.id));
213
+ }
214
+ }
215
+ }