Skip to content

fix(sdc-assemble): preserve regular items mixed with subQuestionnaire placeholders#2001

Draft
oliveregger wants to merge 1 commit into
aehrc:mainfrom
ahdis:fix/assemble-preserve-mixed-items
Draft

fix(sdc-assemble): preserve regular items mixed with subQuestionnaire placeholders#2001
oliveregger wants to merge 1 commit into
aehrc:mainfrom
ahdis:fix/assemble-preserve-mixed-items

Conversation

@oliveregger

Copy link
Copy Markdown
Contributor

Problem

$assemble assumed every child of a form group (item[0].item) is a sdc-questionnaire-subQuestionnaire placeholder. getItems() returns a compact list (one entry per subquestionnaire, in document order) while propagateProperties() indexes it by parent item position. Those only align when the group is all placeholders.

When a regular item is mixed in with placeholders, the child items are applied at the wrong positions — regular items are silently dropped and the placeholder is left in the output with its subQuestionnaire extension unresolved.

Reproduction

Form group mixing a regular question with a placeholder:

// item[0].item
[
  { "linkId": "manifestation", "type": "choice" },           // regular item (index 0)
  { "linkId": "begin-ref", "type": "display", "extension": [ // placeholder  (index 1)
      { "url": ".../sdc-questionnaire-subQuestionnaire",
        "valueCanonical": ".../ManifestationBegin|1.0.0" } ] }
]

child ManifestationBegin[ beginUnknown (boolean), beginDate (date) ]

Expected Actual (before fix)
manifestation, beginUnknown, beginDate beginUnknown, beginDate, begin-ref (unresolved)manifestation dropped

Fix

Add alignItemsWithParentForm() (utils/canonical.ts) that re-expands the compact per-subquestionnaire item list into an array aligned to the parent form's item positions — child items at each placeholder position, null for every regular item. assembleQuestionnaire() aligns the list before calling propagateProperties().

propagateProperties() is unchanged: its existing contract (positional array, null where the parent item is not a placeholder — as its own unit tests already encode) is exactly what it now receives. Also extracts the extension URL into a SUB_QUESTIONNAIRE_EXTENSION_URL constant and an itemIsSubQuestionnaire() predicate, reused by getCanonicalUrls().

Behaviour change

  • Pure-modular forms (all placeholders): identical output — the aligned array equals the compact array index-for-index.
  • Mixed forms: now correct — regular items keep their position, placeholders are replaced in place, no leftover unresolved placeholders.

Tests

  • assemble.test.ts: end-to-end should preserve regular items mixed alongside a subquestionnaire placeholder — verified it fails on main (manifestation dropped) and passes with this change.
  • canonical.test.ts: unit tests for alignItemsWithParentForm (regular-before-placeholder, interleaved, all-placeholder no-op, empty-form passthrough).
  • Full suite: 128 passed (was 123). npm run build (tsup CJS/ESM/DTS) succeeds.

🤖 Generated with Claude Code

… placeholders

$assemble assumed every child of a form group (item[0].item) is a
sdc-questionnaire-subQuestionnaire placeholder. getItems() returns a compact
list (one entry per subquestionnaire) while propagateProperties() indexes it by
parent item position, so the two only align when the group is all placeholders.
When a regular item is mixed in with placeholders, the child items are applied
at the wrong positions: regular items get dropped and placeholders are left
unresolved.

Add alignItemsWithParentForm() to re-expand the compact list into an array
aligned to the parent form's item positions (child items at each placeholder
position, null for every regular item) before calling propagateProperties(),
whose positional contract is now satisfied. Extract the subQuestionnaire URL
into a SUB_QUESTIONNAIRE_EXTENSION_URL constant and an itemIsSubQuestionnaire()
predicate, reused by getCanonicalUrls().

Pure-modular forms (all placeholders) assemble identically; mixed forms are now
correct. Adds an end-to-end assemble test (fails without the fix) and unit tests
for the new helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oliveregger
oliveregger marked this pull request as draft July 13, 2026 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant