diff --git a/src/runtime-js.ts b/src/runtime-js.ts index c840bb3..a67223c 100644 --- a/src/runtime-js.ts +++ b/src/runtime-js.ts @@ -129,20 +129,38 @@ export const _rt = { return { _tag: 'Some', _0: moduleDefs.map(d => prettyPrint(d)).join('\n\n') }; }, "saveImage!": () => { - const saved: Record = {}; - for (const [name, ast] of definitions) { - const source = prettyPrint({ kind: 'definition', name, body: ast }); - saved[name] = source; + const modules = new Map(); + const standalone: Definition[] = []; + + for (const [_name, def] of definitions) { + if (def.module) { + if (!modules.has(def.module)) modules.set(def.module, []); + modules.get(def.module)!.push(def); + } else { + standalone.push(def); + } + } + + // Save modules + for (const [moduleName, defs] of modules) { + const content = '@' + moduleName + '\n\n' + + defs.map(d => prettyPrint(d)).join('\n\n') + '\n\n@\n'; + fetch('/api/save', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: moduleName, content }) + }); + } + + // Save standalone defs + for (const def of definitions) { + const content = prettyPrint(def) + '\n'; + fetch('/api/save', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: def.name, content }) + }); } - const content = Object.values(saved).join('\n\n'); - const blob = new Blob([content], { type: 'text/plain' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `cg-image-${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}.cg`; - a.click(); - URL.revokeObjectURL(url); - return { _tag: 'Ok' }; }, "saveModule!": (moduleName: string) => { const moduleDefs = [...definitions.values()] @@ -160,6 +178,18 @@ export const _rt = { return { _tag: 'Defined', _0: moduleName }; }, + "saveDef!": (name: string) => { + const def = definitions.get(name); + if (!def) return { _tag: 'Err', _0: 'Unknown: ' + name }; + const content = prettyPrint(def) + '\n'; + fetch('/api/save', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: name, content }) + }); + + return { _tag: 'Defined', _0: name }; + }, rebind: (name: string, pathOrValue: any, maybeValue?: any) => { if (maybeValue === undefined) { store[name] = pathOrValue; @@ -240,6 +270,7 @@ export const _rt = { const source = prettyPrint(def); appendChangeLog(def.name, source); saveDefinitions(); + syncToFilesystem(def.name); return { _tag: 'Defined', _0: def.name }; } } catch (e: any) { @@ -428,3 +459,27 @@ function appendChangeLog(name: string, source: string) { console.error('Failed to append changelog:', e); } } + +function syncToFilesystem(name: string) { + const def = definitions.get(name); + if (!def) return; + + if (def.module) { + const moduleDefs = [...definitions.values()] + .filter(d => d.module === def.module); + const content = '@' + def.module + '\n\n' + + moduleDefs.map(d => prettyPrint(d)).join('\n\n') + '\n\n@\n'; + fetch('/api/save', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: def.module, content }) + }); + } else { + const content = prettyPrint(def) + '\n'; + fetch('/api/save', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ filename: name, content }) + }); + } +}