Jostraca code generation, made repeatable

Repeat content inside one file

Emit one block of content per array item inside a single file, with List.

Rendered from docs/how-to/repeat-content-in-one-file.md in the generator repository — where a correction belongs, and where the test suite runs every example on this page or states why it does not.

When the repetition is inside a file rather than across files, List emits one block per item.

import { Jostraca, Project, File, Content, List } from 'jostraca'

const users = [
  { name: 'Alice', role: 'admin' },
  { name: 'Bob', role: 'user' },
]

await Jostraca().generate({ folder: './out' }, () => {
  Project({}, () => {
    File({ name: 'users.txt' }, () => {

      List({ item: users, line: false }, ({ replace }) => {
        Content({ src: '{item.name}: {item.role}\n', replace })
      })
    })
  })
})

The generated users.txt:

Alice: admin
Bob: user

Two things in that call are easy to get wrong, and both fail silently.

replace must be threaded through the props form. The {item.…} substitution arrives in the replace object the child is handed, and Content’s second positional argument is children, not props. So Content('{item.name}', {replace}) substitutes nothing and writes the marker text verbatim. Use Content({src: …, replace}).

line: false turns off the trailing newline. By default List emits one after the whole list, and only the exact value false disables it—line: 0 still emits.

{item.path} resolves with the same path grammar as getx, so {item.a.b} works. It cannot address a $-suffixed key, though, so {item.val$}, {item.key$} and {item.index$} all come out empty. For a list of scalars, or when you want the index, use the item argument directly:

import { Jostraca, Project, File, Content, List } from 'jostraca'

await Jostraca().generate({ folder: './out' }, () => {
  Project({}, () => {
    File({ name: 'flags.txt' }, () => {
      List({ item: ['alpha', 'beta'], line: false }, ({ item }) => {
        Content('--' + item.val$ + '=' + item.index$ + '\n')
      })
    })
  })
})

The generated flags.txt:

--alpha=0
--beta=1

An unresolved {item.nope} yields the empty string, unlike $$nope$$, which is left in place. That asymmetry is a trap when a property name changes: the marker vanishes rather than shouting.

See also#