@rethinkhealth/hl7v2-builder 0.3.4 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,6 +57,23 @@ const tree = m(
57
57
 
58
58
  `tree` is now a `Root` node with two segments (`MSH`, `PID`). You can serialise it, transform it, or feed it into other HL7v2 utilities.
59
59
 
60
+ ### Experimental: Empty Mode
61
+
62
+ The builder respects the `emptyMode` experimental setting from `@rethinkhealth/hl7v2-config`. When `emptyMode: "empty"` is configured in your `.hl7v2rc.json`, empty fields, repetitions, and components will have empty children arrays instead of the legacy full structure.
63
+
64
+ **Legacy mode (default):**
65
+ ```typescript
66
+ f() // → Field → Rep → Comp → Sub("")
67
+ ```
68
+
69
+ **Empty mode (via config):**
70
+ ```typescript
71
+ // With .hl7v2rc.json: { "settings": { "experimental": { "emptyMode": "empty" } } }
72
+ f() // → Field with children: []
73
+ ```
74
+
75
+ See [`@rethinkhealth/hl7v2-config`](../hl7v2-config/) for configuration details.
76
+
60
77
  ## API
61
78
 
62
79
  ### `m(...children: RootContent[]): Root`
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/index.ts
2
+ import { loadConfig } from "@rethinkhealth/hl7v2-config";
2
3
  import { u } from "unist-builder";
4
+ function getEmptyMode() {
5
+ const config = loadConfig();
6
+ return config.settings.experimental.emptyMode;
7
+ }
3
8
  function m(...children) {
4
9
  return u("root", children);
5
10
  }
@@ -24,10 +29,18 @@ function isComponent(value) {
24
29
  }
25
30
  function f(...values) {
26
31
  if (values.length === 0) {
32
+ const emptyMode = getEmptyMode();
33
+ if (emptyMode === "empty") {
34
+ return u("field", []);
35
+ }
27
36
  return u("field", [r()]);
28
37
  }
29
38
  const flat = flatten(values);
30
39
  if (flat.length === 0) {
40
+ const emptyMode = getEmptyMode();
41
+ if (emptyMode === "empty") {
42
+ return u("field", []);
43
+ }
31
44
  return u("field", [r()]);
32
45
  }
33
46
  const repetitions = [];
@@ -57,10 +70,18 @@ function f(...values) {
57
70
  }
58
71
  function r(...components) {
59
72
  if (components.length === 0) {
73
+ const emptyMode = getEmptyMode();
74
+ if (emptyMode === "empty") {
75
+ return u("field-repetition", []);
76
+ }
60
77
  return u("field-repetition", [c()]);
61
78
  }
62
79
  const flat = flatten(components);
63
80
  if (flat.length === 0) {
81
+ const emptyMode = getEmptyMode();
82
+ if (emptyMode === "empty") {
83
+ return u("field-repetition", []);
84
+ }
64
85
  return u("field-repetition", [c()]);
65
86
  }
66
87
  return u(
@@ -70,10 +91,18 @@ function r(...components) {
70
91
  }
71
92
  function c(...values) {
72
93
  if (values.length === 0) {
94
+ const emptyMode = getEmptyMode();
95
+ if (emptyMode === "empty") {
96
+ return u("component", []);
97
+ }
73
98
  return u("component", [u("subcomponent", "")]);
74
99
  }
75
100
  const flat = flatten(values);
76
101
  if (flat.length === 0) {
102
+ const emptyMode = getEmptyMode();
103
+ if (emptyMode === "empty") {
104
+ return u("component", []);
105
+ }
77
106
  return u("component", [u("subcomponent", "")]);
78
107
  }
79
108
  return u(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/** biome-ignore-all lint/style/useUnifiedTypeSignatures: fine */\nimport type {\n Component,\n Field,\n FieldRepetition,\n Group,\n Root,\n RootContent,\n Segment,\n SegmentHeader,\n} from \"@rethinkhealth/hl7v2-ast\";\nimport { u } from \"unist-builder\";\n\nexport function m(...children: RootContent[]): Root {\n return u(\"root\", children);\n}\n\nexport function g(name: string, ...children: Array<Segment | Group>): Group {\n const group: Group = u(\"group\", children);\n group.name = name;\n return group;\n}\n\n// TODO: Add support for string[]\n// export function s(name: string, ...fields: string[]): Segment;\n// export function s(name: string, ...fields: string[] | Field[]): Segment {\nexport function s(name: string, ...fields: Field[]): Segment {\n const header = u(\"segment-header\", name) as SegmentHeader;\n const segment = u(\"segment\", [header, ...fields]) as Segment;\n return segment;\n}\n\ntype FieldValue = FieldRepetition | Component | string;\ntype Flattenable<T> = T | T[];\n\nfunction flatten<T>(values: Flattenable<T>[]): T[] {\n return values.flatMap((value) => (Array.isArray(value) ? value : [value]));\n}\n\nfunction isFieldRepetition(value: FieldValue): value is FieldRepetition {\n return (\n typeof value === \"object\" &&\n value !== null &&\n value.type === \"field-repetition\"\n );\n}\n\nfunction isComponent(value: FieldValue): value is Component {\n return (\n typeof value === \"object\" && value !== null && value.type === \"component\"\n );\n}\n\n/** Empty field */\nexport function f(): Field;\nexport function f(...values: Flattenable<FieldValue>[]): Field;\nexport function f(...values: Flattenable<FieldValue>[]): Field {\n if (values.length === 0) {\n return u(\"field\", [r()]);\n }\n\n const flat = flatten<FieldValue>(values);\n if (flat.length === 0) {\n return u(\"field\", [r()]);\n }\n\n const repetitions: FieldRepetition[] = [];\n let pendingComponents: Array<Component | string> = [];\n\n const flushPending = () => {\n if (pendingComponents.length === 0) {\n return;\n }\n repetitions.push(r(...pendingComponents));\n pendingComponents = [];\n };\n\n for (const value of flat) {\n if (isFieldRepetition(value)) {\n flushPending();\n repetitions.push(value);\n continue;\n }\n\n if (isComponent(value) || typeof value === \"string\") {\n pendingComponents.push(value);\n }\n }\n\n flushPending();\n\n if (repetitions.length === 0) {\n return u(\"field\", [r()]);\n }\n\n return u(\"field\", repetitions);\n}\n\nexport function r(): FieldRepetition;\nexport function r(\n ...components: Flattenable<Component | string>[]\n): FieldRepetition;\nexport function r(\n ...components: Flattenable<Component | string>[]\n): FieldRepetition {\n if (components.length === 0) {\n return u(\"field-repetition\", [c()]);\n }\n\n const flat = flatten<Component | string>(components);\n if (flat.length === 0) {\n return u(\"field-repetition\", [c()]);\n }\n\n return u(\n \"field-repetition\",\n flat.map((value) => (typeof value === \"string\" ? c(value) : value))\n );\n}\n\nexport function c(): Component;\nexport function c(...values: Flattenable<string>[]): Component;\nexport function c(...values: Flattenable<string>[]): Component {\n if (values.length === 0) {\n return u(\"component\", [u(\"subcomponent\", \"\")]);\n }\n\n const flat = flatten<string>(values);\n if (flat.length === 0) {\n return u(\"component\", [u(\"subcomponent\", \"\")]);\n }\n\n return u(\n \"component\",\n flat.map((subcomponent) => u(\"subcomponent\", subcomponent))\n );\n}\n"],"mappings":";AAWA,SAAS,SAAS;AAEX,SAAS,KAAK,UAA+B;AAClD,SAAO,EAAE,QAAQ,QAAQ;AAC3B;AAEO,SAAS,EAAE,SAAiB,UAAyC;AAC1E,QAAM,QAAe,EAAE,SAAS,QAAQ;AACxC,QAAM,OAAO;AACb,SAAO;AACT;AAKO,SAAS,EAAE,SAAiB,QAA0B;AAC3D,QAAM,SAAS,EAAE,kBAAkB,IAAI;AACvC,QAAM,UAAU,EAAE,WAAW,CAAC,QAAQ,GAAG,MAAM,CAAC;AAChD,SAAO;AACT;AAKA,SAAS,QAAW,QAA+B;AACjD,SAAO,OAAO,QAAQ,CAAC,UAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAE;AAC3E;AAEA,SAAS,kBAAkB,OAA6C;AACtE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,MAAM,SAAS;AAEnB;AAEA,SAAS,YAAY,OAAuC;AAC1D,SACE,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,SAAS;AAElE;AAKO,SAAS,KAAK,QAA0C;AAC7D,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,EACzB;AAEA,QAAM,OAAO,QAAoB,MAAM;AACvC,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,EACzB;AAEA,QAAM,cAAiC,CAAC;AACxC,MAAI,oBAA+C,CAAC;AAEpD,QAAM,eAAe,MAAM;AACzB,QAAI,kBAAkB,WAAW,GAAG;AAClC;AAAA,IACF;AACA,gBAAY,KAAK,EAAE,GAAG,iBAAiB,CAAC;AACxC,wBAAoB,CAAC;AAAA,EACvB;AAEA,aAAW,SAAS,MAAM;AACxB,QAAI,kBAAkB,KAAK,GAAG;AAC5B,mBAAa;AACb,kBAAY,KAAK,KAAK;AACtB;AAAA,IACF;AAEA,QAAI,YAAY,KAAK,KAAK,OAAO,UAAU,UAAU;AACnD,wBAAkB,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,eAAa;AAEb,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,EACzB;AAEA,SAAO,EAAE,SAAS,WAAW;AAC/B;AAMO,SAAS,KACX,YACc;AACjB,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,oBAAoB,CAAC,EAAE,CAAC,CAAC;AAAA,EACpC;AAEA,QAAM,OAAO,QAA4B,UAAU;AACnD,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,EAAE,oBAAoB,CAAC,EAAE,CAAC,CAAC;AAAA,EACpC;AAEA,SAAO;AAAA,IACL;AAAA,IACA,KAAK,IAAI,CAAC,UAAW,OAAO,UAAU,WAAW,EAAE,KAAK,IAAI,KAAM;AAAA,EACpE;AACF;AAIO,SAAS,KAAK,QAA0C;AAC7D,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,EAAE,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAAA,EAC/C;AAEA,QAAM,OAAO,QAAgB,MAAM;AACnC,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,EAAE,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAAA,EAC/C;AAEA,SAAO;AAAA,IACL;AAAA,IACA,KAAK,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,YAAY,CAAC;AAAA,EAC5D;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/** biome-ignore-all lint/style/useUnifiedTypeSignatures: fine */\nimport type {\n Component,\n Field,\n FieldRepetition,\n Group,\n Root,\n RootContent,\n Segment,\n SegmentHeader,\n} from \"@rethinkhealth/hl7v2-ast\";\nimport { loadConfig } from \"@rethinkhealth/hl7v2-config\";\nimport { u } from \"unist-builder\";\n\n/**\n * Get the emptyMode setting from the configuration.\n * Falls back to 'legacy' if no config is found or if the setting is not defined.\n */\nfunction getEmptyMode() {\n const config = loadConfig();\n return config.settings.experimental.emptyMode;\n}\n\nexport function m(...children: RootContent[]): Root {\n return u(\"root\", children);\n}\n\nexport function g(name: string, ...children: Array<Segment | Group>): Group {\n const group: Group = u(\"group\", children);\n group.name = name;\n return group;\n}\n\n// TODO: Add support for string[]\n// export function s(name: string, ...fields: string[]): Segment;\n// export function s(name: string, ...fields: string[] | Field[]): Segment {\nexport function s(name: string, ...fields: Field[]): Segment {\n const header = u(\"segment-header\", name) as SegmentHeader;\n const segment = u(\"segment\", [header, ...fields]) as Segment;\n return segment;\n}\n\ntype FieldValue = FieldRepetition | Component | string;\ntype Flattenable<T> = T | T[];\n\nfunction flatten<T>(values: Flattenable<T>[]): T[] {\n return values.flatMap((value) => (Array.isArray(value) ? value : [value]));\n}\n\nfunction isFieldRepetition(value: FieldValue): value is FieldRepetition {\n return (\n typeof value === \"object\" &&\n value !== null &&\n value.type === \"field-repetition\"\n );\n}\n\nfunction isComponent(value: FieldValue): value is Component {\n return (\n typeof value === \"object\" && value !== null && value.type === \"component\"\n );\n}\n\n/** Empty field */\nexport function f(): Field;\nexport function f(...values: Flattenable<FieldValue>[]): Field;\nexport function f(...values: Flattenable<FieldValue>[]): Field {\n if (values.length === 0) {\n // Empty field - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"field\", []);\n }\n return u(\"field\", [r()]);\n }\n\n const flat = flatten<FieldValue>(values);\n if (flat.length === 0) {\n // Empty field - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"field\", []);\n }\n return u(\"field\", [r()]);\n }\n\n const repetitions: FieldRepetition[] = [];\n let pendingComponents: Array<Component | string> = [];\n\n const flushPending = () => {\n if (pendingComponents.length === 0) {\n return;\n }\n repetitions.push(r(...pendingComponents));\n pendingComponents = [];\n };\n\n for (const value of flat) {\n if (isFieldRepetition(value)) {\n flushPending();\n repetitions.push(value);\n continue;\n }\n\n if (isComponent(value) || typeof value === \"string\") {\n pendingComponents.push(value);\n }\n }\n\n flushPending();\n\n if (repetitions.length === 0) {\n return u(\"field\", [r()]);\n }\n\n return u(\"field\", repetitions);\n}\n\nexport function r(): FieldRepetition;\nexport function r(\n ...components: Flattenable<Component | string>[]\n): FieldRepetition;\nexport function r(\n ...components: Flattenable<Component | string>[]\n): FieldRepetition {\n if (components.length === 0) {\n // Empty repetition - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"field-repetition\", []);\n }\n return u(\"field-repetition\", [c()]);\n }\n\n const flat = flatten<Component | string>(components);\n if (flat.length === 0) {\n // Empty repetition - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"field-repetition\", []);\n }\n return u(\"field-repetition\", [c()]);\n }\n\n return u(\n \"field-repetition\",\n flat.map((value) => (typeof value === \"string\" ? c(value) : value))\n );\n}\n\nexport function c(): Component;\nexport function c(...values: Flattenable<string>[]): Component;\nexport function c(...values: Flattenable<string>[]): Component {\n if (values.length === 0) {\n // Empty component - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"component\", []);\n }\n return u(\"component\", [u(\"subcomponent\", \"\")]);\n }\n\n const flat = flatten<string>(values);\n if (flat.length === 0) {\n // Empty component - check emptyMode from config\n const emptyMode = getEmptyMode();\n if (emptyMode === \"empty\") {\n return u(\"component\", []);\n }\n return u(\"component\", [u(\"subcomponent\", \"\")]);\n }\n\n return u(\n \"component\",\n flat.map((subcomponent) => u(\"subcomponent\", subcomponent))\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rethinkhealth/hl7v2-builder",
3
3
  "description": "Build HL7v2 AST nodes",
4
- "version": "0.3.4",
4
+ "version": "0.4.1",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Melek Somai",
@@ -17,18 +17,19 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "unist-builder": "4.0.0",
20
- "@rethinkhealth/hl7v2-ast": "0.3.4"
20
+ "@rethinkhealth/hl7v2-ast": "0.4.1",
21
+ "@rethinkhealth/hl7v2-config": "0.4.1"
21
22
  },
22
23
  "devDependencies": {
23
- "@types/node": "24.10.0",
24
+ "@types/node": "24.10.1",
24
25
  "@types/unist": "^3.0.3",
25
- "@vitest/coverage-v8": "^4.0.5",
26
- "tsup": "8.5.0",
26
+ "@vitest/coverage-v8": "4.0.14",
27
+ "tsup": "8.5.1",
27
28
  "typescript": "^5.9.3",
28
29
  "unified": "^11.0.5",
29
- "vitest": "^4.0.6",
30
- "@rethinkhealth/testing": "0.0.2",
31
- "@rethinkhealth/tsconfig": "0.0.1"
30
+ "vitest": "4.0.14",
31
+ "@rethinkhealth/tsconfig": "0.0.1",
32
+ "@rethinkhealth/testing": "0.0.2"
32
33
  },
33
34
  "engines": {
34
35
  "node": ">=18"