( source: string, line: number, column: number, ops: EditOp[], )
| 1163 | } |
| 1164 | |
| 1165 | export function applyEdit( |
| 1166 | source: string, |
| 1167 | line: number, |
| 1168 | column: number, |
| 1169 | ops: EditOp[], |
| 1170 | ): ApplyEditResult { |
| 1171 | if (ops.length === 0) return { ok: true, source }; |
| 1172 | |
| 1173 | const ast = parseSource(source); |
| 1174 | if (!ast) return { ok: false, status: 422, error: 'could not parse source' }; |
| 1175 | const element = findElementForEdit(ast, line, column, ops); |
| 1176 | if (!element) return { ok: false, status: 422, error: 'no JSX element at location' }; |
| 1177 | |
| 1178 | const splices: Splice[] = []; |
| 1179 | |
| 1180 | const styleOps = ops.flatMap((op) => |
| 1181 | op.kind === 'set-style' ? [{ key: op.key, value: op.value }] : [], |
| 1182 | ); |
| 1183 | if (styleOps.length > 0) { |
| 1184 | const result = buildStyleSplice(source, element, styleOps); |
| 1185 | if (result && 'error' in result) { |
| 1186 | return { ok: false, status: 422, error: result.error }; |
| 1187 | } |
| 1188 | if (result) splices.push(result); |
| 1189 | } |
| 1190 | |
| 1191 | for (const op of ops) { |
| 1192 | if (op.kind !== 'set-text-range-style') continue; |
| 1193 | const result = buildTextRangeStyleSplices( |
| 1194 | ast, |
| 1195 | source, |
| 1196 | element, |
| 1197 | op.start, |
| 1198 | op.end, |
| 1199 | { key: op.key, value: op.value }, |
| 1200 | op.prevText, |
| 1201 | ); |
| 1202 | if (result && 'error' in result) return { ok: false, status: 422, error: result.error }; |
| 1203 | if (result) splices.push(...result); |
| 1204 | } |
| 1205 | |
| 1206 | for (const op of ops) { |
| 1207 | if (op.kind !== 'set-text') continue; |
| 1208 | if (op.prevText !== undefined && (op.value.includes('\n') || op.prevText.includes('\n'))) { |
| 1209 | const richResult = buildTextContentSplices(element, op.value, op.prevText); |
| 1210 | if (!('error' in richResult)) { |
| 1211 | splices.push(...richResult); |
| 1212 | continue; |
| 1213 | } |
| 1214 | } |
| 1215 | const result = buildTextSplice(ast, element, op.value, op.prevText); |
| 1216 | if ('error' in result) { |
| 1217 | if (op.prevText === undefined) return { ok: false, status: 422, error: result.error }; |
| 1218 | const richResult = buildTextContentSplices(element, op.value, op.prevText); |
| 1219 | if ('error' in richResult) return { ok: false, status: 422, error: result.error }; |
| 1220 | splices.push(...richResult); |
| 1221 | } else { |
| 1222 | splices.push(result); |
no test coverage detected