@timo9378/flow2code 0.1.4 → 0.1.6
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/CHANGELOG.md +34 -0
- package/dist/cli.js +215 -103
- package/dist/compiler.cjs +48 -34
- package/dist/compiler.js +48 -34
- package/dist/server.js +134 -52
- package/out/404.html +1 -1
- package/out/__next.__PAGE__.txt +2 -2
- package/out/__next._full.txt +2 -2
- package/out/__next._head.txt +1 -1
- package/out/__next._index.txt +1 -1
- package/out/__next._tree.txt +1 -1
- package/out/_next/static/chunks/{2be31674b47c1089.js → bfa275b7488d8b70.js} +1 -1
- package/out/_not-found/__next._full.txt +1 -1
- package/out/_not-found/__next._head.txt +1 -1
- package/out/_not-found/__next._index.txt +1 -1
- package/out/_not-found/__next._not-found/__PAGE__.txt +1 -1
- package/out/_not-found/__next._not-found.txt +1 -1
- package/out/_not-found/__next._tree.txt +1 -1
- package/out/_not-found.html +1 -1
- package/out/_not-found.txt +1 -1
- package/out/index.html +2 -2
- package/out/index.txt +2 -2
- package/package.json +3 -3
- package/scripts/publish-all.sh +56 -0
- /package/out/_next/static/{OIo5LFjdea8u6u4evHHQo → wFX9tOZWtEdER7XrtbgHQ}/_buildManifest.js +0 -0
- /package/out/_next/static/{OIo5LFjdea8u6u4evHHQo → wFX9tOZWtEdER7XrtbgHQ}/_clientMiddlewareManifest.json +0 -0
- /package/out/_next/static/{OIo5LFjdea8u6u4evHHQo → wFX9tOZWtEdER7XrtbgHQ}/_ssgManifest.js +0 -0
package/dist/compiler.cjs
CHANGED
|
@@ -1831,21 +1831,22 @@ function compile(ir, options) {
|
|
|
1831
1831
|
errors: validation.errors.map((e) => `[${e.code}] ${e.message}`)
|
|
1832
1832
|
};
|
|
1833
1833
|
}
|
|
1834
|
+
const workingIR = validation.migrated && validation.migratedIR ? validation.migratedIR : ir;
|
|
1834
1835
|
let plan;
|
|
1835
1836
|
try {
|
|
1836
|
-
plan = topologicalSort(
|
|
1837
|
+
plan = topologicalSort(workingIR);
|
|
1837
1838
|
} catch (err) {
|
|
1838
1839
|
return {
|
|
1839
1840
|
success: false,
|
|
1840
1841
|
errors: [err instanceof Error ? err.message : String(err)]
|
|
1841
1842
|
};
|
|
1842
1843
|
}
|
|
1843
|
-
const nodeMap = new Map(
|
|
1844
|
+
const nodeMap = new Map(workingIR.nodes.map((n) => [n.id, n]));
|
|
1844
1845
|
const platformName = options?.platform ?? "nextjs";
|
|
1845
1846
|
const platform = getPlatform(platformName);
|
|
1846
|
-
const symbolTable = buildSymbolTable(
|
|
1847
|
+
const symbolTable = buildSymbolTable(workingIR);
|
|
1847
1848
|
const context = {
|
|
1848
|
-
ir,
|
|
1849
|
+
ir: workingIR,
|
|
1849
1850
|
plan,
|
|
1850
1851
|
nodeMap,
|
|
1851
1852
|
envVars: /* @__PURE__ */ new Set(),
|
|
@@ -1862,8 +1863,8 @@ function compile(ir, options) {
|
|
|
1862
1863
|
generatedBlockNodeIds: /* @__PURE__ */ new Set(),
|
|
1863
1864
|
pluginRegistry
|
|
1864
1865
|
};
|
|
1865
|
-
const trigger =
|
|
1866
|
-
const preComputedBlockNodes = computeControlFlowDescendants(
|
|
1866
|
+
const trigger = workingIR.nodes.find((n) => n.category === "trigger" /* TRIGGER */);
|
|
1867
|
+
const preComputedBlockNodes = computeControlFlowDescendants(workingIR, trigger.id);
|
|
1867
1868
|
for (const nodeId of preComputedBlockNodes) {
|
|
1868
1869
|
context.childBlockNodeIds.add(nodeId);
|
|
1869
1870
|
context.symbolTableExclusions.add(nodeId);
|
|
@@ -1873,7 +1874,7 @@ function compile(ir, options) {
|
|
|
1873
1874
|
);
|
|
1874
1875
|
if (hasConcurrency) {
|
|
1875
1876
|
context.dagMode = true;
|
|
1876
|
-
for (const node of
|
|
1877
|
+
for (const node of workingIR.nodes) {
|
|
1877
1878
|
if (node.category !== "trigger" /* TRIGGER */) {
|
|
1878
1879
|
context.symbolTableExclusions.add(node.id);
|
|
1879
1880
|
}
|
|
@@ -1888,8 +1889,8 @@ function compile(ir, options) {
|
|
|
1888
1889
|
});
|
|
1889
1890
|
const code = sourceFile.getFullText();
|
|
1890
1891
|
const filePath = platform.getOutputFilePath(trigger);
|
|
1891
|
-
collectRequiredPackages(
|
|
1892
|
-
const sourceMap = buildSourceMap(code,
|
|
1892
|
+
collectRequiredPackages(workingIR, context);
|
|
1893
|
+
const sourceMap = buildSourceMap(code, workingIR, filePath);
|
|
1893
1894
|
const dependencies = {
|
|
1894
1895
|
all: [...context.requiredPackages].sort(),
|
|
1895
1896
|
missing: [...context.requiredPackages].sort(),
|
|
@@ -2093,7 +2094,7 @@ function generateNodeChainDAG(writer, triggerId, context) {
|
|
|
2093
2094
|
generateNodeBody(writer, node, context);
|
|
2094
2095
|
});
|
|
2095
2096
|
writer.writeLine(`)();`);
|
|
2096
|
-
writer.writeLine(`${promiseVar}.catch(() => {});`);
|
|
2097
|
+
writer.writeLine(`${promiseVar}.catch((err) => { console.error("[Flow2Code DAG Error]", err); });`);
|
|
2097
2098
|
writer.blankLine();
|
|
2098
2099
|
}
|
|
2099
2100
|
if (dagNodeIds.length > 0) {
|
|
@@ -2143,11 +2144,8 @@ function generateConcurrentNodes(writer, nodeIds, context) {
|
|
|
2143
2144
|
writer.writeLine(";");
|
|
2144
2145
|
}
|
|
2145
2146
|
writer.writeLine(
|
|
2146
|
-
`
|
|
2147
|
+
`await Promise.all([${taskNames.map((t) => `${t}()`).join(", ")}]);`
|
|
2147
2148
|
);
|
|
2148
|
-
activeNodeIds.forEach((nodeId, i) => {
|
|
2149
|
-
writer.writeLine(`flowState['${nodeId}'] = r${i};`);
|
|
2150
|
-
});
|
|
2151
2149
|
activeNodeIds.forEach((nodeId) => {
|
|
2152
2150
|
const varName = context.symbolTable.getVarName(nodeId);
|
|
2153
2151
|
writer.writeLine(`const ${varName} = flowState['${nodeId}'];`);
|
|
@@ -2166,7 +2164,18 @@ function generateNodeBody(writer, node, context) {
|
|
|
2166
2164
|
const plugin = context.pluginRegistry.get(node.nodeType);
|
|
2167
2165
|
if (plugin) {
|
|
2168
2166
|
const pluginCtx = createPluginContext(context);
|
|
2169
|
-
|
|
2167
|
+
try {
|
|
2168
|
+
plugin.generate(node, writer, pluginCtx);
|
|
2169
|
+
} catch (err) {
|
|
2170
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2171
|
+
const stack = err instanceof Error ? err.stack : void 0;
|
|
2172
|
+
throw new Error(
|
|
2173
|
+
`[flow2code] Plugin "${node.nodeType}" threw an error while generating node "${node.label}" (${node.id}):
|
|
2174
|
+
${errMsg}` + (stack ? `
|
|
2175
|
+
Stack: ${stack}` : ""),
|
|
2176
|
+
{ cause: err }
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2170
2179
|
} else {
|
|
2171
2180
|
throw new Error(
|
|
2172
2181
|
`[flow2code] Unsupported node type: "${node.nodeType}". Register a plugin via pluginRegistry.register() or use a built-in node type.`
|
|
@@ -2174,6 +2183,13 @@ function generateNodeBody(writer, node, context) {
|
|
|
2174
2183
|
}
|
|
2175
2184
|
}
|
|
2176
2185
|
function createPluginContext(context) {
|
|
2186
|
+
const pendingChildBlockIds = [];
|
|
2187
|
+
const applyChildBlockRegistration = (nodeId) => {
|
|
2188
|
+
pendingChildBlockIds.push(nodeId);
|
|
2189
|
+
context.childBlockNodeIds.add(nodeId);
|
|
2190
|
+
context.symbolTableExclusions.add(nodeId);
|
|
2191
|
+
context.generatedBlockNodeIds.add(nodeId);
|
|
2192
|
+
};
|
|
2177
2193
|
return {
|
|
2178
2194
|
ir: context.ir,
|
|
2179
2195
|
nodeMap: context.nodeMap,
|
|
@@ -2199,9 +2215,7 @@ function createPluginContext(context) {
|
|
|
2199
2215
|
return resolveEnvVars(url, context);
|
|
2200
2216
|
},
|
|
2201
2217
|
generateChildNode(writer, node) {
|
|
2202
|
-
|
|
2203
|
-
context.symbolTableExclusions.add(node.id);
|
|
2204
|
-
context.generatedBlockNodeIds.add(node.id);
|
|
2218
|
+
applyChildBlockRegistration(node.id);
|
|
2205
2219
|
writer.writeLine(`// --- ${node.label} (${node.nodeType}) [${node.id}] ---`);
|
|
2206
2220
|
generateNodeBody(writer, node, context);
|
|
2207
2221
|
generateBlockContinuation(writer, node.id, context);
|
|
@@ -2245,27 +2259,27 @@ function collectRequiredPackages(ir, context) {
|
|
|
2245
2259
|
function buildSourceMap(code, ir, filePath) {
|
|
2246
2260
|
const lines = code.split("\n");
|
|
2247
2261
|
const mappings = {};
|
|
2248
|
-
const
|
|
2262
|
+
const validNodeIds = new Set(ir.nodes.map((n) => n.id));
|
|
2249
2263
|
let currentNodeId = null;
|
|
2250
2264
|
let currentStartLine = 0;
|
|
2251
2265
|
for (let i = 0; i < lines.length; i++) {
|
|
2252
2266
|
const lineNum = i + 1;
|
|
2253
|
-
const
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}
|
|
2266
|
-
currentNodeId = null;
|
|
2267
|
-
}
|
|
2267
|
+
const line = lines[i];
|
|
2268
|
+
const bracketOpen = line.indexOf("[");
|
|
2269
|
+
const bracketClose = line.indexOf("] ---", bracketOpen);
|
|
2270
|
+
if (bracketOpen === -1 || bracketClose === -1) continue;
|
|
2271
|
+
const trimmed = line.trimStart();
|
|
2272
|
+
if (!trimmed.startsWith("//")) continue;
|
|
2273
|
+
const candidateId = line.slice(bracketOpen + 1, bracketClose);
|
|
2274
|
+
if (!validNodeIds.has(candidateId)) continue;
|
|
2275
|
+
if (currentNodeId) {
|
|
2276
|
+
mappings[currentNodeId] = {
|
|
2277
|
+
startLine: currentStartLine,
|
|
2278
|
+
endLine: lineNum - 1
|
|
2279
|
+
};
|
|
2268
2280
|
}
|
|
2281
|
+
currentNodeId = candidateId;
|
|
2282
|
+
currentStartLine = lineNum;
|
|
2269
2283
|
}
|
|
2270
2284
|
if (currentNodeId) {
|
|
2271
2285
|
mappings[currentNodeId] = {
|
package/dist/compiler.js
CHANGED
|
@@ -1764,21 +1764,22 @@ function compile(ir, options) {
|
|
|
1764
1764
|
errors: validation.errors.map((e) => `[${e.code}] ${e.message}`)
|
|
1765
1765
|
};
|
|
1766
1766
|
}
|
|
1767
|
+
const workingIR = validation.migrated && validation.migratedIR ? validation.migratedIR : ir;
|
|
1767
1768
|
let plan;
|
|
1768
1769
|
try {
|
|
1769
|
-
plan = topologicalSort(
|
|
1770
|
+
plan = topologicalSort(workingIR);
|
|
1770
1771
|
} catch (err) {
|
|
1771
1772
|
return {
|
|
1772
1773
|
success: false,
|
|
1773
1774
|
errors: [err instanceof Error ? err.message : String(err)]
|
|
1774
1775
|
};
|
|
1775
1776
|
}
|
|
1776
|
-
const nodeMap = new Map(
|
|
1777
|
+
const nodeMap = new Map(workingIR.nodes.map((n) => [n.id, n]));
|
|
1777
1778
|
const platformName = options?.platform ?? "nextjs";
|
|
1778
1779
|
const platform = getPlatform(platformName);
|
|
1779
|
-
const symbolTable = buildSymbolTable(
|
|
1780
|
+
const symbolTable = buildSymbolTable(workingIR);
|
|
1780
1781
|
const context = {
|
|
1781
|
-
ir,
|
|
1782
|
+
ir: workingIR,
|
|
1782
1783
|
plan,
|
|
1783
1784
|
nodeMap,
|
|
1784
1785
|
envVars: /* @__PURE__ */ new Set(),
|
|
@@ -1795,8 +1796,8 @@ function compile(ir, options) {
|
|
|
1795
1796
|
generatedBlockNodeIds: /* @__PURE__ */ new Set(),
|
|
1796
1797
|
pluginRegistry
|
|
1797
1798
|
};
|
|
1798
|
-
const trigger =
|
|
1799
|
-
const preComputedBlockNodes = computeControlFlowDescendants(
|
|
1799
|
+
const trigger = workingIR.nodes.find((n) => n.category === "trigger" /* TRIGGER */);
|
|
1800
|
+
const preComputedBlockNodes = computeControlFlowDescendants(workingIR, trigger.id);
|
|
1800
1801
|
for (const nodeId of preComputedBlockNodes) {
|
|
1801
1802
|
context.childBlockNodeIds.add(nodeId);
|
|
1802
1803
|
context.symbolTableExclusions.add(nodeId);
|
|
@@ -1806,7 +1807,7 @@ function compile(ir, options) {
|
|
|
1806
1807
|
);
|
|
1807
1808
|
if (hasConcurrency) {
|
|
1808
1809
|
context.dagMode = true;
|
|
1809
|
-
for (const node of
|
|
1810
|
+
for (const node of workingIR.nodes) {
|
|
1810
1811
|
if (node.category !== "trigger" /* TRIGGER */) {
|
|
1811
1812
|
context.symbolTableExclusions.add(node.id);
|
|
1812
1813
|
}
|
|
@@ -1821,8 +1822,8 @@ function compile(ir, options) {
|
|
|
1821
1822
|
});
|
|
1822
1823
|
const code = sourceFile.getFullText();
|
|
1823
1824
|
const filePath = platform.getOutputFilePath(trigger);
|
|
1824
|
-
collectRequiredPackages(
|
|
1825
|
-
const sourceMap = buildSourceMap(code,
|
|
1825
|
+
collectRequiredPackages(workingIR, context);
|
|
1826
|
+
const sourceMap = buildSourceMap(code, workingIR, filePath);
|
|
1826
1827
|
const dependencies = {
|
|
1827
1828
|
all: [...context.requiredPackages].sort(),
|
|
1828
1829
|
missing: [...context.requiredPackages].sort(),
|
|
@@ -2026,7 +2027,7 @@ function generateNodeChainDAG(writer, triggerId, context) {
|
|
|
2026
2027
|
generateNodeBody(writer, node, context);
|
|
2027
2028
|
});
|
|
2028
2029
|
writer.writeLine(`)();`);
|
|
2029
|
-
writer.writeLine(`${promiseVar}.catch(() => {});`);
|
|
2030
|
+
writer.writeLine(`${promiseVar}.catch((err) => { console.error("[Flow2Code DAG Error]", err); });`);
|
|
2030
2031
|
writer.blankLine();
|
|
2031
2032
|
}
|
|
2032
2033
|
if (dagNodeIds.length > 0) {
|
|
@@ -2076,11 +2077,8 @@ function generateConcurrentNodes(writer, nodeIds, context) {
|
|
|
2076
2077
|
writer.writeLine(";");
|
|
2077
2078
|
}
|
|
2078
2079
|
writer.writeLine(
|
|
2079
|
-
`
|
|
2080
|
+
`await Promise.all([${taskNames.map((t) => `${t}()`).join(", ")}]);`
|
|
2080
2081
|
);
|
|
2081
|
-
activeNodeIds.forEach((nodeId, i) => {
|
|
2082
|
-
writer.writeLine(`flowState['${nodeId}'] = r${i};`);
|
|
2083
|
-
});
|
|
2084
2082
|
activeNodeIds.forEach((nodeId) => {
|
|
2085
2083
|
const varName = context.symbolTable.getVarName(nodeId);
|
|
2086
2084
|
writer.writeLine(`const ${varName} = flowState['${nodeId}'];`);
|
|
@@ -2099,7 +2097,18 @@ function generateNodeBody(writer, node, context) {
|
|
|
2099
2097
|
const plugin = context.pluginRegistry.get(node.nodeType);
|
|
2100
2098
|
if (plugin) {
|
|
2101
2099
|
const pluginCtx = createPluginContext(context);
|
|
2102
|
-
|
|
2100
|
+
try {
|
|
2101
|
+
plugin.generate(node, writer, pluginCtx);
|
|
2102
|
+
} catch (err) {
|
|
2103
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2104
|
+
const stack = err instanceof Error ? err.stack : void 0;
|
|
2105
|
+
throw new Error(
|
|
2106
|
+
`[flow2code] Plugin "${node.nodeType}" threw an error while generating node "${node.label}" (${node.id}):
|
|
2107
|
+
${errMsg}` + (stack ? `
|
|
2108
|
+
Stack: ${stack}` : ""),
|
|
2109
|
+
{ cause: err }
|
|
2110
|
+
);
|
|
2111
|
+
}
|
|
2103
2112
|
} else {
|
|
2104
2113
|
throw new Error(
|
|
2105
2114
|
`[flow2code] Unsupported node type: "${node.nodeType}". Register a plugin via pluginRegistry.register() or use a built-in node type.`
|
|
@@ -2107,6 +2116,13 @@ function generateNodeBody(writer, node, context) {
|
|
|
2107
2116
|
}
|
|
2108
2117
|
}
|
|
2109
2118
|
function createPluginContext(context) {
|
|
2119
|
+
const pendingChildBlockIds = [];
|
|
2120
|
+
const applyChildBlockRegistration = (nodeId) => {
|
|
2121
|
+
pendingChildBlockIds.push(nodeId);
|
|
2122
|
+
context.childBlockNodeIds.add(nodeId);
|
|
2123
|
+
context.symbolTableExclusions.add(nodeId);
|
|
2124
|
+
context.generatedBlockNodeIds.add(nodeId);
|
|
2125
|
+
};
|
|
2110
2126
|
return {
|
|
2111
2127
|
ir: context.ir,
|
|
2112
2128
|
nodeMap: context.nodeMap,
|
|
@@ -2132,9 +2148,7 @@ function createPluginContext(context) {
|
|
|
2132
2148
|
return resolveEnvVars(url, context);
|
|
2133
2149
|
},
|
|
2134
2150
|
generateChildNode(writer, node) {
|
|
2135
|
-
|
|
2136
|
-
context.symbolTableExclusions.add(node.id);
|
|
2137
|
-
context.generatedBlockNodeIds.add(node.id);
|
|
2151
|
+
applyChildBlockRegistration(node.id);
|
|
2138
2152
|
writer.writeLine(`// --- ${node.label} (${node.nodeType}) [${node.id}] ---`);
|
|
2139
2153
|
generateNodeBody(writer, node, context);
|
|
2140
2154
|
generateBlockContinuation(writer, node.id, context);
|
|
@@ -2178,27 +2192,27 @@ function collectRequiredPackages(ir, context) {
|
|
|
2178
2192
|
function buildSourceMap(code, ir, filePath) {
|
|
2179
2193
|
const lines = code.split("\n");
|
|
2180
2194
|
const mappings = {};
|
|
2181
|
-
const
|
|
2195
|
+
const validNodeIds = new Set(ir.nodes.map((n) => n.id));
|
|
2182
2196
|
let currentNodeId = null;
|
|
2183
2197
|
let currentStartLine = 0;
|
|
2184
2198
|
for (let i = 0; i < lines.length; i++) {
|
|
2185
2199
|
const lineNum = i + 1;
|
|
2186
|
-
const
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
}
|
|
2199
|
-
currentNodeId = null;
|
|
2200
|
-
}
|
|
2200
|
+
const line = lines[i];
|
|
2201
|
+
const bracketOpen = line.indexOf("[");
|
|
2202
|
+
const bracketClose = line.indexOf("] ---", bracketOpen);
|
|
2203
|
+
if (bracketOpen === -1 || bracketClose === -1) continue;
|
|
2204
|
+
const trimmed = line.trimStart();
|
|
2205
|
+
if (!trimmed.startsWith("//")) continue;
|
|
2206
|
+
const candidateId = line.slice(bracketOpen + 1, bracketClose);
|
|
2207
|
+
if (!validNodeIds.has(candidateId)) continue;
|
|
2208
|
+
if (currentNodeId) {
|
|
2209
|
+
mappings[currentNodeId] = {
|
|
2210
|
+
startLine: currentStartLine,
|
|
2211
|
+
endLine: lineNum - 1
|
|
2212
|
+
};
|
|
2201
2213
|
}
|
|
2214
|
+
currentNodeId = candidateId;
|
|
2215
|
+
currentStartLine = lineNum;
|
|
2202
2216
|
}
|
|
2203
2217
|
if (currentNodeId) {
|
|
2204
2218
|
mappings[currentNodeId] = {
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/server/index.ts
|
|
4
4
|
import { createServer } from "http";
|
|
5
5
|
import { readFile, stat } from "fs/promises";
|
|
6
|
-
import { join as join2, extname, dirname as dirname2 } from "path";
|
|
6
|
+
import { join as join2, extname, dirname as dirname2, resolve as resolve2 } from "path";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
import { existsSync as existsSync2 } from "fs";
|
|
9
9
|
|
|
@@ -1717,21 +1717,22 @@ function compile(ir, options) {
|
|
|
1717
1717
|
errors: validation.errors.map((e) => `[${e.code}] ${e.message}`)
|
|
1718
1718
|
};
|
|
1719
1719
|
}
|
|
1720
|
+
const workingIR = validation.migrated && validation.migratedIR ? validation.migratedIR : ir;
|
|
1720
1721
|
let plan;
|
|
1721
1722
|
try {
|
|
1722
|
-
plan = topologicalSort(
|
|
1723
|
+
plan = topologicalSort(workingIR);
|
|
1723
1724
|
} catch (err) {
|
|
1724
1725
|
return {
|
|
1725
1726
|
success: false,
|
|
1726
1727
|
errors: [err instanceof Error ? err.message : String(err)]
|
|
1727
1728
|
};
|
|
1728
1729
|
}
|
|
1729
|
-
const nodeMap = new Map(
|
|
1730
|
+
const nodeMap = new Map(workingIR.nodes.map((n) => [n.id, n]));
|
|
1730
1731
|
const platformName = options?.platform ?? "nextjs";
|
|
1731
1732
|
const platform = getPlatform(platformName);
|
|
1732
|
-
const symbolTable = buildSymbolTable(
|
|
1733
|
+
const symbolTable = buildSymbolTable(workingIR);
|
|
1733
1734
|
const context = {
|
|
1734
|
-
ir,
|
|
1735
|
+
ir: workingIR,
|
|
1735
1736
|
plan,
|
|
1736
1737
|
nodeMap,
|
|
1737
1738
|
envVars: /* @__PURE__ */ new Set(),
|
|
@@ -1748,8 +1749,8 @@ function compile(ir, options) {
|
|
|
1748
1749
|
generatedBlockNodeIds: /* @__PURE__ */ new Set(),
|
|
1749
1750
|
pluginRegistry
|
|
1750
1751
|
};
|
|
1751
|
-
const trigger =
|
|
1752
|
-
const preComputedBlockNodes = computeControlFlowDescendants(
|
|
1752
|
+
const trigger = workingIR.nodes.find((n) => n.category === "trigger" /* TRIGGER */);
|
|
1753
|
+
const preComputedBlockNodes = computeControlFlowDescendants(workingIR, trigger.id);
|
|
1753
1754
|
for (const nodeId of preComputedBlockNodes) {
|
|
1754
1755
|
context.childBlockNodeIds.add(nodeId);
|
|
1755
1756
|
context.symbolTableExclusions.add(nodeId);
|
|
@@ -1759,7 +1760,7 @@ function compile(ir, options) {
|
|
|
1759
1760
|
);
|
|
1760
1761
|
if (hasConcurrency) {
|
|
1761
1762
|
context.dagMode = true;
|
|
1762
|
-
for (const node of
|
|
1763
|
+
for (const node of workingIR.nodes) {
|
|
1763
1764
|
if (node.category !== "trigger" /* TRIGGER */) {
|
|
1764
1765
|
context.symbolTableExclusions.add(node.id);
|
|
1765
1766
|
}
|
|
@@ -1774,8 +1775,8 @@ function compile(ir, options) {
|
|
|
1774
1775
|
});
|
|
1775
1776
|
const code = sourceFile.getFullText();
|
|
1776
1777
|
const filePath = platform.getOutputFilePath(trigger);
|
|
1777
|
-
collectRequiredPackages(
|
|
1778
|
-
const sourceMap = buildSourceMap(code,
|
|
1778
|
+
collectRequiredPackages(workingIR, context);
|
|
1779
|
+
const sourceMap = buildSourceMap(code, workingIR, filePath);
|
|
1779
1780
|
const dependencies = {
|
|
1780
1781
|
all: [...context.requiredPackages].sort(),
|
|
1781
1782
|
missing: [...context.requiredPackages].sort(),
|
|
@@ -1979,7 +1980,7 @@ function generateNodeChainDAG(writer, triggerId, context) {
|
|
|
1979
1980
|
generateNodeBody(writer, node, context);
|
|
1980
1981
|
});
|
|
1981
1982
|
writer.writeLine(`)();`);
|
|
1982
|
-
writer.writeLine(`${promiseVar}.catch(() => {});`);
|
|
1983
|
+
writer.writeLine(`${promiseVar}.catch((err) => { console.error("[Flow2Code DAG Error]", err); });`);
|
|
1983
1984
|
writer.blankLine();
|
|
1984
1985
|
}
|
|
1985
1986
|
if (dagNodeIds.length > 0) {
|
|
@@ -2029,11 +2030,8 @@ function generateConcurrentNodes(writer, nodeIds, context) {
|
|
|
2029
2030
|
writer.writeLine(";");
|
|
2030
2031
|
}
|
|
2031
2032
|
writer.writeLine(
|
|
2032
|
-
`
|
|
2033
|
+
`await Promise.all([${taskNames.map((t) => `${t}()`).join(", ")}]);`
|
|
2033
2034
|
);
|
|
2034
|
-
activeNodeIds.forEach((nodeId, i) => {
|
|
2035
|
-
writer.writeLine(`flowState['${nodeId}'] = r${i};`);
|
|
2036
|
-
});
|
|
2037
2035
|
activeNodeIds.forEach((nodeId) => {
|
|
2038
2036
|
const varName = context.symbolTable.getVarName(nodeId);
|
|
2039
2037
|
writer.writeLine(`const ${varName} = flowState['${nodeId}'];`);
|
|
@@ -2052,7 +2050,18 @@ function generateNodeBody(writer, node, context) {
|
|
|
2052
2050
|
const plugin = context.pluginRegistry.get(node.nodeType);
|
|
2053
2051
|
if (plugin) {
|
|
2054
2052
|
const pluginCtx = createPluginContext(context);
|
|
2055
|
-
|
|
2053
|
+
try {
|
|
2054
|
+
plugin.generate(node, writer, pluginCtx);
|
|
2055
|
+
} catch (err) {
|
|
2056
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2057
|
+
const stack = err instanceof Error ? err.stack : void 0;
|
|
2058
|
+
throw new Error(
|
|
2059
|
+
`[flow2code] Plugin "${node.nodeType}" threw an error while generating node "${node.label}" (${node.id}):
|
|
2060
|
+
${errMsg}` + (stack ? `
|
|
2061
|
+
Stack: ${stack}` : ""),
|
|
2062
|
+
{ cause: err }
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2056
2065
|
} else {
|
|
2057
2066
|
throw new Error(
|
|
2058
2067
|
`[flow2code] Unsupported node type: "${node.nodeType}". Register a plugin via pluginRegistry.register() or use a built-in node type.`
|
|
@@ -2060,6 +2069,13 @@ function generateNodeBody(writer, node, context) {
|
|
|
2060
2069
|
}
|
|
2061
2070
|
}
|
|
2062
2071
|
function createPluginContext(context) {
|
|
2072
|
+
const pendingChildBlockIds = [];
|
|
2073
|
+
const applyChildBlockRegistration = (nodeId) => {
|
|
2074
|
+
pendingChildBlockIds.push(nodeId);
|
|
2075
|
+
context.childBlockNodeIds.add(nodeId);
|
|
2076
|
+
context.symbolTableExclusions.add(nodeId);
|
|
2077
|
+
context.generatedBlockNodeIds.add(nodeId);
|
|
2078
|
+
};
|
|
2063
2079
|
return {
|
|
2064
2080
|
ir: context.ir,
|
|
2065
2081
|
nodeMap: context.nodeMap,
|
|
@@ -2085,9 +2101,7 @@ function createPluginContext(context) {
|
|
|
2085
2101
|
return resolveEnvVars(url, context);
|
|
2086
2102
|
},
|
|
2087
2103
|
generateChildNode(writer, node) {
|
|
2088
|
-
|
|
2089
|
-
context.symbolTableExclusions.add(node.id);
|
|
2090
|
-
context.generatedBlockNodeIds.add(node.id);
|
|
2104
|
+
applyChildBlockRegistration(node.id);
|
|
2091
2105
|
writer.writeLine(`// --- ${node.label} (${node.nodeType}) [${node.id}] ---`);
|
|
2092
2106
|
generateNodeBody(writer, node, context);
|
|
2093
2107
|
generateBlockContinuation(writer, node.id, context);
|
|
@@ -2131,27 +2145,27 @@ function collectRequiredPackages(ir, context) {
|
|
|
2131
2145
|
function buildSourceMap(code, ir, filePath) {
|
|
2132
2146
|
const lines = code.split("\n");
|
|
2133
2147
|
const mappings = {};
|
|
2134
|
-
const
|
|
2148
|
+
const validNodeIds = new Set(ir.nodes.map((n) => n.id));
|
|
2135
2149
|
let currentNodeId = null;
|
|
2136
2150
|
let currentStartLine = 0;
|
|
2137
2151
|
for (let i = 0; i < lines.length; i++) {
|
|
2138
2152
|
const lineNum = i + 1;
|
|
2139
|
-
const
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
}
|
|
2152
|
-
currentNodeId = null;
|
|
2153
|
-
}
|
|
2153
|
+
const line = lines[i];
|
|
2154
|
+
const bracketOpen = line.indexOf("[");
|
|
2155
|
+
const bracketClose = line.indexOf("] ---", bracketOpen);
|
|
2156
|
+
if (bracketOpen === -1 || bracketClose === -1) continue;
|
|
2157
|
+
const trimmed = line.trimStart();
|
|
2158
|
+
if (!trimmed.startsWith("//")) continue;
|
|
2159
|
+
const candidateId = line.slice(bracketOpen + 1, bracketClose);
|
|
2160
|
+
if (!validNodeIds.has(candidateId)) continue;
|
|
2161
|
+
if (currentNodeId) {
|
|
2162
|
+
mappings[currentNodeId] = {
|
|
2163
|
+
startLine: currentStartLine,
|
|
2164
|
+
endLine: lineNum - 1
|
|
2165
|
+
};
|
|
2154
2166
|
}
|
|
2167
|
+
currentNodeId = candidateId;
|
|
2168
|
+
currentStartLine = lineNum;
|
|
2155
2169
|
}
|
|
2156
2170
|
if (currentNodeId) {
|
|
2157
2171
|
mappings[currentNodeId] = {
|
|
@@ -3469,7 +3483,9 @@ function handleCompile(body, projectRoot) {
|
|
|
3469
3483
|
let writtenPath = null;
|
|
3470
3484
|
if (shouldWrite && result.filePath && result.code) {
|
|
3471
3485
|
const fullPath = resolve(join(projectRoot, result.filePath));
|
|
3472
|
-
|
|
3486
|
+
const resolvedRoot = resolve(projectRoot);
|
|
3487
|
+
const sep = resolvedRoot.endsWith("/") || resolvedRoot.endsWith("\\") ? "" : process.platform === "win32" ? "\\" : "/";
|
|
3488
|
+
if (!fullPath.startsWith(resolvedRoot + sep)) {
|
|
3473
3489
|
return {
|
|
3474
3490
|
status: 400,
|
|
3475
3491
|
body: { success: false, error: "Output path escapes project root" }
|
|
@@ -3687,6 +3703,66 @@ function handleDecompile(body) {
|
|
|
3687
3703
|
}
|
|
3688
3704
|
}
|
|
3689
3705
|
|
|
3706
|
+
// src/lib/logger.ts
|
|
3707
|
+
import pc from "picocolors";
|
|
3708
|
+
var LEVEL_ORDER = {
|
|
3709
|
+
debug: 0,
|
|
3710
|
+
info: 1,
|
|
3711
|
+
warn: 2,
|
|
3712
|
+
error: 3,
|
|
3713
|
+
silent: 4
|
|
3714
|
+
};
|
|
3715
|
+
var Logger = class {
|
|
3716
|
+
/** Minimum log level (default: "info"). Set to "silent" to suppress all output. */
|
|
3717
|
+
level = "info";
|
|
3718
|
+
/** Prefix for all log lines (default: "[flow2code]") */
|
|
3719
|
+
prefix = "[flow2code]";
|
|
3720
|
+
shouldLog(level) {
|
|
3721
|
+
return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level];
|
|
3722
|
+
}
|
|
3723
|
+
debug(...args) {
|
|
3724
|
+
if (!this.shouldLog("debug")) return;
|
|
3725
|
+
console.log(pc.gray(`${this.prefix} ${pc.dim("DEBUG")}`), ...args);
|
|
3726
|
+
}
|
|
3727
|
+
info(...args) {
|
|
3728
|
+
if (!this.shouldLog("info")) return;
|
|
3729
|
+
console.log(pc.blue(`${this.prefix}`), ...args);
|
|
3730
|
+
}
|
|
3731
|
+
success(...args) {
|
|
3732
|
+
if (!this.shouldLog("info")) return;
|
|
3733
|
+
console.log(pc.green(`${this.prefix} \u2705`), ...args);
|
|
3734
|
+
}
|
|
3735
|
+
warn(...args) {
|
|
3736
|
+
if (!this.shouldLog("warn")) return;
|
|
3737
|
+
console.warn(pc.yellow(`${this.prefix} \u26A0\uFE0F`), ...args);
|
|
3738
|
+
}
|
|
3739
|
+
error(...args) {
|
|
3740
|
+
if (!this.shouldLog("error")) return;
|
|
3741
|
+
console.error(pc.red(`${this.prefix} \u274C`), ...args);
|
|
3742
|
+
}
|
|
3743
|
+
/** Print a blank line (respects silent mode) */
|
|
3744
|
+
blank() {
|
|
3745
|
+
if (!this.shouldLog("info")) return;
|
|
3746
|
+
console.log();
|
|
3747
|
+
}
|
|
3748
|
+
/** Print raw text without prefix (respects silent mode) */
|
|
3749
|
+
raw(...args) {
|
|
3750
|
+
if (!this.shouldLog("info")) return;
|
|
3751
|
+
console.log(...args);
|
|
3752
|
+
}
|
|
3753
|
+
/** Formatted key-value line for startup banners */
|
|
3754
|
+
kv(key, value) {
|
|
3755
|
+
if (!this.shouldLog("info")) return;
|
|
3756
|
+
console.log(` ${pc.dim("\u251C\u2500")} ${pc.bold(key)} ${value}`);
|
|
3757
|
+
}
|
|
3758
|
+
/** Last key-value line (uses └─) */
|
|
3759
|
+
kvLast(key, value) {
|
|
3760
|
+
if (!this.shouldLog("info")) return;
|
|
3761
|
+
console.log(` ${pc.dim("\u2514\u2500")} ${pc.bold(key)} ${value}`);
|
|
3762
|
+
}
|
|
3763
|
+
};
|
|
3764
|
+
var logger = new Logger();
|
|
3765
|
+
|
|
3690
3766
|
// src/server/index.ts
|
|
3691
3767
|
var __filename = fileURLToPath(import.meta.url);
|
|
3692
3768
|
var __dirname = dirname2(__filename);
|
|
@@ -3768,7 +3844,7 @@ function sendJson(res, status, body) {
|
|
|
3768
3844
|
}
|
|
3769
3845
|
var MAX_BODY_SIZE = 2 * 1024 * 1024;
|
|
3770
3846
|
async function readBody(req) {
|
|
3771
|
-
return new Promise((
|
|
3847
|
+
return new Promise((resolve3, reject) => {
|
|
3772
3848
|
const chunks = [];
|
|
3773
3849
|
let totalSize = 0;
|
|
3774
3850
|
req.on("data", (chunk) => {
|
|
@@ -3780,7 +3856,7 @@ async function readBody(req) {
|
|
|
3780
3856
|
}
|
|
3781
3857
|
chunks.push(chunk);
|
|
3782
3858
|
});
|
|
3783
|
-
req.on("end", () =>
|
|
3859
|
+
req.on("end", () => resolve3(Buffer.concat(chunks).toString("utf-8")));
|
|
3784
3860
|
req.on("error", reject);
|
|
3785
3861
|
});
|
|
3786
3862
|
}
|
|
@@ -3789,7 +3865,13 @@ async function parseJsonBody(req) {
|
|
|
3789
3865
|
return JSON.parse(raw);
|
|
3790
3866
|
}
|
|
3791
3867
|
async function serveStatic(staticDir, pathname, res) {
|
|
3792
|
-
|
|
3868
|
+
const decodedPath = decodeURIComponent(pathname);
|
|
3869
|
+
let filePath = join2(staticDir, decodedPath === "/" ? "index.html" : decodedPath);
|
|
3870
|
+
const resolvedPath = resolve2(filePath);
|
|
3871
|
+
const resolvedStaticDir = resolve2(staticDir);
|
|
3872
|
+
if (!resolvedPath.startsWith(resolvedStaticDir + (resolvedStaticDir.endsWith("/") || resolvedStaticDir.endsWith("\\") ? "" : process.platform === "win32" ? "\\" : "/"))) {
|
|
3873
|
+
return false;
|
|
3874
|
+
}
|
|
3793
3875
|
if (!extname(filePath)) {
|
|
3794
3876
|
filePath += ".html";
|
|
3795
3877
|
}
|
|
@@ -3877,7 +3959,7 @@ function startServer(options = {}) {
|
|
|
3877
3959
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
3878
3960
|
const server = createServer((req, res) => {
|
|
3879
3961
|
handleRequest(req, res, staticDir, projectRoot).catch((err) => {
|
|
3880
|
-
|
|
3962
|
+
logger.error("Internal error:", err);
|
|
3881
3963
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
3882
3964
|
res.end("Internal Server Error");
|
|
3883
3965
|
});
|
|
@@ -3888,20 +3970,20 @@ function startServer(options = {}) {
|
|
|
3888
3970
|
if (options.onReady) {
|
|
3889
3971
|
options.onReady(url);
|
|
3890
3972
|
} else {
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3973
|
+
logger.blank();
|
|
3974
|
+
logger.info("Flow2Code Dev Server");
|
|
3975
|
+
logger.kv("Local:", url);
|
|
3976
|
+
logger.kv("API:", `${url}/api/compile`);
|
|
3977
|
+
logger.kv("Static:", staticDir);
|
|
3978
|
+
logger.kvLast("Project:", projectRoot);
|
|
3897
3979
|
if (!hasUI) {
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3980
|
+
logger.blank();
|
|
3981
|
+
logger.warn("UI files not found (out/index.html missing).");
|
|
3982
|
+
logger.raw(" The API endpoints still work, but the visual editor won't load.");
|
|
3983
|
+
logger.raw(' To fix: run "pnpm build:ui" in the flow2code source directory,');
|
|
3984
|
+
logger.raw(" or reinstall from npm: npm i @timo9378/flow2code@latest");
|
|
3903
3985
|
}
|
|
3904
|
-
|
|
3986
|
+
logger.blank();
|
|
3905
3987
|
}
|
|
3906
3988
|
});
|
|
3907
3989
|
return server;
|