A generator creates a configuration file but when you add a setting that your project needs, then run the generator again to update something else. Should it replace your file, preserve your addition or leave you with two versions to reconcile?
Each choice has consequences since replacement keeps the output consistent with the generator but can remove customisations. Preserving the edited file leaves you responsible for incorporating generated updates. Merging can retain both changes, although the result still needs checking.
Jostraca provides controls for these situations. I tested version 0.39.0 with a small configuration file, comparing overwrite and merge behaviour after adding a manual change. Both cases worked as documented. My reservation concerns how clearly the configuration expresses the policy for existing files.
Describing the output
Jostraca is a code and project generation library. You declare an output tree through components such as Project, Folder, File and Content, then execute your generator program with Node.
import { Jostraca, Project, File, Content } from 'jostraca'
await Jostraca().generate({ folder: './out' }, () => {
Project({}, () => {
File({ name: 'config.sh' }, () => {
Content('PORT=8080\nHOST=localhost\n')
})
})
})
The nesting reflects the output structure. Repetition and conditions can use ordinary JavaScript, so the generator does not need a separate template language for those operations.
There is still a readability tradeoff. A substantial file assembled through many Content calls requires a reviewer to reconstruct its output from the generator code. Jostraca also supports file templates and slots, which allow more of the target structure to remain visible in its own syntax.
I would choose between those approaches according to what makes the output easier to review. For one static file, a small filesystem script would probably be sufficient. The component structure becomes more useful when maintaining repeated generation across a directory tree.
When replacement is appropriate
My test first generated a file containing a port and host. The script then appended DEBUG=1, representing a developer’s edit. A second generation changed the port from 8080 to 9090.
The overwrite case used:
const generator = Jostraca({
existing: {
txt: {
write: true,
merge: false,
},
},
})
Before regeneration:
PORT=8080
HOST=localhost
DEBUG=1
After regeneration:
PORT=9090
HOST=localhost
The port changed and the manual addition disappeared andhe conflicted-files list were both empty.
This matched the tutorial I found, which identifies overwriting as the default. Replacement is reasonable when the generator owns the complete file. Retaining arbitrary edits could otherwise leave the output inconsistent with its model or template.
The difficulty arises when developers are allowed to customise that output without a clear regeneration policy. A generator author should explain whether changes belong in the model, templates, extension files or generated files themselves. Choosing that boundary is part of designing the generator.
What merge preserved
I repeated the scenario with merging enabled:
const generator = Jostraca({
existing: {
txt: {
write: true,
merge: true,
},
},
})
The resulting file contained:
PORT=9090
HOST=localhost
DEBUG=1
The generated port update and the manual addition both survived and no conflict was reported.
The documentation describes a three-way merge using the previous generated version as a baseline. That provides a reference for distinguishing changes in the edited file from changes in the new generated output.
My example tested separate edits: the generator changed one line while the developer added another. I did not test competing changes to the same line, missing baseline state or substantial restructuring. These results demonstrate preservation in this case, rather than establishing reliability across all regeneration scenarios.
An empty conflict list also says nothing about application correctness. Two textual changes can coexist while introducing incompatible settings or incorrect behaviour. A clean merge still requires review and appropriate tests.
Making the policy easier to read
The documented present option offers a new version beside an existing file. Its example requires:
existing: {
txt: {
write: false,
present: true,
},
}
The tutorial warns that enabling present without disabling the default write behaviour permits replacement to take precedence. This interaction is explained, so it would be inaccurate to call it undocumented.
Nevertheless, I would prefer a single policy selection for the common cases. Someone choosing to present an alternative version should not also need to remember to disable overwriting.
An option such as mode: 'present' could express that intention directly. This is a proposed interface, not an existing Jostraca option. Advanced combinations might still require separate controls, but a simpler selection could make ordinary configurations easier to review.
The website pages I read identify Jostraca 0.36.6, while my executed tests used 0.39.0. I verified overwrite and merge behaviour in the installed version. I did not execute the present example as my concern is about the documented interface.
Keeping customisation recoverable
I want to customise generated output while retaining a recoverable original and a record of accepted changes. Editing a separate copy helps initially, but the next generation still requires a way to reconcile versions.
For customised files, I would generate proposed changes separately, inspect the diff and accept the result through Git. The documented present option appears relevant, although I would verify it against the installed version before adopting it.
The merge baseline, Git history and tests serve different purposes. The baseline supports reconciliation between generated and edited content. Git records accepted revisions and supports recovery. Tests check whether the resulting output meets the application’s requirements.
For files that should remain entirely generated, I would retain overwrite behaviour and direct customisation toward the model or templates. A project can use both approaches if the policy for each file is explicit.
Jostraca handled the two regeneration cases I checked as documented. I would consider it for repeated file-tree generation, with the existing-file policy tested and generated changes reviewed. A clearer policy-selection interface would make that workflow easier to configure correctly.
This is my complete test script if you wish to reproduce both cases. Run node review.mjs write and node review.mjs merge once each from a fresh working directory.
Top comments (0)