From d6466555df792cda43c4db55698cc201cafe211f Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Wed, 1 Apr 2026 21:55:30 -0600 Subject: [PATCH] Saving modules to files --- src/cg/06-textEditor.cg | 10 +++++++--- src/runtime-js.ts | 22 ++++++++++++++++++++++ vite.config.ts | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 vite.config.ts diff --git a/src/cg/06-textEditor.cg b/src/cg/06-textEditor.cg index abcb686..554d72c 100644 --- a/src/cg/06-textEditor.cg +++ b/src/cg/06-textEditor.cg @@ -12,9 +12,13 @@ textEditor = name \ buffersKey = "textEditorBuffers"; # load from staging buffers if it exists there. if not, load from source - source = getAt [buffersKey, name] - | None \ getSource name - | Some v \ v; + # source = getAt [buffersKey, name] + # | None \ getSource name + # | Some v \ v; + + source = getModuleSource name + | Some s \ s + | None \ getSource name; lines = split "\n" source; diff --git a/src/runtime-js.ts b/src/runtime-js.ts index bc4358d..c840bb3 100644 --- a/src/runtime-js.ts +++ b/src/runtime-js.ts @@ -122,6 +122,12 @@ export const _rt = { if (!def) return ""; return prettyPrint(def); }, + getModuleSource: (moduleName: string) => { + const moduleDefs = [...definitions.values()] + .filter(d => d.module === moduleName); + if (moduleDefs.length === 0) return { _tag: 'None' }; + return { _tag: 'Some', _0: moduleDefs.map(d => prettyPrint(d)).join('\n\n') }; + }, "saveImage!": () => { const saved: Record = {}; for (const [name, ast] of definitions) { @@ -138,6 +144,22 @@ export const _rt = { URL.revokeObjectURL(url); return { _tag: 'Ok' }; }, + "saveModule!": (moduleName: string) => { + const moduleDefs = [...definitions.values()] + .filter(d => d.module === moduleName); + if (moduleDefs.length === 0) return { _tag: 'Err', _0: 'No module: ' + moduleName }; + + const content = '@' + moduleName + '\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: moduleName, content }) + }); + + return { _tag: 'Defined', _0: moduleName }; + }, rebind: (name: string, pathOrValue: any, maybeValue?: any) => { if (maybeValue === undefined) { store[name] = pathOrValue; diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..023e558 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite' +import fs from 'fs' +import path from 'path' + +export default defineConfig({ + plugins: [{ + name: 'cg-save', + configureServer(server) { + server.middlewares.use('/api/save', (req, res) => { + if (req.method !== 'POST') { + res.statusCode = 405; + res.end(); + return; + } + + let body = ''; + req.on('data', chunk => body += chunk); + req.on('end', () => { + try { + const { filename, content } = JSON.parse(body); + const filePath = path.join(__dirname, 'src/cg2', filename + '.cg'); + fs.writeFileSync(filePath, content); + res.statusCode = 200; + res.end(JSON.stringify({ ok: true })); + } catch (e: any) { + res.statusCode = 500; + res.end(JSON.stringify({ error: e.message })); + } + }); + }); + } + }] +})