diff --git a/README.md b/README.md index 47599180a..edeecd44c 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ yarn add @atomic-ehr/codegen See the [examples/](examples/) directory for working demonstrations: - **[typescript-r4/](examples/typescript-r4/)** - FHIR R4 type generation with resource creation demo and profile usage -- **[typescript-ccda/](examples/typescript-ccda/)** - C-CDA on FHIR type generation +- **[typescript-ccda/](examples/typescript-ccda/)** - C-CDA on FHIR type generation - **[typescript-sql-on-fhir/](examples/typescript-sql-on-fhir/)** - SQL on FHIR ViewDefinition with tree shaking - **[python/](examples/python/)** - Python/Pydantic model generation with configurable field formats - **[csharp/](examples/csharp/)** - C# class generation with namespace configuration @@ -193,6 +193,32 @@ Tree shaking optimizes the generated output by including only the resources you This feature automatically resolves and includes all dependencies (referenced types, base resources, nested types) while excluding unused resources, significantly reducing the size of generated code and improving compilation times. +##### Field-Level Tree Shaking + +Beyond resource-level filtering, tree shaking supports fine-grained field selection using `selectFields` (whitelist) or `ignoreFields` (blacklist): + +```typescript +.treeShake({ + "hl7.fhir.r4.core#4.0.1": { + "http://hl7.org/fhir/StructureDefinition/Patient": { + selectFields: ["id", "name", "birthDate", "gender"] + }, + "http://hl7.org/fhir/StructureDefinition/Observation": { + ignoreFields: ["performer", "note"] + } + } +}) +``` + +**Configuration Rules:** +- `selectFields`: Only includes the specified fields (whitelist approach) +- `ignoreFields`: Removes specified fields, keeps everything else (blacklist approach) +- These options are **mutually exclusive** - you cannot use both in the same rule + +**Polymorphic Field Handling:** + +FHIR choice types (like `multipleBirth[x]` which can be boolean or integer) are handled intelligently. Selecting/ignoring the base field affects all variants, while targeting specific variants only affects those types. + ### Generation The generation stage uses a `WriterGenerator` system that transforms Type Schema into target language code. The architecture consists of: diff --git a/src/api/builder.ts b/src/api/builder.ts index cafe1f2b4..d11e5a014 100644 --- a/src/api/builder.ts +++ b/src/api/builder.ts @@ -13,7 +13,8 @@ import { CSharp } from "@root/api/writer-generator/csharp/csharp.ts"; import { Python, type PythonGeneratorOptions } from "@root/api/writer-generator/python"; import { generateTypeSchemas } from "@root/typeschema"; import { registerFromManager } from "@root/typeschema/register"; -import { mkTypeSchemaIndex, type TreeShake, type TypeSchemaIndex, treeShake } from "@root/typeschema/utils"; +import { type TreeShake, treeShake } from "@root/typeschema/tree-shake"; +import { mkTypeSchemaIndex, type TypeSchemaIndex } from "@root/typeschema/utils"; import { extractNameFromCanonical, type PackageMeta, diff --git a/src/typeschema/tree-shake.ts b/src/typeschema/tree-shake.ts new file mode 100644 index 000000000..338134825 --- /dev/null +++ b/src/typeschema/tree-shake.ts @@ -0,0 +1,172 @@ +import assert from "node:assert"; +import type { CodegenLogger } from "@root/utils/codegen-logger"; +import { extractDependencies } from "./core/transformer"; +import type { ResolutionTree } from "./register"; +import { + type CanonicalUrl, + type Field, + isBindingSchema, + isChoiceDeclarationField, + isChoiceInstanceField, + isNestedIdentifier, + isNotChoiceDeclarationField, + isPrimitiveTypeSchema, + isSpecializationTypeSchema, + isValueSetTypeSchema, + type NestedType, + type RegularTypeSchema, + type TypeSchema, +} from "./types"; +import { mkTypeSchemaIndex, type TypeSchemaIndex } from "./utils"; + +export type TreeShake = Record>; + +export type TreeShakeRule = { ignoreFields?: string[]; selectFields?: string[] }; + +const mutableSelectFields = (schema: RegularTypeSchema, selectFields: string[]) => { + const selectedFields: Record = {}; + + const selectPolimorphic: Record = {}; + for (const fieldName of selectFields) { + const field = schema.fields?.[fieldName]; + if (!schema.fields || !field) throw new Error(`Field ${fieldName} not found`); + + if (isChoiceDeclarationField(field)) { + if (!selectPolimorphic[fieldName]) selectPolimorphic[fieldName] = {}; + selectPolimorphic[fieldName].declaration = field.choices; + } else if (isChoiceInstanceField(field)) { + const choiceName = field.choiceOf; + if (!selectPolimorphic[choiceName]) selectPolimorphic[choiceName] = {}; + selectPolimorphic[choiceName].instances = [...(selectPolimorphic[choiceName].instances ?? []), fieldName]; + } else { + selectedFields[fieldName] = field; + } + } + + for (const [choiceName, { declaration, instances }] of Object.entries(selectPolimorphic)) { + const choices = instances ?? declaration; + assert(choices); + for (const choiceInstanceName of choices) { + const field = schema.fields?.[choiceInstanceName]; + assert(field); + selectedFields[choiceInstanceName] = field; + } + const decl = schema.fields?.[choiceName]; + assert(decl); + selectedFields[choiceName] = { ...decl, choices: choices }; + } + schema.fields = selectedFields; +}; + +const mutableIgnoreFields = (schema: RegularTypeSchema, ignoreFields: string[]) => { + for (const fieldName of ignoreFields) { + const field = schema.fields?.[fieldName]; + if (!schema.fields || !field) throw new Error(`Field ${fieldName} not found`); + if (schema.fields) { + if (isChoiceDeclarationField(field)) { + for (const choiceName of field.choices) { + delete schema.fields[choiceName]; + } + } + + if (isChoiceInstanceField(field)) { + const choiceDeclaration = schema.fields[field.choiceOf]; + assert(isChoiceDeclarationField(choiceDeclaration)); + choiceDeclaration.choices = choiceDeclaration.choices.filter((c) => c !== fieldName); + if (choiceDeclaration.choices.length === 0) { + delete schema.fields[field.choiceOf]; + } + } + + delete schema.fields[fieldName]; + } + } +}; + +export const treeShakeTypeSchema = (schema: TypeSchema, rule: TreeShakeRule, _logger?: CodegenLogger): TypeSchema => { + schema = structuredClone(schema); + if (isPrimitiveTypeSchema(schema) || isValueSetTypeSchema(schema) || isBindingSchema(schema)) return schema; + + if (rule.selectFields) { + if (rule.ignoreFields) throw new Error("Cannot use both ignoreFields and selectFields in the same rule"); + mutableSelectFields(schema, rule.selectFields); + } + + if (rule.ignoreFields) { + if (rule.selectFields) throw new Error("Cannot use both ignoreFields and selectFields in the same rule"); + mutableIgnoreFields(schema, rule.ignoreFields); + } + + if (schema.nested) { + const usedTypes = new Set(); + const collectUsedNestedTypes = (s: RegularTypeSchema | NestedType) => { + Object.values(s.fields ?? {}) + .filter(isNotChoiceDeclarationField) + .filter((f) => isNestedIdentifier(f.type)) + .forEach((f) => { + const url = f.type.url; + if (!usedTypes.has(url)) { + usedTypes.add(url); + const nestedTypeDef = schema.nested?.find((f) => f.identifier.url === url); + assert(nestedTypeDef); + collectUsedNestedTypes(nestedTypeDef); + } + }); + }; + collectUsedNestedTypes(schema); + schema.nested = schema.nested.filter((n) => usedTypes.has(n.identifier.url)); + } + + schema.dependencies = extractDependencies(schema.identifier, schema.base, schema.fields, schema.nested); + return schema; +}; + +export const treeShake = ( + tsIndex: TypeSchemaIndex, + treeShake: TreeShake, + { resolutionTree, logger }: { resolutionTree?: ResolutionTree; logger?: CodegenLogger }, +): TypeSchemaIndex => { + const focusedSchemas: TypeSchema[] = []; + for (const [pkgId, requires] of Object.entries(treeShake)) { + for (const [url, rule] of Object.entries(requires)) { + const schema = tsIndex.resolveByUrl(pkgId, url as CanonicalUrl); + if (!schema) throw new Error(`Schema not found for ${pkgId} ${url}`); + const shaked = treeShakeTypeSchema(schema, rule); + focusedSchemas.push(shaked); + } + } + const collectDeps = (schemas: TypeSchema[], acc: Record): TypeSchema[] => { + if (schemas.length === 0) return Object.values(acc); + for (const schema of schemas) { + acc[JSON.stringify(schema.identifier)] = schema; + } + + const newSchemas: TypeSchema[] = []; + + for (const schema of schemas) { + if (isSpecializationTypeSchema(schema)) { + if (!schema.dependencies) continue; + schema.dependencies.forEach((dep) => { + const depSchema = tsIndex.resolve(dep); + if (!depSchema) + throw new Error( + `Dependent schema ${JSON.stringify(dep)} not found for ${JSON.stringify(schema.identifier)}`, + ); + const id = JSON.stringify(depSchema.identifier); + if (!acc[id]) newSchemas.push(depSchema); + }); + if (schema.nested) { + for (const nest of schema.nested) { + if (isNestedIdentifier(nest.identifier)) continue; + const id = JSON.stringify(nest.identifier); + if (!acc[id]) newSchemas.push(nest); + } + } + } + } + return collectDeps(newSchemas, acc); + }; + + const shaked = collectDeps(focusedSchemas, {}); + return mkTypeSchemaIndex(shaked, { resolutionTree, logger }); +}; diff --git a/src/typeschema/types.ts b/src/typeschema/types.ts index 39fc95e31..8d9b6900e 100644 --- a/src/typeschema/types.ts +++ b/src/typeschema/types.ts @@ -313,6 +313,11 @@ export const isChoiceDeclarationField = (field: Field | undefined): field is Cho return (field as ChoiceFieldDeclaration).choices !== undefined; }; +export const isChoiceInstanceField = (field: Field | undefined): field is ChoiceFieldInstance => { + if (!field) return false; + return (field as ChoiceFieldInstance).choiceOf !== undefined; +}; + export type TypeschemaParserOptions = { format?: "auto" | "ndjson" | "json"; validate?: boolean; diff --git a/src/typeschema/utils.ts b/src/typeschema/utils.ts index e38b5b24d..8e4b21609 100644 --- a/src/typeschema/utils.ts +++ b/src/typeschema/utils.ts @@ -2,21 +2,16 @@ import * as afs from "node:fs/promises"; import * as Path from "node:path"; import type { CodegenLogger } from "@root/utils/codegen-logger"; import * as YAML from "yaml"; -import { extractDependencies } from "./core/transformer"; import type { ResolutionTree } from "./register"; import { type CanonicalUrl, type Field, type Identifier, - isBindingSchema, isComplexTypeTypeSchema, isLogicalTypeSchema, - isNestedIdentifier, - isPrimitiveTypeSchema, isProfileTypeSchema, isResourceTypeSchema, isSpecializationTypeSchema, - isValueSetTypeSchema, type ProfileTypeSchema, type RegularTypeSchema, type TypeSchema, @@ -44,77 +39,6 @@ export const groupByPackages = (typeSchemas: TypeSchema[]) => { return grouped; }; -export type TypeSchemaShakeRule = { ignoreFields?: string[] }; - -export type TreeShake = Record>; - -export const treeShakeTypeSchema = ( - schema: TypeSchema, - rule: TypeSchemaShakeRule, - _logger?: CodegenLogger, -): TypeSchema => { - schema = structuredClone(schema); - if (isPrimitiveTypeSchema(schema) || isValueSetTypeSchema(schema) || isBindingSchema(schema)) return schema; - - for (const fieldName of rule.ignoreFields ?? []) { - if (schema.fields && !schema.fields[fieldName]) throw new Error(`Field ${fieldName} not found`); - if (schema.fields) { - delete schema.fields[fieldName]; - } - } - - schema.dependencies = extractDependencies(schema.identifier, schema.base, schema.fields, schema.nested); - - return schema; -}; - -export const treeShake = ( - tsIndex: TypeSchemaIndex, - treeShake: TreeShake, - { resolutionTree, logger }: { resolutionTree?: ResolutionTree; logger?: CodegenLogger }, -): TypeSchemaIndex => { - const focusedSchemas: TypeSchema[] = []; - for (const [pkgId, requires] of Object.entries(treeShake)) { - for (const [url, rule] of Object.entries(requires)) { - const schema = tsIndex.resolveByUrl(pkgId, url as CanonicalUrl); - if (!schema) throw new Error(`Schema not found for ${pkgId} ${url}`); - const shaked = treeShakeTypeSchema(schema, rule); - focusedSchemas.push(shaked); - } - } - const collectDeps = (schemas: TypeSchema[], acc: Record): TypeSchema[] => { - if (schemas.length === 0) return Object.values(acc); - for (const schema of schemas) { - acc[JSON.stringify(schema.identifier)] = schema; - } - - const newSchemas: TypeSchema[] = []; - - for (const schema of schemas) { - if (isSpecializationTypeSchema(schema)) { - if (!schema.dependencies) continue; - schema.dependencies.forEach((dep) => { - const depSchema = tsIndex.resolve(dep); - if (!depSchema) throw new Error(`Schema not found for ${dep}`); - const id = JSON.stringify(depSchema.identifier); - if (!acc[id]) newSchemas.push(depSchema); - }); - if (schema.nested) { - for (const nest of schema.nested) { - if (isNestedIdentifier(nest.identifier)) continue; - const id = JSON.stringify(nest.identifier); - if (!acc[id]) newSchemas.push(nest); - } - } - } - } - return collectDeps(newSchemas, acc); - }; - - const shaked = collectDeps(focusedSchemas, {}); - return mkTypeSchemaIndex(shaked, { resolutionTree, logger }); -}; - const buildDependencyGraph = (schemas: RegularTypeSchema[]): Record => { const nameToMap: Record = {}; for (const schema of schemas) { diff --git a/test/unit/typeschema/__snapshots__/tree-shake.test.ts.snap b/test/unit/typeschema/__snapshots__/tree-shake.test.ts.snap new file mode 100644 index 000000000..84a84ee67 --- /dev/null +++ b/test/unit/typeschema/__snapshots__/tree-shake.test.ts.snap @@ -0,0 +1,1570 @@ +// Bun Snapshot v1, https://bun.sh/docs/test/snapshots + +exports[`treeShake specific TypeSchema Original Patient 1`] = ` +"{ + "identifier": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + "base": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + "fields": { + "identifier": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Identifier", + "url": "http://hl7.org/fhir/StructureDefinition/Identifier" + }, + "required": false, + "excluded": false, + "array": true + }, + "active": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false + }, + "name": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + "required": false, + "excluded": false, + "array": true + }, + "telecom": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + "required": false, + "excluded": false, + "array": true + }, + "gender": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + "enum": [ + "male", + "female", + "other", + "unknown" + ] + }, + "birthDate": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + "required": false, + "excluded": false, + "array": false + }, + "deceased": { + "required": false, + "excluded": false, + "array": false, + "choices": [ + "deceasedBoolean", + "deceasedDateTime" + ] + }, + "deceasedBoolean": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "deceased" + }, + "deceasedDateTime": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "dateTime", + "url": "http://hl7.org/fhir/StructureDefinition/dateTime" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "deceased" + }, + "address": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + "required": false, + "excluded": false, + "array": true + }, + "maritalStatus": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "MaritalStatus", + "url": "urn:fhir:binding:MaritalStatus" + } + }, + "multipleBirth": { + "required": false, + "excluded": false, + "array": false, + "choices": [ + "multipleBirthBoolean", + "multipleBirthInteger" + ] + }, + "multipleBirthBoolean": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "multipleBirth" + }, + "multipleBirthInteger": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "integer", + "url": "http://hl7.org/fhir/StructureDefinition/integer" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "multipleBirth" + }, + "photo": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Attachment", + "url": "http://hl7.org/fhir/StructureDefinition/Attachment" + }, + "required": false, + "excluded": false, + "array": true + }, + "contact": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "contact", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#contact" + }, + "array": true, + "required": false, + "excluded": false + }, + "communication": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "communication", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#communication" + }, + "array": true, + "required": false, + "excluded": false + }, + "generalPractitioner": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Practitioner", + "url": "http://hl7.org/fhir/StructureDefinition/Practitioner" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "PractitionerRole", + "url": "http://hl7.org/fhir/StructureDefinition/PractitionerRole" + } + ], + "array": true + }, + "managingOrganization": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + } + ], + "array": false + }, + "link": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "link", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#link" + }, + "array": true, + "required": false, + "excluded": false + } + }, + "nested": [ + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "communication", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#communication" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "language": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": true, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "Language", + "url": "urn:fhir:binding:Language" + } + }, + "preferred": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false + } + } + }, + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "contact", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#contact" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "relationship": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": false, + "excluded": false, + "array": true, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "ContactRelationship", + "url": "urn:fhir:binding:ContactRelationship" + } + }, + "name": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + "required": false, + "excluded": false, + "array": false + }, + "telecom": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + "required": false, + "excluded": false, + "array": true + }, + "address": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + "required": false, + "excluded": false, + "array": false + }, + "gender": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + "enum": [ + "male", + "female", + "other", + "unknown" + ] + }, + "organization": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + } + ], + "array": false + }, + "period": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Period", + "url": "http://hl7.org/fhir/StructureDefinition/Period" + }, + "required": false, + "excluded": false, + "array": false + } + } + }, + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "link", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#link" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "other": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": true, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "RelatedPerson", + "url": "http://hl7.org/fhir/StructureDefinition/RelatedPerson" + } + ], + "array": false + }, + "type": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": true, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "LinkType", + "url": "urn:fhir:binding:LinkType" + }, + "enum": [ + "replaced-by", + "replaces", + "refer", + "seealso" + ] + } + } + } + ], + "description": "Demographics and other administrative information about an individual or animal receiving care or other health-related services.", + "dependencies": [ + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Attachment", + "url": "http://hl7.org/fhir/StructureDefinition/Attachment" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "dateTime", + "url": "http://hl7.org/fhir/StructureDefinition/dateTime" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Identifier", + "url": "http://hl7.org/fhir/StructureDefinition/Identifier" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "integer", + "url": "http://hl7.org/fhir/StructureDefinition/integer" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Period", + "url": "http://hl7.org/fhir/StructureDefinition/Period" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "ContactRelationship", + "url": "urn:fhir:binding:ContactRelationship" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "Language", + "url": "urn:fhir:binding:Language" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "LinkType", + "url": "urn:fhir:binding:LinkType" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "MaritalStatus", + "url": "urn:fhir:binding:MaritalStatus" + } + ] +}" +`; + +exports[`treeShake specific TypeSchema ignoreFields regular field 1`] = ` +"{ + "identifier": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + "base": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + "fields": { + "identifier": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Identifier", + "url": "http://hl7.org/fhir/StructureDefinition/Identifier" + }, + "required": false, + "excluded": false, + "array": true + }, + "active": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false + }, + "name": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + "required": false, + "excluded": false, + "array": true + }, + "telecom": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + "required": false, + "excluded": false, + "array": true + }, + "birthDate": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + "required": false, + "excluded": false, + "array": false + }, + "deceased": { + "required": false, + "excluded": false, + "array": false, + "choices": [ + "deceasedBoolean", + "deceasedDateTime" + ] + }, + "deceasedBoolean": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "deceased" + }, + "deceasedDateTime": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "dateTime", + "url": "http://hl7.org/fhir/StructureDefinition/dateTime" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "deceased" + }, + "address": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + "required": false, + "excluded": false, + "array": true + }, + "maritalStatus": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "MaritalStatus", + "url": "urn:fhir:binding:MaritalStatus" + } + }, + "multipleBirth": { + "required": false, + "excluded": false, + "array": false, + "choices": [ + "multipleBirthBoolean", + "multipleBirthInteger" + ] + }, + "multipleBirthBoolean": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "multipleBirth" + }, + "multipleBirthInteger": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "integer", + "url": "http://hl7.org/fhir/StructureDefinition/integer" + }, + "required": false, + "excluded": false, + "array": false, + "choiceOf": "multipleBirth" + }, + "photo": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Attachment", + "url": "http://hl7.org/fhir/StructureDefinition/Attachment" + }, + "required": false, + "excluded": false, + "array": true + }, + "contact": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "contact", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#contact" + }, + "array": true, + "required": false, + "excluded": false + }, + "communication": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "communication", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#communication" + }, + "array": true, + "required": false, + "excluded": false + }, + "generalPractitioner": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Practitioner", + "url": "http://hl7.org/fhir/StructureDefinition/Practitioner" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "PractitionerRole", + "url": "http://hl7.org/fhir/StructureDefinition/PractitionerRole" + } + ], + "array": true + }, + "managingOrganization": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + } + ], + "array": false + }, + "link": { + "type": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "link", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#link" + }, + "array": true, + "required": false, + "excluded": false + } + }, + "nested": [ + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "communication", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#communication" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "language": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": true, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "Language", + "url": "urn:fhir:binding:Language" + } + }, + "preferred": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false + } + } + }, + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "contact", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#contact" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "relationship": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + "required": false, + "excluded": false, + "array": true, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "ContactRelationship", + "url": "urn:fhir:binding:ContactRelationship" + } + }, + "name": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + "required": false, + "excluded": false, + "array": false + }, + "telecom": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + "required": false, + "excluded": false, + "array": true + }, + "address": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + "required": false, + "excluded": false, + "array": false + }, + "gender": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + "enum": [ + "male", + "female", + "other", + "unknown" + ] + }, + "organization": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": false, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Organization", + "url": "http://hl7.org/fhir/StructureDefinition/Organization" + } + ], + "array": false + }, + "period": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Period", + "url": "http://hl7.org/fhir/StructureDefinition/Period" + }, + "required": false, + "excluded": false, + "array": false + } + } + }, + { + "identifier": { + "kind": "nested", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "link", + "url": "http://hl7.org/fhir/StructureDefinition/Patient#link" + }, + "base": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + "fields": { + "other": { + "type": { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + "required": true, + "excluded": false, + "reference": [ + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "RelatedPerson", + "url": "http://hl7.org/fhir/StructureDefinition/RelatedPerson" + } + ], + "array": false + }, + "type": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": true, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "LinkType", + "url": "urn:fhir:binding:LinkType" + }, + "enum": [ + "replaced-by", + "replaces", + "refer", + "seealso" + ] + } + } + } + ], + "description": "Demographics and other administrative information about an individual or animal receiving care or other health-related services.", + "dependencies": [ + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Address", + "url": "http://hl7.org/fhir/StructureDefinition/Address" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Attachment", + "url": "http://hl7.org/fhir/StructureDefinition/Attachment" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "BackboneElement", + "url": "http://hl7.org/fhir/StructureDefinition/BackboneElement" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "CodeableConcept", + "url": "http://hl7.org/fhir/StructureDefinition/CodeableConcept" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "ContactPoint", + "url": "http://hl7.org/fhir/StructureDefinition/ContactPoint" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "dateTime", + "url": "http://hl7.org/fhir/StructureDefinition/dateTime" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "HumanName", + "url": "http://hl7.org/fhir/StructureDefinition/HumanName" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Identifier", + "url": "http://hl7.org/fhir/StructureDefinition/Identifier" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "integer", + "url": "http://hl7.org/fhir/StructureDefinition/integer" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Period", + "url": "http://hl7.org/fhir/StructureDefinition/Period" + }, + { + "kind": "complex-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Reference", + "url": "http://hl7.org/fhir/StructureDefinition/Reference" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "ContactRelationship", + "url": "urn:fhir:binding:ContactRelationship" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "Language", + "url": "urn:fhir:binding:Language" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "LinkType", + "url": "urn:fhir:binding:LinkType" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "MaritalStatus", + "url": "urn:fhir:binding:MaritalStatus" + } + ] +}" +`; + +exports[`treeShake specific TypeSchema selectFields regular field 1`] = ` +"{ + "identifier": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + "base": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + "fields": { + "gender": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + "enum": [ + "male", + "female", + "other", + "unknown" + ] + } + }, + "nested": [], + "description": "Demographics and other administrative information about an individual or animal receiving care or other health-related services.", + "dependencies": [ + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + } + ] +}" +`; + +exports[`treeShake specific TypeSchema selectFields multiple regular fields 1`] = ` +"{ + "identifier": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "Patient", + "url": "http://hl7.org/fhir/StructureDefinition/Patient" + }, + "base": { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + "fields": { + "gender": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + "required": false, + "excluded": false, + "array": false, + "binding": { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + }, + "enum": [ + "male", + "female", + "other", + "unknown" + ] + }, + "birthDate": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + "required": false, + "excluded": false, + "array": false + }, + "active": { + "type": { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + "required": false, + "excluded": false, + "array": false + } + }, + "nested": [], + "description": "Demographics and other administrative information about an individual or animal receiving care or other health-related services.", + "dependencies": [ + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "boolean", + "url": "http://hl7.org/fhir/StructureDefinition/boolean" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "code", + "url": "http://hl7.org/fhir/StructureDefinition/code" + }, + { + "kind": "primitive-type", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "date", + "url": "http://hl7.org/fhir/StructureDefinition/date" + }, + { + "kind": "resource", + "package": "hl7.fhir.r4.core", + "version": "4.0.1", + "name": "DomainResource", + "url": "http://hl7.org/fhir/StructureDefinition/DomainResource" + }, + { + "kind": "binding", + "package": "shared", + "version": "1.0.0", + "name": "AdministrativeGender", + "url": "urn:fhir:binding:AdministrativeGender" + } + ] +}" +`; diff --git a/test/unit/typeschema/tree-shake.test.ts b/test/unit/typeschema/tree-shake.test.ts new file mode 100644 index 000000000..35bf7e3ed --- /dev/null +++ b/test/unit/typeschema/tree-shake.test.ts @@ -0,0 +1,210 @@ +import { describe, expect, it } from "bun:test"; +import assert from "node:assert"; +import { treeShakeTypeSchema } from "@root/typeschema/tree-shake"; +import type { CanonicalUrl, RegularTypeSchema } from "@root/typeschema/types"; +import { mkR4Register, r4Package, resolveTs } from "@typeschema-test/utils"; + +describe("treeShake specific TypeSchema", async () => { + const r4 = await mkR4Register(); + const patientTss = await resolveTs( + r4, + r4Package, + "http://hl7.org/fhir/StructureDefinition/Patient" as CanonicalUrl, + ); + const patientOrigin = patientTss[0] as RegularTypeSchema; + assert(patientOrigin !== undefined); + + it("Original Patient", () => { + expect(JSON.stringify(patientOrigin, null, 2)).toMatchSnapshot(); + }); + + it("No rule -- no change", () => { + const patient = treeShakeTypeSchema(patientOrigin, {}); + expect(JSON.stringify(patient, null, 2)).toBe(JSON.stringify(patientOrigin, null, 2)); + }); + + it("Select and Ignore fields should be mutually exclusive", () => { + expect(() => { + treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["gender", "link", "active", "address", "birthDate"], + selectFields: ["name", "telecom", "gender", "birthDate"], + }); + }).toThrowError("Cannot use both ignoreFields and selectFields in the same rule"); + }); + + describe("ignoreFields", async () => { + it("regular field", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["gender"], + }) as RegularTypeSchema; + expect(patientOrigin.fields?.gender).toBeDefined(); + expect(patient.fields?.gender).toBeUndefined(); + expect(JSON.stringify(patient, null, 2)).toMatchSnapshot(); + }); + + describe("polimorphic field", () => { + expect(patientOrigin.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean", "multipleBirthInteger"], + }); + expect(patientOrigin.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patientOrigin.fields?.multipleBirthInteger).toMatchObject({ + type: { name: "integer" }, + }); + + it("choice declaration", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["multipleBirth"], + }) as RegularTypeSchema; + expect(patient.fields?.multipleBirth).toBeUndefined(); + expect(patient.fields?.multipleBirthBoolean).toBeUndefined(); + expect(patient.fields?.multipleBirthInteger).toBeUndefined(); + }); + + it("choice instance", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["multipleBirthInteger"], + }) as RegularTypeSchema; + expect(patient.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean"], + }); + expect(patient.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patient.fields?.multipleBirthInteger).toBeUndefined(); + }); + it("all choice instance", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["multipleBirthBoolean", "multipleBirthInteger"], + }) as RegularTypeSchema; + expect(patient.fields?.multipleBirth).toBeUndefined(); + expect(patient.fields?.multipleBirthBoolean).toBeUndefined(); + expect(patient.fields?.multipleBirthInteger).toBeUndefined(); + }); + }); + + describe("edge cases", () => { + it("non-existent field", () => { + expect(() => { + treeShakeTypeSchema(patientOrigin, { + ignoreFields: ["nonExistentField"], + }); + }).toThrowError("Field nonExistentField not found"); + }); + + it("empty ignoreFields array", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + ignoreFields: [], + }) as RegularTypeSchema; + expect(JSON.stringify(patient, null, 2)).toBe(JSON.stringify(patientOrigin, null, 2)); + }); + }); + }); + + describe("selectFields", async () => { + it("regular field", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: ["gender"], + }) as RegularTypeSchema; + expect(patient.fields?.gender).toBeDefined(); + expect(patient.fields?.name).toBeUndefined(); + expect(patient.fields?.birthDate).toBeUndefined(); + expect(patient.fields?.address).toBeUndefined(); + expect(JSON.stringify(patient, null, 2)).toMatchSnapshot(); + }); + + it("multiple regular fields", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: ["gender", "birthDate", "active"], + }) as RegularTypeSchema; + expect(patient.fields?.gender).toBeDefined(); + expect(patient.fields?.birthDate).toBeDefined(); + expect(patient.fields?.active).toBeDefined(); + expect(patient.fields?.name).toBeUndefined(); + expect(patient.fields?.address).toBeUndefined(); + expect(patient.fields?.telecom).toBeUndefined(); + expect(JSON.stringify(patient, null, 2)).toMatchSnapshot(); + }); + + describe("polymorphic field", () => { + expect(patientOrigin.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean", "multipleBirthInteger"], + }); + expect(patientOrigin.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patientOrigin.fields?.multipleBirthInteger).toMatchObject({ + type: { name: "integer" }, + }); + + it("choice declaration - get all polimorphic fields", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: ["multipleBirth"], + }) as RegularTypeSchema; + + expect(patient.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean", "multipleBirthInteger"], + }); + expect(patient.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patient.fields?.multipleBirthInteger).toMatchObject({ + type: { name: "integer" }, + }); + expect(patient.fields?.gender).toBeUndefined(); + expect(patient.fields?.name).toBeUndefined(); + }); + + it("choice instance", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: ["multipleBirthBoolean"], + }) as RegularTypeSchema; + + expect(patient.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean"], + }); + expect(patient.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patient.fields?.multipleBirthInteger).toBeUndefined(); + expect(patient.fields?.gender).toBeUndefined(); + expect(patient.fields?.name).toBeUndefined(); + }); + + it("choice declaration & instance", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: ["multipleBirth", "multipleBirthBoolean"], + }) as RegularTypeSchema; + + expect(patient.fields?.multipleBirth).toMatchObject({ + choices: ["multipleBirthBoolean"], + }); + expect(patient.fields?.multipleBirthBoolean).toMatchObject({ + type: { name: "boolean" }, + }); + expect(patient.fields?.multipleBirthInteger).toBeUndefined(); + expect(patient.fields?.gender).toBeUndefined(); + expect(patient.fields?.name).toBeUndefined(); + }); + }); + + describe("edge cases", () => { + it("empty selectFields array", () => { + const patient = treeShakeTypeSchema(patientOrigin, { + selectFields: [], + }) as RegularTypeSchema; + + expect(patient.fields).toEqual({}); + }); + + it("non-existent field", () => { + expect(() => { + treeShakeTypeSchema(patientOrigin, { + selectFields: ["nonExistentField"], + }); + }).toThrowError("Field nonExistentField not found"); + }); + }); + }); +}); diff --git a/test/unit/typeschema/utils.ts b/test/unit/typeschema/utils.ts index c8a001ce5..6fdc5afff 100644 --- a/test/unit/typeschema/utils.ts +++ b/test/unit/typeschema/utils.ts @@ -40,6 +40,12 @@ export const registerFs = (register: Register, fs: PFS) => { return rfs; }; +export const resolveTs = async (register: Register, pkgMeta: PackageMeta, url: string | CanonicalUrl) => { + const rfs = register.resolveFs(pkgMeta, url as CanonicalUrl); + if (!rfs) throw new Error("Failed to resolve registered FHIR schema"); + return await transformFhirSchema(register, rfs, logger); +}; + export const registerFsAndMkTs = async (register: Register, fs: PFS) => { registerFs(register, fs); if (!fs.package_meta) throw new Error("Package metadata is missing");