* Recursively resolve a trigger output builder function. * Handles the common pattern where builders spread other builders: * `return { ...buildBaseOutputs(), fieldA: { type: 'string', ... } }` * Also handles variable spreads: * `return { ...coreOutputs, ...deploymentOutputs }` * * Searche
( funcName: string, primaryContent: string, utilsContent: string, depth = 0 )
| 3133 | * Recursion depth is capped to avoid infinite loops. |
| 3134 | */ |
| 3135 | function resolveTriggerBuilderFunction( |
| 3136 | funcName: string, |
| 3137 | primaryContent: string, |
| 3138 | utilsContent: string, |
| 3139 | depth = 0 |
| 3140 | ): Record<string, any> { |
| 3141 | if (depth > 8) return {} |
| 3142 | |
| 3143 | const funcRegex = new RegExp(`(?:export\\s+)?function\\s+${funcName}\\s*\\(`) |
| 3144 | let funcBody: string | null = null |
| 3145 | |
| 3146 | for (const content of [primaryContent, utilsContent]) { |
| 3147 | const funcMatch = funcRegex.exec(content) |
| 3148 | if (!funcMatch) continue |
| 3149 | |
| 3150 | const bodyStart = content.indexOf('{', funcMatch.index) |
| 3151 | if (bodyStart === -1) continue |
| 3152 | |
| 3153 | const bodyEnd = findMatchingClose(content, bodyStart) |
| 3154 | if (bodyEnd === -1) continue |
| 3155 | |
| 3156 | funcBody = content.substring(bodyStart + 1, bodyEnd - 1) |
| 3157 | break |
| 3158 | } |
| 3159 | |
| 3160 | if (!funcBody) return {} |
| 3161 | |
| 3162 | // Handle `return anotherFunc(...)` — full delegation to another builder, |
| 3163 | // with or without arguments (argument values are ignored; only structure matters). |
| 3164 | const returnFuncCallMatch = /\breturn\s+([a-z][a-zA-Z0-9_]*)\s*\(/.exec(funcBody.trim()) |
| 3165 | if (returnFuncCallMatch) { |
| 3166 | return resolveTriggerBuilderFunction( |
| 3167 | returnFuncCallMatch[1], |
| 3168 | primaryContent, |
| 3169 | utilsContent, |
| 3170 | depth + 1 |
| 3171 | ) |
| 3172 | } |
| 3173 | |
| 3174 | // Handle `return { ... }` — inline object literal |
| 3175 | const returnMatch = /\breturn\s*\{/.exec(funcBody) |
| 3176 | if (!returnMatch) return {} |
| 3177 | |
| 3178 | const returnObjStart = funcBody.indexOf('{', returnMatch.index) |
| 3179 | const returnObjEnd = findMatchingClose(funcBody, returnObjStart) |
| 3180 | if (returnObjEnd === -1) return {} |
| 3181 | |
| 3182 | const returnBody = funcBody.substring(returnObjStart + 1, returnObjEnd - 1).trim() |
| 3183 | |
| 3184 | const result: Record<string, any> = {} |
| 3185 | |
| 3186 | // Expand function-call spreads first: ...innerFuncName() |
| 3187 | const spreadFuncRegex = /\.\.\.\s*(\w+)\s*\(\s*\)/g |
| 3188 | let spreadMatch: RegExpExecArray | null |
| 3189 | while ((spreadMatch = spreadFuncRegex.exec(returnBody)) !== null) { |
| 3190 | const innerFuncName = spreadMatch[1] |
| 3191 | const resolved = resolveTriggerBuilderFunction( |
| 3192 | innerFuncName, |
no test coverage detected