SourceWork in progressThe weave writer

The weave writer

Part: Work in progress

Chapter: The weave writer

Package: packages/loom-lang/src/weave/LoomWeaver.ts

Language: TypeScript

Raw source

The weave writer

LoomWeaver is weave's disk writer, the mirror of LoomTangler. Where the tangler asks the compiler to compose a file and writes the source it emits, the weaver asks the compiler to project a corpus and writes the data it returns. Tangle writes many source files; weave writes one — the WovenCorpus a consumer renders.

The service is thin, because the compiler does the work. weave runs the compiler's weave verb for the corpus at entry, serialises the WovenCorpus to JSON, and writes it to out. It makes the output's directory first, so a fresh path lands without a missing-directory error, and returns the path it wrote, so the command can report it. The filesystem comes from the runtime, the same Bun platform the tangler writes through.

TypeScript
import { Context, Effect, FileSystem, Layer } from 'effect'
import { dirname } from 'node:path'
import { type Path } from '@athrio/loom-ast/LoomCorpusAst'
import { LoomCompiler } from '../LoomCompiler'

export class LoomWeaver extends Context.Service<LoomWeaver>()('LoomWeaver', {
  make: Effect.gen(function* () {
    const compiler = yield* LoomCompiler
    const fs = yield* FileSystem.FileSystem

    const weave = (entry: Path, out: Path): Effect.Effect<Path> =>
      compiler.weave(entry).pipe(
        Effect.map((corpus) => JSON.stringify(corpus, null, 2)),
        Effect.flatMap((json) =>
          fs
            .makeDirectory(dirname(out), { recursive: true })
            .pipe(Effect.andThen(fs.writeFileString(out, json)), Effect.orDie, Effect.as(out)),
        ),
      )

    return { weave }
  }),
}) {
  static readonly layer = Layer.effect(this, this.make).pipe(Layer.provide(LoomCompiler.layer))
}

The module

Loom