(source: string)
| 83 | } |
| 84 | |
| 85 | export function parseEditmodeBlock(source: string): EditmodeBlock | null { |
| 86 | const block = findMarkerBlock(source, 'EDITMODE'); |
| 87 | if (block === null) return null; |
| 88 | const raw = block.inner.trim(); |
| 89 | if (raw.length === 0) return { tokens: {}, raw, source: 'marked' }; |
| 90 | let parsed: unknown; |
| 91 | try { |
| 92 | parsed = JSON.parse(raw) as unknown; |
| 93 | } catch (cause) { |
| 94 | throw new CodesignError( |
| 95 | 'EDITMODE block contains invalid JSON', |
| 96 | ERROR_CODES.ARTIFACT_PROTOCOL_INVALID, |
| 97 | { |
| 98 | cause, |
| 99 | }, |
| 100 | ); |
| 101 | } |
| 102 | if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) { |
| 103 | throw new CodesignError( |
| 104 | 'EDITMODE block must contain a JSON object', |
| 105 | ERROR_CODES.ARTIFACT_PROTOCOL_INVALID, |
| 106 | ); |
| 107 | } |
| 108 | for (const [key, value] of Object.entries(parsed)) { |
| 109 | if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') { |
| 110 | throw new CodesignError( |
| 111 | `EDITMODE token "${key}" must be a string, number, or boolean`, |
| 112 | ERROR_CODES.ARTIFACT_PROTOCOL_INVALID, |
| 113 | ); |
| 114 | } |
| 115 | } |
| 116 | return { tokens: parsed as EditmodeTokens, raw, source: 'marked' }; |
| 117 | } |
| 118 | |
| 119 | export function replaceEditmodeBlock(source: string, newTokens: EditmodeTokens): string { |
| 120 | const json = JSON.stringify(newTokens, null, 2); |
no test coverage detected