Skip to content

Regeneration and hand-authoring

Who this is for: the project author extending a generated guide with their own FSH and pages - and anyone who needs to know, precisely, what a regenerate run may delete.

Before you start: a generated project (Set up an IG project) and a first successful d2w fhir generate.

You will be able to:

  • tell generated content from yours by looking at one line
  • put hand-authored FSH and markdown where no run will ever touch it
  • predict exactly what a regenerate deletes, and why re-running converges
  • decide what to commit, and read the diff that matters after a metadata change

The regeneration contract

Every generated file opens with a header line, chosen by extension:

// Generated by d2w fhir generate - do not edit
<!-- Generated by d2w fhir generate - do not edit -->

A generate run writes its target subdirectory and then deletes only the header-bearing .fsh / .md files in that subdirectory that it did not just produce. JSON carries no comment syntax, so none of ig/input/resources/registry/, ig/input/resources/terminology/, or ig/input/resources/categories/ can be marked that way: each target owns its directory outright and deletes every *.json in it the run did not produce. That is also why each of the three has a directory to itself.

ig/input/resources/concept-maps/ is the one shared JSON directory, because two targets write into it. Neither owns it outright: each sweeps only the file-name prefix its own id stem produces (ConceptMap-d2-os-, ConceptMap-d2-cat-), so both still converge without deleting each other's maps. The same warning applies - nothing of yours belongs there either.

Put nothing of your own under ig/input/resources/

Those directories are owned outright by their generate targets, and a file without a header cannot protect itself there. Everywhere else, the header rule protects you.

Three consequences worth relying on:

  • Hand-authored content is safe. Drop your own .fsh files anywhere in ig/input/fsh/, or your own markdown in ig/input/pagecontent/, including beside generated files. Without the header they are never touched.
  • Re-running converges. Renaming an option set does not leave the old file behind; the run deletes it.
  • Unchanged output is not rewritten. Files whose content matches keep their timestamps, so a no-op regenerate leaves a clean git status.

What is scaffolded as yours

Two files exist precisely to be hand-authored, written once by d2w fhir init and never again:

File What it is for
ig/input/fsh/aliases.fsh your own aliases - which is why the DHIS2 aliases are generated into foundation/d2-aliases.fsh instead
ig/input/pagecontent/index.md the guide's home page

Beyond those, any markdown you drop into pagecontent/ survives every regenerate; to have it in the site menu, add it to menu: in sushi-config.yaml yourself. The generated prose - the forms.md, registry.md, terminology.md, identifiers.md, periods.md, and capture.md site pages, plus the per-artifact intro files the publisher injects - all carries the markdown header, so the sweep keeps them current and keeps its hands off yours. Every DHIS2 name and description on the generated pages is escaped on the way in: a data set called "Mortality < 5 years by gender" renders as text rather than aborting the publisher's HTML parse.

What to commit

Commit ig/input/fsh/ and ig/input/pagecontent/. Reviewing that diff after a metadata change is the point: the FSH tree is where a rename, a new form, or a changed option set becomes visible as a readable diff. ig/input/resources/ stays out of git - the scaffolded .gitignore covers it, because a national registry plus its terminology is thousands of JSON files that d2w fhir generate rebuilds from the instance in a few minutes.

When SUSHI sees a file twice

Duplicate definition of ... from the SUSHI compile means the same identity reached SUSHI twice, once compiled from FSH and once as a predefined resource. Generation sweeps the FSH it supersedes, so this points at generated FSH left behind by a version of the plugin that wrote a target in the other shape. d2w fhir generate clears it and reports the files in deleted_files; the count in that report is the confirmation.

Build and publish the guide is where the compile picks your hand-authored content up, and Serve the guide serves the very ig/fsh-generated/resources and ig/input/resources trees this page divides ownership of.

Next: the series index - this is the last page of the series.