@fluidgrids/workflows 0.0.0-stage → 2026.1027.1
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/LICENSE +9 -0
- package/README.md +208 -2
- package/dist/assemble-CrpUyd_3.d.ts +587 -0
- package/dist/assemble-DEf3znGD.d.cts +587 -0
- package/dist/chunk-3M34AUIY.cjs +27 -0
- package/dist/chunk-5AW745OG.js +25 -0
- package/dist/chunk-5LUIDMF4.js +42 -0
- package/dist/chunk-6AIAC2FP.cjs +185 -0
- package/dist/chunk-6BEW4QD6.js +95 -0
- package/dist/chunk-6U446SKY.js +263 -0
- package/dist/chunk-7YR7DI7B.cjs +274 -0
- package/dist/chunk-CSYBNN3V.cjs +252 -0
- package/dist/chunk-E3APHA6O.cjs +199 -0
- package/dist/chunk-EEAIM35V.js +748 -0
- package/dist/chunk-G4UEPUGO.cjs +46 -0
- package/dist/chunk-IHKXLG6I.js +246 -0
- package/dist/chunk-MBBKGD7K.js +440 -0
- package/dist/chunk-OSPTJCDI.cjs +102 -0
- package/dist/chunk-TQF7MYEN.cjs +771 -0
- package/dist/chunk-TWOYB4Y7.cjs +76 -0
- package/dist/chunk-UB2BHU2M.js +174 -0
- package/dist/chunk-UJNHTS6D.js +181 -0
- package/dist/chunk-UWQWD7BP.cjs +931 -0
- package/dist/chunk-W32BSO3M.js +74 -0
- package/dist/chunk-XBIID5DY.js +893 -0
- package/dist/chunk-Y7NWR3WH.cjs +450 -0
- package/dist/codegen/index.cjs +18 -0
- package/dist/codegen/index.d.cts +15 -0
- package/dist/codegen/index.d.ts +15 -0
- package/dist/codegen/index.js +5 -0
- package/dist/expressions-DhHaqyar.d.cts +62 -0
- package/dist/expressions-DhHaqyar.d.ts +62 -0
- package/dist/hash-CZkTXPCX.d.cts +15 -0
- package/dist/hash-CZkTXPCX.d.ts +15 -0
- package/dist/index.cjs +117 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +4 -0
- package/dist/ir/index.cjs +1246 -0
- package/dist/ir/index.d.cts +838 -0
- package/dist/ir/index.d.ts +838 -0
- package/dist/ir/index.js +1122 -0
- package/dist/lower-CXggJTIo.d.ts +67 -0
- package/dist/lower-DAzvsJCo.d.cts +67 -0
- package/dist/manifest-Bp9ZJlav.d.ts +60 -0
- package/dist/manifest-Duf-gHdO.d.cts +60 -0
- package/dist/node-evaluator-CH3XCJND.cjs +17 -0
- package/dist/node-evaluator-TULXA3WE.js +8 -0
- package/dist/quickjs/index.cjs +46 -0
- package/dist/quickjs/index.d.cts +18 -0
- package/dist/quickjs/index.d.ts +18 -0
- package/dist/quickjs/index.js +44 -0
- package/dist/roundtrip/index.cjs +1448 -0
- package/dist/roundtrip/index.d.cts +290 -0
- package/dist/roundtrip/index.d.ts +290 -0
- package/dist/roundtrip/index.js +1397 -0
- package/dist/types-Dr2Fn1Ax.d.cts +225 -0
- package/dist/types-Dr2Fn1Ax.d.ts +225 -0
- package/package.json +143 -4
- package/schema/ir-v2.schema.json +655 -0
|
@@ -0,0 +1,931 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkOSPTJCDI_cjs = require('./chunk-OSPTJCDI.cjs');
|
|
4
|
+
var chunk6AIAC2FP_cjs = require('./chunk-6AIAC2FP.cjs');
|
|
5
|
+
var chunkCSYBNN3V_cjs = require('./chunk-CSYBNN3V.cjs');
|
|
6
|
+
var chunkE3APHA6O_cjs = require('./chunk-E3APHA6O.cjs');
|
|
7
|
+
var standalone = require('prettier/standalone');
|
|
8
|
+
var prettierPluginEstree = require('prettier/plugins/estree');
|
|
9
|
+
var prettierPluginTypescript = require('prettier/plugins/typescript');
|
|
10
|
+
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function (k) {
|
|
16
|
+
if (k !== 'default') {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return e[k]; }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var prettierPluginEstree__namespace = /*#__PURE__*/_interopNamespace(prettierPluginEstree);
|
|
30
|
+
var prettierPluginTypescript__namespace = /*#__PURE__*/_interopNamespace(prettierPluginTypescript);
|
|
31
|
+
|
|
32
|
+
// src/roundtrip/naming.ts
|
|
33
|
+
var TS_RESERVED = /* @__PURE__ */ new Set([
|
|
34
|
+
"arguments",
|
|
35
|
+
"await",
|
|
36
|
+
"break",
|
|
37
|
+
"case",
|
|
38
|
+
"catch",
|
|
39
|
+
"class",
|
|
40
|
+
"const",
|
|
41
|
+
"continue",
|
|
42
|
+
"debugger",
|
|
43
|
+
"default",
|
|
44
|
+
"delete",
|
|
45
|
+
"do",
|
|
46
|
+
"else",
|
|
47
|
+
"enum",
|
|
48
|
+
"eval",
|
|
49
|
+
"export",
|
|
50
|
+
"extends",
|
|
51
|
+
"false",
|
|
52
|
+
"finally",
|
|
53
|
+
"for",
|
|
54
|
+
"function",
|
|
55
|
+
"if",
|
|
56
|
+
"implements",
|
|
57
|
+
"import",
|
|
58
|
+
"in",
|
|
59
|
+
"instanceof",
|
|
60
|
+
"interface",
|
|
61
|
+
"let",
|
|
62
|
+
"new",
|
|
63
|
+
"null",
|
|
64
|
+
"package",
|
|
65
|
+
"private",
|
|
66
|
+
"protected",
|
|
67
|
+
"public",
|
|
68
|
+
"return",
|
|
69
|
+
"static",
|
|
70
|
+
"super",
|
|
71
|
+
"switch",
|
|
72
|
+
"this",
|
|
73
|
+
"throw",
|
|
74
|
+
"true",
|
|
75
|
+
"try",
|
|
76
|
+
"typeof",
|
|
77
|
+
"undefined",
|
|
78
|
+
"var",
|
|
79
|
+
"void",
|
|
80
|
+
"while",
|
|
81
|
+
"with",
|
|
82
|
+
"yield"
|
|
83
|
+
]);
|
|
84
|
+
var PY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
85
|
+
"False",
|
|
86
|
+
"None",
|
|
87
|
+
"True",
|
|
88
|
+
"and",
|
|
89
|
+
"as",
|
|
90
|
+
"assert",
|
|
91
|
+
"async",
|
|
92
|
+
"await",
|
|
93
|
+
"break",
|
|
94
|
+
"class",
|
|
95
|
+
"continue",
|
|
96
|
+
"def",
|
|
97
|
+
"del",
|
|
98
|
+
"elif",
|
|
99
|
+
"else",
|
|
100
|
+
"except",
|
|
101
|
+
"finally",
|
|
102
|
+
"for",
|
|
103
|
+
"from",
|
|
104
|
+
"global",
|
|
105
|
+
"if",
|
|
106
|
+
"import",
|
|
107
|
+
"in",
|
|
108
|
+
"is",
|
|
109
|
+
"lambda",
|
|
110
|
+
"nonlocal",
|
|
111
|
+
"not",
|
|
112
|
+
"or",
|
|
113
|
+
"pass",
|
|
114
|
+
"raise",
|
|
115
|
+
"return",
|
|
116
|
+
"try",
|
|
117
|
+
"while",
|
|
118
|
+
"with",
|
|
119
|
+
"yield"
|
|
120
|
+
]);
|
|
121
|
+
var TS_TAKEN = /* @__PURE__ */ new Set([
|
|
122
|
+
"wf",
|
|
123
|
+
"n",
|
|
124
|
+
"nodes",
|
|
125
|
+
"triggers",
|
|
126
|
+
"expr",
|
|
127
|
+
"edge",
|
|
128
|
+
"and",
|
|
129
|
+
"or",
|
|
130
|
+
"defineWorkflow"
|
|
131
|
+
]);
|
|
132
|
+
var PY_TAKEN = /* @__PURE__ */ new Set([
|
|
133
|
+
"wf",
|
|
134
|
+
"n",
|
|
135
|
+
"nodes",
|
|
136
|
+
"triggers",
|
|
137
|
+
"expr",
|
|
138
|
+
"edge",
|
|
139
|
+
"and_",
|
|
140
|
+
"or_",
|
|
141
|
+
"define_workflow"
|
|
142
|
+
]);
|
|
143
|
+
function words(text) {
|
|
144
|
+
return text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
145
|
+
}
|
|
146
|
+
function camelCase(text) {
|
|
147
|
+
const parts = words(text).map((word) => word.toLowerCase());
|
|
148
|
+
const joined = parts.map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
149
|
+
return joined;
|
|
150
|
+
}
|
|
151
|
+
function snakeCase(text) {
|
|
152
|
+
return words(text).map((word) => word.toLowerCase()).join("_");
|
|
153
|
+
}
|
|
154
|
+
function safeTsIdentifier(base, fallbackPrefix) {
|
|
155
|
+
let name = base || fallbackPrefix;
|
|
156
|
+
if (/^[0-9]/.test(name))
|
|
157
|
+
name = `${fallbackPrefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
158
|
+
return name;
|
|
159
|
+
}
|
|
160
|
+
function safePyIdentifier(base, fallbackPrefix) {
|
|
161
|
+
let name = base || fallbackPrefix;
|
|
162
|
+
if (/^[0-9]/.test(name)) name = `${fallbackPrefix}_${name}`;
|
|
163
|
+
return name;
|
|
164
|
+
}
|
|
165
|
+
var NameAllocator = class {
|
|
166
|
+
constructor(language) {
|
|
167
|
+
this.language = language;
|
|
168
|
+
}
|
|
169
|
+
language;
|
|
170
|
+
used = /* @__PURE__ */ new Set();
|
|
171
|
+
/** A unique variable name for a node id. */
|
|
172
|
+
forNode(nodeId) {
|
|
173
|
+
const base = this.language === "ts" ? safeTsIdentifier(camelCase(nodeId), "node") : safePyIdentifier(snakeCase(nodeId), "node");
|
|
174
|
+
const reserved = this.language === "ts" ? TS_RESERVED : PY_KEYWORDS;
|
|
175
|
+
const taken = this.language === "ts" ? TS_TAKEN : PY_TAKEN;
|
|
176
|
+
let name = reserved.has(base) || taken.has(base) ? this.language === "ts" ? `${base}Node` : `${base}_node` : base;
|
|
177
|
+
const stem = name;
|
|
178
|
+
for (let suffix = 2; this.used.has(name); suffix++)
|
|
179
|
+
name = this.language === "ts" ? `${stem}${suffix}` : `${stem}_${suffix}`;
|
|
180
|
+
this.used.add(name);
|
|
181
|
+
return name;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
function tsWorkflowName(key) {
|
|
185
|
+
const name = safeTsIdentifier(camelCase(key), "workflow");
|
|
186
|
+
return TS_RESERVED.has(name) || TS_TAKEN.has(name) ? `${name}Workflow` : name;
|
|
187
|
+
}
|
|
188
|
+
function pyWorkflowName(key) {
|
|
189
|
+
const name = safePyIdentifier(snakeCase(key), "workflow");
|
|
190
|
+
return PY_KEYWORDS.has(name) || PY_TAKEN.has(name) ? `${name}_workflow` : name;
|
|
191
|
+
}
|
|
192
|
+
function groupBase(nodeType) {
|
|
193
|
+
const [namespace, name] = nodeType.includes("/") ? nodeType.split("/", 2) : ["", nodeType];
|
|
194
|
+
return namespace === "store" || namespace === "" ? name ?? nodeType : `${namespace}-${name ?? ""}`;
|
|
195
|
+
}
|
|
196
|
+
function clientNames(manifests) {
|
|
197
|
+
const latest = /* @__PURE__ */ new Map();
|
|
198
|
+
for (const manifest of manifests) {
|
|
199
|
+
if (typeof manifest.nodeType !== "string" || manifest.nodeType.startsWith("internal:"))
|
|
200
|
+
continue;
|
|
201
|
+
const current = latest.get(manifest.nodeType);
|
|
202
|
+
if (!current || chunkOSPTJCDI_cjs.compareVersions(manifest.nodeVersion, current.nodeVersion) > 0)
|
|
203
|
+
latest.set(manifest.nodeType, manifest);
|
|
204
|
+
}
|
|
205
|
+
const usedTs = /* @__PURE__ */ new Set(["internal", "custom"]);
|
|
206
|
+
const usedPy = /* @__PURE__ */ new Set(["internal", "custom"]);
|
|
207
|
+
const out = /* @__PURE__ */ new Map();
|
|
208
|
+
for (const nodeType of [...latest.keys()].sort()) {
|
|
209
|
+
const manifest = latest.get(nodeType);
|
|
210
|
+
const base = groupBase(nodeType);
|
|
211
|
+
let ts = safeTsIdentifier(camelCase(base), "node");
|
|
212
|
+
let py = safePyIdentifier(snakeCase(base), "node");
|
|
213
|
+
if (PY_KEYWORDS.has(py)) py = `${py}_`;
|
|
214
|
+
const tsStem = ts;
|
|
215
|
+
const pyStem = py;
|
|
216
|
+
for (let suffix = 2; usedTs.has(ts); suffix++) ts = `${tsStem}${suffix}`;
|
|
217
|
+
for (let suffix = 2; usedPy.has(py); suffix++) py = `${pyStem}_${suffix}`;
|
|
218
|
+
usedTs.add(ts);
|
|
219
|
+
usedPy.add(py);
|
|
220
|
+
const operations = /* @__PURE__ */ new Map();
|
|
221
|
+
const opTs = /* @__PURE__ */ new Set();
|
|
222
|
+
const opPy = /* @__PURE__ */ new Set();
|
|
223
|
+
for (const operation of chunkOSPTJCDI_cjs.operationsOf(manifest)) {
|
|
224
|
+
if (operations.has(operation.name)) continue;
|
|
225
|
+
let tsName = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(operation.name) ? operation.name : safeTsIdentifier(camelCase(operation.name), "op");
|
|
226
|
+
let pyName = safePyIdentifier(snakeCase(operation.name), "op");
|
|
227
|
+
if (PY_KEYWORDS.has(pyName)) pyName = `${pyName}_`;
|
|
228
|
+
const tsBase = tsName;
|
|
229
|
+
const pyBase = pyName;
|
|
230
|
+
for (let suffix = 2; opTs.has(tsName); suffix++) tsName = `${tsBase}${suffix}`;
|
|
231
|
+
for (let suffix = 2; opPy.has(pyName); suffix++) pyName = `${pyBase}_${suffix}`;
|
|
232
|
+
opTs.add(tsName);
|
|
233
|
+
opPy.add(pyName);
|
|
234
|
+
operations.set(operation.name, { ts: tsName, py: pyName });
|
|
235
|
+
}
|
|
236
|
+
out.set(nodeType, { nodeType, version: manifest.nodeVersion, ts, py, operations });
|
|
237
|
+
}
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/roundtrip/py-format.ts
|
|
242
|
+
var PY_LINE_LENGTH = 88;
|
|
243
|
+
var INDENT = " ";
|
|
244
|
+
function displayWidth(text) {
|
|
245
|
+
let width = 0;
|
|
246
|
+
for (const char of text) {
|
|
247
|
+
const code = char.codePointAt(0) ?? 0;
|
|
248
|
+
const wide = code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 && code !== 12351 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65103 || code >= 65280 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 128591 || code >= 129280 && code <= 129535 || code >= 131072 && code <= 262141;
|
|
249
|
+
width += wide ? 2 : 1;
|
|
250
|
+
}
|
|
251
|
+
return width;
|
|
252
|
+
}
|
|
253
|
+
function escapeBody(text, quote) {
|
|
254
|
+
let out = "";
|
|
255
|
+
for (const char of text) {
|
|
256
|
+
const code = char.codePointAt(0) ?? 0;
|
|
257
|
+
if (char === "\\") out += "\\\\";
|
|
258
|
+
else if (char === quote) out += `\\${quote}`;
|
|
259
|
+
else if (char === "\n") out += "\\n";
|
|
260
|
+
else if (char === "\r") out += "\\r";
|
|
261
|
+
else if (char === " ") out += "\\t";
|
|
262
|
+
else if (code < 32 || code === 127) out += `\\x${code.toString(16).padStart(2, "0")}`;
|
|
263
|
+
else if (code === 8232 || code === 8233 || code >= 128 && code <= 159 || code >= 55296 && code <= 57343) {
|
|
264
|
+
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
265
|
+
} else out += char;
|
|
266
|
+
}
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
function backslashes(text) {
|
|
270
|
+
let count = 0;
|
|
271
|
+
for (const char of text) if (char === "\\") count++;
|
|
272
|
+
return count;
|
|
273
|
+
}
|
|
274
|
+
function pyString(text) {
|
|
275
|
+
const double = escapeBody(text, '"');
|
|
276
|
+
const single = escapeBody(text, "'");
|
|
277
|
+
return backslashes(single) < backslashes(double) ? `'${single}'` : `"${double}"`;
|
|
278
|
+
}
|
|
279
|
+
function pyNumber(value) {
|
|
280
|
+
return String(value);
|
|
281
|
+
}
|
|
282
|
+
function flatElement(element) {
|
|
283
|
+
return element.kind === "keyword" ? `${element.name}=${flat(element.value)}` : flat(element.value);
|
|
284
|
+
}
|
|
285
|
+
function flat(expression) {
|
|
286
|
+
switch (expression.t) {
|
|
287
|
+
case "atom":
|
|
288
|
+
return expression.text;
|
|
289
|
+
case "call":
|
|
290
|
+
return `${flat(expression.func)}(${expression.args.map(flatElement).join(", ")})`;
|
|
291
|
+
case "dict":
|
|
292
|
+
return `{${expression.entries.map(([key, value]) => `${flat(key)}: ${flat(value)}`).join(", ")}}`;
|
|
293
|
+
case "list":
|
|
294
|
+
return `[${expression.items.map(flat).join(", ")}]`;
|
|
295
|
+
case "subscript":
|
|
296
|
+
return `${flat(expression.base)}[${expression.indices.map(flat).join(", ")}]`;
|
|
297
|
+
case "attr":
|
|
298
|
+
return `${flat(expression.base)}.${expression.name}`;
|
|
299
|
+
case "compare":
|
|
300
|
+
return `${flat(expression.left)} ${expression.op} ${flat(expression.right)}`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function bracketsOf(expression) {
|
|
304
|
+
switch (expression.t) {
|
|
305
|
+
case "call":
|
|
306
|
+
return {
|
|
307
|
+
open: `${flat(expression.func)}(`,
|
|
308
|
+
close: ")",
|
|
309
|
+
elements: expression.args.map((element) => ({
|
|
310
|
+
prefix: element.kind === "keyword" ? `${element.name}=` : "",
|
|
311
|
+
value: element.value
|
|
312
|
+
})),
|
|
313
|
+
collection: false
|
|
314
|
+
};
|
|
315
|
+
case "dict":
|
|
316
|
+
return {
|
|
317
|
+
open: "{",
|
|
318
|
+
close: "}",
|
|
319
|
+
elements: expression.entries.map(([key, value]) => ({ prefix: `${flat(key)}: `, value })),
|
|
320
|
+
collection: true
|
|
321
|
+
};
|
|
322
|
+
case "list":
|
|
323
|
+
return {
|
|
324
|
+
open: "[",
|
|
325
|
+
close: "]",
|
|
326
|
+
elements: expression.items.map((value) => ({ prefix: "", value })),
|
|
327
|
+
collection: true
|
|
328
|
+
};
|
|
329
|
+
case "subscript":
|
|
330
|
+
return {
|
|
331
|
+
open: `${flat(expression.base)}[`,
|
|
332
|
+
close: "]",
|
|
333
|
+
elements: expression.indices.map((value) => ({ prefix: "", value })),
|
|
334
|
+
collection: false
|
|
335
|
+
};
|
|
336
|
+
default:
|
|
337
|
+
return void 0;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function formatLines(prefix, expression, suffix, depth) {
|
|
341
|
+
const indent = INDENT.repeat(depth);
|
|
342
|
+
const single = `${indent}${prefix}${flat(expression)}${suffix}`;
|
|
343
|
+
if (displayWidth(single) <= PY_LINE_LENGTH) return [single];
|
|
344
|
+
const brackets = bracketsOf(expression);
|
|
345
|
+
if (!brackets || brackets.elements.length === 0) {
|
|
346
|
+
const inner2 = `${INDENT.repeat(depth + 1)}${flat(expression)}`;
|
|
347
|
+
if (prefix.endsWith(" = ") && suffix === "" && displayWidth(inner2) <= PY_LINE_LENGTH) {
|
|
348
|
+
return [`${indent}${prefix}(`, inner2, `${indent})`];
|
|
349
|
+
}
|
|
350
|
+
return [single];
|
|
351
|
+
}
|
|
352
|
+
const inner = INDENT.repeat(depth + 1);
|
|
353
|
+
const body = brackets.elements.map(({ prefix: elementPrefix, value }) => `${elementPrefix}${flat(value)}`).join(", ");
|
|
354
|
+
const head = `${indent}${prefix}${brackets.open}`;
|
|
355
|
+
const tail = `${indent}${brackets.close}${suffix}`;
|
|
356
|
+
const mustExplode = brackets.collection && brackets.elements.length > 1;
|
|
357
|
+
if (!mustExplode && displayWidth(`${inner}${body}`) <= PY_LINE_LENGTH)
|
|
358
|
+
return [head, `${inner}${body}`, tail];
|
|
359
|
+
if (brackets.elements.length === 1) {
|
|
360
|
+
const [only] = brackets.elements;
|
|
361
|
+
return only ? [head, ...formatLines(only.prefix, only.value, "", depth + 1), tail] : [single];
|
|
362
|
+
}
|
|
363
|
+
return [
|
|
364
|
+
head,
|
|
365
|
+
...brackets.elements.flatMap(
|
|
366
|
+
({ prefix: elementPrefix, value }) => formatLines(elementPrefix, value, ",", depth + 1)
|
|
367
|
+
),
|
|
368
|
+
tail
|
|
369
|
+
];
|
|
370
|
+
}
|
|
371
|
+
function formatImport(module, names) {
|
|
372
|
+
const single = `from ${module} import ${names.join(", ")}`;
|
|
373
|
+
if (displayWidth(single) <= PY_LINE_LENGTH) return [single];
|
|
374
|
+
return [`from ${module} import (`, ...names.map((name) => `${INDENT}${name},`), ")"];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/roundtrip/references.ts
|
|
378
|
+
function refNodes(ref, out) {
|
|
379
|
+
if (ref.target.kind === "node") out.add(ref.target.nodeId);
|
|
380
|
+
}
|
|
381
|
+
function collect(expression, out) {
|
|
382
|
+
switch (expression.k) {
|
|
383
|
+
case "object":
|
|
384
|
+
for (const [, child] of expression.entries) collect(child, out);
|
|
385
|
+
return;
|
|
386
|
+
case "array":
|
|
387
|
+
for (const item of expression.items) collect(item, out);
|
|
388
|
+
return;
|
|
389
|
+
case "ref":
|
|
390
|
+
refNodes(expression.ref, out);
|
|
391
|
+
return;
|
|
392
|
+
case "template":
|
|
393
|
+
for (const part of expression.parts) if ("ref" in part) refNodes(part.ref, out);
|
|
394
|
+
return;
|
|
395
|
+
case "rule":
|
|
396
|
+
refNodes(expression.ref, out);
|
|
397
|
+
return;
|
|
398
|
+
case "group":
|
|
399
|
+
for (const child of expression.children) collect(child, out);
|
|
400
|
+
return;
|
|
401
|
+
case "node":
|
|
402
|
+
case "handle":
|
|
403
|
+
out.add(expression.nodeId);
|
|
404
|
+
return;
|
|
405
|
+
case "edge":
|
|
406
|
+
collect(expression.from, out);
|
|
407
|
+
for (const [, child] of expression.options) collect(child, out);
|
|
408
|
+
return;
|
|
409
|
+
case "literal":
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function referencedLater(plan) {
|
|
414
|
+
const declaredAt = /* @__PURE__ */ new Map();
|
|
415
|
+
plan.statements.forEach((statement, index) => {
|
|
416
|
+
if (statement.kind === "node") declaredAt.set(statement.nodeId, index);
|
|
417
|
+
});
|
|
418
|
+
const needed = /* @__PURE__ */ new Set();
|
|
419
|
+
plan.statements.forEach((statement, index) => {
|
|
420
|
+
const used = /* @__PURE__ */ new Set();
|
|
421
|
+
if (statement.kind === "node")
|
|
422
|
+
for (const [, option] of statement.options) collect(option, used);
|
|
423
|
+
else if (statement.kind === "connect") {
|
|
424
|
+
collect(statement.from, used);
|
|
425
|
+
for (const [, option] of statement.options) collect(option, used);
|
|
426
|
+
}
|
|
427
|
+
for (const nodeId of used) {
|
|
428
|
+
const at = declaredAt.get(nodeId);
|
|
429
|
+
if (at !== void 0 && at < index) needed.add(nodeId);
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
return [...declaredAt.keys()].filter((nodeId) => needed.has(nodeId));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/roundtrip/render-ts.ts
|
|
436
|
+
var TS_FORMAT_OPTIONS = {
|
|
437
|
+
parser: "typescript",
|
|
438
|
+
printWidth: 100,
|
|
439
|
+
singleQuote: true,
|
|
440
|
+
trailingComma: "all",
|
|
441
|
+
semi: true,
|
|
442
|
+
tabWidth: 2,
|
|
443
|
+
useTabs: false,
|
|
444
|
+
bracketSpacing: true,
|
|
445
|
+
arrowParens: "always"
|
|
446
|
+
};
|
|
447
|
+
var TS_NODES_IMPORT = "../.fluidgrids/nodes";
|
|
448
|
+
function str(text) {
|
|
449
|
+
return JSON.stringify(text);
|
|
450
|
+
}
|
|
451
|
+
function propertyKey(key) {
|
|
452
|
+
if (key === "__proto__") return `[${str(key)}]`;
|
|
453
|
+
return chunkE3APHA6O_cjs.isJsIdentifier(key) ? key : str(key);
|
|
454
|
+
}
|
|
455
|
+
function nodeSource(nodeId, ctx) {
|
|
456
|
+
const name = ctx.vars.get(nodeId);
|
|
457
|
+
return name !== void 0 && ctx.declared.has(nodeId) ? name : `wf.ref(${str(nodeId)})`;
|
|
458
|
+
}
|
|
459
|
+
function refText(ref, ctx) {
|
|
460
|
+
let text = ref.target.kind === "node" ? `${nodeSource(ref.target.nodeId, ctx)}.output` : `wf.${ref.target.kind}`;
|
|
461
|
+
for (const segment of ref.path) {
|
|
462
|
+
if (segment.kind === "index") text += `[${segment.index}]`;
|
|
463
|
+
else if (chunkE3APHA6O_cjs.isJsIdentifier(segment.key) && !chunk6AIAC2FP_cjs.RESERVED_REF_KEYS.has(segment.key))
|
|
464
|
+
text += `.${segment.key}`;
|
|
465
|
+
else text += `[${str(segment.key)}]`;
|
|
466
|
+
}
|
|
467
|
+
return text;
|
|
468
|
+
}
|
|
469
|
+
function templateText(text) {
|
|
470
|
+
return text.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
471
|
+
}
|
|
472
|
+
function expressionText(expression, ctx) {
|
|
473
|
+
switch (expression.k) {
|
|
474
|
+
case "literal":
|
|
475
|
+
return typeof expression.value === "string" ? str(expression.value) : String(expression.value);
|
|
476
|
+
case "object":
|
|
477
|
+
return `{ ${expression.entries.map(([key, child]) => `${propertyKey(key)}: ${expressionText(child, ctx)}`).join(", ")} }`;
|
|
478
|
+
case "array":
|
|
479
|
+
return `[${expression.items.map((item) => expressionText(item, ctx)).join(", ")}]`;
|
|
480
|
+
case "ref":
|
|
481
|
+
return refText(expression.ref, ctx);
|
|
482
|
+
case "template":
|
|
483
|
+
ctx.used.add("expr");
|
|
484
|
+
return `expr\`${expression.parts.map((part) => "text" in part ? templateText(part.text) : `\${${refText(part.ref, ctx)}}`).join("")}\``;
|
|
485
|
+
case "rule": {
|
|
486
|
+
const target = refText(expression.ref, ctx);
|
|
487
|
+
if (expression.method === "is") {
|
|
488
|
+
return expression.hasValue ? `${target}.is(${str(expression.operator)}, ${JSON.stringify(expression.value)})` : `${target}.is(${str(expression.operator)})`;
|
|
489
|
+
}
|
|
490
|
+
return expression.hasValue ? `${target}.${expression.method}(${JSON.stringify(expression.value)})` : `${target}.${expression.method}()`;
|
|
491
|
+
}
|
|
492
|
+
case "group":
|
|
493
|
+
ctx.used.add(expression.combinator);
|
|
494
|
+
return `${expression.combinator}(${expression.children.map((child) => expressionText(child, ctx)).join(", ")})`;
|
|
495
|
+
case "node":
|
|
496
|
+
return nodeSource(expression.nodeId, ctx);
|
|
497
|
+
case "handle": {
|
|
498
|
+
const source = nodeSource(expression.nodeId, ctx);
|
|
499
|
+
const declared = ctx.declared.has(expression.nodeId) && ctx.vars.has(expression.nodeId);
|
|
500
|
+
if (declared && expression.accessor.kind === "property")
|
|
501
|
+
return `${source}.${expression.accessor.name}`;
|
|
502
|
+
if (declared && expression.accessor.kind === "case")
|
|
503
|
+
return `${source}.case(${str(expression.handle)})`;
|
|
504
|
+
return `${source}.handle(${str(expression.handle)})`;
|
|
505
|
+
}
|
|
506
|
+
case "edge":
|
|
507
|
+
ctx.used.add("edge");
|
|
508
|
+
return `edge(${expressionText(expression.from, ctx)}, ${expressionText({ k: "object", entries: expression.options }, ctx)})`;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
function operationText(operation, ctx) {
|
|
512
|
+
switch (operation.kind) {
|
|
513
|
+
case "trigger":
|
|
514
|
+
ctx.used.add("triggers");
|
|
515
|
+
return `triggers.${operation.name}`;
|
|
516
|
+
case "internal":
|
|
517
|
+
ctx.used.add("nodes");
|
|
518
|
+
return `nodes.internal.${operation.name}`;
|
|
519
|
+
case "client":
|
|
520
|
+
ctx.used.add("n");
|
|
521
|
+
return `n.${operation.group}.${operation.operationKey}`;
|
|
522
|
+
case "custom": {
|
|
523
|
+
ctx.used.add("nodes");
|
|
524
|
+
const args = [str(operation.nodeType)];
|
|
525
|
+
if (operation.operation !== void 0 || operation.version !== void 0) {
|
|
526
|
+
args.push(operation.operation !== void 0 ? str(operation.operation) : "undefined");
|
|
527
|
+
}
|
|
528
|
+
if (operation.version !== void 0) args.push(str(operation.version));
|
|
529
|
+
return `nodes.custom(${args.join(", ")})`;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
function statementText(statement, ctx) {
|
|
534
|
+
if (statement.kind === "edgeOrder")
|
|
535
|
+
return `wf.edgeOrderIs(${expressionText({ k: "array", items: statement.ids.map((id) => ({ k: "literal", value: id })) }, ctx)});`;
|
|
536
|
+
if (statement.kind === "connect") {
|
|
537
|
+
const options = statement.options.length > 0 ? `, ${expressionText({ k: "object", entries: statement.options }, ctx)}` : "";
|
|
538
|
+
return `wf.connect(${expressionText(statement.from, ctx)}, ${str(statement.to)}${options});`;
|
|
539
|
+
}
|
|
540
|
+
const args = [
|
|
541
|
+
...statement.operation ? [operationText(statement.operation, ctx)] : [],
|
|
542
|
+
expressionText({ k: "object", entries: statement.options }, ctx)
|
|
543
|
+
];
|
|
544
|
+
const call = `wf.${statement.method}(${args.join(", ")});`;
|
|
545
|
+
ctx.declared.add(statement.nodeId);
|
|
546
|
+
const name = ctx.vars.get(statement.nodeId);
|
|
547
|
+
return name !== void 0 ? `const ${name} = ${call}` : call;
|
|
548
|
+
}
|
|
549
|
+
async function renderTypeScript(plan, header = []) {
|
|
550
|
+
const allocator = new NameAllocator("ts");
|
|
551
|
+
const vars = /* @__PURE__ */ new Map();
|
|
552
|
+
for (const nodeId of referencedLater(plan)) vars.set(nodeId, allocator.forNode(nodeId));
|
|
553
|
+
const ctx = { vars, declared: /* @__PURE__ */ new Set(), used: /* @__PURE__ */ new Set() };
|
|
554
|
+
const body = plan.statements.map((statement) => statementText(statement, ctx)).join("\n");
|
|
555
|
+
const optionsText = expressionText({ k: "object", entries: plan.workflowOptions }, ctx);
|
|
556
|
+
const sdkImports = [
|
|
557
|
+
"defineWorkflow",
|
|
558
|
+
...["and", "edge", "expr", "nodes", "or", "triggers"].filter((name) => ctx.used.has(name))
|
|
559
|
+
];
|
|
560
|
+
const lines = [
|
|
561
|
+
...header.map((line) => `// ${line}`),
|
|
562
|
+
`import { ${sdkImports.join(", ")} } from '@fluidgrids/workflows';`,
|
|
563
|
+
...ctx.used.has("n") ? [`import { nodes as n } from '${TS_NODES_IMPORT}';`] : [],
|
|
564
|
+
"",
|
|
565
|
+
`export const ${tsWorkflowName(plan.key)} = defineWorkflow(${optionsText}, (wf) => {`,
|
|
566
|
+
body,
|
|
567
|
+
"});",
|
|
568
|
+
""
|
|
569
|
+
];
|
|
570
|
+
return standalone.format(lines.join("\n"), {
|
|
571
|
+
...TS_FORMAT_OPTIONS,
|
|
572
|
+
plugins: [prettierPluginEstree__namespace, prettierPluginTypescript__namespace]
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/codegen/index.ts
|
|
577
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
578
|
+
function registrySnapshotHash(manifests) {
|
|
579
|
+
const projection = manifests.filter((manifest) => typeof manifest.nodeType === "string").map((manifest) => ({
|
|
580
|
+
nodeType: manifest.nodeType,
|
|
581
|
+
nodeVersion: manifest.nodeVersion ?? null,
|
|
582
|
+
operations: chunkOSPTJCDI_cjs.operationsOf(manifest).map((operation) => ({
|
|
583
|
+
name: operation.name,
|
|
584
|
+
type: operation.type ?? null,
|
|
585
|
+
role: operation.role ?? null,
|
|
586
|
+
input_fields: operation.input_fields ?? null,
|
|
587
|
+
output_fields: operation.output_fields ?? null
|
|
588
|
+
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
589
|
+
})).sort(
|
|
590
|
+
(a, b) => a.nodeType === b.nodeType ? String(a.nodeVersion) < String(b.nodeVersion) ? -1 : 1 : a.nodeType < b.nodeType ? -1 : 1
|
|
591
|
+
);
|
|
592
|
+
return chunkCSYBNN3V_cjs.sha256Tagged(chunkCSYBNN3V_cjs.canonicalJson(projection));
|
|
593
|
+
}
|
|
594
|
+
function fieldOf(value) {
|
|
595
|
+
if (typeof value === "string") return { type: value };
|
|
596
|
+
return chunkE3APHA6O_cjs.isRecord(value) ? value : {};
|
|
597
|
+
}
|
|
598
|
+
function stringChoices(field) {
|
|
599
|
+
const choices = Array.isArray(field.enum) ? field.enum : Array.isArray(field.options) ? field.options : void 0;
|
|
600
|
+
return choices && choices.length > 0 && choices.every((choice) => typeof choice === "string") ? choices : void 0;
|
|
601
|
+
}
|
|
602
|
+
function tsType(value, use, depth = 0) {
|
|
603
|
+
const field = fieldOf(value);
|
|
604
|
+
const choices = stringChoices(field);
|
|
605
|
+
if (choices) return choices.map((choice) => JSON.stringify(choice)).join(" | ");
|
|
606
|
+
if (field.format === "binary") {
|
|
607
|
+
use.add("FileRef");
|
|
608
|
+
return "FileRef";
|
|
609
|
+
}
|
|
610
|
+
switch (field.type) {
|
|
611
|
+
case "string":
|
|
612
|
+
case "code":
|
|
613
|
+
case "workflow":
|
|
614
|
+
case "date":
|
|
615
|
+
case "datetime":
|
|
616
|
+
case "time":
|
|
617
|
+
return "string";
|
|
618
|
+
case "integer":
|
|
619
|
+
case "number":
|
|
620
|
+
return "number";
|
|
621
|
+
case "boolean":
|
|
622
|
+
return "boolean";
|
|
623
|
+
case "array": {
|
|
624
|
+
if (field.items !== void 0 && depth < 4)
|
|
625
|
+
return `Array<${tsType(field.items, use, depth + 1)}>`;
|
|
626
|
+
use.add("Json");
|
|
627
|
+
return "Array<Json>";
|
|
628
|
+
}
|
|
629
|
+
case "object":
|
|
630
|
+
if (chunkE3APHA6O_cjs.isRecord(field.properties) && depth < 4)
|
|
631
|
+
return tsObject(field.properties, false, use, depth + 1);
|
|
632
|
+
use.add("Json");
|
|
633
|
+
return "Json";
|
|
634
|
+
default:
|
|
635
|
+
use.add("Json");
|
|
636
|
+
return "Json";
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
function tsKey(name) {
|
|
640
|
+
return IDENTIFIER.test(name) ? name : JSON.stringify(name);
|
|
641
|
+
}
|
|
642
|
+
function tsObject(fields, requiredFromField, use, depth) {
|
|
643
|
+
const entries = Object.entries(fields).map(([name, field]) => {
|
|
644
|
+
const optional = requiredFromField ? fieldOf(field).required !== true : true;
|
|
645
|
+
return `${tsKey(name)}${optional ? "?" : ""}: ${tsType(field, use, depth)}`;
|
|
646
|
+
});
|
|
647
|
+
if (entries.length === 0) {
|
|
648
|
+
use.add("Json");
|
|
649
|
+
return "Record<string, Json>";
|
|
650
|
+
}
|
|
651
|
+
return `{ ${entries.join("; ")} }`;
|
|
652
|
+
}
|
|
653
|
+
function comment(text) {
|
|
654
|
+
if (!text) return "";
|
|
655
|
+
return `/** ${text.replace(/\*\//g, "* /").replace(/\s+/g, " ").trim()} */
|
|
656
|
+
`;
|
|
657
|
+
}
|
|
658
|
+
function tsDescriptor(manifest, operation, use) {
|
|
659
|
+
const input = tsObject(operation.input_fields ?? {}, true, use, 0);
|
|
660
|
+
const output = tsObject(
|
|
661
|
+
// Output fields are type names or field objects; both are handled per value.
|
|
662
|
+
operation.output_fields ?? {},
|
|
663
|
+
false,
|
|
664
|
+
use,
|
|
665
|
+
0
|
|
666
|
+
);
|
|
667
|
+
const factory = chunkOSPTJCDI_cjs.isTriggerOperation(operation) ? "trigger" : "op";
|
|
668
|
+
const version = manifest.nodeVersion !== void 0 ? JSON.stringify(manifest.nodeVersion) : "undefined";
|
|
669
|
+
return `${factory}<${input}, ${output}>(${JSON.stringify(manifest.nodeType)}, ${version}, ${JSON.stringify(operation.name)})`;
|
|
670
|
+
}
|
|
671
|
+
function latestManifests(manifests, names) {
|
|
672
|
+
const out = [];
|
|
673
|
+
for (const [nodeType, client] of names) {
|
|
674
|
+
const manifest = manifests.find(
|
|
675
|
+
(candidate) => candidate.nodeType === nodeType && candidate.nodeVersion === client.version
|
|
676
|
+
);
|
|
677
|
+
if (manifest) out.push([client, manifest]);
|
|
678
|
+
}
|
|
679
|
+
return out;
|
|
680
|
+
}
|
|
681
|
+
async function generateTypeScript(manifests, snapshot) {
|
|
682
|
+
const names = clientNames(manifests);
|
|
683
|
+
const groups = [];
|
|
684
|
+
const triggerGroups = [];
|
|
685
|
+
let usesTrigger = false;
|
|
686
|
+
let usesOp = false;
|
|
687
|
+
const use = /* @__PURE__ */ new Set();
|
|
688
|
+
for (const [client, manifest] of latestManifests(manifests, names)) {
|
|
689
|
+
const members = [];
|
|
690
|
+
const triggerMembers = [];
|
|
691
|
+
for (const operation of chunkOSPTJCDI_cjs.operationsOf(manifest)) {
|
|
692
|
+
const key = client.operations.get(operation.name)?.ts;
|
|
693
|
+
if (!key) continue;
|
|
694
|
+
const descriptor = tsDescriptor(manifest, operation, use);
|
|
695
|
+
members.push(`${comment(operation.description)}${tsKey(key)}: ${descriptor},`);
|
|
696
|
+
if (chunkOSPTJCDI_cjs.isTriggerOperation(operation)) {
|
|
697
|
+
usesTrigger = true;
|
|
698
|
+
triggerMembers.push(`${tsKey(key)}: ${descriptor},`);
|
|
699
|
+
} else usesOp = true;
|
|
700
|
+
}
|
|
701
|
+
groups.push(`${comment(manifest.name)}${tsKey(client.ts)}: {
|
|
702
|
+
${members.join("\n")}
|
|
703
|
+
},`);
|
|
704
|
+
if (triggerMembers.length > 0)
|
|
705
|
+
triggerGroups.push(`${tsKey(client.ts)}: {
|
|
706
|
+
${triggerMembers.join("\n")}
|
|
707
|
+
},`);
|
|
708
|
+
}
|
|
709
|
+
const imports = [
|
|
710
|
+
...usesOp ? ["op"] : [],
|
|
711
|
+
...usesTrigger ? ["trigger"] : [],
|
|
712
|
+
...["FileRef", "Json"].filter((name) => use.has(name)).map((name) => `type ${name}`)
|
|
713
|
+
];
|
|
714
|
+
const source = [
|
|
715
|
+
"// Generated by @fluidgrids/workflows codegen. Do not edit; run `fluidgrids codegen` instead.",
|
|
716
|
+
`// Node registry snapshot ${snapshot}.`,
|
|
717
|
+
...imports.length > 0 ? [`import { ${imports.join(", ")} } from '@fluidgrids/workflows';`] : [],
|
|
718
|
+
"",
|
|
719
|
+
"/** The registry snapshot these clients were generated from. */",
|
|
720
|
+
`export const registrySnapshot = ${JSON.stringify(snapshot)};`,
|
|
721
|
+
"",
|
|
722
|
+
`export const nodes = {
|
|
723
|
+
${groups.join("\n")}
|
|
724
|
+
} as const;`,
|
|
725
|
+
"",
|
|
726
|
+
`export const triggers = {
|
|
727
|
+
${triggerGroups.join("\n")}
|
|
728
|
+
} as const;`,
|
|
729
|
+
""
|
|
730
|
+
].join("\n");
|
|
731
|
+
return standalone.format(source, {
|
|
732
|
+
...TS_FORMAT_OPTIONS,
|
|
733
|
+
plugins: [prettierPluginEstree__namespace, prettierPluginTypescript__namespace]
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
var atom = (text) => ({ t: "atom", text });
|
|
737
|
+
function pyType(value, use, depth = 0) {
|
|
738
|
+
const field = fieldOf(value);
|
|
739
|
+
const choices = stringChoices(field);
|
|
740
|
+
if (choices) {
|
|
741
|
+
use.literal = true;
|
|
742
|
+
return {
|
|
743
|
+
t: "subscript",
|
|
744
|
+
base: atom("Literal"),
|
|
745
|
+
indices: choices.map((choice) => atom(pyString(choice)))
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
if (field.format === "binary") {
|
|
749
|
+
use.fileRef = true;
|
|
750
|
+
return atom("FileRef");
|
|
751
|
+
}
|
|
752
|
+
switch (field.type) {
|
|
753
|
+
case "string":
|
|
754
|
+
case "code":
|
|
755
|
+
case "workflow":
|
|
756
|
+
case "date":
|
|
757
|
+
case "datetime":
|
|
758
|
+
case "time":
|
|
759
|
+
return atom("str");
|
|
760
|
+
case "integer":
|
|
761
|
+
return atom("int");
|
|
762
|
+
case "number":
|
|
763
|
+
return atom("float");
|
|
764
|
+
case "boolean":
|
|
765
|
+
return atom("bool");
|
|
766
|
+
case "array":
|
|
767
|
+
return {
|
|
768
|
+
t: "subscript",
|
|
769
|
+
base: atom("list"),
|
|
770
|
+
indices: [
|
|
771
|
+
field.items !== void 0 && depth < 4 ? pyType(field.items, use, depth + 1) : atom("Json")
|
|
772
|
+
]
|
|
773
|
+
};
|
|
774
|
+
default:
|
|
775
|
+
return atom("Json");
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function pascal(text) {
|
|
779
|
+
return text.split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
780
|
+
}
|
|
781
|
+
function typedDict(name, fields, requiredFromField, use) {
|
|
782
|
+
const entries = Object.entries(fields).map(([fieldName, field]) => {
|
|
783
|
+
const type = pyType(field, use);
|
|
784
|
+
const required = requiredFromField && fieldOf(field).required === true;
|
|
785
|
+
return [
|
|
786
|
+
atom(pyString(fieldName)),
|
|
787
|
+
required ? { t: "subscript", base: atom("Required"), indices: [type] } : type
|
|
788
|
+
];
|
|
789
|
+
});
|
|
790
|
+
const value = {
|
|
791
|
+
t: "call",
|
|
792
|
+
func: atom("TypedDict"),
|
|
793
|
+
args: [
|
|
794
|
+
{ kind: "positional", value: atom(pyString(name)) },
|
|
795
|
+
{ kind: "positional", value: { t: "dict", entries } },
|
|
796
|
+
{ kind: "keyword", name: "total", value: atom("False") }
|
|
797
|
+
]
|
|
798
|
+
};
|
|
799
|
+
return formatLines(`${name} = `, value, "", 0);
|
|
800
|
+
}
|
|
801
|
+
function generatePython(manifests, snapshot) {
|
|
802
|
+
const names = clientNames(manifests);
|
|
803
|
+
const use = { literal: false, fileRef: false };
|
|
804
|
+
const typeBlocks = [];
|
|
805
|
+
const classBlocks = [];
|
|
806
|
+
const nodeAttributes = [];
|
|
807
|
+
const triggerAttributes = [];
|
|
808
|
+
const usedTypeNames = /* @__PURE__ */ new Set();
|
|
809
|
+
let usesOp = false;
|
|
810
|
+
let usesTrigger = false;
|
|
811
|
+
const uniqueTypeName = (base) => {
|
|
812
|
+
let name = base;
|
|
813
|
+
for (let suffix = 2; usedTypeNames.has(name); suffix++) name = `${base}${suffix}`;
|
|
814
|
+
usedTypeNames.add(name);
|
|
815
|
+
return name;
|
|
816
|
+
};
|
|
817
|
+
for (const [client, manifest] of latestManifests(manifests, names)) {
|
|
818
|
+
const className = uniqueTypeName(`_${pascal(client.py)}Nodes`);
|
|
819
|
+
const triggerClassName = uniqueTypeName(`_${pascal(client.py)}Triggers`);
|
|
820
|
+
const body = [];
|
|
821
|
+
const triggerBody = [];
|
|
822
|
+
for (const operation of chunkOSPTJCDI_cjs.operationsOf(manifest)) {
|
|
823
|
+
const opName = client.operations.get(operation.name)?.py;
|
|
824
|
+
if (!opName) continue;
|
|
825
|
+
const stem = `${pascal(client.py)}${pascal(opName)}`;
|
|
826
|
+
const inputName = uniqueTypeName(`${stem}Input`);
|
|
827
|
+
const outputName = uniqueTypeName(`${stem}Output`);
|
|
828
|
+
typeBlocks.push(typedDict(inputName, operation.input_fields ?? {}, true, use));
|
|
829
|
+
typeBlocks.push(
|
|
830
|
+
typedDict(
|
|
831
|
+
outputName,
|
|
832
|
+
// Output fields are type names or field objects; both are handled per value.
|
|
833
|
+
operation.output_fields ?? {},
|
|
834
|
+
false,
|
|
835
|
+
use
|
|
836
|
+
)
|
|
837
|
+
);
|
|
838
|
+
const trigger = chunkOSPTJCDI_cjs.isTriggerOperation(operation);
|
|
839
|
+
if (trigger) usesTrigger = true;
|
|
840
|
+
else usesOp = true;
|
|
841
|
+
const descriptor = {
|
|
842
|
+
t: "call",
|
|
843
|
+
func: atom(trigger ? "trigger" : "op"),
|
|
844
|
+
args: [
|
|
845
|
+
{ kind: "positional", value: atom(pyString(manifest.nodeType)) },
|
|
846
|
+
{
|
|
847
|
+
kind: "positional",
|
|
848
|
+
value: manifest.nodeVersion !== void 0 ? atom(pyString(manifest.nodeVersion)) : atom("None")
|
|
849
|
+
},
|
|
850
|
+
{ kind: "positional", value: atom(pyString(operation.name)) },
|
|
851
|
+
{ kind: "positional", value: atom(inputName) },
|
|
852
|
+
{ kind: "positional", value: atom(outputName) }
|
|
853
|
+
]
|
|
854
|
+
};
|
|
855
|
+
const line = formatLines(`${opName} = `, descriptor, "", 1);
|
|
856
|
+
body.push(...line);
|
|
857
|
+
if (trigger) triggerBody.push(...line);
|
|
858
|
+
}
|
|
859
|
+
classBlocks.push([`class ${className}:`, ...body.length > 0 ? body : [" pass"]]);
|
|
860
|
+
nodeAttributes.push(` ${client.py} = ${className}()`);
|
|
861
|
+
if (triggerBody.length > 0) {
|
|
862
|
+
classBlocks.push([`class ${triggerClassName}:`, ...triggerBody]);
|
|
863
|
+
triggerAttributes.push(` ${client.py} = ${triggerClassName}()`);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
const typing = ["Required", "TypedDict", ...use.literal ? ["Literal"] : []].sort();
|
|
867
|
+
const sdk = [
|
|
868
|
+
"Json",
|
|
869
|
+
...use.fileRef ? ["FileRef"] : [],
|
|
870
|
+
...usesOp ? ["op"] : [],
|
|
871
|
+
...usesTrigger ? ["trigger"] : []
|
|
872
|
+
].sort(
|
|
873
|
+
(a, b) => a.toLowerCase() === b.toLowerCase() ? a < b ? -1 : 1 : a.toLowerCase() < b.toLowerCase() ? -1 : 1
|
|
874
|
+
);
|
|
875
|
+
const sections = [
|
|
876
|
+
...typeBlocks.map((block) => block),
|
|
877
|
+
...classBlocks,
|
|
878
|
+
["class _Nodes:", ...nodeAttributes.length > 0 ? nodeAttributes : [" pass"]],
|
|
879
|
+
["class _Triggers:", ...triggerAttributes.length > 0 ? triggerAttributes : [" pass"]]
|
|
880
|
+
];
|
|
881
|
+
const lines = [
|
|
882
|
+
"# Generated by @fluidgrids/workflows codegen. Do not edit; run `fluidgrids codegen` instead.",
|
|
883
|
+
`# Node registry snapshot ${snapshot}.`,
|
|
884
|
+
...formatImport("typing", typing),
|
|
885
|
+
"",
|
|
886
|
+
...formatImport("fluidgrids_workflows", sdk),
|
|
887
|
+
"",
|
|
888
|
+
...formatLines("REGISTRY_SNAPSHOT = ", atom(pyString(snapshot)), "", 0)
|
|
889
|
+
];
|
|
890
|
+
for (const section of sections) {
|
|
891
|
+
const isClass = section[0]?.startsWith("class ") === true;
|
|
892
|
+
lines.push(...isClass ? ["", ""] : [""], ...section);
|
|
893
|
+
}
|
|
894
|
+
lines.push("", "", "nodes = _Nodes()", "triggers = _Triggers()", "");
|
|
895
|
+
return lines.join("\n");
|
|
896
|
+
}
|
|
897
|
+
async function generateNodeClients(manifests, lang) {
|
|
898
|
+
const external = manifests.filter(
|
|
899
|
+
(manifest) => typeof manifest.nodeType === "string" && !manifest.nodeType.startsWith("internal:")
|
|
900
|
+
);
|
|
901
|
+
const snapshot = registrySnapshotHash(external);
|
|
902
|
+
if (lang === "ts") {
|
|
903
|
+
return {
|
|
904
|
+
path: ".fluidgrids/nodes.ts",
|
|
905
|
+
content: await generateTypeScript(external, snapshot),
|
|
906
|
+
registrySnapshot: snapshot
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
path: ".fluidgrids/nodes.py",
|
|
911
|
+
content: generatePython(external, snapshot),
|
|
912
|
+
registrySnapshot: snapshot
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
exports.NameAllocator = NameAllocator;
|
|
917
|
+
exports.PY_KEYWORDS = PY_KEYWORDS;
|
|
918
|
+
exports.PY_LINE_LENGTH = PY_LINE_LENGTH;
|
|
919
|
+
exports.TS_FORMAT_OPTIONS = TS_FORMAT_OPTIONS;
|
|
920
|
+
exports.TS_NODES_IMPORT = TS_NODES_IMPORT;
|
|
921
|
+
exports.clientNames = clientNames;
|
|
922
|
+
exports.formatImport = formatImport;
|
|
923
|
+
exports.formatLines = formatLines;
|
|
924
|
+
exports.generateNodeClients = generateNodeClients;
|
|
925
|
+
exports.pyNumber = pyNumber;
|
|
926
|
+
exports.pyString = pyString;
|
|
927
|
+
exports.pyWorkflowName = pyWorkflowName;
|
|
928
|
+
exports.referencedLater = referencedLater;
|
|
929
|
+
exports.registrySnapshotHash = registrySnapshotHash;
|
|
930
|
+
exports.renderTypeScript = renderTypeScript;
|
|
931
|
+
exports.snakeCase = snakeCase;
|