|
|
@@ -212,6 +212,10 @@ nlohmann::json StoredNode::toJson() const {
|
|
|
j["outputs"].push_back(output.toJson());
|
|
|
}
|
|
|
|
|
|
+ if (!dynamic_outputs.is_null()) {
|
|
|
+ j["dynamicOutputs"] = dynamic_outputs;
|
|
|
+ }
|
|
|
+
|
|
|
return j;
|
|
|
}
|
|
|
|
|
|
@@ -253,6 +257,10 @@ StoredNode StoredNode::fromJson(const nlohmann::json& j) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (j.contains("dynamicOutputs")) {
|
|
|
+ node.dynamic_outputs = j["dynamicOutputs"];
|
|
|
+ }
|
|
|
+
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
@@ -375,6 +383,49 @@ StoredNode StoredNode::parseFromCode(const std::string& code, const std::string&
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Parse dynamicOutputs object - ports a placed node derives from its config
|
|
|
+ std::regex dynamic_outputs_regex(R"(const\s+dynamicOutputs\s*=\s*)");
|
|
|
+ if (std::regex_search(code, match, dynamic_outputs_regex)) {
|
|
|
+ size_t start_pos = match.position() + match.length();
|
|
|
+ size_t brace_pos = code.find('{', start_pos);
|
|
|
+ if (brace_pos != std::string::npos) {
|
|
|
+ std::string jsonStr = jsLiteralToJson(code, brace_pos);
|
|
|
+ if (!jsonStr.empty()) {
|
|
|
+ try {
|
|
|
+ node.dynamic_outputs = nlohmann::json::parse(jsonStr);
|
|
|
+ } catch (const nlohmann::json::exception& e) {
|
|
|
+ LOG_WARN("Failed to parse dynamicOutputs for {}: {}", node.id, e.what());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Parse inputs array - a node with more than one input handle
|
|
|
+ std::regex inputs_start_regex(R"(const\s+inputs\s*=\s*\[)");
|
|
|
+ if (std::regex_search(code, match, inputs_start_regex)) {
|
|
|
+ size_t start_pos = match.position() + match.length() - 1;
|
|
|
+ std::string jsonStr = jsLiteralToJson(code, start_pos);
|
|
|
+ if (!jsonStr.empty()) {
|
|
|
+ try {
|
|
|
+ auto inputs_json = nlohmann::json::parse(jsonStr);
|
|
|
+ if (inputs_json.is_array()) {
|
|
|
+ for (const auto& in : inputs_json) {
|
|
|
+ NodeIO input;
|
|
|
+ input.name = in.value("name", "");
|
|
|
+ input.display_name = in.value("displayName", in.value("name", ""));
|
|
|
+ input.type = in.value("type", "any");
|
|
|
+ input.required = in.value("required", false);
|
|
|
+ if (!input.name.empty()) {
|
|
|
+ node.inputs.push_back(input);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (const nlohmann::json::exception& e) {
|
|
|
+ LOG_DEBUG("Failed to parse inputs array for {}: {}", node.id, e.what());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Default inputs (non-triggers get a data input)
|
|
|
if (node.inputs.empty() && !node.is_trigger) {
|
|
|
NodeIO default_input;
|