From 916f2fdfd9e444d6f89f0d3569ad0c3d75556688 Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Tue, 13 Jan 2026 11:55:14 +0000 Subject: [PATCH 01/10] rebase --- Makefile | 4 + .../__snapshots__/ccda.test.ts.snap | 149 +++++++++ .../__snapshots__/local-package.test.ts.snap | 127 ++++++++ .../__snapshots__/sql-on-fhir.test.ts.snap | 289 ++++++++++++++++++ .../multi-package/ccda.test.ts | 83 +++++ .../multi-package/local-package.test.ts | 110 +++++++ .../multi-package/sql-on-fhir.test.ts | 107 +++++++ .../example-notebook.structuredefinition.json | 175 +++++++++++ 8 files changed, 1044 insertions(+) create mode 100644 test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap create mode 100644 test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap create mode 100644 test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap create mode 100644 test/api/write-generator/multi-package/ccda.test.ts create mode 100644 test/api/write-generator/multi-package/local-package.test.ts create mode 100644 test/api/write-generator/multi-package/sql-on-fhir.test.ts create mode 100644 test/assets/local-package/structure-definitions/example-notebook.structuredefinition.json diff --git a/Makefile b/Makefile index 8df815027..89ad62b22 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,10 @@ test-python-fhirpy-sdk: typecheck format prepare-aidbox-runme lint generate-pyth . venv/bin/activate && \ mypy --strict . +py-run: + $(TYPECHECK) --project examples/python/tsconfig.json + bun run examples/python/generate.ts + release: echo Push tag for $(VERSION) git tag -a v$(VERSION) -m "Release $(VERSION)" diff --git a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap new file mode 100644 index 000000000..d07c60a42 --- /dev/null +++ b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap @@ -0,0 +1,149 @@ +// Bun Snapshot v1, https://bun.sh/docs/test/snapshots + +exports[`CCDA Package - Multi-Package Generation TypeScript Generation should generate ClinicalDocument type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { ANY } from "../hl7-cda-uv-core/Any"; +import type { Authenticator } from "../hl7-cda-uv-core/Authenticator"; +import type { Author } from "../hl7-cda-uv-core/Author"; +import type { Authorization } from "../hl7-cda-uv-core/Authorization"; +import type { CD } from "../hl7-cda-uv-core/Cd"; +import type { CE } from "../hl7-cda-uv-core/Ce"; +import type { Component } from "../hl7-cda-uv-core/Component"; +import type { ComponentOf } from "../hl7-cda-uv-core/ComponentOf"; +import type { CS } from "../hl7-cda-uv-core/Cs"; +import type { Custodian } from "../hl7-cda-uv-core/Custodian"; +import type { DataEnterer } from "../hl7-cda-uv-core/DataEnterer"; +import type { DocumentationOf } from "../hl7-cda-uv-core/DocumentationOf"; +import type { II } from "../hl7-cda-uv-core/Ii"; +import type { Informant } from "../hl7-cda-uv-core/Informant"; +import type { InformationRecipient } from "../hl7-cda-uv-core/InformationRecipient"; +import type { InFulfillmentOf } from "../hl7-cda-uv-core/InFulfillmentOf"; +import type { INT } from "../hl7-cda-uv-core/Int"; +import type { LegalAuthenticator } from "../hl7-cda-uv-core/LegalAuthenticator"; +import type { Participant1 } from "../hl7-cda-uv-core/Participant1"; +import type { RecordTarget } from "../hl7-cda-uv-core/RecordTarget"; +import type { RelatedDocument } from "../hl7-cda-uv-core/RelatedDocument"; +import type { ST } from "../hl7-cda-uv-core/St"; +import type { TS } from "../hl7-cda-uv-core/Ts"; + +import type { Element } from "../hl7-fhir-r5-core/Element"; +// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument +export interface ClinicalDocument extends ANY { + resourceType: "ClinicalDocument"; + + authenticator?: Authenticator[]; + author: Author[]; + authorization?: Authorization[]; + classCode?: string; + _classCode?: Element; + code: CE; + component: Component; + componentOf?: ComponentOf; + confidentialityCode: CE; + copyTime?: TS; + custodian: Custodian; + dataEnterer?: DataEnterer; + documentationOf?: DocumentationOf[]; + effectiveTime: TS; + id: II; + informant?: Informant[]; + informationRecipient?: InformationRecipient[]; + inFulfillmentOf?: InFulfillmentOf[]; + languageCode?: CS; + legalAuthenticator?: LegalAuthenticator; + moodCode?: ("INT" | "APT" | "ARQ" | "PRMS" | "PRP" | "RQO" | "SLOT" | "DEF" | "EVN" | "EVN.CRT" | "GOL" | "OPT" | "PERM" | "PERMRQ"); + _moodCode?: Element; + participant?: Participant1[]; + realmCode?: CS[]; + recordTarget: RecordTarget[]; + relatedDocument?: RelatedDocument[]; + sdtcCategory?: CD[]; + sdtcStatusCode?: CS; + setId?: II; + templateId?: II[]; + title?: ST; + typeId?: II; + versionNumber?: INT; +} +export const isClinicalDocument = (resource: unknown): resource is ClinicalDocument => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ClinicalDocument"; +} +" +`; + +exports[`CCDA TypeScript Generation should generate ClinicalDocument type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { ANY } from "../hl7-cda-uv-core/Any"; +import type { Authenticator } from "../hl7-cda-uv-core/Authenticator"; +import type { Author } from "../hl7-cda-uv-core/Author"; +import type { Authorization } from "../hl7-cda-uv-core/Authorization"; +import type { CD } from "../hl7-cda-uv-core/Cd"; +import type { CE } from "../hl7-cda-uv-core/Ce"; +import type { Component } from "../hl7-cda-uv-core/Component"; +import type { ComponentOf } from "../hl7-cda-uv-core/ComponentOf"; +import type { CS } from "../hl7-cda-uv-core/Cs"; +import type { Custodian } from "../hl7-cda-uv-core/Custodian"; +import type { DataEnterer } from "../hl7-cda-uv-core/DataEnterer"; +import type { DocumentationOf } from "../hl7-cda-uv-core/DocumentationOf"; +import type { II } from "../hl7-cda-uv-core/Ii"; +import type { Informant } from "../hl7-cda-uv-core/Informant"; +import type { InformationRecipient } from "../hl7-cda-uv-core/InformationRecipient"; +import type { InFulfillmentOf } from "../hl7-cda-uv-core/InFulfillmentOf"; +import type { INT } from "../hl7-cda-uv-core/Int"; +import type { LegalAuthenticator } from "../hl7-cda-uv-core/LegalAuthenticator"; +import type { Participant1 } from "../hl7-cda-uv-core/Participant1"; +import type { RecordTarget } from "../hl7-cda-uv-core/RecordTarget"; +import type { RelatedDocument } from "../hl7-cda-uv-core/RelatedDocument"; +import type { ST } from "../hl7-cda-uv-core/St"; +import type { TS } from "../hl7-cda-uv-core/Ts"; + +import type { Element } from "../hl7-fhir-r5-core/Element"; +// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument +export interface ClinicalDocument extends ANY { + resourceType: "ClinicalDocument"; + + authenticator?: Authenticator[]; + author: Author[]; + authorization?: Authorization[]; + classCode?: string; + _classCode?: Element; + code: CE; + component: Component; + componentOf?: ComponentOf; + confidentialityCode: CE; + copyTime?: TS; + custodian: Custodian; + dataEnterer?: DataEnterer; + documentationOf?: DocumentationOf[]; + effectiveTime: TS; + id: II; + informant?: Informant[]; + informationRecipient?: InformationRecipient[]; + inFulfillmentOf?: InFulfillmentOf[]; + languageCode?: CS; + legalAuthenticator?: LegalAuthenticator; + moodCode?: ("INT" | "APT" | "ARQ" | "PRMS" | "PRP" | "RQO" | "SLOT" | "DEF" | "EVN" | "EVN.CRT" | "GOL" | "OPT" | "PERM" | "PERMRQ"); + _moodCode?: Element; + participant?: Participant1[]; + realmCode?: CS[]; + recordTarget: RecordTarget[]; + relatedDocument?: RelatedDocument[]; + sdtcCategory?: CD[]; + sdtcStatusCode?: CS; + setId?: II; + templateId?: II[]; + title?: ST; + typeId?: II; + versionNumber?: INT; +} +export const isClinicalDocument = (resource: unknown): resource is ClinicalDocument => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ClinicalDocument"; +} +" +`; diff --git a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap new file mode 100644 index 000000000..9725d1eba --- /dev/null +++ b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap @@ -0,0 +1,127 @@ +// Bun Snapshot v1, https://bun.sh/docs/test/snapshots + +exports[`Local Package Folder - Multi-Package Generation TypeScript Generation should generate ExampleNotebook type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { Coding } from "../hl7-fhir-r4-core/Coding"; +import type { DomainResource } from "../hl7-fhir-r4-core/DomainResource"; +import type { Identifier } from "../hl7-fhir-r4-core/Identifier"; +import type { Reference } from "../hl7-fhir-r4-core/Reference"; + +import type { Element } from "../hl7-fhir-r4-core/Element"; +export type { Coding } from "../hl7-fhir-r4-core/Coding"; +export type { Identifier } from "../hl7-fhir-r4-core/Identifier"; +export type { Reference } from "../hl7-fhir-r4-core/Reference"; + +// CanonicalURL: http://example.org/fhir/StructureDefinition/ExampleNotebook +export interface ExampleNotebook extends DomainResource { + resourceType: "ExampleNotebook"; + + author: Reference<"Patient" | "Practitioner">; + content: string; + _content?: Element; + identifier: Identifier; + tag?: Coding[]; + title: string; + _title?: Element; +} +export const isExampleNotebook = (resource: unknown): resource is ExampleNotebook => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ExampleNotebook"; +} +" +`; + +exports[`Local Package Folder - Multi-Package Generation TypeScript Generation should generate ExampleNotebook type in custom package folder 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { Coding } from "../hl7-fhir-r4-core/Coding"; +import type { DomainResource } from "../hl7-fhir-r4-core/DomainResource"; +import type { Identifier } from "../hl7-fhir-r4-core/Identifier"; +import type { Reference } from "../hl7-fhir-r4-core/Reference"; + +import type { Element } from "../hl7-fhir-r4-core/Element"; +export type { Coding } from "../hl7-fhir-r4-core/Coding"; +export type { Identifier } from "../hl7-fhir-r4-core/Identifier"; +export type { Reference } from "../hl7-fhir-r4-core/Reference"; + +// CanonicalURL: http://example.org/fhir/StructureDefinition/ExampleNotebook +export interface ExampleNotebook extends DomainResource { + resourceType: "ExampleNotebook"; + + author: Reference<"Patient" | "Practitioner">; + content: string; + _content?: Element; + identifier: Identifier; + tag?: Coding[]; + title: string; + _title?: Element; +} +export const isExampleNotebook = (resource: unknown): resource is ExampleNotebook => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ExampleNotebook"; +} +" +`; + +exports[`Local Package Folder - Multi-Package Generation Python Generation should generate base types for dependencies 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r4_core.base import Extension, Narrative +from fhir_types.hl7_fhir_r4_core.resource import Resource +from fhir_types.hl7_fhir_r4_core.resource_families import ResourceFamily + + +class DomainResource(Resource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='DomainResource', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='DomainResource' + ) + contained: PyList[ResourceFamily] | None = Field(None, alias="contained", serialization_alias="contained") + extension: PyList[Extension] | None = Field(None, alias="extension", serialization_alias="extension") + modifier_extension: PyList[Extension] | None = Field(None, alias="modifierExtension", serialization_alias="modifierExtension") + text: Narrative | None = Field(None, alias="text", serialization_alias="text") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> DomainResource: + return cls.model_validate_json(json) + +" +`; + +exports[`Local Package Folder - Multi-Package Generation C# Generation should generate DomainResource base class 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7FhirR4Core; + +public class DomainResource : Resource { + public Resource[]? Contained { get; set; } + public Extension[]? Extension { get; set; } + public Extension[]? ModifierExtension { get; set; } + public Narrative? Text { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; diff --git a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap new file mode 100644 index 000000000..9ec2d4f90 --- /dev/null +++ b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap @@ -0,0 +1,289 @@ +// Bun Snapshot v1, https://bun.sh/docs/test/snapshots + +exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation TypeScript Generation should generate ViewDefinition type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; +import type { CanonicalResource } from "../hl7-fhir-r5-core/CanonicalResource"; + +import type { Element } from "../hl7-fhir-r5-core/Element"; +export type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; + +export interface ViewDefinitionConstant extends BackboneElement { + name: string; + valueBase64Binary?: string; + valueBoolean?: boolean; + valueCanonical?: string; + valueCode?: string; + valueDate?: string; + valueDateTime?: string; + valueDecimal?: number; + valueId?: string; + valueInstant?: string; + valueInteger?: number; + valueInteger64?: number; + valueOid?: string; + valuePositiveInt?: number; + valueString?: string; + valueTime?: string; + valueUnsignedInt?: number; + valueUri?: string; + valueUrl?: string; + valueUuid?: string; +} + +export interface ViewDefinitionSelect extends BackboneElement { + column?: ViewDefinitionSelectColumn[]; + forEach?: string; + forEachOrNull?: string; + repeat?: string[]; + select?: ViewDefinitionSelect[]; + unionAll?: ViewDefinitionSelect[]; +} + +export interface ViewDefinitionSelectColumn extends BackboneElement { + collection?: boolean; + description?: string; + name: string; + path: string; + tag?: ViewDefinitionSelectColumnTag[]; + type?: string; +} + +export interface ViewDefinitionSelectColumnTag extends BackboneElement { + name: string; + value: string; +} + +export interface ViewDefinitionWhere extends BackboneElement { + description?: string; + path: string; +} + +// CanonicalURL: https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition +export interface ViewDefinition extends CanonicalResource { + resourceType: "ViewDefinition"; + + constant?: ViewDefinitionConstant[]; + fhirVersion?: ("0.01" | "0.05" | "0.06" | "0.11" | "0.0" | "0.0.80" | "0.0.81" | "0.0.82" | "0.4" | "0.4.0" | "0.5" | "0.5.0" | "1.0" | "1.0.0" | "1.0.1" | "1.0.2" | "1.1" | "1.1.0" | "1.4" | "1.4.0" | "1.6" | "1.6.0" | "1.8" | "1.8.0" | "3.0" | "3.0.0" | "3.0.1" | "3.0.2" | "3.3" | "3.3.0" | "3.5" | "3.5.0" | "4.0" | "4.0.0" | "4.0.1" | "4.1" | "4.1.0" | "4.2" | "4.2.0" | "4.3" | "4.3.0" | "4.3.0-cibuild" | "4.3.0-snapshot1" | "4.4" | "4.4.0" | "4.5" | "4.5.0" | "4.6" | "4.6.0" | "5.0" | "5.0.0" | "5.0.0-cibuild" | "5.0.0-snapshot1" | "5.0.0-snapshot2" | "5.0.0-ballot" | "5.0.0-snapshot3" | "5.0.0-draft-final")[]; + _fhirVersion?: Element; + name?: string; + _name?: Element; + profile?: string[]; + _profile?: Element; + resource: string; + _resource?: Element; + select: ViewDefinitionSelect[]; + where?: ViewDefinitionWhere[]; +} +export const isViewDefinition = (resource: unknown): resource is ViewDefinition => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ViewDefinition"; +} +" +`; + +exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation Python Generation should generate domain_resource for R5 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r5_core.base import Extension, Narrative +from fhir_types.hl7_fhir_r5_core.resource import Resource +from fhir_types.hl7_fhir_r5_core.resource_families import ResourceFamily + + +class DomainResource(Resource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='DomainResource', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='DomainResource' + ) + contained: PyList[ResourceFamily] | None = Field(None, alias="contained", serialization_alias="contained") + extension: PyList[Extension] | None = Field(None, alias="extension", serialization_alias="extension") + modifier_extension: PyList[Extension] | None = Field(None, alias="modifierExtension", serialization_alias="modifierExtension") + text: Narrative | None = Field(None, alias="text", serialization_alias="text") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> DomainResource: + return cls.model_validate_json(json) + +" +`; + +exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation C# Generation should generate DomainResource for R5 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7FhirR5Core; + +public class DomainResource : Resource { + public Resource[]? Contained { get; set; } + public Extension[]? Extension { get; set; } + public Extension[]? ModifierExtension { get; set; } + public Narrative? Text { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; + +exports[`SQL-on-FHIR TypeScript Generation should generate ViewDefinition type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; +import type { CanonicalResource } from "../hl7-fhir-r5-core/CanonicalResource"; + +import type { Element } from "../hl7-fhir-r5-core/Element"; +export type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; + +export interface ViewDefinitionConstant extends BackboneElement { + name: string; + valueBase64Binary?: string; + valueBoolean?: boolean; + valueCanonical?: string; + valueCode?: string; + valueDate?: string; + valueDateTime?: string; + valueDecimal?: number; + valueId?: string; + valueInstant?: string; + valueInteger?: number; + valueInteger64?: number; + valueOid?: string; + valuePositiveInt?: number; + valueString?: string; + valueTime?: string; + valueUnsignedInt?: number; + valueUri?: string; + valueUrl?: string; + valueUuid?: string; +} + +export interface ViewDefinitionSelect extends BackboneElement { + column?: ViewDefinitionSelectColumn[]; + forEach?: string; + forEachOrNull?: string; + repeat?: string[]; + select?: ViewDefinitionSelect[]; + unionAll?: ViewDefinitionSelect[]; +} + +export interface ViewDefinitionSelectColumn extends BackboneElement { + collection?: boolean; + description?: string; + name: string; + path: string; + tag?: ViewDefinitionSelectColumnTag[]; + type?: string; +} + +export interface ViewDefinitionSelectColumnTag extends BackboneElement { + name: string; + value: string; +} + +export interface ViewDefinitionWhere extends BackboneElement { + description?: string; + path: string; +} + +// CanonicalURL: https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition +export interface ViewDefinition extends CanonicalResource { + resourceType: "ViewDefinition"; + + constant?: ViewDefinitionConstant[]; + fhirVersion?: ("0.01" | "0.05" | "0.06" | "0.11" | "0.0" | "0.0.80" | "0.0.81" | "0.0.82" | "0.4" | "0.4.0" | "0.5" | "0.5.0" | "1.0" | "1.0.0" | "1.0.1" | "1.0.2" | "1.1" | "1.1.0" | "1.4" | "1.4.0" | "1.6" | "1.6.0" | "1.8" | "1.8.0" | "3.0" | "3.0.0" | "3.0.1" | "3.0.2" | "3.3" | "3.3.0" | "3.5" | "3.5.0" | "4.0" | "4.0.0" | "4.0.1" | "4.1" | "4.1.0" | "4.2" | "4.2.0" | "4.3" | "4.3.0" | "4.3.0-cibuild" | "4.3.0-snapshot1" | "4.4" | "4.4.0" | "4.5" | "4.5.0" | "4.6" | "4.6.0" | "5.0" | "5.0.0" | "5.0.0-cibuild" | "5.0.0-snapshot1" | "5.0.0-snapshot2" | "5.0.0-ballot" | "5.0.0-snapshot3" | "5.0.0-draft-final")[]; + _fhirVersion?: Element; + name?: string; + _name?: Element; + profile?: string[]; + _profile?: Element; + resource: string; + _resource?: Element; + select: ViewDefinitionSelect[]; + where?: ViewDefinitionWhere[]; +} +export const isViewDefinition = (resource: unknown): resource is ViewDefinition => { + return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ViewDefinition"; +} +" +`; + +exports[`SQL-on-FHIR Python Generation should generate domain_resource for R5 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r5_core.base import Extension, Narrative +from fhir_types.hl7_fhir_r5_core.resource import Resource +from fhir_types.hl7_fhir_r5_core.resource_families import ResourceFamily + + +class DomainResource(Resource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='DomainResource', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='DomainResource' + ) + contained: PyList[ResourceFamily] | None = Field(None, alias="contained", serialization_alias="contained") + extension: PyList[Extension] | None = Field(None, alias="extension", serialization_alias="extension") + modifier_extension: PyList[Extension] | None = Field(None, alias="modifierExtension", serialization_alias="modifierExtension") + text: Narrative | None = Field(None, alias="text", serialization_alias="text") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> DomainResource: + return cls.model_validate_json(json) + +" +`; + +exports[`SQL-on-FHIR C# Generation should generate DomainResource for R5 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7FhirR5Core; + +public class DomainResource : Resource { + public Resource[]? Contained { get; set; } + public Extension[]? Extension { get; set; } + public Extension[]? ModifierExtension { get; set; } + public Narrative? Text { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/ccda.test.ts new file mode 100644 index 000000000..6768710b8 --- /dev/null +++ b/test/api/write-generator/multi-package/ccda.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from "bun:test"; +import { APIBuilder } from "@root/api/builder"; + +/** + * Tests for CCDA package generation. + * Package: hl7.cda.uv.core@2.0.1-sd + */ +describe("CCDA", async () => { + const treeShakeConfig = { + "hl7.cda.uv.core": { + "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument": {}, + }, + }; + + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("should generate ClinicalDocument type", () => { + const clinicalDoc = result.filesGenerated["generated/types/hl7-cda-uv-core/ClinicalDocument.ts"]; + expect(clinicalDoc).toBeDefined(); + expect(clinicalDoc).toMatchSnapshot(); + }); + + it("should generate CDA-specific types", () => { + const files = Object.keys(result.filesGenerated); + const cdaFiles = files.filter((f) => f.includes("hl7-cda-uv-core")); + expect(cdaFiles.length).toBeGreaterThan(0); + + expect(files.some((f) => f.includes("/Ad.ts") || f.includes("/Cd.ts"))).toBeTrue(); + }); + }); + + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // Python generator does not support logical models (ClinicalDocument is kind: "logical") + it.todo("should generate ClinicalDocument type", () => {}); + + it("should generate base package structure", () => { + expect(result.filesGenerated["generated/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/requirements.txt"]).toBeDefined(); + }); + }); + + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // C# generator does not support logical models (ClinicalDocument is kind: "logical") + it.todo("should generate ClinicalDocument type", () => {}); + + it("should generate base helper files", () => { + expect(result.filesGenerated["generated/types/base.cs"]).toBeDefined(); + expect(result.filesGenerated["generated/types/Helper.cs"]).toBeDefined(); + }); + }); +}); diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts new file mode 100644 index 000000000..a6828e8fc --- /dev/null +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -0,0 +1,110 @@ +import * as Path from "node:path"; +import { describe, expect, it } from "bun:test"; +import { APIBuilder } from "@root/api/builder"; + +const LOCAL_PACKAGE_PATH = Path.join(__dirname, "../../../assets/local-package/structure-definitions"); + +/** + * Tests for local package folder functionality with multi-package dependency resolution. + * */ +describe("Local Package Folder - Multi-Package Generation", async () => { + const localPackageConfig = { + package: { name: "example.folder.structures", version: "0.0.1" }, + path: LOCAL_PACKAGE_PATH, + dependencies: [{ name: "hl7.fhir.r4.core", version: "4.0.1" }], + }; + + const treeShakeConfig = { + "example.folder.structures": { + "http://example.org/fhir/StructureDefinition/ExampleNotebook": {}, + }, + }; + + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("should generate ExampleNotebook type in custom package folder", () => { + const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; + expect(notebookFile).toBeDefined(); + expect(notebookFile).toMatchSnapshot(); + }); + + it("should resolve R4 dependencies (Identifier, Reference, Coding)", () => { + const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; + expect(notebookFile).toContain("Identifier"); + expect(notebookFile).toContain("Reference"); + expect(notebookFile).toContain("Coding"); + }); + + it("should generate R4 dependency types", () => { + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Identifier.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Reference.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Coding.ts"]).toBeDefined(); + }); + }); + + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // Python generator does not support logical models (ExampleNotebook is kind: "logical") + it.todo("should generate ExampleNotebook type", () => {}); + + it("should generate R4 dependency types", () => { + // Python generator resolves R4 dependencies from tree-shaking + expect(result.filesGenerated["generated/hl7_fhir_r4_core/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]).toBeDefined(); + }); + + it("should generate base types for dependencies", () => { + const domainResource = result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); + + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // C# generator does not support logical models (ExampleNotebook is kind: "logical") + it.todo("should generate ExampleNotebook type", () => {}); + + it("should generate R4 dependency types", () => { + // C# generator resolves R4 dependencies from tree-shaking + expect(result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]).toBeDefined(); + expect(result.filesGenerated["generated/types/Hl7FhirR4Core/Resource.cs"]).toBeDefined(); + }); + + it("should generate DomainResource base class", () => { + const domainResource = result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); +}); \ No newline at end of file diff --git a/test/api/write-generator/multi-package/sql-on-fhir.test.ts b/test/api/write-generator/multi-package/sql-on-fhir.test.ts new file mode 100644 index 000000000..2f5b74cee --- /dev/null +++ b/test/api/write-generator/multi-package/sql-on-fhir.test.ts @@ -0,0 +1,107 @@ +import { describe, expect, it } from "bun:test"; +import { APIBuilder } from "@root/api/builder"; + +/** + * Tests for SQL-on-FHIR package. + * The SQL-on-FHIR package depends on hl7.fhir.r5.core. + */ +describe("SQL-on-FHIR", async () => { + const packageUrl = "https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/package.tgz"; + + const treeShakeConfig = { + "org.sql-on-fhir.ig": { + "https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition": {}, + }, + }; + + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("should generate ViewDefinition type", () => { + const viewDef = result.filesGenerated["generated/types/org-sql-on-fhir-ig/ViewDefinition.ts"]; + expect(viewDef).toBeDefined(); + expect(viewDef).toMatchSnapshot(); + }); + + it("should resolve R5 dependencies (required by SQL-on-FHIR)", () => { + const files = Object.keys(result.filesGenerated); + const r5Files = files.filter((f) => f.includes("hl7-fhir-r5-core")); + expect(r5Files.length).toBeGreaterThan(0); + + // Core R5 types should be included + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/Element.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/DomainResource.ts"]).toBeDefined(); + }); + + it("should generate package index files", () => { + expect(result.filesGenerated["generated/types/org-sql-on-fhir-ig/index.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/index.ts"]).toBeDefined(); + }); + }); + + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // Python generator does not support logical models (ViewDefinition is kind: "logical") + it.todo("should generate ViewDefinition type", () => {}); + + it("should generate R5 dependency package", () => { + // Python generator creates R5 base types for dependencies + expect(result.filesGenerated["generated/hl7_fhir_r5_core/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]).toBeDefined(); + }); + + it("should generate domain_resource for R5", () => { + const domainResource = result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); + + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // C# generator does not support logical models (ViewDefinition is kind: "logical") + it.todo("should generate ViewDefinition type", () => {}); + + it("should generate R5 dependency namespace", () => { + // C# generator creates R5 types for dependencies + const files = Object.keys(result.filesGenerated); + const r5Files = files.filter((f) => f.includes("Hl7FhirR5Core")); + expect(r5Files.length).toBeGreaterThan(0); + }); + + it("should generate DomainResource for R5", () => { + const domainResource = result.filesGenerated["generated/types/Hl7FhirR5Core/DomainResource.cs"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); +}); diff --git a/test/assets/local-package/structure-definitions/example-notebook.structuredefinition.json b/test/assets/local-package/structure-definitions/example-notebook.structuredefinition.json new file mode 100644 index 000000000..6b39bc4ea --- /dev/null +++ b/test/assets/local-package/structure-definitions/example-notebook.structuredefinition.json @@ -0,0 +1,175 @@ +{ + "resourceType": "StructureDefinition", + "id": "example-notebook", + "url": "http://example.org/fhir/StructureDefinition/ExampleNotebook", + "version": "0.0.1", + "name": "ExampleNotebook", + "title": "Example Notebook Logical Model", + "status": "draft", + "date": "2024-01-01", + "publisher": "Atomic Example Studio", + "description": "Logical resource showcasing a simple notebook record with fields used in examples.", + "fhirVersion": "4.0.1", + "kind": "logical", + "abstract": false, + "type": "ExampleNotebook", + "baseDefinition": "http://hl7.org/fhir/StructureDefinition/DomainResource", + "derivation": "specialization", + "snapshot": { + "element": [ + { + "id": "ExampleNotebook", + "path": "ExampleNotebook", + "short": "Example logical notebook resource", + "definition": "A lightweight notebook entry capturing author, title, and content.", + "min": 0, + "max": "*", + "type": [ + { + "code": "DomainResource" + } + ] + }, + { + "id": "ExampleNotebook.identifier", + "path": "ExampleNotebook.identifier", + "min": 1, + "max": "1", + "short": "Unique identifier for the notebook entry", + "type": [ + { + "code": "Identifier" + } + ] + }, + { + "id": "ExampleNotebook.title", + "path": "ExampleNotebook.title", + "min": 1, + "max": "1", + "short": "Human readable title", + "type": [ + { + "code": "string" + } + ] + }, + { + "id": "ExampleNotebook.author", + "path": "ExampleNotebook.author", + "min": 1, + "max": "1", + "short": "Reference to the author of the notebook entry", + "type": [ + { + "code": "Reference", + "targetProfile": [ + "http://hl7.org/fhir/StructureDefinition/Practitioner", + "http://hl7.org/fhir/StructureDefinition/Patient" + ] + } + ] + }, + { + "id": "ExampleNotebook.content", + "path": "ExampleNotebook.content", + "min": 1, + "max": "1", + "short": "Markdown content of the notebook entry", + "type": [ + { + "code": "markdown" + } + ] + }, + { + "id": "ExampleNotebook.tag", + "path": "ExampleNotebook.tag", + "min": 0, + "max": "*", + "short": "User defined tags", + "type": [ + { + "code": "Coding" + } + ] + } + ] + }, + "differential": { + "element": [ + { + "id": "ExampleNotebook", + "path": "ExampleNotebook", + "short": "Example logical notebook resource", + "definition": "A lightweight notebook entry capturing author, title, and content.", + "min": 0, + "max": "*" + }, + { + "id": "ExampleNotebook.identifier", + "path": "ExampleNotebook.identifier", + "min": 1, + "max": "1", + "short": "Unique identifier for the notebook entry", + "type": [ + { + "code": "Identifier" + } + ] + }, + { + "id": "ExampleNotebook.title", + "path": "ExampleNotebook.title", + "min": 1, + "max": "1", + "short": "Human readable title", + "type": [ + { + "code": "string" + } + ] + }, + { + "id": "ExampleNotebook.author", + "path": "ExampleNotebook.author", + "min": 1, + "max": "1", + "short": "Reference to the author", + "type": [ + { + "code": "Reference", + "targetProfile": [ + "http://hl7.org/fhir/StructureDefinition/Practitioner", + "http://hl7.org/fhir/StructureDefinition/Patient" + ] + } + ] + }, + { + "id": "ExampleNotebook.content", + "path": "ExampleNotebook.content", + "min": 1, + "max": "1", + "short": "Markdown content of the notebook entry", + "type": [ + { + "code": "markdown" + } + ] + }, + { + "id": "ExampleNotebook.tag", + "path": "ExampleNotebook.tag", + "min": 0, + "max": "*", + "short": "User defined tags", + "type": [ + { + "code": "Coding" + } + ] + } + ] + } +} \ No newline at end of file From 25b14428c0c876953131be8d6578f588332da5be Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Wed, 21 Jan 2026 18:26:15 +0000 Subject: [PATCH 02/10] minor format fixes --- .../multi-package/ccda.test.ts | 122 +++++------ .../multi-package/local-package.test.ts | 200 +++++++++--------- .../multi-package/sql-on-fhir.test.ts | 196 ++++++++--------- 3 files changed, 259 insertions(+), 259 deletions(-) diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/ccda.test.ts index 6768710b8..4798cf0b0 100644 --- a/test/api/write-generator/multi-package/ccda.test.ts +++ b/test/api/write-generator/multi-package/ccda.test.ts @@ -6,78 +6,78 @@ import { APIBuilder } from "@root/api/builder"; * Package: hl7.cda.uv.core@2.0.1-sd */ describe("CCDA", async () => { - const treeShakeConfig = { - "hl7.cda.uv.core": { - "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument": {}, - }, - }; + const treeShakeConfig = { + "hl7.cda.uv.core": { + "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument": {}, + }, + }; - describe("TypeScript Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) - .typescript({ inMemoryOnly: true }) - .generate(); + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); - it("should generate ClinicalDocument type", () => { - const clinicalDoc = result.filesGenerated["generated/types/hl7-cda-uv-core/ClinicalDocument.ts"]; - expect(clinicalDoc).toBeDefined(); - expect(clinicalDoc).toMatchSnapshot(); - }); + it("should generate ClinicalDocument type", () => { + const clinicalDoc = result.filesGenerated["generated/types/hl7-cda-uv-core/ClinicalDocument.ts"]; + expect(clinicalDoc).toBeDefined(); + expect(clinicalDoc).toMatchSnapshot(); + }); - it("should generate CDA-specific types", () => { - const files = Object.keys(result.filesGenerated); - const cdaFiles = files.filter((f) => f.includes("hl7-cda-uv-core")); - expect(cdaFiles.length).toBeGreaterThan(0); + it("should generate CDA-specific types", () => { + const files = Object.keys(result.filesGenerated); + const cdaFiles = files.filter((f) => f.includes("hl7-cda-uv-core")); + expect(cdaFiles.length).toBeGreaterThan(0); - expect(files.some((f) => f.includes("/Ad.ts") || f.includes("/Cd.ts"))).toBeTrue(); - }); - }); + expect(files.some((f) => f.includes("/Ad.ts") || f.includes("/Cd.ts"))).toBeTrue(); + }); + }); - describe("Python Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) - .python({ inMemoryOnly: true }) - .generate(); + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); - // Python generator does not support logical models (ClinicalDocument is kind: "logical") - it.todo("should generate ClinicalDocument type", () => {}); + // Python generator does not support logical models (ClinicalDocument is kind: "logical") + it.todo("should generate ClinicalDocument type", () => {}); - it("should generate base package structure", () => { - expect(result.filesGenerated["generated/__init__.py"]).toBeDefined(); - expect(result.filesGenerated["generated/requirements.txt"]).toBeDefined(); - }); - }); + it("should generate base package structure", () => { + expect(result.filesGenerated["generated/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/requirements.txt"]).toBeDefined(); + }); + }); - describe("C# Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) - .csharp({ inMemoryOnly: true }) - .generate(); + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackage("hl7.cda.uv.core", "2.0.1-sd") + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); - // C# generator does not support logical models (ClinicalDocument is kind: "logical") - it.todo("should generate ClinicalDocument type", () => {}); + // C# generator does not support logical models (ClinicalDocument is kind: "logical") + it.todo("should generate ClinicalDocument type", () => {}); - it("should generate base helper files", () => { - expect(result.filesGenerated["generated/types/base.cs"]).toBeDefined(); - expect(result.filesGenerated["generated/types/Helper.cs"]).toBeDefined(); - }); - }); + it("should generate base helper files", () => { + expect(result.filesGenerated["generated/types/base.cs"]).toBeDefined(); + expect(result.filesGenerated["generated/types/Helper.cs"]).toBeDefined(); + }); + }); }); diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts index a6828e8fc..d72fdf373 100644 --- a/test/api/write-generator/multi-package/local-package.test.ts +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -8,103 +8,103 @@ const LOCAL_PACKAGE_PATH = Path.join(__dirname, "../../../assets/local-package/s * Tests for local package folder functionality with multi-package dependency resolution. * */ describe("Local Package Folder - Multi-Package Generation", async () => { - const localPackageConfig = { - package: { name: "example.folder.structures", version: "0.0.1" }, - path: LOCAL_PACKAGE_PATH, - dependencies: [{ name: "hl7.fhir.r4.core", version: "4.0.1" }], - }; - - const treeShakeConfig = { - "example.folder.structures": { - "http://example.org/fhir/StructureDefinition/ExampleNotebook": {}, - }, - }; - - describe("TypeScript Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) - .typescript({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - it("should generate ExampleNotebook type in custom package folder", () => { - const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; - expect(notebookFile).toBeDefined(); - expect(notebookFile).toMatchSnapshot(); - }); - - it("should resolve R4 dependencies (Identifier, Reference, Coding)", () => { - const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; - expect(notebookFile).toContain("Identifier"); - expect(notebookFile).toContain("Reference"); - expect(notebookFile).toContain("Coding"); - }); - - it("should generate R4 dependency types", () => { - expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Identifier.ts"]).toBeDefined(); - expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Reference.ts"]).toBeDefined(); - expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Coding.ts"]).toBeDefined(); - }); - }); - - describe("Python Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) - .python({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - // Python generator does not support logical models (ExampleNotebook is kind: "logical") - it.todo("should generate ExampleNotebook type", () => {}); - - it("should generate R4 dependency types", () => { - // Python generator resolves R4 dependencies from tree-shaking - expect(result.filesGenerated["generated/hl7_fhir_r4_core/__init__.py"]).toBeDefined(); - expect(result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]).toBeDefined(); - }); - - it("should generate base types for dependencies", () => { - const domainResource = result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]; - expect(domainResource).toBeDefined(); - expect(domainResource).toMatchSnapshot(); - }); - }); - - describe("C# Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) - .csharp({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - // C# generator does not support logical models (ExampleNotebook is kind: "logical") - it.todo("should generate ExampleNotebook type", () => {}); - - it("should generate R4 dependency types", () => { - // C# generator resolves R4 dependencies from tree-shaking - expect(result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]).toBeDefined(); - expect(result.filesGenerated["generated/types/Hl7FhirR4Core/Resource.cs"]).toBeDefined(); - }); - - it("should generate DomainResource base class", () => { - const domainResource = result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]; - expect(domainResource).toBeDefined(); - expect(domainResource).toMatchSnapshot(); - }); - }); -}); \ No newline at end of file + const localPackageConfig = { + package: { name: "example.folder.structures", version: "0.0.1" }, + path: LOCAL_PACKAGE_PATH, + dependencies: [{ name: "hl7.fhir.r4.core", version: "4.0.1" }], + }; + + const treeShakeConfig = { + "example.folder.structures": { + "http://example.org/fhir/StructureDefinition/ExampleNotebook": {}, + }, + }; + + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("should generate ExampleNotebook type in custom package folder", () => { + const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; + expect(notebookFile).toBeDefined(); + expect(notebookFile).toMatchSnapshot(); + }); + + it("should resolve R4 dependencies (Identifier, Reference, Coding)", () => { + const notebookFile = result.filesGenerated["generated/types/example-folder-structures/ExampleNotebook.ts"]; + expect(notebookFile).toContain("Identifier"); + expect(notebookFile).toContain("Reference"); + expect(notebookFile).toContain("Coding"); + }); + + it("should generate R4 dependency types", () => { + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Identifier.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Reference.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r4-core/Coding.ts"]).toBeDefined(); + }); + }); + + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // Python generator does not support logical models (ExampleNotebook is kind: "logical") + it.todo("should generate ExampleNotebook type", () => {}); + + it("should generate R4 dependency types", () => { + // Python generator resolves R4 dependencies from tree-shaking + expect(result.filesGenerated["generated/hl7_fhir_r4_core/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]).toBeDefined(); + }); + + it("should generate base types for dependencies", () => { + const domainResource = result.filesGenerated["generated/hl7_fhir_r4_core/domain_resource.py"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); + + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .localStructureDefinitions(localPackageConfig) + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // C# generator does not support logical models (ExampleNotebook is kind: "logical") + it.todo("should generate ExampleNotebook type", () => {}); + + it("should generate R4 dependency types", () => { + // C# generator resolves R4 dependencies from tree-shaking + expect(result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]).toBeDefined(); + expect(result.filesGenerated["generated/types/Hl7FhirR4Core/Resource.cs"]).toBeDefined(); + }); + + it("should generate DomainResource base class", () => { + const domainResource = result.filesGenerated["generated/types/Hl7FhirR4Core/DomainResource.cs"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); +}); diff --git a/test/api/write-generator/multi-package/sql-on-fhir.test.ts b/test/api/write-generator/multi-package/sql-on-fhir.test.ts index 2f5b74cee..b7f10c210 100644 --- a/test/api/write-generator/multi-package/sql-on-fhir.test.ts +++ b/test/api/write-generator/multi-package/sql-on-fhir.test.ts @@ -6,102 +6,102 @@ import { APIBuilder } from "@root/api/builder"; * The SQL-on-FHIR package depends on hl7.fhir.r5.core. */ describe("SQL-on-FHIR", async () => { - const packageUrl = "https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/package.tgz"; - - const treeShakeConfig = { - "org.sql-on-fhir.ig": { - "https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition": {}, - }, - }; - - describe("TypeScript Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) - .typescript({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - it("should generate ViewDefinition type", () => { - const viewDef = result.filesGenerated["generated/types/org-sql-on-fhir-ig/ViewDefinition.ts"]; - expect(viewDef).toBeDefined(); - expect(viewDef).toMatchSnapshot(); - }); - - it("should resolve R5 dependencies (required by SQL-on-FHIR)", () => { - const files = Object.keys(result.filesGenerated); - const r5Files = files.filter((f) => f.includes("hl7-fhir-r5-core")); - expect(r5Files.length).toBeGreaterThan(0); - - // Core R5 types should be included - expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/Element.ts"]).toBeDefined(); - expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/DomainResource.ts"]).toBeDefined(); - }); - - it("should generate package index files", () => { - expect(result.filesGenerated["generated/types/org-sql-on-fhir-ig/index.ts"]).toBeDefined(); - expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/index.ts"]).toBeDefined(); - }); - }); - - describe("Python Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) - .python({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - // Python generator does not support logical models (ViewDefinition is kind: "logical") - it.todo("should generate ViewDefinition type", () => {}); - - it("should generate R5 dependency package", () => { - // Python generator creates R5 base types for dependencies - expect(result.filesGenerated["generated/hl7_fhir_r5_core/__init__.py"]).toBeDefined(); - expect(result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]).toBeDefined(); - }); - - it("should generate domain_resource for R5", () => { - const domainResource = result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]; - expect(domainResource).toBeDefined(); - expect(domainResource).toMatchSnapshot(); - }); - }); - - describe("C# Generation", async () => { - const result = await new APIBuilder() - .setLogLevel("SILENT") - .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) - .csharp({ inMemoryOnly: true }) - .generate(); - - it("should succeed", () => { - expect(result.success).toBeTrue(); - }); - - // C# generator does not support logical models (ViewDefinition is kind: "logical") - it.todo("should generate ViewDefinition type", () => {}); - - it("should generate R5 dependency namespace", () => { - // C# generator creates R5 types for dependencies - const files = Object.keys(result.filesGenerated); - const r5Files = files.filter((f) => f.includes("Hl7FhirR5Core")); - expect(r5Files.length).toBeGreaterThan(0); - }); - - it("should generate DomainResource for R5", () => { - const domainResource = result.filesGenerated["generated/types/Hl7FhirR5Core/DomainResource.cs"]; - expect(domainResource).toBeDefined(); - expect(domainResource).toMatchSnapshot(); - }); - }); + const packageUrl = "https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/package.tgz"; + + const treeShakeConfig = { + "org.sql-on-fhir.ig": { + "https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition": {}, + }, + }; + + describe("TypeScript Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .typescript({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("should generate ViewDefinition type", () => { + const viewDef = result.filesGenerated["generated/types/org-sql-on-fhir-ig/ViewDefinition.ts"]; + expect(viewDef).toBeDefined(); + expect(viewDef).toMatchSnapshot(); + }); + + it("should resolve R5 dependencies (required by SQL-on-FHIR)", () => { + const files = Object.keys(result.filesGenerated); + const r5Files = files.filter((f) => f.includes("hl7-fhir-r5-core")); + expect(r5Files.length).toBeGreaterThan(0); + + // Core R5 types should be included + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/Element.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/DomainResource.ts"]).toBeDefined(); + }); + + it("should generate package index files", () => { + expect(result.filesGenerated["generated/types/org-sql-on-fhir-ig/index.ts"]).toBeDefined(); + expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/index.ts"]).toBeDefined(); + }); + }); + + describe("Python Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .python({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // Python generator does not support logical models (ViewDefinition is kind: "logical") + it.todo("should generate ViewDefinition type", () => {}); + + it("should generate R5 dependency package", () => { + // Python generator creates R5 base types for dependencies + expect(result.filesGenerated["generated/hl7_fhir_r5_core/__init__.py"]).toBeDefined(); + expect(result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]).toBeDefined(); + }); + + it("should generate domain_resource for R5", () => { + const domainResource = result.filesGenerated["generated/hl7_fhir_r5_core/domain_resource.py"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); + + describe("C# Generation", async () => { + const result = await new APIBuilder() + .setLogLevel("SILENT") + .fromPackageRef(packageUrl) + .treeShake(treeShakeConfig) + .csharp({ inMemoryOnly: true }) + .generate(); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + // C# generator does not support logical models (ViewDefinition is kind: "logical") + it.todo("should generate ViewDefinition type", () => {}); + + it("should generate R5 dependency namespace", () => { + // C# generator creates R5 types for dependencies + const files = Object.keys(result.filesGenerated); + const r5Files = files.filter((f) => f.includes("Hl7FhirR5Core")); + expect(r5Files.length).toBeGreaterThan(0); + }); + + it("should generate DomainResource for R5", () => { + const domainResource = result.filesGenerated["generated/types/Hl7FhirR5Core/DomainResource.cs"]; + expect(domainResource).toBeDefined(); + expect(domainResource).toMatchSnapshot(); + }); + }); }); From f5c9cb91a0d556338f48848e0415c53018715663 Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Wed, 21 Jan 2026 18:29:31 +0000 Subject: [PATCH 03/10] minor format fixes --- test/api/write-generator/multi-package/local-package.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts index d72fdf373..9a8bb5718 100644 --- a/test/api/write-generator/multi-package/local-package.test.ts +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -1,5 +1,5 @@ -import * as Path from "node:path"; import { describe, expect, it } from "bun:test"; +import * as Path from "node:path"; import { APIBuilder } from "@root/api/builder"; const LOCAL_PACKAGE_PATH = Path.join(__dirname, "../../../assets/local-package/structure-definitions"); From 11b53d544d7b2a777bfd756f6108ba6345b6f9a2 Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Thu, 29 Jan 2026 16:40:15 +0000 Subject: [PATCH 04/10] test: fixed ccda.test.ts --- src/api/writer-generator/python.ts | 8 ++------ src/api/writer-generator/writer.ts | 1 + .../api/write-generator/__snapshots__/python.test.ts.snap | 8 +++++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/api/writer-generator/python.ts b/src/api/writer-generator/python.ts index ccbd07159..b14b1a846 100644 --- a/src/api/writer-generator/python.ts +++ b/src/api/writer-generator/python.ts @@ -165,12 +165,8 @@ export class Python extends Writer { private generateRootPackages(groups: TypeSchemaPackageGroups): void { this.generateRootInitFile(groups); - if (this.forFhirpyClient) - this.copyAssets( - resolvePyAssets("fhirpy_base_model.py"), - Path.resolve(this.opts.outputDir, "fhirpy_base_model.py"), - ); - this.copyAssets(resolvePyAssets("requirements.txt"), Path.resolve(this.opts.outputDir, "requirements.txt")); + if (this.forFhirpyClient) this.copyAssets(resolvePyAssets("fhirpy_base_model.py"), "fhirpy_base_model.py"); + this.copyAssets(resolvePyAssets("requirements.txt"), "requirements.txt"); } private generateSDKPackages(groups: TypeSchemaPackageGroups): void { diff --git a/src/api/writer-generator/writer.ts b/src/api/writer-generator/writer.ts index 335954989..70938815b 100644 --- a/src/api/writer-generator/writer.ts +++ b/src/api/writer-generator/writer.ts @@ -114,6 +114,7 @@ export abstract class FileSystemWriter=2.32.0,<3.0.0 +pytest>=8.3.0,<9.0.0 +pydantic>=2.11.0,<3.0.0 +mypy>=1.9.0,<2.0.0 +types-requests>=2.32.0,<3.0.0" +`; From 10c7936b22a620ad3036aeab11385e6cab35a921 Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Thu, 5 Feb 2026 17:03:04 +0000 Subject: [PATCH 05/10] test: updated version of multi-package tests --- .../__snapshots__/ccda.test.ts.snap | 97 ++--------- .../__snapshots__/local-package.test.ts.snap | 40 +---- .../__snapshots__/sql-on-fhir.test.ts.snap | 151 +----------------- .../multi-package/ccda.test.ts | 8 +- .../multi-package/local-package.test.ts | 6 +- .../multi-package/sql-on-fhir.test.ts | 6 +- 6 files changed, 21 insertions(+), 287 deletions(-) diff --git a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap index d07c60a42..7ea90e28a 100644 --- a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap @@ -1,113 +1,37 @@ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots -exports[`CCDA Package - Multi-Package Generation TypeScript Generation should generate ClinicalDocument type 1`] = ` -"// WARNING: This file is autogenerated by @atomic-ehr/codegen. -// GitHub: https://github.com/atomic-ehr/codegen -// Any manual changes made to this file may be overwritten. - -import type { ANY } from "../hl7-cda-uv-core/Any"; -import type { Authenticator } from "../hl7-cda-uv-core/Authenticator"; -import type { Author } from "../hl7-cda-uv-core/Author"; -import type { Authorization } from "../hl7-cda-uv-core/Authorization"; -import type { CD } from "../hl7-cda-uv-core/Cd"; -import type { CE } from "../hl7-cda-uv-core/Ce"; -import type { Component } from "../hl7-cda-uv-core/Component"; -import type { ComponentOf } from "../hl7-cda-uv-core/ComponentOf"; -import type { CS } from "../hl7-cda-uv-core/Cs"; -import type { Custodian } from "../hl7-cda-uv-core/Custodian"; -import type { DataEnterer } from "../hl7-cda-uv-core/DataEnterer"; -import type { DocumentationOf } from "../hl7-cda-uv-core/DocumentationOf"; -import type { II } from "../hl7-cda-uv-core/Ii"; -import type { Informant } from "../hl7-cda-uv-core/Informant"; -import type { InformationRecipient } from "../hl7-cda-uv-core/InformationRecipient"; -import type { InFulfillmentOf } from "../hl7-cda-uv-core/InFulfillmentOf"; -import type { INT } from "../hl7-cda-uv-core/Int"; -import type { LegalAuthenticator } from "../hl7-cda-uv-core/LegalAuthenticator"; -import type { Participant1 } from "../hl7-cda-uv-core/Participant1"; -import type { RecordTarget } from "../hl7-cda-uv-core/RecordTarget"; -import type { RelatedDocument } from "../hl7-cda-uv-core/RelatedDocument"; -import type { ST } from "../hl7-cda-uv-core/St"; -import type { TS } from "../hl7-cda-uv-core/Ts"; - -import type { Element } from "../hl7-fhir-r5-core/Element"; -// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument -export interface ClinicalDocument extends ANY { - resourceType: "ClinicalDocument"; - - authenticator?: Authenticator[]; - author: Author[]; - authorization?: Authorization[]; - classCode?: string; - _classCode?: Element; - code: CE; - component: Component; - componentOf?: ComponentOf; - confidentialityCode: CE; - copyTime?: TS; - custodian: Custodian; - dataEnterer?: DataEnterer; - documentationOf?: DocumentationOf[]; - effectiveTime: TS; - id: II; - informant?: Informant[]; - informationRecipient?: InformationRecipient[]; - inFulfillmentOf?: InFulfillmentOf[]; - languageCode?: CS; - legalAuthenticator?: LegalAuthenticator; - moodCode?: ("INT" | "APT" | "ARQ" | "PRMS" | "PRP" | "RQO" | "SLOT" | "DEF" | "EVN" | "EVN.CRT" | "GOL" | "OPT" | "PERM" | "PERMRQ"); - _moodCode?: Element; - participant?: Participant1[]; - realmCode?: CS[]; - recordTarget: RecordTarget[]; - relatedDocument?: RelatedDocument[]; - sdtcCategory?: CD[]; - sdtcStatusCode?: CS; - setId?: II; - templateId?: II[]; - title?: ST; - typeId?: II; - versionNumber?: INT; -} -export const isClinicalDocument = (resource: unknown): resource is ClinicalDocument => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ClinicalDocument"; -} -" -`; - exports[`CCDA TypeScript Generation should generate ClinicalDocument type 1`] = ` "// WARNING: This file is autogenerated by @atomic-ehr/codegen. // GitHub: https://github.com/atomic-ehr/codegen // Any manual changes made to this file may be overwritten. -import type { ANY } from "../hl7-cda-uv-core/Any"; +import type { ANY } from "../hl7-cda-uv-core/ANY"; import type { Authenticator } from "../hl7-cda-uv-core/Authenticator"; import type { Author } from "../hl7-cda-uv-core/Author"; import type { Authorization } from "../hl7-cda-uv-core/Authorization"; -import type { CD } from "../hl7-cda-uv-core/Cd"; -import type { CE } from "../hl7-cda-uv-core/Ce"; +import type { CD } from "../hl7-cda-uv-core/CD"; +import type { CE } from "../hl7-cda-uv-core/CE"; import type { Component } from "../hl7-cda-uv-core/Component"; import type { ComponentOf } from "../hl7-cda-uv-core/ComponentOf"; -import type { CS } from "../hl7-cda-uv-core/Cs"; +import type { CS } from "../hl7-cda-uv-core/CS"; import type { Custodian } from "../hl7-cda-uv-core/Custodian"; import type { DataEnterer } from "../hl7-cda-uv-core/DataEnterer"; import type { DocumentationOf } from "../hl7-cda-uv-core/DocumentationOf"; -import type { II } from "../hl7-cda-uv-core/Ii"; +import type { II } from "../hl7-cda-uv-core/II"; import type { Informant } from "../hl7-cda-uv-core/Informant"; import type { InformationRecipient } from "../hl7-cda-uv-core/InformationRecipient"; import type { InFulfillmentOf } from "../hl7-cda-uv-core/InFulfillmentOf"; -import type { INT } from "../hl7-cda-uv-core/Int"; +import type { INT } from "../hl7-cda-uv-core/INT"; import type { LegalAuthenticator } from "../hl7-cda-uv-core/LegalAuthenticator"; import type { Participant1 } from "../hl7-cda-uv-core/Participant1"; import type { RecordTarget } from "../hl7-cda-uv-core/RecordTarget"; import type { RelatedDocument } from "../hl7-cda-uv-core/RelatedDocument"; -import type { ST } from "../hl7-cda-uv-core/St"; -import type { TS } from "../hl7-cda-uv-core/Ts"; +import type { ST } from "../hl7-cda-uv-core/ST"; +import type { TS } from "../hl7-cda-uv-core/TS"; import type { Element } from "../hl7-fhir-r5-core/Element"; -// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument +// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument (pkg: hl7.cda.uv.core#2.0.1-sd) export interface ClinicalDocument extends ANY { - resourceType: "ClinicalDocument"; - authenticator?: Authenticator[]; author: Author[]; authorization?: Authorization[]; @@ -142,8 +66,5 @@ export interface ClinicalDocument extends ANY { typeId?: II; versionNumber?: INT; } -export const isClinicalDocument = (resource: unknown): resource is ClinicalDocument => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ClinicalDocument"; -} " `; diff --git a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap index 9725d1eba..9f5a757d4 100644 --- a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap @@ -1,38 +1,5 @@ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots -exports[`Local Package Folder - Multi-Package Generation TypeScript Generation should generate ExampleNotebook type 1`] = ` -"// WARNING: This file is autogenerated by @atomic-ehr/codegen. -// GitHub: https://github.com/atomic-ehr/codegen -// Any manual changes made to this file may be overwritten. - -import type { Coding } from "../hl7-fhir-r4-core/Coding"; -import type { DomainResource } from "../hl7-fhir-r4-core/DomainResource"; -import type { Identifier } from "../hl7-fhir-r4-core/Identifier"; -import type { Reference } from "../hl7-fhir-r4-core/Reference"; - -import type { Element } from "../hl7-fhir-r4-core/Element"; -export type { Coding } from "../hl7-fhir-r4-core/Coding"; -export type { Identifier } from "../hl7-fhir-r4-core/Identifier"; -export type { Reference } from "../hl7-fhir-r4-core/Reference"; - -// CanonicalURL: http://example.org/fhir/StructureDefinition/ExampleNotebook -export interface ExampleNotebook extends DomainResource { - resourceType: "ExampleNotebook"; - - author: Reference<"Patient" | "Practitioner">; - content: string; - _content?: Element; - identifier: Identifier; - tag?: Coding[]; - title: string; - _title?: Element; -} -export const isExampleNotebook = (resource: unknown): resource is ExampleNotebook => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ExampleNotebook"; -} -" -`; - exports[`Local Package Folder - Multi-Package Generation TypeScript Generation should generate ExampleNotebook type in custom package folder 1`] = ` "// WARNING: This file is autogenerated by @atomic-ehr/codegen. // GitHub: https://github.com/atomic-ehr/codegen @@ -48,10 +15,8 @@ export type { Coding } from "../hl7-fhir-r4-core/Coding"; export type { Identifier } from "../hl7-fhir-r4-core/Identifier"; export type { Reference } from "../hl7-fhir-r4-core/Reference"; -// CanonicalURL: http://example.org/fhir/StructureDefinition/ExampleNotebook +// CanonicalURL: http://example.org/fhir/StructureDefinition/ExampleNotebook (pkg: example.folder.structures#0.0.1) export interface ExampleNotebook extends DomainResource { - resourceType: "ExampleNotebook"; - author: Reference<"Patient" | "Practitioner">; content: string; _content?: Element; @@ -60,9 +25,6 @@ export interface ExampleNotebook extends DomainResource { title: string; _title?: Element; } -export const isExampleNotebook = (resource: unknown): resource is ExampleNotebook => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ExampleNotebook"; -} " `; diff --git a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap index 9ec2d4f90..39366ae6a 100644 --- a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap @@ -1,149 +1,5 @@ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots -exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation TypeScript Generation should generate ViewDefinition type 1`] = ` -"// WARNING: This file is autogenerated by @atomic-ehr/codegen. -// GitHub: https://github.com/atomic-ehr/codegen -// Any manual changes made to this file may be overwritten. - -import type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; -import type { CanonicalResource } from "../hl7-fhir-r5-core/CanonicalResource"; - -import type { Element } from "../hl7-fhir-r5-core/Element"; -export type { BackboneElement } from "../hl7-fhir-r5-core/BackboneElement"; - -export interface ViewDefinitionConstant extends BackboneElement { - name: string; - valueBase64Binary?: string; - valueBoolean?: boolean; - valueCanonical?: string; - valueCode?: string; - valueDate?: string; - valueDateTime?: string; - valueDecimal?: number; - valueId?: string; - valueInstant?: string; - valueInteger?: number; - valueInteger64?: number; - valueOid?: string; - valuePositiveInt?: number; - valueString?: string; - valueTime?: string; - valueUnsignedInt?: number; - valueUri?: string; - valueUrl?: string; - valueUuid?: string; -} - -export interface ViewDefinitionSelect extends BackboneElement { - column?: ViewDefinitionSelectColumn[]; - forEach?: string; - forEachOrNull?: string; - repeat?: string[]; - select?: ViewDefinitionSelect[]; - unionAll?: ViewDefinitionSelect[]; -} - -export interface ViewDefinitionSelectColumn extends BackboneElement { - collection?: boolean; - description?: string; - name: string; - path: string; - tag?: ViewDefinitionSelectColumnTag[]; - type?: string; -} - -export interface ViewDefinitionSelectColumnTag extends BackboneElement { - name: string; - value: string; -} - -export interface ViewDefinitionWhere extends BackboneElement { - description?: string; - path: string; -} - -// CanonicalURL: https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition -export interface ViewDefinition extends CanonicalResource { - resourceType: "ViewDefinition"; - - constant?: ViewDefinitionConstant[]; - fhirVersion?: ("0.01" | "0.05" | "0.06" | "0.11" | "0.0" | "0.0.80" | "0.0.81" | "0.0.82" | "0.4" | "0.4.0" | "0.5" | "0.5.0" | "1.0" | "1.0.0" | "1.0.1" | "1.0.2" | "1.1" | "1.1.0" | "1.4" | "1.4.0" | "1.6" | "1.6.0" | "1.8" | "1.8.0" | "3.0" | "3.0.0" | "3.0.1" | "3.0.2" | "3.3" | "3.3.0" | "3.5" | "3.5.0" | "4.0" | "4.0.0" | "4.0.1" | "4.1" | "4.1.0" | "4.2" | "4.2.0" | "4.3" | "4.3.0" | "4.3.0-cibuild" | "4.3.0-snapshot1" | "4.4" | "4.4.0" | "4.5" | "4.5.0" | "4.6" | "4.6.0" | "5.0" | "5.0.0" | "5.0.0-cibuild" | "5.0.0-snapshot1" | "5.0.0-snapshot2" | "5.0.0-ballot" | "5.0.0-snapshot3" | "5.0.0-draft-final")[]; - _fhirVersion?: Element; - name?: string; - _name?: Element; - profile?: string[]; - _profile?: Element; - resource: string; - _resource?: Element; - select: ViewDefinitionSelect[]; - where?: ViewDefinitionWhere[]; -} -export const isViewDefinition = (resource: unknown): resource is ViewDefinition => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ViewDefinition"; -} -" -`; - -exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation Python Generation should generate domain_resource for R5 1`] = ` -"# WARNING: This file is autogenerated by @atomic-ehr/codegen. -# GitHub: https://github.com/atomic-ehr/codegen -# Any manual changes made to this file may be overwritten. - -from __future__ import annotations -from pydantic import BaseModel, ConfigDict, Field, PositiveInt -from typing import List as PyList, Literal - -from fhir_types.hl7_fhir_r5_core.base import Extension, Narrative -from fhir_types.hl7_fhir_r5_core.resource import Resource -from fhir_types.hl7_fhir_r5_core.resource_families import ResourceFamily - - -class DomainResource(Resource): - model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - resource_type: str = Field( - default='DomainResource', - alias='resourceType', - serialization_alias='resourceType', - frozen=True, - pattern='DomainResource' - ) - contained: PyList[ResourceFamily] | None = Field(None, alias="contained", serialization_alias="contained") - extension: PyList[Extension] | None = Field(None, alias="extension", serialization_alias="extension") - modifier_extension: PyList[Extension] | None = Field(None, alias="modifierExtension", serialization_alias="modifierExtension") - text: Narrative | None = Field(None, alias="text", serialization_alias="text") - - def to_json(self, indent: int | None = None) -> str: - return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) - - @classmethod - def from_json(cls, json: str) -> DomainResource: - return cls.model_validate_json(json) - -" -`; - -exports[`SQL-on-FHIR Package - Remote URL Multi-Package Generation C# Generation should generate DomainResource for R5 1`] = ` -"// WARNING: This file is autogenerated by @atomic-ehr/codegen. -// GitHub: https://github.com/atomic-ehr/codegen -// Any manual changes made to this file may be overwritten. - - -namespace Fhir.Types.Hl7FhirR5Core; - -public class DomainResource : Resource { - public Resource[]? Contained { get; set; } - public Extension[]? Extension { get; set; } - public Extension[]? ModifierExtension { get; set; } - public Narrative? Text { get; set; } - - public override string ToString() => - JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); - -} - -" -`; - exports[`SQL-on-FHIR TypeScript Generation should generate ViewDefinition type 1`] = ` "// WARNING: This file is autogenerated by @atomic-ehr/codegen. // GitHub: https://github.com/atomic-ehr/codegen @@ -206,10 +62,8 @@ export interface ViewDefinitionWhere extends BackboneElement { path: string; } -// CanonicalURL: https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition +// CanonicalURL: https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition (pkg: org.sql-on-fhir.ig#2.1.0-pre) export interface ViewDefinition extends CanonicalResource { - resourceType: "ViewDefinition"; - constant?: ViewDefinitionConstant[]; fhirVersion?: ("0.01" | "0.05" | "0.06" | "0.11" | "0.0" | "0.0.80" | "0.0.81" | "0.0.82" | "0.4" | "0.4.0" | "0.5" | "0.5.0" | "1.0" | "1.0.0" | "1.0.1" | "1.0.2" | "1.1" | "1.1.0" | "1.4" | "1.4.0" | "1.6" | "1.6.0" | "1.8" | "1.8.0" | "3.0" | "3.0.0" | "3.0.1" | "3.0.2" | "3.3" | "3.3.0" | "3.5" | "3.5.0" | "4.0" | "4.0.0" | "4.0.1" | "4.1" | "4.1.0" | "4.2" | "4.2.0" | "4.3" | "4.3.0" | "4.3.0-cibuild" | "4.3.0-snapshot1" | "4.4" | "4.4.0" | "4.5" | "4.5.0" | "4.6" | "4.6.0" | "5.0" | "5.0.0" | "5.0.0-cibuild" | "5.0.0-snapshot1" | "5.0.0-snapshot2" | "5.0.0-ballot" | "5.0.0-snapshot3" | "5.0.0-draft-final")[]; _fhirVersion?: Element; @@ -222,9 +76,6 @@ export interface ViewDefinition extends CanonicalResource { select: ViewDefinitionSelect[]; where?: ViewDefinitionWhere[]; } -export const isViewDefinition = (resource: unknown): resource is ViewDefinition => { - return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "ViewDefinition"; -} " `; diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/ccda.test.ts index 4798cf0b0..025c6e7e4 100644 --- a/test/api/write-generator/multi-package/ccda.test.ts +++ b/test/api/write-generator/multi-package/ccda.test.ts @@ -16,7 +16,7 @@ describe("CCDA", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .typescript({ inMemoryOnly: true }) .generate(); @@ -35,7 +35,7 @@ describe("CCDA", async () => { const cdaFiles = files.filter((f) => f.includes("hl7-cda-uv-core")); expect(cdaFiles.length).toBeGreaterThan(0); - expect(files.some((f) => f.includes("/Ad.ts") || f.includes("/Cd.ts"))).toBeTrue(); + expect(files.some((f) => f.includes("/AD.ts") || f.includes("/CD.ts"))).toBeTrue(); }); }); @@ -43,7 +43,7 @@ describe("CCDA", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -64,7 +64,7 @@ describe("CCDA", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .csharp({ inMemoryOnly: true }) .generate(); diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts index 9a8bb5718..76ef39a17 100644 --- a/test/api/write-generator/multi-package/local-package.test.ts +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -24,7 +24,7 @@ describe("Local Package Folder - Multi-Package Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .typescript({ inMemoryOnly: true }) .generate(); @@ -56,7 +56,7 @@ describe("Local Package Folder - Multi-Package Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -84,7 +84,7 @@ describe("Local Package Folder - Multi-Package Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .localStructureDefinitions(localPackageConfig) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .csharp({ inMemoryOnly: true }) .generate(); diff --git a/test/api/write-generator/multi-package/sql-on-fhir.test.ts b/test/api/write-generator/multi-package/sql-on-fhir.test.ts index b7f10c210..2d368cb37 100644 --- a/test/api/write-generator/multi-package/sql-on-fhir.test.ts +++ b/test/api/write-generator/multi-package/sql-on-fhir.test.ts @@ -18,7 +18,7 @@ describe("SQL-on-FHIR", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .typescript({ inMemoryOnly: true }) .generate(); @@ -52,7 +52,7 @@ describe("SQL-on-FHIR", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -80,7 +80,7 @@ describe("SQL-on-FHIR", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackageRef(packageUrl) - .treeShake(treeShakeConfig) + .typeSchema({ treeShake: treeShakeConfig }) .csharp({ inMemoryOnly: true }) .generate(); From d4efeda6099ae12e034faa2645d7462b87fb15df Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Thu, 5 Feb 2026 17:58:38 +0000 Subject: [PATCH 06/10] Test: multi-package tests and logic-promotion nested field bug - Fix APIBuilder usage: .typeSchema({ treeShake }) - Fix typo (?) in logic-promotion.ts: "nested" to "fields" for NestedType - Enable promoteLogical for Python/C# tests, convert it.todo to snapshots - Add Patient snapshot tests for local-package --- Makefile | 4 - src/typeschema/ir/logic-promotion.ts | 2 +- .../__snapshots__/ccda.test.ts.snap | 111 +++++++++ .../__snapshots__/local-package.test.ts.snap | 228 ++++++++++++++++++ .../__snapshots__/sql-on-fhir.test.ts.snap | 190 +++++++++++++++ .../multi-package/ccda.test.ts | 25 +- .../multi-package/local-package.test.ts | 46 +++- .../multi-package/sql-on-fhir.test.ts | 25 +- 8 files changed, 608 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 89ad62b22..8df815027 100644 --- a/Makefile +++ b/Makefile @@ -133,10 +133,6 @@ test-python-fhirpy-sdk: typecheck format prepare-aidbox-runme lint generate-pyth . venv/bin/activate && \ mypy --strict . -py-run: - $(TYPECHECK) --project examples/python/tsconfig.json - bun run examples/python/generate.ts - release: echo Push tag for $(VERSION) git tag -a v$(VERSION) -m "Release $(VERSION)" diff --git a/src/typeschema/ir/logic-promotion.ts b/src/typeschema/ir/logic-promotion.ts index 29e913e34..91da02e08 100644 --- a/src/typeschema/ir/logic-promotion.ts +++ b/src/typeschema/ir/logic-promotion.ts @@ -53,7 +53,7 @@ export const promoteLogical = (tsIndex: TypeSchemaIndex, promotes: LogicalPromot return { ...n, base: replace(n.base), - nested: replaceInFields(n.fields), + fields: replaceInFields(n.fields), }; }); } diff --git a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap index 7ea90e28a..80c12dc9f 100644 --- a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap @@ -68,3 +68,114 @@ export interface ClinicalDocument extends ANY { } " `; + +exports[`CCDA Python Generation should generate ClinicalDocument type (promoted logical) 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + + + +class ClinicalDocument(ANY): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='ClinicalDocument', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='ClinicalDocument' + ) + authenticator: PyList[Authenticator] | None = Field(None, alias="authenticator", serialization_alias="authenticator") + author: PyList[Author] = Field(alias="author", serialization_alias="author") + authorization: PyList[Authorization] | None = Field(None, alias="authorization", serialization_alias="authorization") + class_code: str | None = Field(None, alias="classCode", serialization_alias="classCode") + code: CE = Field(alias="code", serialization_alias="code") + component: Component = Field(alias="component", serialization_alias="component") + component_of: ComponentOf | None = Field(None, alias="componentOf", serialization_alias="componentOf") + confidentiality_code: CE = Field(alias="confidentialityCode", serialization_alias="confidentialityCode") + copy_time: TS | None = Field(None, alias="copyTime", serialization_alias="copyTime") + custodian: Custodian = Field(alias="custodian", serialization_alias="custodian") + data_enterer: DataEnterer | None = Field(None, alias="dataEnterer", serialization_alias="dataEnterer") + documentation_of: PyList[DocumentationOf] | None = Field(None, alias="documentationOf", serialization_alias="documentationOf") + effective_time: TS = Field(alias="effectiveTime", serialization_alias="effectiveTime") + id: II = Field(alias="id", serialization_alias="id") + informant: PyList[Informant] | None = Field(None, alias="informant", serialization_alias="informant") + information_recipient: PyList[InformationRecipient] | None = Field(None, alias="informationRecipient", serialization_alias="informationRecipient") + in_fulfillment_of: PyList[InFulfillmentOf] | None = Field(None, alias="inFulfillmentOf", serialization_alias="inFulfillmentOf") + language_code: CS | None = Field(None, alias="languageCode", serialization_alias="languageCode") + legal_authenticator: LegalAuthenticator | None = Field(None, alias="legalAuthenticator", serialization_alias="legalAuthenticator") + mood_code: Literal["INT", "APT", "ARQ", "PRMS", "PRP", "RQO", "SLOT", "DEF", "EVN", "EVN.CRT", "GOL", "OPT", "PERM", "PERMRQ"] | None = Field(None, alias="moodCode", serialization_alias="moodCode") + participant: PyList[Participant1] | None = Field(None, alias="participant", serialization_alias="participant") + realm_code: PyList[CS] | None = Field(None, alias="realmCode", serialization_alias="realmCode") + record_target: PyList[RecordTarget] = Field(alias="recordTarget", serialization_alias="recordTarget") + related_document: PyList[RelatedDocument] | None = Field(None, alias="relatedDocument", serialization_alias="relatedDocument") + sdtc_category: PyList[CD] | None = Field(None, alias="sdtcCategory", serialization_alias="sdtcCategory") + sdtc_status_code: CS | None = Field(None, alias="sdtcStatusCode", serialization_alias="sdtcStatusCode") + set_id: II | None = Field(None, alias="setId", serialization_alias="setId") + template_id: PyList[II] | None = Field(None, alias="templateId", serialization_alias="templateId") + title: ST | None = Field(None, alias="title", serialization_alias="title") + type_id: II | None = Field(None, alias="typeId", serialization_alias="typeId") + version_number: INT | None = Field(None, alias="versionNumber", serialization_alias="versionNumber") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> ClinicalDocument: + return cls.model_validate_json(json) + +" +`; + +exports[`CCDA C# Generation should generate ClinicalDocument type (promoted logical) 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7CdaUvCore; + +public class ClinicalDocument : ANY { + public Authenticator[]? Authenticator { get; set; } + public required Author[] Author { get; set; } + public Authorization[]? Authorization { get; set; } + public string? ClassCode { get; set; } + public required CE Code { get; set; } + public required Component Component { get; set; } + public ComponentOf? ComponentOf { get; set; } + public required CE ConfidentialityCode { get; set; } + public TS? CopyTime { get; set; } + public required Custodian Custodian { get; set; } + public DataEnterer? DataEnterer { get; set; } + public DocumentationOf[]? DocumentationOf { get; set; } + public required TS EffectiveTime { get; set; } + public required II Id { get; set; } + public Informant[]? Informant { get; set; } + public InformationRecipient[]? InformationRecipient { get; set; } + public InFulfillmentOf[]? InFulfillmentOf { get; set; } + public CS? LanguageCode { get; set; } + public LegalAuthenticator? LegalAuthenticator { get; set; } + public ClinicalDocumentMoodCodeBindingEnum? MoodCode { get; set; } + public Participant1[]? Participant { get; set; } + public CS[]? RealmCode { get; set; } + public required RecordTarget[] RecordTarget { get; set; } + public RelatedDocument[]? RelatedDocument { get; set; } + public CD[]? SdtcCategory { get; set; } + public CS? SdtcStatusCode { get; set; } + public II? SetId { get; set; } + public II[]? TemplateId { get; set; } + public ST? Title { get; set; } + public II? TypeId { get; set; } + public INT? VersionNumber { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; diff --git a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap index 9f5a757d4..bab48675a 100644 --- a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap @@ -28,6 +28,45 @@ export interface ExampleNotebook extends DomainResource { " `; +exports[`Local Package Folder - Multi-Package Generation Python Generation should generate ExampleNotebook type (promoted logical) 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r4_core.base import Coding, Identifier, Reference +from fhir_types.hl7_fhir_r4_core.domain_resource import DomainResource +from fhir_types.hl7_fhir_r4_core.resource_families import DomainResourceFamily + + +class ExampleNotebook(DomainResource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='ExampleNotebook', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='ExampleNotebook' + ) + author: Reference = Field(alias="author", serialization_alias="author") + content: str = Field(alias="content", serialization_alias="content") + identifier: Identifier = Field(alias="identifier", serialization_alias="identifier") + tag: PyList[Coding] | None = Field(None, alias="tag", serialization_alias="tag") + title: str = Field(alias="title", serialization_alias="title") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> ExampleNotebook: + return cls.model_validate_json(json) + +" +`; + exports[`Local Package Folder - Multi-Package Generation Python Generation should generate base types for dependencies 1`] = ` "# WARNING: This file is autogenerated by @atomic-ehr/codegen. # GitHub: https://github.com/atomic-ehr/codegen @@ -66,6 +105,104 @@ class DomainResource(Resource): " `; +exports[`Local Package Folder - Multi-Package Generation Python Generation should generate Patient resource 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r4_core.base import (\\ + Address, Attachment, BackboneElement, CodeableConcept, ContactPoint, HumanName, Identifier, Period, Reference +) +from fhir_types.hl7_fhir_r4_core.domain_resource import DomainResource +from fhir_types.hl7_fhir_r4_core.resource_families import DomainResourceFamily + + +class PatientCommunication(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + language: CodeableConcept = Field(alias="language", serialization_alias="language") + preferred: bool | None = Field(None, alias="preferred", serialization_alias="preferred") + +class PatientContact(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + address: Address | None = Field(None, alias="address", serialization_alias="address") + gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") + name: HumanName | None = Field(None, alias="name", serialization_alias="name") + organization: Reference | None = Field(None, alias="organization", serialization_alias="organization") + period: Period | None = Field(None, alias="period", serialization_alias="period") + relationship: PyList[CodeableConcept] | None = Field(None, alias="relationship", serialization_alias="relationship") + telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") + +class PatientLink(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + other: Reference = Field(alias="other", serialization_alias="other") + type: Literal["replaced-by", "replaces", "refer", "seealso"] = Field(alias="type", serialization_alias="type") + + +class Patient(DomainResource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='Patient', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='Patient' + ) + active: bool | None = Field(None, alias="active", serialization_alias="active") + address: PyList[Address] | None = Field(None, alias="address", serialization_alias="address") + birth_date: str | None = Field(None, alias="birthDate", serialization_alias="birthDate") + communication: PyList[PatientCommunication] | None = Field(None, alias="communication", serialization_alias="communication") + contact: PyList[PatientContact] | None = Field(None, alias="contact", serialization_alias="contact") + deceased_boolean: bool | None = Field(None, alias="deceasedBoolean", serialization_alias="deceasedBoolean") + deceased_date_time: str | None = Field(None, alias="deceasedDateTime", serialization_alias="deceasedDateTime") + gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") + general_practitioner: PyList[Reference] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") + identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") + link: PyList[PatientLink] | None = Field(None, alias="link", serialization_alias="link") + managing_organization: Reference | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") + marital_status: CodeableConcept | None = Field(None, alias="maritalStatus", serialization_alias="maritalStatus") + multiple_birth_boolean: bool | None = Field(None, alias="multipleBirthBoolean", serialization_alias="multipleBirthBoolean") + multiple_birth_integer: int | None = Field(None, alias="multipleBirthInteger", serialization_alias="multipleBirthInteger") + name: PyList[HumanName] | None = Field(None, alias="name", serialization_alias="name") + photo: PyList[Attachment] | None = Field(None, alias="photo", serialization_alias="photo") + telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> Patient: + return cls.model_validate_json(json) + +" +`; + +exports[`Local Package Folder - Multi-Package Generation C# Generation should generate ExampleNotebook type (promoted logical) 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.ExampleFolderStructures; + +public class ExampleNotebook : DomainResource { + public required ResourceReference Author { get; set; } + public required string Content { get; set; } + public required Identifier Identifier { get; set; } + public Coding[]? Tag { get; set; } + public required string Title { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; + exports[`Local Package Folder - Multi-Package Generation C# Generation should generate DomainResource base class 1`] = ` "// WARNING: This file is autogenerated by @atomic-ehr/codegen. // GitHub: https://github.com/atomic-ehr/codegen @@ -87,3 +224,94 @@ public class DomainResource : Resource { " `; + +exports[`Local Package Folder - Multi-Package Generation C# Generation should generate Resource base class 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7FhirR4Core; + +public class Resource { + public string? Id { get; set; } + public string? ImplicitRules { get; set; } + public string? Language { get; set; } + public Meta? Meta { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; + +exports[`Local Package Folder - Multi-Package Generation C# Generation should generate Patient resource 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.Hl7FhirR4Core; + +public class Patient : DomainResource { + public bool? Active { get; set; } + public Address[]? Address { get; set; } + public string? BirthDate { get; set; } + public PatientCommunication[]? Communication { get; set; } + public PatientContact[]? Contact { get; set; } + public bool? DeceasedBoolean { get; set; } + public string? DeceasedDateTime { get; set; } + public AdministrativeGenderEnum? Gender { get; set; } + public ResourceReference[]? GeneralPractitioner { get; set; } + public Identifier[]? Identifier { get; set; } + public PatientLink[]? Link { get; set; } + public ResourceReference? ManagingOrganization { get; set; } + public CodeableConcept? MaritalStatus { get; set; } + public bool? MultipleBirthBoolean { get; set; } + public int? MultipleBirthInteger { get; set; } + public HumanName[]? Name { get; set; } + public Attachment[]? Photo { get; set; } + public ContactPoint[]? Telecom { get; set; } + + public class PatientCommunication : BackboneElement { + public required CodeableConcept Language { get; set; } + public bool? Preferred { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class PatientContact : BackboneElement { + public Address? Address { get; set; } + public AdministrativeGenderEnum? Gender { get; set; } + public HumanName? Name { get; set; } + public ResourceReference? Organization { get; set; } + public Period? Period { get; set; } + public CodeableConcept[]? Relationship { get; set; } + public ContactPoint[]? Telecom { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class PatientLink : BackboneElement { + public required ResourceReference Other { get; set; } + public required LinkTypeEnum Type { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; diff --git a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap index 39366ae6a..31ffce722 100644 --- a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap @@ -79,6 +79,99 @@ export interface ViewDefinition extends CanonicalResource { " `; +exports[`SQL-on-FHIR Python Generation should generate ViewDefinition type (promoted logical) 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + +from fhir_types.hl7_fhir_r5_core.base import BackboneElement +from fhir_types.hl7_fhir_r5_core.canonical_resource import CanonicalResource +from fhir_types.hl7_fhir_r5_core.resource_families import CanonicalResourceFamily + + +class ViewDefinitionConstant(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + name: str = Field(alias="name", serialization_alias="name") + value_base64binary: str | None = Field(None, alias="valueBase64Binary", serialization_alias="valueBase64Binary") + value_boolean: bool | None = Field(None, alias="valueBoolean", serialization_alias="valueBoolean") + value_canonical: str | None = Field(None, alias="valueCanonical", serialization_alias="valueCanonical") + value_code: str | None = Field(None, alias="valueCode", serialization_alias="valueCode") + value_date: str | None = Field(None, alias="valueDate", serialization_alias="valueDate") + value_date_time: str | None = Field(None, alias="valueDateTime", serialization_alias="valueDateTime") + value_decimal: float | None = Field(None, alias="valueDecimal", serialization_alias="valueDecimal") + value_id: str | None = Field(None, alias="valueId", serialization_alias="valueId") + value_instant: str | None = Field(None, alias="valueInstant", serialization_alias="valueInstant") + value_integer: int | None = Field(None, alias="valueInteger", serialization_alias="valueInteger") + value_integer64: int | None = Field(None, alias="valueInteger64", serialization_alias="valueInteger64") + value_oid: str | None = Field(None, alias="valueOid", serialization_alias="valueOid") + value_positive_int: PositiveInt | None = Field(None, alias="valuePositiveInt", serialization_alias="valuePositiveInt") + value_string: str | None = Field(None, alias="valueString", serialization_alias="valueString") + value_time: str | None = Field(None, alias="valueTime", serialization_alias="valueTime") + value_unsigned_int: int | None = Field(None, alias="valueUnsignedInt", serialization_alias="valueUnsignedInt") + value_uri: str | None = Field(None, alias="valueUri", serialization_alias="valueUri") + value_url: str | None = Field(None, alias="valueUrl", serialization_alias="valueUrl") + value_uuid: str | None = Field(None, alias="valueUuid", serialization_alias="valueUuid") + +class ViewDefinitionSelect(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + column: PyList[ViewDefinitionSelectColumn] | None = Field(None, alias="column", serialization_alias="column") + for_each: str | None = Field(None, alias="forEach", serialization_alias="forEach") + for_each_or_null: str | None = Field(None, alias="forEachOrNull", serialization_alias="forEachOrNull") + repeat: PyList[str] | None = Field(None, alias="repeat", serialization_alias="repeat") + select: PyList[ViewDefinitionSelect] | None = Field(None, alias="select", serialization_alias="select") + union_all: PyList[ViewDefinitionSelect] | None = Field(None, alias="unionAll", serialization_alias="unionAll") + +class ViewDefinitionSelectColumn(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + collection: bool | None = Field(None, alias="collection", serialization_alias="collection") + description: str | None = Field(None, alias="description", serialization_alias="description") + name: str = Field(alias="name", serialization_alias="name") + path: str = Field(alias="path", serialization_alias="path") + tag: PyList[ViewDefinitionSelectColumnTag] | None = Field(None, alias="tag", serialization_alias="tag") + type: str | None = Field(None, alias="type", serialization_alias="type") + +class ViewDefinitionSelectColumnTag(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + name: str = Field(alias="name", serialization_alias="name") + value: str = Field(alias="value", serialization_alias="value") + +class ViewDefinitionWhere(BackboneElement): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + description: str | None = Field(None, alias="description", serialization_alias="description") + path: str = Field(alias="path", serialization_alias="path") + + +class ViewDefinition(CanonicalResource): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='ViewDefinition', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='ViewDefinition' + ) + constant: PyList[ViewDefinitionConstant] | None = Field(None, alias="constant", serialization_alias="constant") + fhir_version: PyList[Literal["0.01", "0.05", "0.06", "0.11", "0.0", "0.0.80", "0.0.81", "0.0.82", "0.4", "0.4.0", "0.5", "0.5.0", "1.0", "1.0.0", "1.0.1", "1.0.2", "1.1", "1.1.0", "1.4", "1.4.0", "1.6", "1.6.0", "1.8", "1.8.0", "3.0", "3.0.0", "3.0.1", "3.0.2", "3.3", "3.3.0", "3.5", "3.5.0", "4.0", "4.0.0", "4.0.1", "4.1", "4.1.0", "4.2", "4.2.0", "4.3", "4.3.0", "4.3.0-cibuild", "4.3.0-snapshot1", "4.4", "4.4.0", "4.5", "4.5.0", "4.6", "4.6.0", "5.0", "5.0.0", "5.0.0-cibuild", "5.0.0-snapshot1", "5.0.0-snapshot2", "5.0.0-ballot", "5.0.0-snapshot3", "5.0.0-draft-final"]] | None = Field(None, alias="fhirVersion", serialization_alias="fhirVersion") + name: str | None = Field(None, alias="name", serialization_alias="name") + profile: PyList[str] | None = Field(None, alias="profile", serialization_alias="profile") + resource: str = Field(alias="resource", serialization_alias="resource") + select: PyList[ViewDefinitionSelect] = Field(alias="select", serialization_alias="select") + where: PyList[ViewDefinitionWhere] | None = Field(None, alias="where", serialization_alias="where") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> ViewDefinition: + return cls.model_validate_json(json) + +" +`; + exports[`SQL-on-FHIR Python Generation should generate domain_resource for R5 1`] = ` "# WARNING: This file is autogenerated by @atomic-ehr/codegen. # GitHub: https://github.com/atomic-ehr/codegen @@ -117,6 +210,103 @@ class DomainResource(Resource): " `; +exports[`SQL-on-FHIR C# Generation should generate ViewDefinition type (promoted logical) 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + +namespace Fhir.Types.OrgSqlOnFhirIg; + +public class ViewDefinition : CanonicalResource { + public ViewDefinitionConstant[]? Constant { get; set; } + public ViewDefinitionFhirVersionBindingEnum[]? FhirVersion { get; set; } + public string? Name { get; set; } + public string[]? Profile { get; set; } + public required string Resource { get; set; } + public required ViewDefinitionSelect[] Select { get; set; } + public ViewDefinitionWhere[]? Where { get; set; } + + public class ViewDefinitionConstant : BackboneElement { + public required string Name { get; set; } + public string? ValueBase64binary { get; set; } + public bool? ValueBoolean { get; set; } + public string? ValueCanonical { get; set; } + public string? ValueCode { get; set; } + public string? ValueDate { get; set; } + public string? ValueDateTime { get; set; } + public decimal? ValueDecimal { get; set; } + public string? ValueId { get; set; } + public string? ValueInstant { get; set; } + public int? ValueInteger { get; set; } + public long? ValueInteger64 { get; set; } + public string? ValueOid { get; set; } + public long? ValuePositiveInt { get; set; } + public string? ValueString { get; set; } + public string? ValueTime { get; set; } + public long? ValueUnsignedInt { get; set; } + public string? ValueUri { get; set; } + public string? ValueUrl { get; set; } + public string? ValueUuid { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class ViewDefinitionSelect : BackboneElement { + public ViewDefinitionSelectColumn[]? Column { get; set; } + public string? ForEach { get; set; } + public string? ForEachOrNull { get; set; } + public string[]? Repeat { get; set; } + public ViewDefinitionSelect[]? Select { get; set; } + public ViewDefinitionSelect[]? UnionAll { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class ViewDefinitionSelectColumn : BackboneElement { + public bool? Collection { get; set; } + public string? Description { get; set; } + public required string Name { get; set; } + public required string Path { get; set; } + public ViewDefinitionSelectColumnTag[]? Tag { get; set; } + public string? Type { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class ViewDefinitionSelectColumnTag : BackboneElement { + public required string Name { get; set; } + public required string Value { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + public class ViewDefinitionWhere : BackboneElement { + public string? Description { get; set; } + public required string Path { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + + } + + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; + exports[`SQL-on-FHIR C# Generation should generate DomainResource for R5 1`] = ` "// WARNING: This file is autogenerated by @atomic-ehr/codegen. // GitHub: https://github.com/atomic-ehr/codegen diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/ccda.test.ts index 025c6e7e4..4a630ecdf 100644 --- a/test/api/write-generator/multi-package/ccda.test.ts +++ b/test/api/write-generator/multi-package/ccda.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "bun:test"; import { APIBuilder } from "@root/api/builder"; +import type { CanonicalUrl } from "@root/typeschema/types"; /** * Tests for CCDA package generation. @@ -12,6 +13,12 @@ describe("CCDA", async () => { }, }; + const promoteLogicalConfig = { + "hl7.cda.uv.core": [ + "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument" as CanonicalUrl, + ], + }; + describe("TypeScript Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") @@ -43,7 +50,7 @@ describe("CCDA", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -51,8 +58,11 @@ describe("CCDA", async () => { expect(result.success).toBeTrue(); }); - // Python generator does not support logical models (ClinicalDocument is kind: "logical") - it.todo("should generate ClinicalDocument type", () => {}); + it("should generate ClinicalDocument type (promoted logical)", () => { + const clinicalDoc = result.filesGenerated["generated/hl7_cda_uv_core/clinical_document.py"]; + expect(clinicalDoc).toBeDefined(); + expect(clinicalDoc).toMatchSnapshot(); + }); it("should generate base package structure", () => { expect(result.filesGenerated["generated/__init__.py"]).toBeDefined(); @@ -64,7 +74,7 @@ describe("CCDA", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackage("hl7.cda.uv.core", "2.0.1-sd") - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .csharp({ inMemoryOnly: true }) .generate(); @@ -72,8 +82,11 @@ describe("CCDA", async () => { expect(result.success).toBeTrue(); }); - // C# generator does not support logical models (ClinicalDocument is kind: "logical") - it.todo("should generate ClinicalDocument type", () => {}); + it("should generate ClinicalDocument type (promoted logical)", () => { + const clinicalDoc = result.filesGenerated["generated/types/Hl7CdaUvCore/ClinicalDocument.cs"]; + expect(clinicalDoc).toBeDefined(); + expect(clinicalDoc).toMatchSnapshot(); + }); it("should generate base helper files", () => { expect(result.filesGenerated["generated/types/base.cs"]).toBeDefined(); diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts index 76ef39a17..b591c8c21 100644 --- a/test/api/write-generator/multi-package/local-package.test.ts +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "bun:test"; import * as Path from "node:path"; import { APIBuilder } from "@root/api/builder"; +import type { CanonicalUrl } from "@root/typeschema/types"; const LOCAL_PACKAGE_PATH = Path.join(__dirname, "../../../assets/local-package/structure-definitions"); @@ -18,6 +19,15 @@ describe("Local Package Folder - Multi-Package Generation", async () => { "example.folder.structures": { "http://example.org/fhir/StructureDefinition/ExampleNotebook": {}, }, + "hl7.fhir.r4.core": { + "http://hl7.org/fhir/StructureDefinition/Patient": {}, + }, + }; + + const promoteLogicalConfig = { + "example.folder.structures": [ + "http://example.org/fhir/StructureDefinition/ExampleNotebook" as CanonicalUrl, + ], }; describe("TypeScript Generation", async () => { @@ -56,7 +66,7 @@ describe("Local Package Folder - Multi-Package Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .localStructureDefinitions(localPackageConfig) - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -64,8 +74,11 @@ describe("Local Package Folder - Multi-Package Generation", async () => { expect(result.success).toBeTrue(); }); - // Python generator does not support logical models (ExampleNotebook is kind: "logical") - it.todo("should generate ExampleNotebook type", () => {}); + it("should generate ExampleNotebook type (promoted logical)", () => { + const notebook = result.filesGenerated["generated/example_folder_structures/example_notebook.py"]; + expect(notebook).toBeDefined(); + expect(notebook).toMatchSnapshot(); + }); it("should generate R4 dependency types", () => { // Python generator resolves R4 dependencies from tree-shaking @@ -78,13 +91,19 @@ describe("Local Package Folder - Multi-Package Generation", async () => { expect(domainResource).toBeDefined(); expect(domainResource).toMatchSnapshot(); }); + + it("should generate Patient resource", () => { + const patient = result.filesGenerated["generated/hl7_fhir_r4_core/patient.py"]; + expect(patient).toBeDefined(); + expect(patient).toMatchSnapshot(); + }); }); describe("C# Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .localStructureDefinitions(localPackageConfig) - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .csharp({ inMemoryOnly: true }) .generate(); @@ -92,8 +111,11 @@ describe("Local Package Folder - Multi-Package Generation", async () => { expect(result.success).toBeTrue(); }); - // C# generator does not support logical models (ExampleNotebook is kind: "logical") - it.todo("should generate ExampleNotebook type", () => {}); + it("should generate ExampleNotebook type (promoted logical)", () => { + const notebook = result.filesGenerated["generated/types/ExampleFolderStructures/ExampleNotebook.cs"]; + expect(notebook).toBeDefined(); + expect(notebook).toMatchSnapshot(); + }); it("should generate R4 dependency types", () => { // C# generator resolves R4 dependencies from tree-shaking @@ -106,5 +128,17 @@ describe("Local Package Folder - Multi-Package Generation", async () => { expect(domainResource).toBeDefined(); expect(domainResource).toMatchSnapshot(); }); + + it("should generate Resource base class", () => { + const resource = result.filesGenerated["generated/types/Hl7FhirR4Core/Resource.cs"]; + expect(resource).toBeDefined(); + expect(resource).toMatchSnapshot(); + }); + + it("should generate Patient resource", () => { + const patient = result.filesGenerated["generated/types/Hl7FhirR4Core/Patient.cs"]; + expect(patient).toBeDefined(); + expect(patient).toMatchSnapshot(); + }); }); }); diff --git a/test/api/write-generator/multi-package/sql-on-fhir.test.ts b/test/api/write-generator/multi-package/sql-on-fhir.test.ts index 2d368cb37..1c8ba3d35 100644 --- a/test/api/write-generator/multi-package/sql-on-fhir.test.ts +++ b/test/api/write-generator/multi-package/sql-on-fhir.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "bun:test"; import { APIBuilder } from "@root/api/builder"; +import type { CanonicalUrl } from "@root/typeschema/types"; /** * Tests for SQL-on-FHIR package. @@ -14,6 +15,12 @@ describe("SQL-on-FHIR", async () => { }, }; + const promoteLogicalConfig = { + "org.sql-on-fhir.ig": [ + "https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition" as CanonicalUrl, + ], + }; + describe("TypeScript Generation", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") @@ -52,7 +59,7 @@ describe("SQL-on-FHIR", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackageRef(packageUrl) - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .python({ inMemoryOnly: true }) .generate(); @@ -60,8 +67,11 @@ describe("SQL-on-FHIR", async () => { expect(result.success).toBeTrue(); }); - // Python generator does not support logical models (ViewDefinition is kind: "logical") - it.todo("should generate ViewDefinition type", () => {}); + it("should generate ViewDefinition type (promoted logical)", () => { + const viewDef = result.filesGenerated["generated/org_sql_on_fhir_ig/view_definition.py"]; + expect(viewDef).toBeDefined(); + expect(viewDef).toMatchSnapshot(); + }); it("should generate R5 dependency package", () => { // Python generator creates R5 base types for dependencies @@ -80,7 +90,7 @@ describe("SQL-on-FHIR", async () => { const result = await new APIBuilder() .setLogLevel("SILENT") .fromPackageRef(packageUrl) - .typeSchema({ treeShake: treeShakeConfig }) + .typeSchema({ treeShake: treeShakeConfig, promoteLogical: promoteLogicalConfig }) .csharp({ inMemoryOnly: true }) .generate(); @@ -88,8 +98,11 @@ describe("SQL-on-FHIR", async () => { expect(result.success).toBeTrue(); }); - // C# generator does not support logical models (ViewDefinition is kind: "logical") - it.todo("should generate ViewDefinition type", () => {}); + it("should generate ViewDefinition type (promoted logical)", () => { + const viewDef = result.filesGenerated["generated/types/OrgSqlOnFhirIg/ViewDefinition.cs"]; + expect(viewDef).toBeDefined(); + expect(viewDef).toMatchSnapshot(); + }); it("should generate R5 dependency namespace", () => { // C# generator creates R5 types for dependencies From fcf052e31d3d5aeb8a350a9ca5344bf22cfdb98f Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Wed, 11 Feb 2026 16:42:37 +0000 Subject: [PATCH 07/10] test: replace toBeGreaterThan(0) with exact file counts in multi-package tests --- test/api/write-generator/multi-package/ccda.test.ts | 6 ++---- .../write-generator/multi-package/local-package.test.ts | 4 +--- .../api/write-generator/multi-package/sql-on-fhir.test.ts | 8 +++----- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/ccda.test.ts index 4a630ecdf..26e6a1cdb 100644 --- a/test/api/write-generator/multi-package/ccda.test.ts +++ b/test/api/write-generator/multi-package/ccda.test.ts @@ -14,9 +14,7 @@ describe("CCDA", async () => { }; const promoteLogicalConfig = { - "hl7.cda.uv.core": [ - "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument" as CanonicalUrl, - ], + "hl7.cda.uv.core": ["http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument" as CanonicalUrl], }; describe("TypeScript Generation", async () => { @@ -40,7 +38,7 @@ describe("CCDA", async () => { it("should generate CDA-specific types", () => { const files = Object.keys(result.filesGenerated); const cdaFiles = files.filter((f) => f.includes("hl7-cda-uv-core")); - expect(cdaFiles.length).toBeGreaterThan(0); + expect(cdaFiles.length).toBe(78); expect(files.some((f) => f.includes("/AD.ts") || f.includes("/CD.ts"))).toBeTrue(); }); diff --git a/test/api/write-generator/multi-package/local-package.test.ts b/test/api/write-generator/multi-package/local-package.test.ts index b591c8c21..e3a8e9594 100644 --- a/test/api/write-generator/multi-package/local-package.test.ts +++ b/test/api/write-generator/multi-package/local-package.test.ts @@ -25,9 +25,7 @@ describe("Local Package Folder - Multi-Package Generation", async () => { }; const promoteLogicalConfig = { - "example.folder.structures": [ - "http://example.org/fhir/StructureDefinition/ExampleNotebook" as CanonicalUrl, - ], + "example.folder.structures": ["http://example.org/fhir/StructureDefinition/ExampleNotebook" as CanonicalUrl], }; describe("TypeScript Generation", async () => { diff --git a/test/api/write-generator/multi-package/sql-on-fhir.test.ts b/test/api/write-generator/multi-package/sql-on-fhir.test.ts index 1c8ba3d35..29228e42d 100644 --- a/test/api/write-generator/multi-package/sql-on-fhir.test.ts +++ b/test/api/write-generator/multi-package/sql-on-fhir.test.ts @@ -16,9 +16,7 @@ describe("SQL-on-FHIR", async () => { }; const promoteLogicalConfig = { - "org.sql-on-fhir.ig": [ - "https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition" as CanonicalUrl, - ], + "org.sql-on-fhir.ig": ["https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition" as CanonicalUrl], }; describe("TypeScript Generation", async () => { @@ -42,7 +40,7 @@ describe("SQL-on-FHIR", async () => { it("should resolve R5 dependencies (required by SQL-on-FHIR)", () => { const files = Object.keys(result.filesGenerated); const r5Files = files.filter((f) => f.includes("hl7-fhir-r5-core")); - expect(r5Files.length).toBeGreaterThan(0); + expect(r5Files.length).toBe(45); // Core R5 types should be included expect(result.filesGenerated["generated/types/hl7-fhir-r5-core/Element.ts"]).toBeDefined(); @@ -108,7 +106,7 @@ describe("SQL-on-FHIR", async () => { // C# generator creates R5 types for dependencies const files = Object.keys(result.filesGenerated); const r5Files = files.filter((f) => f.includes("Hl7FhirR5Core")); - expect(r5Files.length).toBeGreaterThan(0); + expect(r5Files.length).toBe(5); }); it("should generate DomainResource for R5", () => { From f3b179d8257adc22bd5c167a9096c90691a6096a Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Tue, 24 Feb 2026 13:31:34 +0000 Subject: [PATCH 08/10] minor change in naming --- .../__snapshots__/{ccda.test.ts.snap => cda.test.ts.snap} | 0 .../multi-package/{ccda.test.ts => cda.test.ts} | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename test/api/write-generator/multi-package/__snapshots__/{ccda.test.ts.snap => cda.test.ts.snap} (100%) rename test/api/write-generator/multi-package/{ccda.test.ts => cda.test.ts} (98%) diff --git a/test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap similarity index 100% rename from test/api/write-generator/multi-package/__snapshots__/ccda.test.ts.snap rename to test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap diff --git a/test/api/write-generator/multi-package/ccda.test.ts b/test/api/write-generator/multi-package/cda.test.ts similarity index 98% rename from test/api/write-generator/multi-package/ccda.test.ts rename to test/api/write-generator/multi-package/cda.test.ts index 26e6a1cdb..12a77a9b3 100644 --- a/test/api/write-generator/multi-package/ccda.test.ts +++ b/test/api/write-generator/multi-package/cda.test.ts @@ -3,10 +3,10 @@ import { APIBuilder } from "@root/api/builder"; import type { CanonicalUrl } from "@root/typeschema/types"; /** - * Tests for CCDA package generation. + * Tests for CDA package generation. * Package: hl7.cda.uv.core@2.0.1-sd */ -describe("CCDA", async () => { +describe("CDA", async () => { const treeShakeConfig = { "hl7.cda.uv.core": { "http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument": {}, From acb3a8862e4f0093f98b7fae9d7b0e6d89bb4bf5 Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Tue, 24 Feb 2026 14:19:58 +0000 Subject: [PATCH 09/10] snapshot fix --- .../__snapshots__/cda.test.ts.snap | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap index 80c12dc9f..ab988c188 100644 --- a/test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/cda.test.ts.snap @@ -137,6 +137,186 @@ exports[`CCDA C# Generation should generate ClinicalDocument type (promoted logi // Any manual changes made to this file may be overwritten. +namespace Fhir.Types.Hl7CdaUvCore; + +public class ClinicalDocument : ANY { + public Authenticator[]? Authenticator { get; set; } + public required Author[] Author { get; set; } + public Authorization[]? Authorization { get; set; } + public string? ClassCode { get; set; } + public required CE Code { get; set; } + public required Component Component { get; set; } + public ComponentOf? ComponentOf { get; set; } + public required CE ConfidentialityCode { get; set; } + public TS? CopyTime { get; set; } + public required Custodian Custodian { get; set; } + public DataEnterer? DataEnterer { get; set; } + public DocumentationOf[]? DocumentationOf { get; set; } + public required TS EffectiveTime { get; set; } + public required II Id { get; set; } + public Informant[]? Informant { get; set; } + public InformationRecipient[]? InformationRecipient { get; set; } + public InFulfillmentOf[]? InFulfillmentOf { get; set; } + public CS? LanguageCode { get; set; } + public LegalAuthenticator? LegalAuthenticator { get; set; } + public ClinicalDocumentMoodCodeBindingEnum? MoodCode { get; set; } + public Participant1[]? Participant { get; set; } + public CS[]? RealmCode { get; set; } + public required RecordTarget[] RecordTarget { get; set; } + public RelatedDocument[]? RelatedDocument { get; set; } + public CD[]? SdtcCategory { get; set; } + public CS? SdtcStatusCode { get; set; } + public II? SetId { get; set; } + public II[]? TemplateId { get; set; } + public ST? Title { get; set; } + public II? TypeId { get; set; } + public INT? VersionNumber { get; set; } + + public override string ToString() => + JsonSerializer.Serialize(this, Helper.JsonSerializerOptions); + +} + +" +`; + +exports[`CDA TypeScript Generation should generate ClinicalDocument type 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + +import type { ANY } from "../hl7-cda-uv-core/ANY"; +import type { Authenticator } from "../hl7-cda-uv-core/Authenticator"; +import type { Author } from "../hl7-cda-uv-core/Author"; +import type { Authorization } from "../hl7-cda-uv-core/Authorization"; +import type { CD } from "../hl7-cda-uv-core/CD"; +import type { CE } from "../hl7-cda-uv-core/CE"; +import type { Component } from "../hl7-cda-uv-core/Component"; +import type { ComponentOf } from "../hl7-cda-uv-core/ComponentOf"; +import type { CS } from "../hl7-cda-uv-core/CS"; +import type { Custodian } from "../hl7-cda-uv-core/Custodian"; +import type { DataEnterer } from "../hl7-cda-uv-core/DataEnterer"; +import type { DocumentationOf } from "../hl7-cda-uv-core/DocumentationOf"; +import type { II } from "../hl7-cda-uv-core/II"; +import type { Informant } from "../hl7-cda-uv-core/Informant"; +import type { InformationRecipient } from "../hl7-cda-uv-core/InformationRecipient"; +import type { InFulfillmentOf } from "../hl7-cda-uv-core/InFulfillmentOf"; +import type { INT } from "../hl7-cda-uv-core/INT"; +import type { LegalAuthenticator } from "../hl7-cda-uv-core/LegalAuthenticator"; +import type { Participant1 } from "../hl7-cda-uv-core/Participant1"; +import type { RecordTarget } from "../hl7-cda-uv-core/RecordTarget"; +import type { RelatedDocument } from "../hl7-cda-uv-core/RelatedDocument"; +import type { ST } from "../hl7-cda-uv-core/ST"; +import type { TS } from "../hl7-cda-uv-core/TS"; + +import type { Element } from "../hl7-fhir-r5-core/Element"; +// CanonicalURL: http://hl7.org/cda/stds/core/StructureDefinition/ClinicalDocument (pkg: hl7.cda.uv.core#2.0.1-sd) +export interface ClinicalDocument extends ANY { + authenticator?: Authenticator[]; + author: Author[]; + authorization?: Authorization[]; + classCode?: string; + _classCode?: Element; + code: CE; + component: Component; + componentOf?: ComponentOf; + confidentialityCode: CE; + copyTime?: TS; + custodian: Custodian; + dataEnterer?: DataEnterer; + documentationOf?: DocumentationOf[]; + effectiveTime: TS; + id: II; + informant?: Informant[]; + informationRecipient?: InformationRecipient[]; + inFulfillmentOf?: InFulfillmentOf[]; + languageCode?: CS; + legalAuthenticator?: LegalAuthenticator; + moodCode?: ("INT" | "APT" | "ARQ" | "PRMS" | "PRP" | "RQO" | "SLOT" | "DEF" | "EVN" | "EVN.CRT" | "GOL" | "OPT" | "PERM" | "PERMRQ"); + _moodCode?: Element; + participant?: Participant1[]; + realmCode?: CS[]; + recordTarget: RecordTarget[]; + relatedDocument?: RelatedDocument[]; + sdtcCategory?: CD[]; + sdtcStatusCode?: CS; + setId?: II; + templateId?: II[]; + title?: ST; + typeId?: II; + versionNumber?: INT; +} +" +`; + +exports[`CDA Python Generation should generate ClinicalDocument type (promoted logical) 1`] = ` +"# WARNING: This file is autogenerated by @atomic-ehr/codegen. +# GitHub: https://github.com/atomic-ehr/codegen +# Any manual changes made to this file may be overwritten. + +from __future__ import annotations +from pydantic import BaseModel, ConfigDict, Field, PositiveInt +from typing import List as PyList, Literal + + + +class ClinicalDocument(ANY): + model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") + resource_type: str = Field( + default='ClinicalDocument', + alias='resourceType', + serialization_alias='resourceType', + frozen=True, + pattern='ClinicalDocument' + ) + authenticator: PyList[Authenticator] | None = Field(None, alias="authenticator", serialization_alias="authenticator") + author: PyList[Author] = Field(alias="author", serialization_alias="author") + authorization: PyList[Authorization] | None = Field(None, alias="authorization", serialization_alias="authorization") + class_code: str | None = Field(None, alias="classCode", serialization_alias="classCode") + code: CE = Field(alias="code", serialization_alias="code") + component: Component = Field(alias="component", serialization_alias="component") + component_of: ComponentOf | None = Field(None, alias="componentOf", serialization_alias="componentOf") + confidentiality_code: CE = Field(alias="confidentialityCode", serialization_alias="confidentialityCode") + copy_time: TS | None = Field(None, alias="copyTime", serialization_alias="copyTime") + custodian: Custodian = Field(alias="custodian", serialization_alias="custodian") + data_enterer: DataEnterer | None = Field(None, alias="dataEnterer", serialization_alias="dataEnterer") + documentation_of: PyList[DocumentationOf] | None = Field(None, alias="documentationOf", serialization_alias="documentationOf") + effective_time: TS = Field(alias="effectiveTime", serialization_alias="effectiveTime") + id: II = Field(alias="id", serialization_alias="id") + informant: PyList[Informant] | None = Field(None, alias="informant", serialization_alias="informant") + information_recipient: PyList[InformationRecipient] | None = Field(None, alias="informationRecipient", serialization_alias="informationRecipient") + in_fulfillment_of: PyList[InFulfillmentOf] | None = Field(None, alias="inFulfillmentOf", serialization_alias="inFulfillmentOf") + language_code: CS | None = Field(None, alias="languageCode", serialization_alias="languageCode") + legal_authenticator: LegalAuthenticator | None = Field(None, alias="legalAuthenticator", serialization_alias="legalAuthenticator") + mood_code: Literal["INT", "APT", "ARQ", "PRMS", "PRP", "RQO", "SLOT", "DEF", "EVN", "EVN.CRT", "GOL", "OPT", "PERM", "PERMRQ"] | None = Field(None, alias="moodCode", serialization_alias="moodCode") + participant: PyList[Participant1] | None = Field(None, alias="participant", serialization_alias="participant") + realm_code: PyList[CS] | None = Field(None, alias="realmCode", serialization_alias="realmCode") + record_target: PyList[RecordTarget] = Field(alias="recordTarget", serialization_alias="recordTarget") + related_document: PyList[RelatedDocument] | None = Field(None, alias="relatedDocument", serialization_alias="relatedDocument") + sdtc_category: PyList[CD] | None = Field(None, alias="sdtcCategory", serialization_alias="sdtcCategory") + sdtc_status_code: CS | None = Field(None, alias="sdtcStatusCode", serialization_alias="sdtcStatusCode") + set_id: II | None = Field(None, alias="setId", serialization_alias="setId") + template_id: PyList[II] | None = Field(None, alias="templateId", serialization_alias="templateId") + title: ST | None = Field(None, alias="title", serialization_alias="title") + type_id: II | None = Field(None, alias="typeId", serialization_alias="typeId") + version_number: INT | None = Field(None, alias="versionNumber", serialization_alias="versionNumber") + + def to_json(self, indent: int | None = None) -> str: + return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent) + + @classmethod + def from_json(cls, json: str) -> ClinicalDocument: + return cls.model_validate_json(json) + +" +`; + +exports[`CDA C# Generation should generate ClinicalDocument type (promoted logical) 1`] = ` +"// WARNING: This file is autogenerated by @atomic-ehr/codegen. +// GitHub: https://github.com/atomic-ehr/codegen +// Any manual changes made to this file may be overwritten. + + namespace Fhir.Types.Hl7CdaUvCore; public class ClinicalDocument : ANY { From cfdf0bfbd9aa80950af26622fa7478a582419aaa Mon Sep 17 00:00:00 2001 From: MikhailArtemyev Date: Tue, 24 Feb 2026 14:24:07 +0000 Subject: [PATCH 10/10] snapshot fix --- .../multi-package/__snapshots__/sql-on-fhir.test.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap index 31ffce722..082dacb2b 100644 --- a/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/sql-on-fhir.test.ts.snap @@ -66,11 +66,11 @@ export interface ViewDefinitionWhere extends BackboneElement { export interface ViewDefinition extends CanonicalResource { constant?: ViewDefinitionConstant[]; fhirVersion?: ("0.01" | "0.05" | "0.06" | "0.11" | "0.0" | "0.0.80" | "0.0.81" | "0.0.82" | "0.4" | "0.4.0" | "0.5" | "0.5.0" | "1.0" | "1.0.0" | "1.0.1" | "1.0.2" | "1.1" | "1.1.0" | "1.4" | "1.4.0" | "1.6" | "1.6.0" | "1.8" | "1.8.0" | "3.0" | "3.0.0" | "3.0.1" | "3.0.2" | "3.3" | "3.3.0" | "3.5" | "3.5.0" | "4.0" | "4.0.0" | "4.0.1" | "4.1" | "4.1.0" | "4.2" | "4.2.0" | "4.3" | "4.3.0" | "4.3.0-cibuild" | "4.3.0-snapshot1" | "4.4" | "4.4.0" | "4.5" | "4.5.0" | "4.6" | "4.6.0" | "5.0" | "5.0.0" | "5.0.0-cibuild" | "5.0.0-snapshot1" | "5.0.0-snapshot2" | "5.0.0-ballot" | "5.0.0-snapshot3" | "5.0.0-draft-final")[]; - _fhirVersion?: Element; + _fhirVersion?: (Element | null)[]; name?: string; _name?: Element; profile?: string[]; - _profile?: Element; + _profile?: (Element | null)[]; resource: string; _resource?: Element; select: ViewDefinitionSelect[];