@synergenius/flow-weaver 0.17.9 → 0.17.11
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/dist/ast/types.d.ts +1 -1
- package/dist/chevrotain-parser/port-parser.d.ts +1 -0
- package/dist/chevrotain-parser/port-parser.js +57 -1
- package/dist/cli/flow-weaver.mjs +80 -23
- package/dist/diagram/geometry.js +4 -4
- package/dist/diagram/renderer.js +6 -6
- package/dist/diagram/theme.d.ts +1 -0
- package/dist/diagram/theme.js +2 -1
- package/dist/editor-completions/annotationValues.js +1 -1
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/jsdoc-parser.js +12 -6
- package/docs/reference/advanced-annotations.md +37 -1
- package/docs/reference/concepts.md +1 -0
- package/docs/reference/jsdoc-grammar.md +1 -1
- package/package.json +1 -1
package/dist/ast/types.d.ts
CHANGED
|
@@ -786,7 +786,7 @@ export type TNodeTagAST = {
|
|
|
786
786
|
};
|
|
787
787
|
/** Visual customization for node types */
|
|
788
788
|
export type TNodeVisualsAST = {
|
|
789
|
-
/** Theme color: blue, purple,
|
|
789
|
+
/** Theme color: blue, purple, cyan, orange, pink, green, red, yellow (teal is an alias for cyan) */
|
|
790
790
|
color?: string;
|
|
791
791
|
/** Icon preset name */
|
|
792
792
|
icon?: string;
|
|
@@ -98,6 +98,7 @@ class PortParser extends CstParser {
|
|
|
98
98
|
{ ALT: () => this.SUBRULE(this.typeAttr) },
|
|
99
99
|
{ ALT: () => this.SUBRULE(this.mergeStrategyAttr) },
|
|
100
100
|
{ ALT: () => this.SUBRULE(this.hiddenAttr) },
|
|
101
|
+
{ ALT: () => this.SUBRULE(this.customAttr) },
|
|
101
102
|
]);
|
|
102
103
|
},
|
|
103
104
|
});
|
|
@@ -131,6 +132,18 @@ class PortParser extends CstParser {
|
|
|
131
132
|
hiddenAttr = this.RULE('hiddenAttr', () => {
|
|
132
133
|
this.CONSUME(HiddenKeyword);
|
|
133
134
|
});
|
|
135
|
+
// customAttr: key:value pairs for arbitrary metadata (e.g., artifactPath:"dist/")
|
|
136
|
+
customAttr = this.RULE('customAttr', () => {
|
|
137
|
+
this.CONSUME(Identifier, { LABEL: 'customKey' });
|
|
138
|
+
this.CONSUME(Colon);
|
|
139
|
+
this.OR([
|
|
140
|
+
{ ALT: () => this.CONSUME(StringLiteral, { LABEL: 'customStrVal' }) },
|
|
141
|
+
{ ALT: () => this.CONSUME(TrueKeyword, { LABEL: 'customTrue' }) },
|
|
142
|
+
{ ALT: () => this.CONSUME(FalseKeyword, { LABEL: 'customFalse' }) },
|
|
143
|
+
{ ALT: () => this.CONSUME2(Identifier, { LABEL: 'customIdVal' }) },
|
|
144
|
+
{ ALT: () => this.CONSUME(Integer, { LABEL: 'customIntVal' }) },
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
134
147
|
// - description text
|
|
135
148
|
// Note: We just consume the dash here. The actual description text is extracted
|
|
136
149
|
// from the raw input in parsePortLine() to handle special characters like &, :, etc.
|
|
@@ -232,6 +245,7 @@ class PortVisitor extends BaseVisitor {
|
|
|
232
245
|
scope = this.visit(ctx.scopeClause);
|
|
233
246
|
}
|
|
234
247
|
let hidden;
|
|
248
|
+
let customMetadata;
|
|
235
249
|
if (ctx.metadataBracket) {
|
|
236
250
|
// Handle multiple metadata brackets (e.g., [order:1] [placement:TOP])
|
|
237
251
|
for (const bracket of ctx.metadataBracket) {
|
|
@@ -246,6 +260,9 @@ class PortVisitor extends BaseVisitor {
|
|
|
246
260
|
mergeStrategy = metadata.mergeStrategy;
|
|
247
261
|
if (metadata.hidden)
|
|
248
262
|
hidden = true;
|
|
263
|
+
if (metadata.customMetadata) {
|
|
264
|
+
customMetadata = { ...customMetadata, ...metadata.customMetadata };
|
|
265
|
+
}
|
|
249
266
|
}
|
|
250
267
|
}
|
|
251
268
|
if (ctx.descriptionClause) {
|
|
@@ -263,6 +280,7 @@ class PortVisitor extends BaseVisitor {
|
|
|
263
280
|
...(mergeStrategy && { mergeStrategy }),
|
|
264
281
|
...(hidden && { hidden }),
|
|
265
282
|
...(description && { description }),
|
|
283
|
+
...(customMetadata && { customMetadata }),
|
|
266
284
|
};
|
|
267
285
|
}
|
|
268
286
|
outputPort(ctx) {
|
|
@@ -276,6 +294,7 @@ class PortVisitor extends BaseVisitor {
|
|
|
276
294
|
scope = this.visit(ctx.scopeClause);
|
|
277
295
|
}
|
|
278
296
|
let hidden;
|
|
297
|
+
let customMetadata;
|
|
279
298
|
if (ctx.metadataBracket) {
|
|
280
299
|
// Handle multiple metadata brackets (e.g., [order:1] [placement:TOP])
|
|
281
300
|
for (const bracket of ctx.metadataBracket) {
|
|
@@ -288,6 +307,9 @@ class PortVisitor extends BaseVisitor {
|
|
|
288
307
|
dataType = metadata.dataType;
|
|
289
308
|
if (metadata.hidden)
|
|
290
309
|
hidden = true;
|
|
310
|
+
if (metadata.customMetadata) {
|
|
311
|
+
customMetadata = { ...customMetadata, ...metadata.customMetadata };
|
|
312
|
+
}
|
|
291
313
|
}
|
|
292
314
|
}
|
|
293
315
|
if (ctx.descriptionClause) {
|
|
@@ -302,6 +324,7 @@ class PortVisitor extends BaseVisitor {
|
|
|
302
324
|
...(dataType && { dataType }),
|
|
303
325
|
...(hidden && { hidden }),
|
|
304
326
|
...(description && { description }),
|
|
327
|
+
...(customMetadata && { customMetadata }),
|
|
305
328
|
};
|
|
306
329
|
}
|
|
307
330
|
stepPort(ctx) {
|
|
@@ -325,6 +348,7 @@ class PortVisitor extends BaseVisitor {
|
|
|
325
348
|
let dataType;
|
|
326
349
|
let mergeStrategy;
|
|
327
350
|
let hidden;
|
|
351
|
+
let customMetadata;
|
|
328
352
|
if (ctx.orderAttr) {
|
|
329
353
|
for (const attr of ctx.orderAttr) {
|
|
330
354
|
order = this.visit(attr);
|
|
@@ -348,7 +372,14 @@ class PortVisitor extends BaseVisitor {
|
|
|
348
372
|
if (ctx.hiddenAttr) {
|
|
349
373
|
hidden = true;
|
|
350
374
|
}
|
|
351
|
-
|
|
375
|
+
if (ctx.customAttr) {
|
|
376
|
+
customMetadata = customMetadata || {};
|
|
377
|
+
for (const attr of ctx.customAttr) {
|
|
378
|
+
const { key, value } = this.visit(attr);
|
|
379
|
+
customMetadata[key] = value;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return { order, placement, dataType, mergeStrategy, hidden, customMetadata };
|
|
352
383
|
}
|
|
353
384
|
orderAttr(ctx) {
|
|
354
385
|
return parseInt(ctx.orderValue[0].image, 10);
|
|
@@ -365,6 +396,31 @@ class PortVisitor extends BaseVisitor {
|
|
|
365
396
|
mergeStrategyAttr(ctx) {
|
|
366
397
|
return ctx.mergeStrategyValue[0].image;
|
|
367
398
|
}
|
|
399
|
+
customAttr(ctx) {
|
|
400
|
+
const key = ctx.customKey[0].image;
|
|
401
|
+
let value;
|
|
402
|
+
if (ctx.customStrVal) {
|
|
403
|
+
// Remove quotes from string literal
|
|
404
|
+
const raw = ctx.customStrVal[0].image;
|
|
405
|
+
value = raw.slice(1, -1);
|
|
406
|
+
}
|
|
407
|
+
else if (ctx.customTrue) {
|
|
408
|
+
value = true;
|
|
409
|
+
}
|
|
410
|
+
else if (ctx.customFalse) {
|
|
411
|
+
value = false;
|
|
412
|
+
}
|
|
413
|
+
else if (ctx.customIntVal) {
|
|
414
|
+
value = parseInt(ctx.customIntVal[0].image, 10);
|
|
415
|
+
}
|
|
416
|
+
else if (ctx.customIdVal) {
|
|
417
|
+
value = ctx.customIdVal[0].image;
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
value = '';
|
|
421
|
+
}
|
|
422
|
+
return { key, value };
|
|
423
|
+
}
|
|
368
424
|
descriptionClause(ctx) {
|
|
369
425
|
if (ctx.Identifier) {
|
|
370
426
|
return ctx.Identifier.map((token) => token.image).join(' ');
|
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -9671,7 +9671,7 @@ var VERSION;
|
|
|
9671
9671
|
var init_generated_version = __esm({
|
|
9672
9672
|
"src/generated-version.ts"() {
|
|
9673
9673
|
"use strict";
|
|
9674
|
-
VERSION = "0.17.
|
|
9674
|
+
VERSION = "0.17.11";
|
|
9675
9675
|
}
|
|
9676
9676
|
});
|
|
9677
9677
|
|
|
@@ -31902,7 +31902,8 @@ var init_port_parser = __esm({
|
|
|
31902
31902
|
{ ALT: () => this.SUBRULE(this.placementAttr) },
|
|
31903
31903
|
{ ALT: () => this.SUBRULE(this.typeAttr) },
|
|
31904
31904
|
{ ALT: () => this.SUBRULE(this.mergeStrategyAttr) },
|
|
31905
|
-
{ ALT: () => this.SUBRULE(this.hiddenAttr) }
|
|
31905
|
+
{ ALT: () => this.SUBRULE(this.hiddenAttr) },
|
|
31906
|
+
{ ALT: () => this.SUBRULE(this.customAttr) }
|
|
31906
31907
|
]);
|
|
31907
31908
|
}
|
|
31908
31909
|
});
|
|
@@ -31936,6 +31937,18 @@ var init_port_parser = __esm({
|
|
|
31936
31937
|
hiddenAttr = this.RULE("hiddenAttr", () => {
|
|
31937
31938
|
this.CONSUME(HiddenKeyword);
|
|
31938
31939
|
});
|
|
31940
|
+
// customAttr: key:value pairs for arbitrary metadata (e.g., artifactPath:"dist/")
|
|
31941
|
+
customAttr = this.RULE("customAttr", () => {
|
|
31942
|
+
this.CONSUME(Identifier, { LABEL: "customKey" });
|
|
31943
|
+
this.CONSUME(Colon);
|
|
31944
|
+
this.OR([
|
|
31945
|
+
{ ALT: () => this.CONSUME(StringLiteral, { LABEL: "customStrVal" }) },
|
|
31946
|
+
{ ALT: () => this.CONSUME(TrueKeyword, { LABEL: "customTrue" }) },
|
|
31947
|
+
{ ALT: () => this.CONSUME(FalseKeyword, { LABEL: "customFalse" }) },
|
|
31948
|
+
{ ALT: () => this.CONSUME2(Identifier, { LABEL: "customIdVal" }) },
|
|
31949
|
+
{ ALT: () => this.CONSUME(Integer, { LABEL: "customIntVal" }) }
|
|
31950
|
+
]);
|
|
31951
|
+
});
|
|
31939
31952
|
// - description text
|
|
31940
31953
|
// Note: We just consume the dash here. The actual description text is extracted
|
|
31941
31954
|
// from the raw input in parsePortLine() to handle special characters like &, :, etc.
|
|
@@ -32022,6 +32035,7 @@ var init_port_parser = __esm({
|
|
|
32022
32035
|
scope = this.visit(ctx.scopeClause);
|
|
32023
32036
|
}
|
|
32024
32037
|
let hidden;
|
|
32038
|
+
let customMetadata;
|
|
32025
32039
|
if (ctx.metadataBracket) {
|
|
32026
32040
|
for (const bracket of ctx.metadataBracket) {
|
|
32027
32041
|
const metadata = this.visit(bracket);
|
|
@@ -32030,6 +32044,9 @@ var init_port_parser = __esm({
|
|
|
32030
32044
|
if (metadata.dataType !== void 0) dataType = metadata.dataType;
|
|
32031
32045
|
if (metadata.mergeStrategy !== void 0) mergeStrategy = metadata.mergeStrategy;
|
|
32032
32046
|
if (metadata.hidden) hidden = true;
|
|
32047
|
+
if (metadata.customMetadata) {
|
|
32048
|
+
customMetadata = { ...customMetadata, ...metadata.customMetadata };
|
|
32049
|
+
}
|
|
32033
32050
|
}
|
|
32034
32051
|
}
|
|
32035
32052
|
if (ctx.descriptionClause) {
|
|
@@ -32046,7 +32063,8 @@ var init_port_parser = __esm({
|
|
|
32046
32063
|
...dataType && { dataType },
|
|
32047
32064
|
...mergeStrategy && { mergeStrategy },
|
|
32048
32065
|
...hidden && { hidden },
|
|
32049
|
-
...description && { description }
|
|
32066
|
+
...description && { description },
|
|
32067
|
+
...customMetadata && { customMetadata }
|
|
32050
32068
|
};
|
|
32051
32069
|
}
|
|
32052
32070
|
outputPort(ctx) {
|
|
@@ -32060,6 +32078,7 @@ var init_port_parser = __esm({
|
|
|
32060
32078
|
scope = this.visit(ctx.scopeClause);
|
|
32061
32079
|
}
|
|
32062
32080
|
let hidden;
|
|
32081
|
+
let customMetadata;
|
|
32063
32082
|
if (ctx.metadataBracket) {
|
|
32064
32083
|
for (const bracket of ctx.metadataBracket) {
|
|
32065
32084
|
const metadata = this.visit(bracket);
|
|
@@ -32067,6 +32086,9 @@ var init_port_parser = __esm({
|
|
|
32067
32086
|
if (metadata.placement !== void 0) placement = metadata.placement;
|
|
32068
32087
|
if (metadata.dataType !== void 0) dataType = metadata.dataType;
|
|
32069
32088
|
if (metadata.hidden) hidden = true;
|
|
32089
|
+
if (metadata.customMetadata) {
|
|
32090
|
+
customMetadata = { ...customMetadata, ...metadata.customMetadata };
|
|
32091
|
+
}
|
|
32070
32092
|
}
|
|
32071
32093
|
}
|
|
32072
32094
|
if (ctx.descriptionClause) {
|
|
@@ -32080,7 +32102,8 @@ var init_port_parser = __esm({
|
|
|
32080
32102
|
...placement && { placement },
|
|
32081
32103
|
...dataType && { dataType },
|
|
32082
32104
|
...hidden && { hidden },
|
|
32083
|
-
...description && { description }
|
|
32105
|
+
...description && { description },
|
|
32106
|
+
...customMetadata && { customMetadata }
|
|
32084
32107
|
};
|
|
32085
32108
|
}
|
|
32086
32109
|
stepPort(ctx) {
|
|
@@ -32104,6 +32127,7 @@ var init_port_parser = __esm({
|
|
|
32104
32127
|
let dataType;
|
|
32105
32128
|
let mergeStrategy;
|
|
32106
32129
|
let hidden;
|
|
32130
|
+
let customMetadata;
|
|
32107
32131
|
if (ctx.orderAttr) {
|
|
32108
32132
|
for (const attr of ctx.orderAttr) {
|
|
32109
32133
|
order = this.visit(attr);
|
|
@@ -32127,7 +32151,14 @@ var init_port_parser = __esm({
|
|
|
32127
32151
|
if (ctx.hiddenAttr) {
|
|
32128
32152
|
hidden = true;
|
|
32129
32153
|
}
|
|
32130
|
-
|
|
32154
|
+
if (ctx.customAttr) {
|
|
32155
|
+
customMetadata = customMetadata || {};
|
|
32156
|
+
for (const attr of ctx.customAttr) {
|
|
32157
|
+
const { key, value: value2 } = this.visit(attr);
|
|
32158
|
+
customMetadata[key] = value2;
|
|
32159
|
+
}
|
|
32160
|
+
}
|
|
32161
|
+
return { order, placement, dataType, mergeStrategy, hidden, customMetadata };
|
|
32131
32162
|
}
|
|
32132
32163
|
orderAttr(ctx) {
|
|
32133
32164
|
return parseInt(ctx.orderValue[0].image, 10);
|
|
@@ -32144,6 +32175,25 @@ var init_port_parser = __esm({
|
|
|
32144
32175
|
mergeStrategyAttr(ctx) {
|
|
32145
32176
|
return ctx.mergeStrategyValue[0].image;
|
|
32146
32177
|
}
|
|
32178
|
+
customAttr(ctx) {
|
|
32179
|
+
const key = ctx.customKey[0].image;
|
|
32180
|
+
let value2;
|
|
32181
|
+
if (ctx.customStrVal) {
|
|
32182
|
+
const raw = ctx.customStrVal[0].image;
|
|
32183
|
+
value2 = raw.slice(1, -1);
|
|
32184
|
+
} else if (ctx.customTrue) {
|
|
32185
|
+
value2 = true;
|
|
32186
|
+
} else if (ctx.customFalse) {
|
|
32187
|
+
value2 = false;
|
|
32188
|
+
} else if (ctx.customIntVal) {
|
|
32189
|
+
value2 = parseInt(ctx.customIntVal[0].image, 10);
|
|
32190
|
+
} else if (ctx.customIdVal) {
|
|
32191
|
+
value2 = ctx.customIdVal[0].image;
|
|
32192
|
+
} else {
|
|
32193
|
+
value2 = "";
|
|
32194
|
+
}
|
|
32195
|
+
return { key, value: value2 };
|
|
32196
|
+
}
|
|
32147
32197
|
descriptionClause(ctx) {
|
|
32148
32198
|
if (ctx.Identifier) {
|
|
32149
32199
|
return ctx.Identifier.map((token) => token.image).join(" ");
|
|
@@ -34219,7 +34269,7 @@ var init_jsdoc_parser = __esm({
|
|
|
34219
34269
|
if (!result) {
|
|
34220
34270
|
return;
|
|
34221
34271
|
}
|
|
34222
|
-
const { name, defaultValue, isOptional, scope, order, mergeStrategy, hidden, description } = result;
|
|
34272
|
+
const { name, defaultValue, isOptional, scope, order, mergeStrategy, hidden, description, customMetadata } = result;
|
|
34223
34273
|
let type2;
|
|
34224
34274
|
let tsType;
|
|
34225
34275
|
const isScopedStepInput = scope && isScopedMandatoryPort(name);
|
|
@@ -34280,7 +34330,9 @@ var init_jsdoc_parser = __esm({
|
|
|
34280
34330
|
...scope && { scope },
|
|
34281
34331
|
...mergeStrategy && { mergeStrategy },
|
|
34282
34332
|
...hidden && { hidden },
|
|
34283
|
-
...order !== void 0
|
|
34333
|
+
...(order !== void 0 || customMetadata) && {
|
|
34334
|
+
metadata: { ...order !== void 0 && { order }, ...customMetadata }
|
|
34335
|
+
},
|
|
34284
34336
|
...tsType && { tsType }
|
|
34285
34337
|
};
|
|
34286
34338
|
}
|
|
@@ -34294,7 +34346,7 @@ var init_jsdoc_parser = __esm({
|
|
|
34294
34346
|
if (!result) {
|
|
34295
34347
|
return;
|
|
34296
34348
|
}
|
|
34297
|
-
const { name, scope, order, hidden, description } = result;
|
|
34349
|
+
const { name, scope, order, hidden, description, customMetadata } = result;
|
|
34298
34350
|
let type2;
|
|
34299
34351
|
let tsType;
|
|
34300
34352
|
const isScopedStepOutput = scope && isScopedMandatoryPort(name);
|
|
@@ -34348,7 +34400,9 @@ var init_jsdoc_parser = __esm({
|
|
|
34348
34400
|
label: description?.trim(),
|
|
34349
34401
|
...scope && { scope },
|
|
34350
34402
|
...hidden && { hidden },
|
|
34351
|
-
...order !== void 0
|
|
34403
|
+
...(order !== void 0 || customMetadata) && {
|
|
34404
|
+
metadata: { ...order !== void 0 && { order }, ...customMetadata }
|
|
34405
|
+
},
|
|
34352
34406
|
...tsType && { tsType }
|
|
34353
34407
|
};
|
|
34354
34408
|
}
|
|
@@ -34386,7 +34440,7 @@ var init_jsdoc_parser = __esm({
|
|
|
34386
34440
|
if (!result) {
|
|
34387
34441
|
return;
|
|
34388
34442
|
}
|
|
34389
|
-
const { name, order, description } = result;
|
|
34443
|
+
const { name, order, description, customMetadata } = result;
|
|
34390
34444
|
let type2 = "ANY";
|
|
34391
34445
|
if (isSuccessPort(name) || isFailurePort(name)) {
|
|
34392
34446
|
type2 = "STEP";
|
|
@@ -34407,7 +34461,9 @@ var init_jsdoc_parser = __esm({
|
|
|
34407
34461
|
config2.returnPorts[name] = {
|
|
34408
34462
|
dataType: type2,
|
|
34409
34463
|
label: description?.trim(),
|
|
34410
|
-
...order !== void 0
|
|
34464
|
+
...(order !== void 0 || customMetadata) && {
|
|
34465
|
+
metadata: { ...order !== void 0 && { order }, ...customMetadata }
|
|
34466
|
+
}
|
|
34411
34467
|
};
|
|
34412
34468
|
}
|
|
34413
34469
|
/**
|
|
@@ -37833,7 +37889,7 @@ function darkenHex(hex, amount) {
|
|
|
37833
37889
|
const nb = Math.round(b * (1 - amount));
|
|
37834
37890
|
return `#${nr.toString(16).padStart(2, "0")}${ng.toString(16).padStart(2, "0")}${nb.toString(16).padStart(2, "0")}`;
|
|
37835
37891
|
}
|
|
37836
|
-
var DARK_PORT_COLORS, LIGHT_PORT_COLORS, DARK_FAILURE_COLOR, LIGHT_FAILURE_COLOR, NODE_VARIANT_COLORS, DARK_PALETTE, LIGHT_PALETTE, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, VALID_NODE_ICONS;
|
|
37892
|
+
var DARK_PORT_COLORS, LIGHT_PORT_COLORS, DARK_FAILURE_COLOR, LIGHT_FAILURE_COLOR, NODE_DEFAULT_COLOR, NODE_VARIANT_COLORS, DARK_PALETTE, LIGHT_PALETTE, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, VALID_NODE_ICONS;
|
|
37837
37893
|
var init_theme = __esm({
|
|
37838
37894
|
"src/diagram/theme.ts"() {
|
|
37839
37895
|
"use strict";
|
|
@@ -37875,6 +37931,7 @@ var init_theme = __esm({
|
|
|
37875
37931
|
};
|
|
37876
37932
|
DARK_FAILURE_COLOR = "#ff4f4f";
|
|
37877
37933
|
LIGHT_FAILURE_COLOR = "#e34646";
|
|
37934
|
+
NODE_DEFAULT_COLOR = "#334155";
|
|
37878
37935
|
NODE_VARIANT_COLORS = {
|
|
37879
37936
|
blue: { border: "#548ce3", darkBorder: "#5e9eff" },
|
|
37880
37937
|
// blue-shade-2 / blue-dark-shade-1
|
|
@@ -37882,6 +37939,8 @@ var init_theme = __esm({
|
|
|
37882
37939
|
// purple-shade-2 / purple-dark-shade-1
|
|
37883
37940
|
cyan: { border: "#63ccc4", darkBorder: "#6fe5dc" },
|
|
37884
37941
|
// cyan-shade-2 / cyan-dark-shade-1
|
|
37942
|
+
teal: { border: "#63ccc4", darkBorder: "#6fe5dc" },
|
|
37943
|
+
// alias for cyan
|
|
37885
37944
|
orange: { border: "#e3732d", darkBorder: "#ff8133" },
|
|
37886
37945
|
// orange-shade-2 / orange-dark-shade-1
|
|
37887
37946
|
pink: { border: "#e349c2", darkBorder: "#ff52da" },
|
|
@@ -37890,10 +37949,8 @@ var init_theme = __esm({
|
|
|
37890
37949
|
// green-shade-2 / green-dark-shade-1
|
|
37891
37950
|
red: { border: "#e34646", darkBorder: "#ff4f4f" },
|
|
37892
37951
|
// red-shade-2 / red-dark-shade-1
|
|
37893
|
-
yellow: { border: "#e3a82b", darkBorder: "#ffbd30" }
|
|
37952
|
+
yellow: { border: "#e3a82b", darkBorder: "#ffbd30" }
|
|
37894
37953
|
// yellow-shade-2 / yellow-dark-shade-1
|
|
37895
|
-
teal: { border: "#3db0a8", darkBorder: "#4dc7be" }
|
|
37896
|
-
// teal-shade-2 / teal-dark-shade-1
|
|
37897
37954
|
};
|
|
37898
37955
|
DARK_PALETTE = {
|
|
37899
37956
|
background: "#202139",
|
|
@@ -50796,7 +50853,7 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
50796
50853
|
diagramNodes.set("Start", {
|
|
50797
50854
|
id: "Start",
|
|
50798
50855
|
label: "Start",
|
|
50799
|
-
color:
|
|
50856
|
+
color: NODE_DEFAULT_COLOR,
|
|
50800
50857
|
icon: "startNode",
|
|
50801
50858
|
isVirtual: true,
|
|
50802
50859
|
inputs: [],
|
|
@@ -50819,7 +50876,7 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
50819
50876
|
diagramNodes.set("Exit", {
|
|
50820
50877
|
id: "Exit",
|
|
50821
50878
|
label: "Exit",
|
|
50822
|
-
color:
|
|
50879
|
+
color: NODE_DEFAULT_COLOR,
|
|
50823
50880
|
icon: "exitNode",
|
|
50824
50881
|
isVirtual: true,
|
|
50825
50882
|
inputs: exitInputs,
|
|
@@ -51125,7 +51182,7 @@ function filterNonScopedPorts(ports) {
|
|
|
51125
51182
|
return result;
|
|
51126
51183
|
}
|
|
51127
51184
|
function resolveNodeColor(color, theme = "dark") {
|
|
51128
|
-
if (!color) return
|
|
51185
|
+
if (!color) return NODE_DEFAULT_COLOR;
|
|
51129
51186
|
const variant = NODE_VARIANT_COLORS[color];
|
|
51130
51187
|
if (variant) return theme === "dark" ? variant.darkBorder : variant.border;
|
|
51131
51188
|
return color;
|
|
@@ -51834,12 +51891,12 @@ function renderScopeConnection(parts2, conn, allConnections, parentNodeId) {
|
|
|
51834
51891
|
);
|
|
51835
51892
|
}
|
|
51836
51893
|
function renderNodeBody(parts2, node, theme, indent) {
|
|
51837
|
-
const strokeColor = node.color !==
|
|
51894
|
+
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
51838
51895
|
parts2.push(
|
|
51839
51896
|
`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`
|
|
51840
51897
|
);
|
|
51841
51898
|
const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
|
|
51842
|
-
const iconColor = node.color !==
|
|
51899
|
+
const iconColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
51843
51900
|
const iconSize = 40;
|
|
51844
51901
|
const iconX = node.x + (node.width - iconSize) / 2;
|
|
51845
51902
|
const iconY = node.y + (node.height - iconSize) / 2;
|
|
@@ -51851,7 +51908,7 @@ function renderNode(node, theme, themeName, allConnections) {
|
|
|
51851
51908
|
const parts2 = [];
|
|
51852
51909
|
parts2.push(` <g data-node-id="${escapeXml(node.id)}">`);
|
|
51853
51910
|
if (node.scopeChildren && node.scopeChildren.length > 0) {
|
|
51854
|
-
const strokeColor = node.color !==
|
|
51911
|
+
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
51855
51912
|
parts2.push(
|
|
51856
51913
|
` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`
|
|
51857
51914
|
);
|
|
@@ -51898,7 +51955,7 @@ function renderNodeLabel(parts2, node, theme) {
|
|
|
51898
51955
|
const labelAnchor = isScoped ? "start" : "middle";
|
|
51899
51956
|
parts2.push(` <g data-label-for="${escapeXml(node.id)}">`);
|
|
51900
51957
|
parts2.push(` <rect x="${labelBgX}" y="${labelBgY}" width="${labelBgWidth}" height="${labelBgHeight}" rx="6" fill="${theme.labelBadgeFill}" opacity="0.8"/>`);
|
|
51901
|
-
parts2.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !==
|
|
51958
|
+
parts2.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor}">${labelText}</text>`);
|
|
51902
51959
|
parts2.push(` </g>`);
|
|
51903
51960
|
}
|
|
51904
51961
|
function renderPortLabelsForNode(parts2, node, theme, themeName, showPortLabels) {
|
|
@@ -105820,7 +105877,7 @@ function displayInstalledPackage(pkg) {
|
|
|
105820
105877
|
// src/cli/index.ts
|
|
105821
105878
|
init_logger();
|
|
105822
105879
|
init_error_utils();
|
|
105823
|
-
var version2 = true ? "0.17.
|
|
105880
|
+
var version2 = true ? "0.17.11" : "0.0.0-dev";
|
|
105824
105881
|
var program2 = new Command();
|
|
105825
105882
|
program2.name("flow-weaver").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
|
|
105826
105883
|
logger.banner(version2);
|
package/dist/diagram/geometry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isExecutePort, isSuccessPort, isFailurePort, SCOPED_PORT_NAMES, isScopedStartPort, isScopedSuccessPort, isScopedFailurePort } from '../constants.js';
|
|
2
2
|
import { assignImplicitPortOrders } from '../utils/port-ordering.js';
|
|
3
|
-
import { getPortColor, NODE_VARIANT_COLORS, TYPE_ABBREVIATIONS } from './theme.js';
|
|
3
|
+
import { getPortColor, NODE_VARIANT_COLORS, NODE_DEFAULT_COLOR, TYPE_ABBREVIATIONS } from './theme.js';
|
|
4
4
|
import { layoutWorkflow } from './layout.js';
|
|
5
5
|
import { calculateOrthogonalPathSafe, TrackAllocator } from './orthogonal-router.js';
|
|
6
6
|
// ---- Constants (matching React component-node) ----
|
|
@@ -707,7 +707,7 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
707
707
|
diagramNodes.set('Start', {
|
|
708
708
|
id: 'Start',
|
|
709
709
|
label: 'Start',
|
|
710
|
-
color:
|
|
710
|
+
color: NODE_DEFAULT_COLOR,
|
|
711
711
|
icon: 'startNode',
|
|
712
712
|
isVirtual: true,
|
|
713
713
|
inputs: [],
|
|
@@ -731,7 +731,7 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
731
731
|
diagramNodes.set('Exit', {
|
|
732
732
|
id: 'Exit',
|
|
733
733
|
label: 'Exit',
|
|
734
|
-
color:
|
|
734
|
+
color: NODE_DEFAULT_COLOR,
|
|
735
735
|
icon: 'exitNode',
|
|
736
736
|
isVirtual: true,
|
|
737
737
|
inputs: exitInputs,
|
|
@@ -1098,7 +1098,7 @@ function filterNonScopedPorts(ports) {
|
|
|
1098
1098
|
}
|
|
1099
1099
|
function resolveNodeColor(color, theme = 'dark') {
|
|
1100
1100
|
if (!color)
|
|
1101
|
-
return
|
|
1101
|
+
return NODE_DEFAULT_COLOR;
|
|
1102
1102
|
const variant = NODE_VARIANT_COLORS[color];
|
|
1103
1103
|
if (variant)
|
|
1104
1104
|
return theme === 'dark' ? variant.darkBorder : variant.border;
|
package/dist/diagram/renderer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getTheme, getPortColor, getPortRingColor, TYPE_ABBREVIATIONS, NODE_ICON_PATHS } from './theme.js';
|
|
1
|
+
import { getTheme, getPortColor, getPortRingColor, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, NODE_DEFAULT_COLOR } from './theme.js';
|
|
2
2
|
import { PORT_RADIUS, BORDER_RADIUS, LABEL_HEIGHT, LABEL_GAP, SCOPE_PORT_COLUMN, measureText } from './geometry.js';
|
|
3
3
|
function escapeXml(str) {
|
|
4
4
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
@@ -113,10 +113,10 @@ function renderScopeConnection(parts, conn, allConnections, parentNodeId) {
|
|
|
113
113
|
// ---- Node rendering ----
|
|
114
114
|
/** Render node body rect + icon */
|
|
115
115
|
function renderNodeBody(parts, node, theme, indent) {
|
|
116
|
-
const strokeColor = node.color !==
|
|
116
|
+
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
117
117
|
parts.push(`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
|
|
118
118
|
const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
|
|
119
|
-
const iconColor = node.color !==
|
|
119
|
+
const iconColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
120
120
|
const iconSize = 40;
|
|
121
121
|
const iconX = node.x + (node.width - iconSize) / 2;
|
|
122
122
|
const iconY = node.y + (node.height - iconSize) / 2;
|
|
@@ -126,8 +126,8 @@ function renderNode(node, theme, themeName, allConnections) {
|
|
|
126
126
|
const parts = [];
|
|
127
127
|
parts.push(` <g data-node-id="${escapeXml(node.id)}">`);
|
|
128
128
|
if (node.scopeChildren && node.scopeChildren.length > 0) {
|
|
129
|
-
// Scoped node: body rect only (
|
|
130
|
-
const strokeColor = node.color !==
|
|
129
|
+
// Scoped node: body rect only (icon omitted — children occupy the inner area)
|
|
130
|
+
const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
|
|
131
131
|
parts.push(` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
|
|
132
132
|
renderScopedContent(parts, node, theme, themeName, allConnections);
|
|
133
133
|
}
|
|
@@ -178,7 +178,7 @@ function renderNodeLabel(parts, node, theme) {
|
|
|
178
178
|
const labelAnchor = isScoped ? 'start' : 'middle';
|
|
179
179
|
parts.push(` <g data-label-for="${escapeXml(node.id)}">`);
|
|
180
180
|
parts.push(` <rect x="${labelBgX}" y="${labelBgY}" width="${labelBgWidth}" height="${labelBgHeight}" rx="6" fill="${theme.labelBadgeFill}" opacity="0.8"/>`);
|
|
181
|
-
parts.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !==
|
|
181
|
+
parts.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor}">${labelText}</text>`);
|
|
182
182
|
parts.push(` </g>`);
|
|
183
183
|
}
|
|
184
184
|
/** Render port labels for a node if showPortLabels is enabled */
|
package/dist/diagram/theme.d.ts
CHANGED
package/dist/diagram/theme.js
CHANGED
|
@@ -26,16 +26,17 @@ const LIGHT_FAILURE_COLOR = '#e34646'; // red-shade-2
|
|
|
26
26
|
// ---- Node theme variant colors ----
|
|
27
27
|
// Dark: border = X-dark-shade-1 (base), icon = X-dark-shade-3
|
|
28
28
|
// Light: border = X-shade-2
|
|
29
|
+
export const NODE_DEFAULT_COLOR = '#334155';
|
|
29
30
|
export const NODE_VARIANT_COLORS = {
|
|
30
31
|
blue: { border: '#548ce3', darkBorder: '#5e9eff' }, // blue-shade-2 / blue-dark-shade-1
|
|
31
32
|
purple: { border: '#9f5fe3', darkBorder: '#b36bff' }, // purple-shade-2 / purple-dark-shade-1
|
|
32
33
|
cyan: { border: '#63ccc4', darkBorder: '#6fe5dc' }, // cyan-shade-2 / cyan-dark-shade-1
|
|
34
|
+
teal: { border: '#63ccc4', darkBorder: '#6fe5dc' }, // alias for cyan
|
|
33
35
|
orange: { border: '#e3732d', darkBorder: '#ff8133' }, // orange-shade-2 / orange-dark-shade-1
|
|
34
36
|
pink: { border: '#e349c2', darkBorder: '#ff52da' }, // pink-shade-2 / pink-dark-shade-1
|
|
35
37
|
green: { border: '#0ec850', darkBorder: '#10e15a' }, // green-shade-2 / green-dark-shade-1
|
|
36
38
|
red: { border: '#e34646', darkBorder: '#ff4f4f' }, // red-shade-2 / red-dark-shade-1
|
|
37
39
|
yellow: { border: '#e3a82b', darkBorder: '#ffbd30' }, // yellow-shade-2 / yellow-dark-shade-1
|
|
38
|
-
teal: { border: '#3db0a8', darkBorder: '#4dc7be' }, // teal-shade-2 / teal-dark-shade-1
|
|
39
40
|
};
|
|
40
41
|
// ---- Theme palettes (exact values from token system) ----
|
|
41
42
|
const DARK_PALETTE = {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.17.
|
|
1
|
+
export declare const VERSION = "0.17.11";
|
|
2
2
|
//# sourceMappingURL=generated-version.d.ts.map
|
package/dist/jsdoc-parser.js
CHANGED
|
@@ -522,7 +522,7 @@ export class JSDocParser {
|
|
|
522
522
|
if (!result) {
|
|
523
523
|
return;
|
|
524
524
|
}
|
|
525
|
-
const { name, defaultValue, isOptional, scope, order, mergeStrategy, hidden, description } = result;
|
|
525
|
+
const { name, defaultValue, isOptional, scope, order, mergeStrategy, hidden, description, customMetadata } = result;
|
|
526
526
|
// Infer type from signature or scope callback return type
|
|
527
527
|
let type;
|
|
528
528
|
let tsType;
|
|
@@ -599,7 +599,9 @@ export class JSDocParser {
|
|
|
599
599
|
...(scope && { scope }),
|
|
600
600
|
...(mergeStrategy && { mergeStrategy: mergeStrategy }),
|
|
601
601
|
...(hidden && { hidden }),
|
|
602
|
-
...(order !== undefined
|
|
602
|
+
...((order !== undefined || customMetadata) && {
|
|
603
|
+
metadata: { ...(order !== undefined && { order }), ...customMetadata },
|
|
604
|
+
}),
|
|
603
605
|
...(tsType && { tsType }),
|
|
604
606
|
};
|
|
605
607
|
}
|
|
@@ -613,7 +615,7 @@ export class JSDocParser {
|
|
|
613
615
|
if (!result) {
|
|
614
616
|
return;
|
|
615
617
|
}
|
|
616
|
-
const { name, scope, order, hidden, description } = result;
|
|
618
|
+
const { name, scope, order, hidden, description, customMetadata } = result;
|
|
617
619
|
// Infer type from return type or scope callback parameter
|
|
618
620
|
let type;
|
|
619
621
|
let tsType;
|
|
@@ -683,7 +685,9 @@ export class JSDocParser {
|
|
|
683
685
|
label: description?.trim(),
|
|
684
686
|
...(scope && { scope }),
|
|
685
687
|
...(hidden && { hidden }),
|
|
686
|
-
...(order !== undefined
|
|
688
|
+
...((order !== undefined || customMetadata) && {
|
|
689
|
+
metadata: { ...(order !== undefined && { order }), ...customMetadata },
|
|
690
|
+
}),
|
|
687
691
|
...(tsType && { tsType }),
|
|
688
692
|
};
|
|
689
693
|
}
|
|
@@ -727,7 +731,7 @@ export class JSDocParser {
|
|
|
727
731
|
if (!result) {
|
|
728
732
|
return;
|
|
729
733
|
}
|
|
730
|
-
const { name, order, description } = result;
|
|
734
|
+
const { name, order, description, customMetadata } = result;
|
|
731
735
|
// Infer type from return type signature
|
|
732
736
|
let type = 'ANY';
|
|
733
737
|
if (isSuccessPort(name) || isFailurePort(name)) {
|
|
@@ -753,7 +757,9 @@ export class JSDocParser {
|
|
|
753
757
|
config.returnPorts[name] = {
|
|
754
758
|
dataType: type,
|
|
755
759
|
label: description?.trim(),
|
|
756
|
-
...(order !== undefined
|
|
760
|
+
...((order !== undefined || customMetadata) && {
|
|
761
|
+
metadata: { ...(order !== undefined && { order }), ...customMetadata },
|
|
762
|
+
}),
|
|
757
763
|
};
|
|
758
764
|
}
|
|
759
765
|
/**
|
|
@@ -481,7 +481,7 @@ These annotations go on `@flowWeaver nodeType` blocks:
|
|
|
481
481
|
| `@name` | Override display name | `@name MyCustomName` |
|
|
482
482
|
| `@label` | Human-readable label | `@label Fetch with Timeout` |
|
|
483
483
|
| `@description` | Node description | `@description Validates expense data` |
|
|
484
|
-
| `@color` | Custom color | `@color "#ff6b35"` |
|
|
484
|
+
| `@color` | Custom color | `@color purple` or `@color "#ff6b35"` |
|
|
485
485
|
| `@icon` | Custom icon | `@icon "database"` |
|
|
486
486
|
| `@tag` | Visual tag/badge | `@tag async` or `@tag beta "Experimental"` |
|
|
487
487
|
| `@scope` | Provides a named scope | `@scope processItem` |
|
|
@@ -491,6 +491,42 @@ These annotations go on `@flowWeaver nodeType` blocks:
|
|
|
491
491
|
|
|
492
492
|
---
|
|
493
493
|
|
|
494
|
+
## Available Colors
|
|
495
|
+
|
|
496
|
+
Named colors adapt to the diagram theme (dark/light). You can also pass any hex color directly (e.g. `@color "#ff6b35"`).
|
|
497
|
+
|
|
498
|
+
`blue` · `purple` · `cyan` · `orange` · `pink` · `green` · `red` · `yellow` · `teal` (alias for cyan)
|
|
499
|
+
|
|
500
|
+
## Available Icons
|
|
501
|
+
|
|
502
|
+
Icons render inside the node body in SVG diagrams. Names correspond to Material Symbols (outlined, weight 500).
|
|
503
|
+
|
|
504
|
+
**AI & ML:** `psychology` · `smartToy` · `autoAwesome` · `modelTraining` · `science` · `biotech`
|
|
505
|
+
|
|
506
|
+
**Data & storage:** `database` · `dataObject` · `tableChart` · `token` · `storage` · `memory`
|
|
507
|
+
|
|
508
|
+
**Cloud & network:** `api` · `webhook` · `cloudSync` · `cloudUpload` · `cloudDownload` · `dns` · `router` · `http` · `link`
|
|
509
|
+
|
|
510
|
+
**Security & auth:** `key` · `shield` · `vpnKey` · `verified` · `security` · `policy` · `adminPanelSettings`
|
|
511
|
+
|
|
512
|
+
**Logic & flow:** `altRoute` · `callSplit` · `callMerge` · `rule` · `filterAlt` · `repeat` · `sort`
|
|
513
|
+
|
|
514
|
+
**Actions & status:** `bolt` · `build` · `rocketLaunch` · `send` · `sync` · `refresh`
|
|
515
|
+
|
|
516
|
+
**Communication:** `notifications` · `email` · `campaign`
|
|
517
|
+
|
|
518
|
+
**Scheduling:** `event` · `schedule` · `timer`
|
|
519
|
+
|
|
520
|
+
**General tools:** `terminal` · `settings` · `tune` · `search` · `save` · `upload` · `download` · `edit` · `delete`
|
|
521
|
+
|
|
522
|
+
**Status:** `checkCircle` · `error` · `warning` · `info` · `help` · `visibility`
|
|
523
|
+
|
|
524
|
+
**Files:** `folder` · `description` · `attachFile`
|
|
525
|
+
|
|
526
|
+
**Structural:** `code` (default) · `flow` (workflow nodes) · `startNode` · `exitNode`
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
494
530
|
## Related Topics
|
|
495
531
|
|
|
496
532
|
- [Concepts](concepts) — Core workflow fundamentals
|
|
@@ -137,6 +137,7 @@ Expression nodes are pure functions where:
|
|
|
137
137
|
- Primitive/array return -> single output port
|
|
138
138
|
- Object return `{ a, b }` -> one port per property
|
|
139
139
|
- Best for: transformers, math, utilities, data mapping, async fetchers, API calls
|
|
140
|
+
- Optional `@color` and `@icon` annotations customize the node's appearance in SVG diagrams (see `advanced-annotations` for available values)
|
|
140
141
|
|
|
141
142
|
> **Start with expression mode.** Only switch to normal mode when you need to return data alongside a failure (error-with-data patterns) or for void side-effect functions. Expression nodes handle success/failure branching automatically — throw to trigger the `onFailure` path.
|
|
142
143
|
|
|
@@ -244,7 +244,7 @@ Multiple attribute brackets are allowed (zero or more). Attributes can be split
|
|
|
244
244
|
@node myAdd Add [minimized, label: "Compact"]
|
|
245
245
|
@node myAdd Add [pullExecution: trigger]
|
|
246
246
|
@node myAdd Add [size: 200 150]
|
|
247
|
-
@node myAdd Add [color: "
|
|
247
|
+
@node myAdd Add [color: "red", icon: "database"]
|
|
248
248
|
@node myAdd Add [tags: "math" "Math operation", "transform"]
|
|
249
249
|
@node myAdd Add [position: 180 0]
|
|
250
250
|
@node myAdd Add [label: "hi"] [color: "#f00"] [position: 360 0]
|
package/package.json
CHANGED