(content: string)
| 133 | * ``` |
| 134 | */ |
| 135 | export function parseMarimoFormat(content: string): MarimoApp { |
| 136 | const cells: MarimoCell[] = [] |
| 137 | |
| 138 | // Extract version |
| 139 | const versionMatch = /__generated_with\s*=\s*["']([^"']+)["']/.exec(content) |
| 140 | const generatedWith = versionMatch?.[1] |
| 141 | |
| 142 | // Extract app width - handle both 'marimo.App' and 'mo.App' |
| 143 | const widthMatch = /(?:marimo|mo)\.App\([^)]*width\s*=\s*["']([^"']+)["']/.exec(content) |
| 144 | const width = widthMatch?.[1] |
| 145 | |
| 146 | // Extract title - handle both 'marimo.App' and 'mo.App' |
| 147 | const titleMatch = /(?:marimo|mo)\.App\([^)]*title\s*=\s*["']([^"']+)["']/.exec(content) |
| 148 | const title = titleMatch?.[1] |
| 149 | |
| 150 | // Parse cells - look for @app.cell and @app.function decorated functions |
| 151 | // This regex matches @app.cell or @app.function (with optional parameters) followed by def |
| 152 | // Capture group 1: decorator type ('cell' or 'function') |
| 153 | // Capture group 2: decorator arguments (if any) |
| 154 | // Capture group 3: function name |
| 155 | // Capture group 4: function parameters |
| 156 | // Capture group 5: function body |
| 157 | const cellRegex = |
| 158 | /@app\.(cell|function)(?:\(([^)]*)\))?\s*\n\s*def\s+(\w+)\s*\(([^)]*)\)\s*(?:->.*?)?\s*:\s*\n([\s\S]*?)(?=@app\.cell|@app\.function|if\s+__name__|$)/g |
| 159 | |
| 160 | let match: RegExpExecArray | null = cellRegex.exec(content) |
| 161 | |
| 162 | while (match !== null) { |
| 163 | const decoratorType = match[1] // 'cell' or 'function' |
| 164 | const decoratorArgs = match[2] || '' |
| 165 | const functionName = match[3] |
| 166 | const params = match[4].trim() |
| 167 | let body = match[5] |
| 168 | |
| 169 | // @app.function creates a reusable function, convert to code cell |
| 170 | const isAppFunction = decoratorType === 'function' |
| 171 | |
| 172 | // For @app.function, reconstruct the full function definition |
| 173 | if (isAppFunction) { |
| 174 | // Get the return type if present (captured separately) |
| 175 | const returnTypeMatch = /@app\.function(?:\([^)]*\))?\s*\n\s*def\s+\w+\s*\([^)]*\)\s*(->.*?)?\s*:/.exec( |
| 176 | content.slice(match.index) |
| 177 | ) |
| 178 | const returnType = returnTypeMatch?.[1] || '' |
| 179 | |
| 180 | // Reconstruct the function definition |
| 181 | const funcDef = `def ${functionName}(${params})${returnType}:\n${body}` |
| 182 | |
| 183 | cells.push({ |
| 184 | cellType: 'code', |
| 185 | content: funcDef.trim(), |
| 186 | functionName, |
| 187 | hidden: /hide_code\s*=\s*True/.test(decoratorArgs), |
| 188 | disabled: /disabled\s*=\s*True/.test(decoratorArgs), |
| 189 | }) |
| 190 | |
| 191 | match = cellRegex.exec(content) |
| 192 | continue |
no test coverage detected