Skip to content

move out into write module #25

Closed
Closed

Description

@atherdon

Task: Pull filesystem I/O out of the generate-template core

Repo: LLazyEmail/generate-template
Goal: Core engine is catalog + render + payload → HTML. Disk is an adapter. run({ templateId, payload }) must not touch fs.

Why

The public contract is already GenerateRequest / GenerateResult. Filesystem leftover from the old in-app script still lives in the engine:

  • listTemplateFiles() scans templatesDir
  • payload.ts probes dataDir / {slug}.data.js / require()
  • render/file-adapter.ts writes temp files and spawnSyncs Node
  • CLI existsSyncs catalog file entries
  • Defaults still assume src/templates and src/data

Writers already go through markup-generator. Reads should follow the same split.

Out of scope

  • Do not add HTTP/Express
  • Do not publish to npmjs
  • Do not merge markup-generator into this package
  • Do not keep file + exportName on the default path

Target shape

src/
  engine/          createGenerator, run, render  (no node:fs)
  catalog/         find / slug / ids
  persist/         Writer → markup-generator only
  adapters/
    payload-files.ts    dataPath json / *.data.js
    file-renderer.ts    spawn path, opt-in
    list-files.ts       directory scan for CLI --list
  cli.ts           uses adapters, not the engine internals

Steps

  1. Audit every fs, path.resolve(process.cwd()), createRequire, spawnSync, os.tmpdir() import. Table: file, API, required or adapter.
  2. Engine rule: TemplateGenerator.render / run / loadPayload (default) use only:
    • catalog
    • injected render
    • explicit payload or samplePayloads or config.loadPayload
    • no templatesDir / dataDir unless an adapter is registered
  3. Move payload file loading to adapters/payload-files.ts. Wire it only when dataPath is set or useDataFiles: true. Default: missing payload → NO_PAYLOAD, do not existsSync(dataDir).
  4. Move listTemplateFiles off the class public API used by other repos, or keep it as listTemplateFiles(dir) on the CLI adapter. Engine lists catalog ids, not directories.
  5. Keep file-spawn in adapters/file-renderer.ts. Still gated by allowFileTemplates. Engine must not import spawnSync.
  6. CLI may import adapters. --list uses list-files. --data= uses payload-files. Generate still goes through run().
  7. Defaults: stop inventing src/templates and src/data when config omits them. outDir stays 'generated' only for writes.
  8. Tests
    • engine test with no temp dirs and no fs mock required for run({ templateId, payload })
    • payload-files adapter tests isolated
    • file-renderer tests stay behind the flag
    • sandbox keeps injected render + run({ write }) — that write path is markup-generator, allowed
  9. Docs: MIGRATION.md + README: “pass payload or loadPayload; do not rely on src/data/*.data.js unless you opt into the adapter.”

Done when

  • rg "node:fs|spawnSync|createRequire" src only hits src/adapters/ and src/cli.ts
  • run({ templateId, payload }) works in a process with no project src/templates or src/data
  • CI + npm run sandbox still produce HTML
  • Sibling note: if anyone used {slug}.data.js auto-load, they pass payload or enable the payload-files adapter

Suggested split

  • PR A: stop default dataDir probe; require explicit payload / sample / hook
  • PR B: move listTemplateFiles to CLI adapter
  • PR C: isolate file-spawn so generator.ts / render.ts have no fs

Activity

  1. atherdon commented on Sep 29, 2026

    @atherdon
    ContributorAuthor

    Issue #25 is: the engine should only catalog + render + payload. Disk belongs in markup-generator (writes already did; reads should too).

    Two PRs:

    1. markup-generator #275

    New public helpers:

    • pathExists(path)
    • listTemplateFiles(dir, { skipFiles, extensions }) — missing dir → []

    loadData / readJson / writeGeneratedFile were already here.

    2. generate-template #26

    • src/adapters/list-files.ts → listTemplateFiles from markup-generator
    • src/adapters/payload-files.ts → loadData + pathExists
    • generator.ts no longer imports node:fs
    • No default dataDir probe. Missing payload throws NO_PAYLOAD unless you pass payload, dataPath, samplePayloads, loadPayload, or useDataFiles: true

    Merge order: #275 → publish markup-generator → bump the dependency → merge #26.

    Still later (issue PR C): move spawnSync file-renderer so render.ts is also fs-free. Not in these PRs.

  2. added 2 commits that reference this issue on Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions