@bobtail.software/b-durable 1.0.5 → 1.0.7
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/README.md +1 -232
- package/dist/compiler/cli.mjs +46 -703
- package/dist/index.d.mts +174 -26
- package/dist/index.mjs +86 -546
- package/package.json +2 -1
package/dist/compiler/cli.mjs
CHANGED
|
@@ -1,721 +1,64 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
SyntaxKind,
|
|
14
|
-
ts,
|
|
15
|
-
VariableDeclarationKind
|
|
16
|
-
} from "ts-morph";
|
|
17
|
-
var DURABLE_WRAPPER_NAME = "bDurable";
|
|
18
|
-
var TYPE_FORMAT_FLAGS = ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | ts.TypeFormatFlags.NoTruncation;
|
|
19
|
-
async function formatSourceFileWithPrettier(sourceFile) {
|
|
20
|
-
const filePath = sourceFile.getFilePath();
|
|
21
|
-
const unformattedText = sourceFile.getFullText();
|
|
22
|
-
const prettierConfig = await prettier.resolveConfig(filePath);
|
|
23
|
-
const formattedText = await prettier.format(unformattedText, {
|
|
24
|
-
...prettierConfig,
|
|
25
|
-
parser: "typescript"
|
|
26
|
-
});
|
|
27
|
-
sourceFile.replaceWithText(formattedText);
|
|
28
|
-
}
|
|
29
|
-
async function compileWorkflows(options) {
|
|
30
|
-
console.log("Iniciando compilador de workflows duraderos...");
|
|
31
|
-
const { inputDir, outputDir, packageName } = options;
|
|
32
|
-
const project = new Project({
|
|
33
|
-
tsConfigFilePath: path.resolve(process.cwd(), "tsconfig.json")
|
|
34
|
-
});
|
|
35
|
-
const sourceFiles = project.addSourceFilesAtPaths(`${inputDir}/**/*.ts`);
|
|
36
|
-
if (existsSync(outputDir)) {
|
|
37
|
-
console.log(`Limpiando directorio de salida: ${outputDir}`);
|
|
38
|
-
rmSync(outputDir, { recursive: true, force: true });
|
|
39
|
-
}
|
|
40
|
-
mkdirSync(outputDir, { recursive: true });
|
|
41
|
-
const compiledDir = project.createDirectory(outputDir);
|
|
42
|
-
console.log(`Encontrados ${sourceFiles.length} archivos de workflow para procesar.`);
|
|
43
|
-
const workflowRegistry = [];
|
|
44
|
-
const generatedFiles = [];
|
|
45
|
-
for (const sourceFile of sourceFiles) {
|
|
46
|
-
console.log(`
|
|
47
|
-
Procesando archivo: ${sourceFile.getBaseName()}`);
|
|
48
|
-
const durableCalls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).filter((call) => call.getExpression().getText() === DURABLE_WRAPPER_NAME);
|
|
49
|
-
if (durableCalls.length === 0) continue;
|
|
50
|
-
for (const call of durableCalls) {
|
|
51
|
-
const workflowVarDecl = call.getParentIfKind(SyntaxKind.VariableDeclaration);
|
|
52
|
-
if (!workflowVarDecl) continue;
|
|
53
|
-
const workflowName = workflowVarDecl.getName();
|
|
54
|
-
console.log(` -> Transformando workflow: ${workflowName}`);
|
|
55
|
-
const [arg] = call.getArguments();
|
|
56
|
-
if (!Node.isObjectLiteralExpression(arg)) continue;
|
|
57
|
-
const workflowProperty = arg.getProperty("workflow");
|
|
58
|
-
if (!workflowProperty || !Node.isPropertyAssignment(workflowProperty)) continue;
|
|
59
|
-
const workflowFunc = workflowProperty.getInitializer();
|
|
60
|
-
if (!workflowFunc || !Node.isArrowFunction(workflowFunc)) continue;
|
|
61
|
-
const originalBaseName = sourceFile.getBaseName();
|
|
62
|
-
const compiledFileName = originalBaseName.replace(/\.ts$/, ".compiled.mts");
|
|
63
|
-
const newFilePath = path.join(compiledDir.getPath(), compiledFileName);
|
|
64
|
-
const newSourceFile = project.createSourceFile(newFilePath, "", {
|
|
65
|
-
overwrite: true
|
|
66
|
-
});
|
|
67
|
-
generatedFiles.push(newSourceFile);
|
|
68
|
-
transformWorkflowFunction(
|
|
69
|
-
workflowName,
|
|
70
|
-
workflowFunc,
|
|
71
|
-
call,
|
|
72
|
-
newSourceFile,
|
|
73
|
-
packageName
|
|
74
|
-
);
|
|
75
|
-
console.log(
|
|
76
|
-
` -> Archivo generado: ${path.relative(process.cwd(), newFilePath)}`
|
|
77
|
-
);
|
|
78
|
-
const importPathName = compiledFileName;
|
|
79
|
-
workflowRegistry.push({ name: workflowName, importPath: `./${importPathName}` });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (workflowRegistry.length > 0) {
|
|
83
|
-
const indexFilePath = path.join(compiledDir.getPath(), "index.mts");
|
|
84
|
-
const indexSourceFile = project.createSourceFile(indexFilePath, "", {
|
|
85
|
-
overwrite: true
|
|
86
|
-
});
|
|
87
|
-
generatedFiles.push(indexSourceFile);
|
|
88
|
-
indexSourceFile.addStatements(
|
|
89
|
-
"// Este archivo fue generado autom\xE1ticamente. NO EDITAR MANUALMENTE.\n"
|
|
90
|
-
);
|
|
91
|
-
indexSourceFile.addImportDeclaration({
|
|
92
|
-
isTypeOnly: true,
|
|
93
|
-
moduleSpecifier: packageName,
|
|
94
|
-
namedImports: ["DurableFunction"]
|
|
95
|
-
});
|
|
96
|
-
for (const wf of workflowRegistry) {
|
|
97
|
-
indexSourceFile.addImportDeclaration({
|
|
98
|
-
moduleSpecifier: wf.importPath,
|
|
99
|
-
namedImports: [wf.name]
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
indexSourceFile.addExportDeclaration({
|
|
103
|
-
namedExports: workflowRegistry.map((wf) => wf.name)
|
|
104
|
-
});
|
|
105
|
-
indexSourceFile.addStatements("\n");
|
|
106
|
-
indexSourceFile.addVariableStatement({
|
|
107
|
-
declarationKind: VariableDeclarationKind.Const,
|
|
108
|
-
declarations: [
|
|
109
|
-
{
|
|
110
|
-
name: "durableFunctions",
|
|
111
|
-
type: "Map<string, DurableFunction<any, any, any>>",
|
|
112
|
-
initializer: "new Map()"
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
});
|
|
116
|
-
const setStatements = workflowRegistry.map(
|
|
117
|
-
(wf) => `durableFunctions.set(${wf.name}.name, ${wf.name});`
|
|
118
|
-
);
|
|
119
|
-
indexSourceFile.addStatements(setStatements);
|
|
120
|
-
indexSourceFile.addStatements("\n");
|
|
121
|
-
indexSourceFile.addExportAssignment({
|
|
122
|
-
isExportEquals: false,
|
|
123
|
-
expression: "durableFunctions"
|
|
124
|
-
});
|
|
125
|
-
console.log(`
|
|
126
|
-
-> Archivo de \xEDndice generado: ${path.basename(indexFilePath)}`);
|
|
127
|
-
}
|
|
128
|
-
console.log("\nFormateando archivos generados con Prettier...");
|
|
129
|
-
for (const file of generatedFiles) {
|
|
130
|
-
await formatSourceFileWithPrettier(file);
|
|
131
|
-
}
|
|
132
|
-
await project.save();
|
|
133
|
-
console.log("\nCompilaci\xF3n completada exitosamente.");
|
|
134
|
-
}
|
|
135
|
-
function transformWorkflowFunction(workflowName, func, bDurableCall, targetSourceFile, packageName) {
|
|
136
|
-
const body = func.getBody();
|
|
137
|
-
if (!Node.isBlock(body)) {
|
|
138
|
-
throw new Error(`El cuerpo del workflow '${workflowName}' debe ser un bloque {}.`);
|
|
139
|
-
}
|
|
140
|
-
const { clauses: caseClauses } = processStatementsRecursive(body.getStatements(), {
|
|
141
|
-
step: 0,
|
|
142
|
-
persistedVariables: /* @__PURE__ */ new Map()
|
|
143
|
-
});
|
|
144
|
-
let returnTypeNode = func.getReturnType();
|
|
145
|
-
if (returnTypeNode.getSymbol()?.getName() === "Promise" && returnTypeNode.isObject()) {
|
|
146
|
-
returnTypeNode = returnTypeNode.getTypeArguments()[0] || returnTypeNode;
|
|
147
|
-
}
|
|
148
|
-
const returnType = returnTypeNode.getText(void 0, TYPE_FORMAT_FLAGS);
|
|
149
|
-
const dependencyStatements = /* @__PURE__ */ new Set();
|
|
150
|
-
const originalSourceFile = func.getSourceFile();
|
|
151
|
-
const typeArgs = bDurableCall.getTypeArguments();
|
|
152
|
-
const paramType = typeArgs.length > 0 ? typeArgs[0].getText() : "unknown";
|
|
153
|
-
const eventsType = typeArgs.length > 2 ? typeArgs[2].getText() : "Record<string, never>";
|
|
154
|
-
originalSourceFile.getImportDeclarations().forEach((importDecl) => {
|
|
155
|
-
if (importDecl.getModuleSpecifierValue() === packageName) return;
|
|
156
|
-
let moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
157
|
-
if (moduleSpecifier.includes(".workflow")) {
|
|
158
|
-
const parsedPath = path.parse(moduleSpecifier);
|
|
159
|
-
let joinedPath = path.join(parsedPath.dir, parsedPath.base + ".compiled.mts");
|
|
160
|
-
if (!joinedPath.startsWith(".") && !path.isAbsolute(joinedPath)) {
|
|
161
|
-
joinedPath = "./" + joinedPath;
|
|
162
|
-
}
|
|
163
|
-
moduleSpecifier = joinedPath.replace(/\\/g, "/");
|
|
164
|
-
} else if (moduleSpecifier.startsWith(".")) {
|
|
165
|
-
if (path.extname(moduleSpecifier) === "") {
|
|
166
|
-
moduleSpecifier += ".mjs";
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const valueImports = [];
|
|
170
|
-
const typeImports = [];
|
|
171
|
-
importDecl.getNamedImports().forEach((specifier) => {
|
|
172
|
-
const name = specifier.getName();
|
|
173
|
-
const alias = specifier.getAliasNode()?.getText();
|
|
174
|
-
const importText = alias ? `${name} as ${alias}` : name;
|
|
175
|
-
const symbol = specifier.getNameNode().getSymbol()?.getAliasedSymbol() ?? specifier.getNameNode().getSymbol();
|
|
176
|
-
const declarations = symbol?.getDeclarations() ?? [];
|
|
177
|
-
const isEnum = declarations.some((d) => Node.isEnumDeclaration(d));
|
|
178
|
-
const isPurelyType = specifier.isTypeOnly() || !isEnum && declarations.every(
|
|
179
|
-
(d) => Node.isInterfaceDeclaration(d) || Node.isTypeAliasDeclaration(d)
|
|
180
|
-
);
|
|
181
|
-
if (isPurelyType) {
|
|
182
|
-
typeImports.push(importText);
|
|
183
|
-
} else {
|
|
184
|
-
valueImports.push(importText);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
if (valueImports.length > 0) {
|
|
188
|
-
targetSourceFile.addImportDeclaration({
|
|
189
|
-
moduleSpecifier,
|
|
190
|
-
namedImports: valueImports
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
if (typeImports.length > 0) {
|
|
194
|
-
targetSourceFile.addImportDeclaration({
|
|
195
|
-
isTypeOnly: true,
|
|
196
|
-
moduleSpecifier,
|
|
197
|
-
namedImports: typeImports
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
const defaultImport = importDecl.getDefaultImport();
|
|
201
|
-
if (defaultImport) {
|
|
202
|
-
targetSourceFile.addImportDeclaration({
|
|
203
|
-
moduleSpecifier,
|
|
204
|
-
defaultImport: defaultImport.getText()
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
originalSourceFile.getInterfaces().forEach((iface) => {
|
|
209
|
-
dependencyStatements.add(
|
|
210
|
-
iface.getText().startsWith("export") ? iface.getText() : `export ${iface.getText()}`
|
|
211
|
-
);
|
|
212
|
-
});
|
|
213
|
-
originalSourceFile.getTypeAliases().forEach((typeAlias) => {
|
|
214
|
-
dependencyStatements.add(
|
|
215
|
-
typeAlias.getText().startsWith("export") ? typeAlias.getText() : `export ${typeAlias.getText()}`
|
|
216
|
-
);
|
|
217
|
-
});
|
|
218
|
-
const [params] = func.getParameters();
|
|
219
|
-
let paramAssignment = "";
|
|
220
|
-
if (params) {
|
|
221
|
-
const paramName = params.getNameNode().getText();
|
|
222
|
-
if (paramName !== "input") {
|
|
223
|
-
paramAssignment = `const ${paramName} = input;`;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
targetSourceFile.addImportDeclaration({
|
|
227
|
-
isTypeOnly: true,
|
|
228
|
-
moduleSpecifier: packageName,
|
|
229
|
-
namedImports: ["DurableFunction", "WorkflowContext", "Instruction"]
|
|
230
|
-
});
|
|
231
|
-
if (dependencyStatements.size > 0) {
|
|
232
|
-
targetSourceFile.addStatements("\n");
|
|
233
|
-
targetSourceFile.addStatements(Array.from(dependencyStatements));
|
|
234
|
-
}
|
|
235
|
-
targetSourceFile.addStatements(
|
|
236
|
-
"\n// Este archivo fue generado autom\xE1ticamente. NO EDITAR MANUALMENTE.\n"
|
|
237
|
-
);
|
|
238
|
-
const initializerObjectString = `{
|
|
2
|
+
import H from"path";import{existsSync as X,mkdirSync as Y,rmSync as J}from"fs";import T from"path";import*as M from"prettier";import{Node as i,Project as Q,SyntaxKind as b,ts as _,VariableDeclarationKind as z}from"ts-morph";var Z="bDurable",V=_.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope|_.TypeFormatFlags.NoTruncation;async function ee(e){let n=e.getFilePath(),o=e.getFullText(),s=await M.resolveConfig(n),a=await M.format(o,{...s,parser:"typescript"});e.replaceWithText(a)}async function U(e){console.log("Iniciando compilador de workflows duraderos...");let{inputDir:n,outputDir:o,packageName:s}=e,a=new Q({tsConfigFilePath:T.resolve(process.cwd(),"tsconfig.json")}),c=a.addSourceFilesAtPaths(`${n}/**/*.ts`);X(o)&&(console.log(`Limpiando directorio de salida: ${o}`),J(o,{recursive:!0,force:!0})),Y(o,{recursive:!0});let g=a.createDirectory(o);console.log(`Encontrados ${c.length} archivos de workflow para procesar.`);let r=[],l=[];for(let u of c){console.log(`
|
|
3
|
+
Procesando archivo: ${u.getBaseName()}`);let t=u.getDescendantsOfKind(b.CallExpression).filter(m=>m.getExpression().getText()===Z);if(t.length!==0)for(let m of t){let p=m.getParentIfKind(b.VariableDeclaration);if(!p)continue;let d=p.getName();console.log(` -> Transformando workflow: ${d}`);let[f]=m.getArguments();if(!i.isObjectLiteralExpression(f))continue;let S=f.getProperty("workflow");if(!S||!i.isPropertyAssignment(S))continue;let x=S.getInitializer();if(!x||!i.isArrowFunction(x))continue;let D=u.getBaseName().replace(/\.ts$/,".compiled.mts"),I=T.join(g.getPath(),D),w=a.createSourceFile(I,"",{overwrite:!0});l.push(w),te(d,x,m,w,s),console.log(` -> Archivo generado: ${T.relative(process.cwd(),I)}`);let E=D;r.push({name:d,importPath:`./${E}`})}}if(r.length>0){let u=T.join(g.getPath(),"index.mts"),t=a.createSourceFile(u,"",{overwrite:!0});l.push(t),t.addStatements(`// Este archivo fue generado autom\xE1ticamente. NO EDITAR MANUALMENTE.
|
|
4
|
+
`),t.addImportDeclaration({isTypeOnly:!0,moduleSpecifier:s,namedImports:["DurableFunction"]});for(let p of r)t.addImportDeclaration({moduleSpecifier:p.importPath,namedImports:[p.name]});t.addExportDeclaration({namedExports:r.map(p=>p.name)}),t.addStatements(`
|
|
5
|
+
`),t.addVariableStatement({declarationKind:z.Const,declarations:[{name:"durableFunctions",type:"Map<string, DurableFunction<any, any, any, any>>",initializer:"new Map()"}]});let m=r.map(p=>`durableFunctions.set(${p.name}.name, ${p.name});`);t.addStatements(m),t.addStatements(`
|
|
6
|
+
`),t.addExportAssignment({isExportEquals:!1,expression:"durableFunctions"}),console.log(`
|
|
7
|
+
-> Archivo de \xEDndice generado: ${T.basename(u)}`)}console.log(`
|
|
8
|
+
Formateando archivos generados con Prettier...`);for(let u of l)await ee(u);await a.save(),console.log(`
|
|
9
|
+
Compilaci\xF3n completada exitosamente.`)}function te(e,n,o,s,a){let c=n.getBody();if(!i.isBlock(c))throw new Error(`El cuerpo del workflow '${e}' debe ser un bloque {}.`);let[g]=o.getArguments();if(!i.isObjectLiteralExpression(g))throw new Error("El argumento de bDurable debe ser un objeto.");let r=g.getProperty("version");if(!r||!i.isPropertyAssignment(r))throw new Error(`El workflow '${e}' debe tener una propiedad 'version'.`);let l=r.getInitializer();if(!l||!i.isStringLiteral(l))throw new Error(`La versi\xF3n del workflow '${e}' debe ser un string literal.`);let u=g.getProperty("retryOptions"),t="undefined";u&&i.isPropertyAssignment(u)&&(t=u.getInitializer()?.getText()||"undefined");let{clauses:m}=$(c.getStatements(),{step:0,persistedVariables:new Map}),p=n.getReturnType();p.getSymbol()?.getName()==="Promise"&&p.isObject()&&(p=p.getTypeArguments()[0]||p);let d=p.getText(void 0,V),f=new Set,S=n.getSourceFile(),x=o.getTypeArguments(),N=x.length>0?x[0].getText():"unknown",D=x.length>2?x[2].getText():"Record<string, never>",I=x.length>3?x[3].getText():"Record<string, never>";S.getImportDeclarations().forEach(y=>{if(y.getModuleSpecifierValue()===a)return;let h=y.getModuleSpecifierValue();if(h.includes(".workflow")){let A=T.parse(h),C=T.join(A.dir,A.base+".compiled.mts");!C.startsWith(".")&&!T.isAbsolute(C)&&(C="./"+C),h=C.replace(/\\/g,"/")}else h.startsWith(".")&&T.extname(h)===""&&(h+=".mjs");let R=[],B=[];y.getNamedImports().forEach(A=>{let C=A.getName(),j=A.getAliasNode()?.getText(),W=j?`${C} as ${j}`:C,K=(A.getNameNode().getSymbol()?.getAliasedSymbol()??A.getNameNode().getSymbol())?.getDeclarations()??[],G=K.some(O=>i.isEnumDeclaration(O));A.isTypeOnly()||!G&&K.every(O=>i.isInterfaceDeclaration(O)||i.isTypeAliasDeclaration(O))?B.push(W):R.push(W)}),R.length>0&&s.addImportDeclaration({moduleSpecifier:h,namedImports:R}),B.length>0&&s.addImportDeclaration({isTypeOnly:!0,moduleSpecifier:h,namedImports:B});let L=y.getDefaultImport();L&&s.addImportDeclaration({moduleSpecifier:h,defaultImport:L.getText()})}),S.getInterfaces().forEach(y=>{f.add(y.getText().startsWith("export")?y.getText():`export ${y.getText()}`)}),S.getTypeAliases().forEach(y=>{f.add(y.getText().startsWith("export")?y.getText():`export ${y.getText()}`)});let[w]=n.getParameters(),E="";if(w){let y=w.getNameNode().getText();y!=="input"&&(E=`const ${y} = input;`)}s.addImportDeclaration({isTypeOnly:!0,moduleSpecifier:a,namedImports:["DurableFunction","WorkflowContext","Instruction"]}),f.size>0&&(s.addStatements(`
|
|
10
|
+
`),s.addStatements(Array.from(f))),s.addStatements(`
|
|
11
|
+
// Este archivo fue generado autom\xE1ticamente. NO EDITAR MANUALMENTE.
|
|
12
|
+
`);let P=l.getLiteralValue(),F=`{
|
|
239
13
|
__isDurable: true,
|
|
240
|
-
name: '${
|
|
241
|
-
|
|
14
|
+
name: '${e}',
|
|
15
|
+
version: '${P}',
|
|
16
|
+
retryOptions: ${t},
|
|
17
|
+
async execute(context: WorkflowContext<${N}>): Promise<Instruction<${d}>> {
|
|
242
18
|
const { input, state, result, log, workflowId } = context;
|
|
243
|
-
${
|
|
19
|
+
${E}
|
|
244
20
|
while (true) {
|
|
245
21
|
switch (context.step) {
|
|
246
|
-
${
|
|
22
|
+
${m.join(`
|
|
23
|
+
`)}
|
|
247
24
|
default:
|
|
248
25
|
throw new Error(\`Paso desconocido: \${context.step}\`);
|
|
249
26
|
}
|
|
250
27
|
}
|
|
251
28
|
}
|
|
252
|
-
}`;
|
|
253
|
-
|
|
254
|
-
isExported: true,
|
|
255
|
-
declarationKind: VariableDeclarationKind.Const,
|
|
256
|
-
declarations: [
|
|
257
|
-
{
|
|
258
|
-
name: workflowName,
|
|
259
|
-
type: `DurableFunction<${paramType}, ${returnType}, ${eventsType}>`,
|
|
260
|
-
initializer: initializerObjectString
|
|
261
|
-
}
|
|
262
|
-
]
|
|
263
|
-
});
|
|
264
|
-
targetSourceFile.organizeImports();
|
|
265
|
-
}
|
|
266
|
-
function processStatementsRecursive(statements, initialState) {
|
|
267
|
-
if (statements.length === 0) {
|
|
268
|
-
const clauses = [];
|
|
269
|
-
if (initialState.pendingStateAssignment) {
|
|
270
|
-
const finalClause = `case ${initialState.step}: {
|
|
271
|
-
${initialState.pendingStateAssignment}
|
|
29
|
+
}`;s.addVariableStatement({isExported:!0,declarationKind:z.Const,declarations:[{name:e,type:`DurableFunction<${N}, ${d}, ${D}, ${I}>`,initializer:F}]}),s.organizeImports()}function $(e,n){if(e.length===0){let f=[];if(n.pendingStateAssignment){let S=`case ${n.step}: {
|
|
30
|
+
${n.pendingStateAssignment}
|
|
272
31
|
return { type: 'COMPLETE', result: undefined };
|
|
273
|
-
}`;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
const updatedPersistedVariables = new Map([
|
|
288
|
-
...initialState.persistedVariables,
|
|
289
|
-
...newlyPersistedVariables
|
|
290
|
-
]);
|
|
291
|
-
if (!durableStatement) {
|
|
292
|
-
const syncCode2 = rewrittenSyncStatements.join("\n");
|
|
293
|
-
const lastStatementIsReturn = syncBlock.length > 0 && Node.isReturnStatement(syncBlock[syncBlock.length - 1]);
|
|
294
|
-
const finalInstruction = lastStatementIsReturn ? "" : `
|
|
295
|
-
return { type: 'COMPLETE', result: undefined };`;
|
|
296
|
-
const clause = `case ${initialState.step}: {
|
|
297
|
-
${syncCode2}${finalInstruction}
|
|
298
|
-
}`;
|
|
299
|
-
return { clauses: [clause], nextStep: initialState.step + 1 };
|
|
300
|
-
}
|
|
301
|
-
if (Node.isIfStatement(durableStatement)) {
|
|
302
|
-
return processIfStatement(
|
|
303
|
-
durableStatement,
|
|
304
|
-
nextStatements,
|
|
305
|
-
{
|
|
306
|
-
...initialState,
|
|
307
|
-
persistedVariables: updatedPersistedVariables
|
|
308
|
-
},
|
|
309
|
-
rewrittenSyncStatements
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
if (Node.isTryStatement(durableStatement)) {
|
|
313
|
-
return processTryStatement(
|
|
314
|
-
durableStatement,
|
|
315
|
-
nextStatements,
|
|
316
|
-
{ ...initialState, persistedVariables: updatedPersistedVariables },
|
|
317
|
-
rewrittenSyncStatements
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
const { instruction, nextPendingStateAssignment } = generateDurableInstruction(
|
|
321
|
-
durableStatement,
|
|
322
|
-
updatedPersistedVariables
|
|
323
|
-
);
|
|
324
|
-
rewrittenSyncStatements.push(instruction);
|
|
325
|
-
const syncCode = rewrittenSyncStatements.join("\n");
|
|
326
|
-
const currentClause = `case ${initialState.step}: {
|
|
327
|
-
${syncCode}
|
|
328
|
-
}`;
|
|
329
|
-
const nextState = {
|
|
330
|
-
step: initialState.step + 1,
|
|
331
|
-
persistedVariables: updatedPersistedVariables,
|
|
332
|
-
pendingStateAssignment: nextPendingStateAssignment
|
|
333
|
-
};
|
|
334
|
-
const restResult = processStatementsRecursive(nextStatements, nextState);
|
|
335
|
-
return {
|
|
336
|
-
clauses: [currentClause, ...restResult.clauses],
|
|
337
|
-
nextStep: restResult.nextStep
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
function processIfStatement(ifStatement, followingStatements, currentState, rewrittenSyncStatements) {
|
|
341
|
-
const condition = rewriteNode(ifStatement.getExpression(), currentState.persistedVariables);
|
|
342
|
-
const thenBlock = ifStatement.getThenStatement();
|
|
343
|
-
const thenStatements = Node.isBlock(thenBlock) ? thenBlock.getStatements() : [thenBlock];
|
|
344
|
-
const thenResult = processStatementsRecursive(thenStatements, {
|
|
345
|
-
step: currentState.step + 1,
|
|
346
|
-
persistedVariables: new Map(currentState.persistedVariables)
|
|
347
|
-
// Clona para aislamiento de ramas
|
|
348
|
-
});
|
|
349
|
-
let elseResult;
|
|
350
|
-
const elseStatement = ifStatement.getElseStatement();
|
|
351
|
-
if (elseStatement) {
|
|
352
|
-
const elseStatements = Node.isBlock(elseStatement) ? elseStatement.getStatements() : [elseStatement];
|
|
353
|
-
elseResult = processStatementsRecursive(elseStatements, {
|
|
354
|
-
step: thenResult.nextStep,
|
|
355
|
-
// La rama 'else' comienza donde termina la 'then'
|
|
356
|
-
persistedVariables: new Map(currentState.persistedVariables)
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
const nextStepAfterIf = elseResult ? elseResult.nextStep : thenResult.nextStep;
|
|
360
|
-
const afterIfResult = processStatementsRecursive(followingStatements, {
|
|
361
|
-
step: nextStepAfterIf,
|
|
362
|
-
persistedVariables: currentState.persistedVariables
|
|
363
|
-
// Usa el mapa original
|
|
364
|
-
});
|
|
365
|
-
const syncCode = rewrittenSyncStatements.join("\n");
|
|
366
|
-
const jumpToElseStep = thenResult.nextStep;
|
|
367
|
-
const ifClause = `
|
|
368
|
-
case ${currentState.step}: {
|
|
369
|
-
${syncCode}
|
|
370
|
-
if (${condition}) {
|
|
371
|
-
context.step = ${currentState.step + 1};
|
|
32
|
+
}`;f.push(S)}return{clauses:f,nextStep:n.step+1}}let{syncBlock:o,durableStatement:s,nextStatements:a}=le(e),{rewrittenSyncStatements:c,newlyPersistedVariables:g}=re(o,s?[s,...a]:[],n.persistedVariables);n.pendingStateAssignment&&c.unshift(n.pendingStateAssignment);let r=new Map([...n.persistedVariables,...g]);if(!s){let f=c.join(`
|
|
33
|
+
`),x=o.length>0&&i.isReturnStatement(o[o.length-1])?"":`
|
|
34
|
+
return { type: 'COMPLETE', result: undefined };`;return{clauses:[`case ${n.step}: {
|
|
35
|
+
${f}${x}
|
|
36
|
+
}`],nextStep:n.step+1}}if(i.isIfStatement(s))return ne(s,a,{...n,persistedVariables:r},c);if(i.isTryStatement(s))return se(s,a,{...n,persistedVariables:r},c);let{instruction:l,nextPendingStateAssignment:u}=ae(s,r);c.push(l);let t=c.join(`
|
|
37
|
+
`),m=`case ${n.step}: {
|
|
38
|
+
${t}
|
|
39
|
+
}`,p={step:n.step+1,persistedVariables:r,pendingStateAssignment:u},d=$(a,p);return{clauses:[m,...d.clauses],nextStep:d.nextStep}}function ne(e,n,o,s){let a=k(e.getExpression(),o.persistedVariables),c=e.getThenStatement(),g=i.isBlock(c)?c.getStatements():[c],r=$(g,{step:o.step+1,persistedVariables:new Map(o.persistedVariables)}),l,u=e.getElseStatement();if(u){let S=i.isBlock(u)?u.getStatements():[u];l=$(S,{step:r.nextStep,persistedVariables:new Map(o.persistedVariables)})}let t=l?l.nextStep:r.nextStep,m=$(n,{step:t,persistedVariables:o.persistedVariables}),p=s.join(`
|
|
40
|
+
`),d=r.nextStep;return{clauses:[`
|
|
41
|
+
case ${o.step}: {
|
|
42
|
+
${p}
|
|
43
|
+
if (${a}) {
|
|
44
|
+
context.step = ${o.step+1};
|
|
372
45
|
} else {
|
|
373
|
-
${
|
|
46
|
+
${u?`context.step = ${d};`:`context.step = ${t};`}
|
|
374
47
|
}
|
|
375
48
|
break;
|
|
376
49
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
...thenResult.clauses,
|
|
382
|
-
...elseResult ? elseResult.clauses : [],
|
|
383
|
-
...afterIfResult.clauses
|
|
384
|
-
],
|
|
385
|
-
nextStep: afterIfResult.nextStep
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
function processTryStatement(tryStatement, followingStatements, currentState, rewrittenSyncStatements) {
|
|
389
|
-
const { step, persistedVariables } = currentState;
|
|
390
|
-
const tryBlock = tryStatement.getTryBlock();
|
|
391
|
-
const catchClause = tryStatement.getCatchClause();
|
|
392
|
-
const finallyBlock = tryStatement.getFinallyBlock();
|
|
393
|
-
const tryResult = processStatementsRecursive(tryBlock.getStatements(), {
|
|
394
|
-
step: step + 1,
|
|
395
|
-
// El bloque try comienza en el siguiente step
|
|
396
|
-
persistedVariables: new Map(persistedVariables)
|
|
397
|
-
});
|
|
398
|
-
let catchResult;
|
|
399
|
-
let catchVarName;
|
|
400
|
-
const catchStep = tryResult.nextStep;
|
|
401
|
-
if (catchClause) {
|
|
402
|
-
const catchBlock = catchClause.getBlock();
|
|
403
|
-
const varDeclaration = catchClause.getVariableDeclaration();
|
|
404
|
-
if (varDeclaration) {
|
|
405
|
-
catchVarName = varDeclaration.getName();
|
|
406
|
-
}
|
|
407
|
-
catchResult = processStatementsRecursive(catchBlock.getStatements(), {
|
|
408
|
-
step: catchStep,
|
|
409
|
-
persistedVariables: new Map(persistedVariables)
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
let finallyResult;
|
|
413
|
-
const finallyStep = catchResult ? catchResult.nextStep : catchStep;
|
|
414
|
-
if (finallyBlock) {
|
|
415
|
-
finallyResult = processStatementsRecursive(finallyBlock.getStatements(), {
|
|
416
|
-
step: finallyStep,
|
|
417
|
-
persistedVariables: new Map(persistedVariables)
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
const endStep = finallyResult ? finallyResult.nextStep : finallyStep;
|
|
421
|
-
const afterTryResult = processStatementsRecursive(followingStatements, {
|
|
422
|
-
step: endStep,
|
|
423
|
-
persistedVariables
|
|
424
|
-
});
|
|
425
|
-
const handler = `{ catchStep: ${catchClause ? catchStep : "undefined"}, finallyStep: ${finallyBlock ? finallyStep : "undefined"} }`;
|
|
426
|
-
const pushClause = `
|
|
427
|
-
case ${step}: {
|
|
428
|
-
${rewrittenSyncStatements.join("\n")}
|
|
50
|
+
`,...r.clauses,...l?l.clauses:[],...m.clauses],nextStep:m.nextStep}}function se(e,n,o,s){let{step:a,persistedVariables:c}=o,g=e.getTryBlock(),r=e.getCatchClause(),l=e.getFinallyBlock(),u=$(g.getStatements(),{step:a+1,persistedVariables:new Map(c)}),t,m,p=u.nextStep;if(r){let E=r.getBlock(),P=r.getVariableDeclaration();P&&(m=P.getName()),t=$(E.getStatements(),{step:p,persistedVariables:new Map(c)})}let d,f=t?t.nextStep:p;l&&(d=$(l.getStatements(),{step:f,persistedVariables:new Map(c)}));let S=d?d.nextStep:f,x=$(n,{step:S,persistedVariables:c}),N=`{ catchStep: ${r?p:"undefined"}, finallyStep: ${l?f:"undefined"} }`,D=`
|
|
51
|
+
case ${a}: {
|
|
52
|
+
${s.join(`
|
|
53
|
+
`)}
|
|
429
54
|
state.tryCatchStack = state.tryCatchStack || [];
|
|
430
|
-
state.tryCatchStack.push(${
|
|
431
|
-
context.step = ${
|
|
55
|
+
state.tryCatchStack.push(${N});
|
|
56
|
+
context.step = ${a+1}; // Salta al inicio del bloque try
|
|
432
57
|
break;
|
|
433
58
|
}
|
|
434
|
-
`;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
`context.step = ${jumpToAfterTryStep}; break;`
|
|
441
|
-
)
|
|
442
|
-
);
|
|
443
|
-
if (catchResult) {
|
|
444
|
-
if (catchVarName) {
|
|
445
|
-
const firstCatchClause = catchResult.clauses[0] || `case ${catchStep}: {}`;
|
|
446
|
-
catchResult.clauses[0] = firstCatchClause.replace(
|
|
447
|
-
"{",
|
|
448
|
-
`{
|
|
449
|
-
const ${catchVarName} = result as Error;`
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
const lastCatchClause = catchResult.clauses.pop() || "";
|
|
453
|
-
catchResult.clauses.push(
|
|
454
|
-
lastCatchClause.replace(
|
|
455
|
-
/return { type: 'COMPLETE'.* };/,
|
|
456
|
-
`context.step = ${jumpToAfterTryStep}; break;`
|
|
457
|
-
)
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
if (finallyResult) {
|
|
461
|
-
const lastFinallyClause = finallyResult.clauses.pop() || "";
|
|
462
|
-
finallyResult.clauses.push(
|
|
463
|
-
lastFinallyClause.replace(
|
|
464
|
-
/return { type: 'COMPLETE'.* };/,
|
|
465
|
-
`state.tryCatchStack?.pop(); context.step = ${endStep}; break;`
|
|
466
|
-
)
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
return {
|
|
470
|
-
clauses: [
|
|
471
|
-
pushClause,
|
|
472
|
-
...tryResult.clauses,
|
|
473
|
-
...catchResult ? catchResult.clauses : [],
|
|
474
|
-
...finallyResult ? finallyResult.clauses : [],
|
|
475
|
-
...afterTryResult.clauses
|
|
476
|
-
],
|
|
477
|
-
nextStep: afterTryResult.nextStep
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
function processSyncBlock(syncBlock, followingStatements, persistedVariables) {
|
|
481
|
-
const rewrittenSyncStatements = [];
|
|
482
|
-
const newlyPersistedVariables = /* @__PURE__ */ new Map();
|
|
483
|
-
const usedLaterIdentifiers = findUsedIdentifiers(followingStatements);
|
|
484
|
-
const currentPersistedVars = new Map(persistedVariables);
|
|
485
|
-
for (const statement of syncBlock) {
|
|
486
|
-
let handledAsStatePersistence = false;
|
|
487
|
-
if (Node.isVariableStatement(statement)) {
|
|
488
|
-
for (const decl of statement.getDeclarations()) {
|
|
489
|
-
const initializer = decl.getInitializer();
|
|
490
|
-
if (!initializer) continue;
|
|
491
|
-
const varInfos = getVarInfoFromDeclaration(decl);
|
|
492
|
-
const varsToPersist = varInfos.filter(
|
|
493
|
-
(v) => usedLaterIdentifiers.has(v.name)
|
|
494
|
-
);
|
|
495
|
-
if (varsToPersist.length > 0) {
|
|
496
|
-
const rewrittenInitializer = rewriteNode(
|
|
497
|
-
initializer,
|
|
498
|
-
persistedVariables
|
|
499
|
-
);
|
|
500
|
-
for (const { name, type } of varsToPersist) {
|
|
501
|
-
newlyPersistedVariables.set(name, { type });
|
|
502
|
-
currentPersistedVars.set(name, { type });
|
|
503
|
-
const assignmentRightHand = varInfos.length > 1 ? `${rewrittenInitializer}.${name}` : rewrittenInitializer;
|
|
504
|
-
rewrittenSyncStatements.push(
|
|
505
|
-
`state.${name} = ${assignmentRightHand};`
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
if (varsToPersist.length === varInfos.length) {
|
|
509
|
-
handledAsStatePersistence = true;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
if (!handledAsStatePersistence) {
|
|
515
|
-
rewrittenSyncStatements.push(rewriteNode(statement, currentPersistedVars));
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
return { rewrittenSyncStatements, newlyPersistedVariables };
|
|
519
|
-
}
|
|
520
|
-
function getVarInfoFromDeclaration(decl) {
|
|
521
|
-
const nameNode = decl.getNameNode();
|
|
522
|
-
const result = [];
|
|
523
|
-
if (Node.isIdentifier(nameNode)) {
|
|
524
|
-
const type = decl.getType().getText(decl, TYPE_FORMAT_FLAGS);
|
|
525
|
-
result.push({ name: nameNode.getText(), type });
|
|
526
|
-
} else if (Node.isObjectBindingPattern(nameNode)) {
|
|
527
|
-
for (const element of nameNode.getElements()) {
|
|
528
|
-
const name = element.getName();
|
|
529
|
-
const type = element.getType().getText(element, TYPE_FORMAT_FLAGS);
|
|
530
|
-
result.push({ name, type });
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return result;
|
|
534
|
-
}
|
|
535
|
-
function generateDurableInstruction(statement, persistedVariables) {
|
|
536
|
-
if (Node.isReturnStatement(statement)) {
|
|
537
|
-
const returnExpr = statement.getExpression() ? rewriteNode(statement.getExpressionOrThrow(), persistedVariables) : "undefined";
|
|
538
|
-
return {
|
|
539
|
-
instruction: `return { type: 'COMPLETE', result: ${returnExpr} };`,
|
|
540
|
-
nextPendingStateAssignment: void 0
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
let nextPendingStateAssignment = void 0;
|
|
544
|
-
const varDecl = statement.getFirstDescendantByKind(SyntaxKind.VariableDeclaration);
|
|
545
|
-
if (varDecl) {
|
|
546
|
-
const varName = varDecl.getName();
|
|
547
|
-
const varType = varDecl.getType().getText(varDecl, TYPE_FORMAT_FLAGS);
|
|
548
|
-
persistedVariables.set(varName, { type: varType });
|
|
549
|
-
nextPendingStateAssignment = `state.${varName} = result;`;
|
|
550
|
-
}
|
|
551
|
-
const awaitExpression = statement.getFirstDescendantByKind(SyntaxKind.AwaitExpression);
|
|
552
|
-
if (awaitExpression) {
|
|
553
|
-
const callExpr = awaitExpression.getExpression();
|
|
554
|
-
if (Node.isCallExpression(callExpr)) {
|
|
555
|
-
return {
|
|
556
|
-
instruction: `return ${createInstructionForCall(callExpr, persistedVariables)};`,
|
|
557
|
-
nextPendingStateAssignment
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
instruction: rewriteNode(statement, persistedVariables),
|
|
563
|
-
nextPendingStateAssignment
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
function findUsedIdentifiers(nodes) {
|
|
567
|
-
const identifiers = /* @__PURE__ */ new Set();
|
|
568
|
-
for (const node of nodes) {
|
|
569
|
-
node.getDescendantsOfKind(SyntaxKind.Identifier).forEach((ident) => {
|
|
570
|
-
identifiers.add(ident.getText());
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
return identifiers;
|
|
574
|
-
}
|
|
575
|
-
function rewriteNode(node, persistedVariables) {
|
|
576
|
-
const tempSourceFile = node.getProject().createSourceFile(
|
|
577
|
-
`temp_rewrite_${Math.random()}.ts`,
|
|
578
|
-
`const temp = ${node.getText()};`,
|
|
579
|
-
// Se envuelve para asegurar que sea un AST válido
|
|
580
|
-
{ overwrite: true }
|
|
581
|
-
);
|
|
582
|
-
const nodeClone = tempSourceFile.getVariableDeclarationOrThrow("temp").getInitializerOrThrow();
|
|
583
|
-
const descendants = [nodeClone, ...nodeClone.getDescendants()].reverse();
|
|
584
|
-
for (const currentNode of descendants) {
|
|
585
|
-
if (Node.isIdentifier(currentNode) && !currentNode.wasForgotten() && persistedVariables.has(currentNode.getText())) {
|
|
586
|
-
const varName = currentNode.getText();
|
|
587
|
-
const parent = currentNode.getParent();
|
|
588
|
-
const isDeclaration = Node.isVariableDeclaration(parent) && parent.getNameNode() === currentNode;
|
|
589
|
-
const isProperty = Node.isPropertyAccessExpression(parent) && parent.getNameNode() === currentNode || Node.isPropertyAssignment(parent) && parent.getNameNode() === currentNode;
|
|
590
|
-
const isBindingElement = Node.isBindingElement(parent) && parent.getNameNode() === currentNode;
|
|
591
|
-
if (!isDeclaration && !isProperty && !isBindingElement) {
|
|
592
|
-
const typeInfo = persistedVariables.get(varName);
|
|
593
|
-
currentNode.replaceWithText(`(state.${varName} as ${typeInfo.type})`);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
const fullText = tempSourceFile.getFullText().trim();
|
|
598
|
-
tempSourceFile.forget();
|
|
599
|
-
const prefix = "const temp = ";
|
|
600
|
-
let newText = fullText;
|
|
601
|
-
if (newText.startsWith(prefix)) {
|
|
602
|
-
newText = newText.substring(prefix.length);
|
|
603
|
-
}
|
|
604
|
-
if (newText.endsWith(";")) {
|
|
605
|
-
newText = newText.slice(0, -1);
|
|
606
|
-
}
|
|
607
|
-
return newText;
|
|
608
|
-
}
|
|
609
|
-
function createInstructionForCall(callExpr, persistedVariables) {
|
|
610
|
-
const identifier = callExpr.getExpression();
|
|
611
|
-
let functionName;
|
|
612
|
-
let isContextCall = false;
|
|
613
|
-
if (Node.isPropertyAccessExpression(identifier)) {
|
|
614
|
-
const expr = identifier.getExpression();
|
|
615
|
-
if (expr.getText() === "context") {
|
|
616
|
-
isContextCall = true;
|
|
617
|
-
}
|
|
618
|
-
functionName = identifier.getName();
|
|
619
|
-
} else {
|
|
620
|
-
functionName = identifier.getText();
|
|
621
|
-
}
|
|
622
|
-
const args = callExpr.getArguments().map((arg) => rewriteNode(arg, persistedVariables)).join(", ");
|
|
623
|
-
if (isContextCall) {
|
|
624
|
-
if (functionName === "bSleep") {
|
|
625
|
-
return `{ type: 'SCHEDULE_SLEEP', duration: ${args} }`;
|
|
626
|
-
}
|
|
627
|
-
if (functionName === "bWaitForEvent") {
|
|
628
|
-
return `{ type: 'WAIT_FOR_EVENT', eventName: ${args} }`;
|
|
629
|
-
}
|
|
630
|
-
if (functionName === "bExecute") {
|
|
631
|
-
const [workflowArg, inputArg] = callExpr.getArguments();
|
|
632
|
-
const subWorkflowName = workflowArg.getText();
|
|
633
|
-
const subWorkflowInput = inputArg ? rewriteNode(inputArg, persistedVariables) : "undefined";
|
|
634
|
-
return `{ type: 'EXECUTE_SUBWORKFLOW', workflowName: ${subWorkflowName}.name, input: ${subWorkflowInput} }`;
|
|
635
|
-
}
|
|
636
|
-
throw new Error(`Funci\xF3n de contexto durable desconocida: '${functionName}'.`);
|
|
637
|
-
}
|
|
638
|
-
const symbol = identifier.getSymbol();
|
|
639
|
-
if (!symbol) throw new Error(`S\xEDmbolo no encontrado para '${functionName}'.`);
|
|
640
|
-
const importSpecifier = symbol.getDeclarations()[0]?.asKind(SyntaxKind.ImportSpecifier);
|
|
641
|
-
if (!importSpecifier) throw new Error(`'${functionName}' debe ser importada.`);
|
|
642
|
-
const sourceFile = importSpecifier.getImportDeclaration().getModuleSpecifierSourceFileOrThrow();
|
|
643
|
-
const relativeSourcePath = path.relative(process.cwd(), sourceFile.getFilePath()).replace(/\\/g, "/");
|
|
644
|
-
return `{ type: 'SCHEDULE_TASK', modulePath: '${relativeSourcePath}', exportName: '${functionName}', args: [${args}] }`;
|
|
645
|
-
}
|
|
646
|
-
function hasDurableCall(node) {
|
|
647
|
-
for (const awaitExpr of node.getDescendantsOfKind(SyntaxKind.AwaitExpression)) {
|
|
648
|
-
const callExpr = awaitExpr.getExpressionIfKind(SyntaxKind.CallExpression);
|
|
649
|
-
if (callExpr) {
|
|
650
|
-
const expression = callExpr.getExpression();
|
|
651
|
-
if (Node.isPropertyAccessExpression(expression)) {
|
|
652
|
-
const propName = expression.getName();
|
|
653
|
-
if (expression.getExpression().getText() === "context" && (propName === "bSleep" || propName === "bWaitForEvent" || propName === "bExecute") || expression.getSymbol()?.getDeclarations()[0]?.isKind(SyntaxKind.ImportSpecifier)) {
|
|
654
|
-
return true;
|
|
655
|
-
}
|
|
656
|
-
} else {
|
|
657
|
-
if (expression.getSymbol()?.getDeclarations()[0]?.isKind(SyntaxKind.ImportSpecifier)) {
|
|
658
|
-
return true;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
if (Node.isTryStatement(node)) {
|
|
664
|
-
if (hasDurableCall(node.getTryBlock())) return true;
|
|
665
|
-
if (node.getCatchClause() && hasDurableCall(node.getCatchClause().getBlock()))
|
|
666
|
-
return true;
|
|
667
|
-
if (node.getFinallyBlock() && hasDurableCall(node.getFinallyBlock())) return true;
|
|
668
|
-
}
|
|
669
|
-
if (Node.isIfStatement(node)) {
|
|
670
|
-
const thenHas = hasDurableCall(node.getThenStatement());
|
|
671
|
-
const elseHas = node.getElseStatement() ? hasDurableCall(node.getElseStatement()) : false;
|
|
672
|
-
return thenHas || elseHas;
|
|
673
|
-
}
|
|
674
|
-
if (Node.isBlock(node)) {
|
|
675
|
-
return node.getStatements().some(hasDurableCall);
|
|
676
|
-
}
|
|
677
|
-
return false;
|
|
678
|
-
}
|
|
679
|
-
function splitAtNextDurableCall(statements) {
|
|
680
|
-
for (let i = 0; i < statements.length; i++) {
|
|
681
|
-
const statement = statements[i];
|
|
682
|
-
if (Node.isReturnStatement(statement) || hasDurableCall(statement) || Node.isTryStatement(statement)) {
|
|
683
|
-
return {
|
|
684
|
-
syncBlock: statements.slice(0, i),
|
|
685
|
-
durableStatement: statement,
|
|
686
|
-
nextStatements: statements.slice(i + 1)
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
return { syncBlock: statements, durableStatement: null, nextStatements: [] };
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// src/compiler/cli.ts
|
|
694
|
-
var getArg = (name) => {
|
|
695
|
-
const argIndex = process.argv.indexOf(name);
|
|
696
|
-
if (argIndex !== -1 && process.argv.length > argIndex + 1) {
|
|
697
|
-
return process.argv[argIndex + 1];
|
|
698
|
-
}
|
|
699
|
-
return void 0;
|
|
700
|
-
};
|
|
701
|
-
async function run() {
|
|
702
|
-
const inputDir = getArg("--in");
|
|
703
|
-
const outputDir = getArg("--out");
|
|
704
|
-
if (!inputDir || !outputDir) {
|
|
705
|
-
console.error(
|
|
706
|
-
"Uso: b-durable-compiler --in <directorio_entrada> --out <directorio_salida>"
|
|
707
|
-
);
|
|
708
|
-
process.exit(1);
|
|
709
|
-
}
|
|
710
|
-
const absInput = path2.resolve(process.cwd(), inputDir);
|
|
711
|
-
const absOutput = path2.resolve(process.cwd(), outputDir);
|
|
712
|
-
await compileWorkflows({
|
|
713
|
-
inputDir: absInput,
|
|
714
|
-
outputDir: absOutput,
|
|
715
|
-
packageName: "@bobtail.software/b-durable"
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
run().catch((error) => {
|
|
719
|
-
console.error("Error durante la compilaci\xF3n:", error);
|
|
720
|
-
process.exit(1);
|
|
721
|
-
});
|
|
59
|
+
`,I=u.clauses.pop()||"",w=l?f:S;if(u.clauses.push(I.replace(/return { type: 'COMPLETE'.* };/,`context.step = ${w}; break;`)),t){if(m){let P=t.clauses[0]||`case ${p}: {}`;t.clauses[0]=P.replace("{",`{
|
|
60
|
+
const ${m} = result as unknown;`)}let E=t.clauses.pop()||"";t.clauses.push(E.replace(/return { type: 'COMPLETE'.* };/,`context.step = ${w}; break;`))}if(d){let E=d.clauses.pop()||"";d.clauses.push(E.replace(/return { type: 'COMPLETE'.* };/,`state.tryCatchStack?.pop(); context.step = ${S}; break;`))}return{clauses:[D,...u.clauses,...t?t.clauses:[],...d?d.clauses:[],...x.clauses],nextStep:x.nextStep}}function re(e,n,o){let s=[],a=new Map,c=ie(n),g=new Map(o);for(let r of e){if(i.isVariableStatement(r))for(let u of r.getDeclarations()){let t=u.getInitializer();if(!t)continue;let m=oe(u),p=m.filter(d=>c.has(d.name));if(p.length>0){let d=k(t,o);for(let{name:f,type:S}of p){a.set(f,{type:S}),g.set(f,{type:S});let x=m.length>1?`${d}.${f}`:d;s.push(`state.${f} = ${x};`)}}}s.push(k(r,g))}return{rewrittenSyncStatements:s,newlyPersistedVariables:a}}function oe(e){let n=e.getNameNode(),o=[];if(i.isIdentifier(n)){let s=e.getType().getText(e,V);o.push({name:n.getText(),type:s})}else if(i.isObjectBindingPattern(n))for(let s of n.getElements()){let a=s.getName(),c=s.getType().getText(s,V);o.push({name:a,type:c})}return o}function ae(e,n){if(i.isReturnStatement(e))return{instruction:`return { type: 'COMPLETE', result: ${e.getExpression()?k(e.getExpressionOrThrow(),n):"undefined"} };`,nextPendingStateAssignment:void 0};if(e.getDescendantsOfKind(b.AwaitExpression).length>1)throw new Error(`[b-durable Compiler Error] Multiple 'await' expressions found in a single statement at line ${e.getStartLineNumber()}.
|
|
61
|
+
Please split them into separate lines/variables to ensure safe state persistence.`);let s,a=e.getFirstDescendantByKind(b.VariableDeclaration);if(a){let g=a.getName(),r=a.getType().getText(a,V);n.set(g,{type:r}),s=`state.${g} = result;`}let c=e.getFirstDescendantByKind(b.AwaitExpression);if(c){let g=c.getParent();if(!(i.isExpressionStatement(g)||i.isVariableDeclaration(g)||i.isCallExpression(g)&&i.isExpressionStatement(g.getParent()))&&a&&a.getInitializer()!==c)throw new Error(`[b-durable Compiler Error] Complex 'await' usage detected at line ${e.getStartLineNumber()}.
|
|
62
|
+
The 'await' keyword must be the direct value of the assignment.
|
|
63
|
+
Invalid: const x = 1 + await foo();
|
|
64
|
+
Valid: const temp = await foo(); const x = 1 + temp;`);let l=c.getExpression();if(i.isCallExpression(l))return{instruction:`return ${ce(l,n)};`,nextPendingStateAssignment:s}}return{instruction:k(e,n),nextPendingStateAssignment:s}}function ie(e){let n=new Set;for(let o of e)o.getDescendantsOfKind(b.Identifier).forEach(s=>{n.add(s.getText())});return n}function k(e,n){let o=e.getText(),s=e.getStart(),a=[],c=e.getDescendantsOfKind(b.Identifier);i.isIdentifier(e)&&c.push(e),c.forEach(r=>{let l=r.getText();if(!n.has(l))return;let u=r.getSymbol();if(u&&u.getDeclarations().some(y=>y.getStart()>=e.getStart()&&y.getEnd()<=e.getEnd()))return;let t=r.getParent(),m=i.isVariableDeclaration(t)&&t.getNameNode()===r,p=i.isPropertyAccessExpression(t)&&t.getNameNode()===r||i.isPropertyAssignment(t)&&t.getNameNode()===r,d=i.isBindingElement(t)&&t.getNameNode()===r,f=i.isShorthandPropertyAssignment(t)&&t.getNameNode()===r,S=i.isParameterDeclaration(t)&&t.getNameNode()===r,x=i.isFunctionDeclaration(t)&&t.getNameNode()===r,N=i.isClassDeclaration(t)&&t.getNameNode()===r,D=i.isInterfaceDeclaration(t)&&t.getNameNode()===r,I=i.isTypeAliasDeclaration(t)&&t.getNameNode()===r,w=i.isEnumDeclaration(t)&&t.getNameNode()===r,E=i.isMethodDeclaration(t)&&t.getNameNode()===r;if(!m&&!p&&!d&&!S&&!x&&!N&&!D&&!I&&!w&&!E){let P=n.get(l),F=r.getStart()-s,y=r.getEnd()-s,h=`(state.${l} as ${P.type})`;f&&(h=`${l}: ${h}`),a.push({start:F,end:y,text:h})}}),a.sort((r,l)=>l.start-r.start);let g=o;for(let{start:r,end:l,text:u}of a)g=g.substring(0,r)+u+g.substring(l);return g}function ce(e,n){let o=e.getExpression(),s,a=!1;i.isPropertyAccessExpression(o)?(o.getExpression().getText()==="context"&&(a=!0),s=o.getName()):s=o.getText();let c=e.getArguments().map(t=>k(t,n)).join(", ");if(a)switch(s){case"bSleep":return`{ type: 'SCHEDULE_SLEEP', duration: ${c} }`;case"bWaitForEvent":return`{ type: 'WAIT_FOR_SIGNAL', signalName: ${c} }`;case"bExecute":{let[t,m]=e.getArguments(),p=t.getText(),d=m?k(m,n):"undefined";return`{ type: 'EXECUTE_SUBWORKFLOW', workflowName: ${p}.name, input: ${d} }`}case"bSignal":{let[t,m]=e.getArguments().map(p=>k(p,n));return`{ type: 'EMIT_EVENT', eventName: ${t}, payload: ${m} }`}default:throw new Error(`Funci\xF3n de contexto durable desconocida: '${s}'.`)}let g=o.getSymbol();if(!g)throw new Error(`S\xEDmbolo no encontrado para '${s}'.`);let r=g.getDeclarations()[0]?.asKind(b.ImportSpecifier);if(!r)throw new Error(`'${s}' debe ser importada.`);let l=r.getImportDeclaration().getModuleSpecifierSourceFileOrThrow();return`{ type: 'SCHEDULE_TASK', modulePath: '${T.relative(process.cwd(),l.getFilePath()).replace(/\\/g,"/")}', exportName: '${s}', args: [${c}] }`}function v(e){for(let n of e.getDescendantsOfKind(b.AwaitExpression)){let o=n.getExpressionIfKind(b.CallExpression);if(o){let s=o.getExpression();if(i.isPropertyAccessExpression(s)){let a=s.getName();if(s.getExpression().getText()==="context"&&(a==="bSleep"||a==="bWaitForEvent"||a==="bExecute"||a==="bSignal")||s.getSymbol()?.getDeclarations()[0]?.isKind(b.ImportSpecifier))return!0}else if(s.getSymbol()?.getDeclarations()[0]?.isKind(b.ImportSpecifier))return!0}}if(i.isTryStatement(e)&&(v(e.getTryBlock())||e.getCatchClause()&&v(e.getCatchClause().getBlock())||e.getFinallyBlock()&&v(e.getFinallyBlock())))return!0;if(i.isIfStatement(e)){let n=v(e.getThenStatement()),o=e.getElseStatement()?v(e.getElseStatement()):!1;return n||o}return i.isBlock(e)?e.getStatements().some(v):!1}function le(e){for(let n=0;n<e.length;n++){let o=e[n];if(i.isReturnStatement(o)||v(o)||i.isTryStatement(o))return{syncBlock:e.slice(0,n),durableStatement:o,nextStatements:e.slice(n+1)}}return{syncBlock:e,durableStatement:null,nextStatements:[]}}var q=e=>{let n=process.argv.indexOf(e);if(n!==-1&&process.argv.length>n+1)return process.argv[n+1]};async function pe(){let e=q("--in"),n=q("--out");(!e||!n)&&(console.error("Uso: b-durable-compiler --in <directorio_entrada> --out <directorio_salida>"),process.exit(1));let o=H.resolve(process.cwd(),e),s=H.resolve(process.cwd(),n);await U({inputDir:o,outputDir:s,packageName:"@bobtail.software/b-durable"})}pe().catch(e=>{console.error("Error durante la compilaci\xF3n:",e),process.exit(1)});
|