|
9 | 9 | setPluginRegistry, |
10 | 10 | } from "./plugin-service/plugin-registry"; |
11 | 11 | import { hydrateConfigValues } from "./utils"; |
| 12 | +import { merge } from "lodash"; |
12 | 13 |
|
13 | 14 | async function main() { |
14 | 15 | const app = express(); |
@@ -92,26 +93,96 @@ async function main() { |
92 | 93 | } |
93 | 94 | }); |
94 | 95 |
|
| 96 | + /** |
| 97 | + * Combines transform results, merging objects or returning the new result |
| 98 | + */ |
| 99 | + function combineResults(prevResult: unknown, newResult: unknown): unknown { |
| 100 | + // If both are objects (not arrays), merge them with new values taking precedence |
| 101 | + if ( |
| 102 | + typeof prevResult === "object" && |
| 103 | + prevResult !== null && |
| 104 | + !Array.isArray(prevResult) && |
| 105 | + typeof newResult === "object" && |
| 106 | + newResult !== null && |
| 107 | + !Array.isArray(newResult) |
| 108 | + ) { |
| 109 | + return merge({}, prevResult, newResult); |
| 110 | + } |
| 111 | + |
| 112 | + // Otherwise return the new result (string will just return) |
| 113 | + return newResult; |
| 114 | + } |
| 115 | + |
| 116 | + /** |
| 117 | + * Apply a series of transformations to content |
| 118 | + */ |
| 119 | + async function applyTransforms( |
| 120 | + content: any, |
| 121 | + transforms: Array<{ plugin: string; config: any }> = [], |
| 122 | + stage: string = "global", |
| 123 | + ) { |
| 124 | + let result = content; |
| 125 | + |
| 126 | + for (let i = 0; i < transforms.length; i++) { |
| 127 | + const transform = transforms[i]; |
| 128 | + try { |
| 129 | + // Hydrate config with environment variables |
| 130 | + const hydratedConfig = hydrateConfigValues(transform.config); |
| 131 | + |
| 132 | + // Load and configure transform plugin |
| 133 | + const plugin = await pluginService.getPlugin<"transformer">( |
| 134 | + transform.plugin, |
| 135 | + { |
| 136 | + type: "transformer", |
| 137 | + config: hydratedConfig, |
| 138 | + }, |
| 139 | + ); |
| 140 | + |
| 141 | + console.log( |
| 142 | + `Applying ${stage} transform #${i + 1} (${transform.plugin})`, |
| 143 | + ); |
| 144 | + const transformResult = await plugin.transform({ |
| 145 | + input: result, |
| 146 | + config: hydratedConfig, |
| 147 | + }); |
| 148 | + |
| 149 | + // Validate transform output |
| 150 | + if (transformResult === undefined || transformResult === null) { |
| 151 | + throw new Error( |
| 152 | + `Transform ${transform.plugin} returned null or undefined`, |
| 153 | + ); |
| 154 | + } |
| 155 | + |
| 156 | + // Combine results, either merging objects or using new result |
| 157 | + result = combineResults(result, transformResult); |
| 158 | + } catch (error) { |
| 159 | + console.error(`Transform error (${transform.plugin}):`, error); |
| 160 | + throw new Error( |
| 161 | + `Transform failed at ${stage} stage, plugin ${transform.plugin}, index ${i}: ${ |
| 162 | + error instanceof Error ? error.message : "Unknown error" |
| 163 | + }`, |
| 164 | + ); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + return result; |
| 169 | + } |
| 170 | + |
95 | 171 | // Transform endpoint |
96 | 172 | app.post("/api/transform", async (req, res) => { |
97 | 173 | try { |
98 | | - const { plugin: pluginName, config: pluginConfig, content } = req.body; |
| 174 | + const { transform, content } = req.body; |
99 | 175 |
|
100 | 176 | if (!content) { |
101 | 177 | throw new Error("No content provided for transformation"); |
102 | 178 | } |
103 | 179 |
|
104 | | - // Hydrate config with environment variables |
105 | | - const hydratedConfig = hydrateConfigValues(pluginConfig); |
106 | | - |
107 | | - // Load and configure transform plugin |
108 | | - const plugin = await pluginService.getPlugin<"transformer">(pluginName, { |
109 | | - type: "transformer", |
110 | | - config: hydratedConfig, |
111 | | - }); |
| 180 | + if (!Array.isArray(transform) || transform.length === 0) { |
| 181 | + throw new Error("No transforms specified"); |
| 182 | + } |
112 | 183 |
|
113 | | - // Transform content |
114 | | - const result = await plugin.transform({ input: content }); |
| 184 | + // Apply all transforms in sequence |
| 185 | + const result = await applyTransforms(content, transform); |
115 | 186 | res.json({ success: true, output: result }); |
116 | 187 | } catch (error) { |
117 | 188 | const errorMessage = |
|
0 commit comments