This repository was archived by the owner on Mar 18, 2026. It is now read-only.
feat: complex-type-constraint and JSDoc support with type-schema v0.0.16#40
Open
Palid wants to merge 5 commits intofhir-schema:mainfrom
Open
feat: complex-type-constraint and JSDoc support with type-schema v0.0.16#40Palid wants to merge 5 commits intofhir-schema:mainfrom
Palid wants to merge 5 commits intofhir-schema:mainfrom
Conversation
…v0.0.16 Implements comprehensive FHIR profile constraint handling for Norwegian Basis and other complex-type profiles, plus rich JSDoc generation from FHIR metadata. Core Changes: - Add 'complex-type-constraint' TypeRefType variant - Extend ClassField with profileConstraints and documentation fields - Fix profile field merging to preserve base constraints and dependencies - Implement 144-line JSDoc generator with @summary/@description/@remarks - Prioritize profileConstraints for type selection (NoBasisHumanName vs HumanName) - Add CLI flags: --include-profile-constraints, --include-field-docs - Update type-schema to v0.0.16 This enables proper Norwegian Basis profile support with constrained types (NoBasisHumanName, NoBasisAddress) and comprehensive field documentation for improved developer experience.
4 tasks
Author
|
This PR has been mostly created with a significant help of AI agents. I assume similar changes would have to be done for python and c# generators, for properly being feature complete, but if that's the case I can prepare the code too. |
…d unions
Fixes critical spec violation where Extension profiles inherited ALL 55+ value[x]
types from base Extension, when they should only include CONSTRAINED type(s).
Implements discriminated unions per FHIR R4 extensibility specification.
Core Changes:
- Add isExtensionProfile() to detect Extension-based profiles
- Add extractValueXConstraints() to identify constrained value[x] types
- Add extractFixedUrl() to capture fixed URL constraints
- Add generateExtensionProfile() with discriminated union generation
- Add generateExtensionImports() for minimal import optimization
- Detect complex extensions (nested sub-extensions vs simple value)
- Route extension profiles to specialized generator in generateProfile()
Extension Type Handling:
1. Simple Extensions: Generate discriminated union for constrained value types
- Single type: export type NameValue = { valueCoding: Coding }
- Multiple: export type NameValue = { valueString: string } | { valueCoding: Coding }
2. Complex Extensions: Generate extension[] for nested sub-extensions
- No value field (mutual exclusivity per FHIR spec)
Type Safety Benefits:
- Discriminated unions enforce "ONE value type at a time" semantics
- TypeScript prevents multiple value properties simultaneously
- Compile-time errors for wrong value types
- Bundle size reduction: 50+ imports → 2-3 per extension
- Extends Element (not Extension) to avoid type pollution
FHIR Spec Compliance:
- "Extension SHALL have either value OR sub-extensions, not both" ✅
- "value[x] means value with TitleCased type name" ✅
- Per https://build.fhir.org/extensibility.html
Example Output (Norwegian Municipality Code):
Before: 55 properties (all value types), extends Extension
After: 2 properties (url + value union), extends Element, type-safe
This fix is essential for Norwegian Basis profiles and all FHIR extension
definitions. Prevents runtime errors from malformed FHIR resources.
…ation
Implements DRY principle for Extension value[x] discriminated unions by creating
a canonical ExtensionValueAll type that all extensions reference via helper.
Core Changes:
1. Add extension-values.ts static file with canonical types:
- ExtensionValueAll: Complete discriminated union of all 52 value[x] types
- ExtensionValueTypes: Interface mapping field names to types
- ExtractExtensionValue<K>: Helper to extract specific value types
2. Update generateExtensionProfile() to use shared helper:
- Generate: export type NameValue = ExtractExtensionValue<'valueCoding'>
- Instead of: 50+ line inline discriminated union
- Cross-references canonical ExtensionValueAll type
3. Fix meta property bug for complex-type profiles:
- Only add meta field for resource profiles (base.kind === 'resource')
- Complex types (Address, HumanName) don't have meta property
- Prevents TypeScript errors: "meta does not exist on type Address"
4. Add comprehensive test suite (extension-generation.test.ts):
- Test shared helper usage (no inline unions)
- Test simple extensions (constrained value types)
- Test complex extensions (extension[] array)
- Test type safety (discriminated unions prevent multiple values)
- Test cross-referencing (all extensions use same canonical type)
Benefits:
- DRY: Single source of truth for all Extension value types
- Maintainability: Update ExtensionValueAll once, affects all extensions
- Consistency: All extensions use identical discriminated union structure
- Bundle Size: Shared type reduces duplication across 50+ extensions
- Type Safety: ExtractExtensionValue enforces correct value types
Example Output:
Before: 50+ lines of inline | { valueString: string } | { valueCoding: Coding } ...
After: export type MunicipalityCodeValue = ExtractExtensionValue<'valueCoding'>
Testing:
✅ Extensions import from ../../extension-values
✅ No inline discriminated unions generated
✅ Type safety preserved with helper
✅ Complex-type profiles don't include meta property
154c420 to
5446357
Compare
Fix assertion in generateProfile() to accept both 'constraint' and 'complex-type-constraint' schema kinds. This prevents 28+ assertion failures during FHIR type generation. Error Before: Assertion failed (x28 during generation) Root Cause: assert(schema.identifier.kind === 'constraint') // ❌ Only allowed 'constraint', rejected 'complex-type-constraint' Fix: assert(schema.identifier.kind === 'constraint' || schema.identifier.kind === 'complex-type-constraint') // ✅ Allows both constraint types Impact: - Norwegian Basis profiles use 'complex-type-constraint' kind - Without this fix, profile generation silently fails assertion - Causes incomplete type generation and potential runtime errors Tested: ✅ bun run fhir:install completes without assertion failures ✅ All profiles generate successfully (NoBasisAddress, NoBasisHumanName, etc.) ✅ Type check passes (only 13 minor re-export warnings remain)
- Changes export { ... } to export type { ... } in index file generation
- Fixes TS1205 errors when isolatedModules is enabled
- Required for proper TypeScript compilation in consuming projects
Author
|
This requires a tiny cleanup (package.lock, etc), but generally close to being mergable. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Problem
FHIR profiles like Norwegian Basis define complex-type-constraints that extend base FHIR types with additional constraints. For example:
NoBasisHumanNameextendsHumanNamewith Norwegian-specific rulesNoBasisAddressextendsAddresswith postal code requirementsNoBasisPatientuses these constrained types instead of base typesCurrent Issues:
complex-type-constraintprofilesThis causes TypeScript errors and poor developer experience:
💡 Solution
This PR implements comprehensive support for complex-type-constraint profiles and field documentation:
1. Complex-Type-Constraint Recognition
'complex-type-constraint'toTypeRefTypeunion2. Profile Field Merging Fixes
Critical fixes for TypeScript subtype compatibility:
3. profileConstraints Type Priority
Generator now checks profileConstraints FIRST:
4. Comprehensive JSDoc Generation (144 lines)
5. CLI Flag Integration
New flags pass through to type-schema v0.0.16:
--include-profile-constraints: Extract profile URLs--include-field-docs: Extract field documentation📊 Evidence & Testing
Test Results
✅ Build: TypeScript compilation successful
✅ Tests: 28 pass, 6 fail (FHIR server integration tests - expected without server)
✅ Type Checking: Generated code passes
tsc --noEmitBefore/After Comparison
Before (without flags):
After (with flags):
🔧 Implementation Details
Files Modified (7 files, ~245 additions, ~12 deletions)
src/typeschema.ts: Extended TypeRefType and ClassField interfacesrc/loader.ts: Include complex-type-constraint in profiles()src/utils/code.ts: Filter complex-type-constraint appropriatelysrc/profile.ts: Complete field merging rewrite (41 lines)src/generators/typescript/index.ts: JSDoc + type priority (184 lines)src/utils/type-schema.ts: v0.0.16 + flag parameterssrc/commands/generate.ts: CLI option definitionsSingle Commit
5550d2b: feat: add complex-type-constraint and JSDoc support with type-schema v0.0.16🔗 Dependencies & Coordination
Requires: type-schema >= v0.0.16
JAR Download (for testing):
This PR Replaces:
patches/@fhirschema%2Fcodegen@0.0.24.patch🧪 Testing Instructions
🔄 Backward Compatibility
✅ All features are opt-in via CLI flags
✅ Existing workflows unchanged
✅ No breaking changes to generated code
✅ Tests confirm backward compatibility
⏭️ Merge Coordination
Recommended Order:
Alternative (can merge now):
✅ Checklist