{"id":37185131,"url":"https://github.com/singl3focus/hl7-converter","last_synced_at":"2026-05-03T17:01:32.790Z","repository":{"id":245859077,"uuid":"816853043","full_name":"singl3focus/hl7-converter","owner":"singl3focus","description":"Go toolkit for converting HL7/ASTM-style lab messages via declarative JSON mappings. Validated configs, positional or input-driven generation, optional JS post-processing, and aliases for easy routing. Ideal for LIS connectors, ETL bridges, and quick vendor-to-vendor integrations","archived":false,"fork":false,"pushed_at":"2026-04-08T11:08:56.000Z","size":239,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-08T13:12:05.845Z","etag":null,"topics":["astm","converter","go","hl7","medtech"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/singl3focus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-06-18T14:20:29.000Z","updated_at":"2026-01-30T22:40:49.000Z","dependencies_parsed_at":"2024-08-27T15:43:10.027Z","dependency_job_id":"f7214694-9da6-4301-9d28-61bef5483e6f","html_url":"https://github.com/singl3focus/hl7-converter","commit_stats":null,"previous_names":["singl3focus/hl7-converter"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/singl3focus/hl7-converter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/singl3focus%2Fhl7-converter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/singl3focus%2Fhl7-converter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/singl3focus%2Fhl7-converter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/singl3focus%2Fhl7-converter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/singl3focus","download_url":"https://codeload.github.com/singl3focus/hl7-converter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/singl3focus%2Fhl7-converter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32577126,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astm","converter","go","hl7","medtech"],"created_at":"2026-01-14T21:24:31.501Z","updated_at":"2026-05-03T17:01:32.784Z","avatar_url":"https://github.com/singl3focus.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/singl3focus/hl7-converter/actions/workflows/go.yml\"\u003e\u003cimg src=\"https://github.com/singl3focus/hl7-converter/actions/workflows/go.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/made_by-singl3focus-blue\" alt=\"Made by singl3focus\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat\" alt=\"PRs welcome\"\u003e\n\u003c/p\u003e\n\n# HL7 Converter\n\n`hl7-converter` is a config-driven Go toolkit for transforming HL7, ASTM, and other row-based lab messages with declarative JSON mappings.\n\nIt is built for teams that need a small, embeddable mapping engine inside LIS bridges, ETL adapters, middleware services, or device integrations, without committing to a heavyweight integration platform.\n\n## What Problem It Solves\n\nLab and device integrations usually fail in the same place: the message structure is close to HL7, but never close enough.\n\nOne analyzer emits ASTM-like rows, another vendor expects HL7-ish segments, and the integration layer ends up full of one-off string parsing code. That code is hard to review, hard to test, and expensive to change when a new device or customer mapping appears.\n\n`hl7-converter` moves that logic into JSON configuration:\n\n- define separators and row structure once\n- map input tags to output tags\n- describe field templates with links like `\u003cTAG-3\u003e` or `\u003cTAG-3.1\u003e`\n- add aliases for downstream routing or logging\n- optionally post-process the converted result with trusted JavaScript\n\n## When To Use It\n\n- You need a small Go library, not a full integration server.\n- Message transformation rules should live in config instead of hand-written code.\n- The source and target formats are row-oriented and field-position driven.\n- You need to embed conversion into an existing Go service or adapter.\n- You want repeatable test coverage around mappings and templates.\n\n## When Not To Use It\n\n- You need a visual integration designer, queues, retries, persistence, or orchestration.\n- Your mappings require deep business workflows rather than deterministic field transformation.\n- Your payloads are not fundamentally row/tag based.\n- You need sandboxed user scripting. JavaScript hooks here are trusted-code only.\n\n## 30-Second Quick Start\n\n```bash\ngo get github.com/singl3focus/hl7-converter/v2@latest\n```\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\n\thl7converter \"github.com/singl3focus/hl7-converter/v2\"\n)\n\nfunc main() {\n\tparams, err := hl7converter.NewConverterParams(\"./examples/config.json\", \"astm_hbl\", \"mindray_hbl\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tconverter, err := hl7converter.NewConverter(\n\t\tparams,\n\t\thl7converter.WithUsingPositions(),\n\t\thl7converter.WithUsingAliases(),\n\t)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tinput := []byte(\"H|\\\\^\u0026|||sireAstmCom|||||||P|LIS02-A2|20220327\\n\" +\n\t\t\"P|1||||^||||||||||||||||||||||||||||\\n\" +\n\t\t\"O|1|142212||^^^Urina4^screening^|||||||||^||URI^^||||||||||F|||||\\n\" +\n\t\t\"R|1|^^^Urina4^screening^^tempo-analisi-minuti|180|||||F|||||\\n\" +\n\t\t\"R|2|^^^Urina4^screening^^tempo-analisi-minuti|90|||||F|||||\")\n\n\tresult, err := converter.Convert(input)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlog.Print(result.String())\n}\n```\n\nRepository sample config: `examples/config.json`.\n\n## Input / Output Example\n\nInput:\n\n```text\nH|\\^\u0026|||sireAstmCom|||||||P|LIS02-A2|20220327\nP|1||||^||||||||||||||||||||||||||||\nO|1|142212||^^^Urina4^screening^|||||||||^||URI^^||||||||||F|||||\nR|1|^^^Urina4^screening^^tempo-analisi-minuti|180|||||F|||||\nR|2|^^^Urina4^screening^^tempo-analisi-minuti|90|||||F|||||\n```\n\nOutput:\n\n```text\nMSH|^\\\u0026|Manufacturer|Model|||20220327||ORU^R01||P|2.3.1||||||ASCII|\nPID||142212|||||||||||||||||||||||||||\nOBR||142212|||||||||||||URI|||||||||||||||||||||||||||\nOBX|||Urina4^screening^tempo-analisi-minuti|tempo-analisi-minuti|180||||||F|||||\nOBX|||Urina4^screening^tempo-analisi-minuti|tempo-analisi-minuti|90||||||F|||||\n```\n\n## Mapping Config Example\n\n```json\n{\n  \"mindray_hbl\": {\n    \"component_separator\": \"^\",\n    \"component_array_separator\": \" \",\n    \"field_separator\": \"|\",\n    \"line_separator\": \"\\r\",\n    \"aliases\": {\n      \"Header\": \"MSH-9.2\",\n      \"PatientID\": \"PID-3\",\n      \"Key\": \"OBR-16\"\n    },\n    \"tags_info\": {\n      \"positions\": {\n        \"1\": \"MSH\",\n        \"2\": \"PID\",\n        \"3\": \"OBR\",\n        \"4\": \"OBX\"\n      },\n      \"tags\": {\n        \"MSH\": {\n          \"linked\": \"H\",\n          \"options\": [\"autofill\"],\n          \"fields_number\": 19,\n          \"template\": \"MSH|??^\\\\\u0026|??Manufacturer|??Model|||\u003cH-14\u003e||??ORU^R01|\u003cH-3\u003e|\u003cH-12\u003e|??2.3.1||||||??ASCII|\"\n        },\n        \"PID\": {\n          \"linked\": \"P\",\n          \"fields_number\": 30,\n          \"template\": \"PID||\u003cO-3\u003e|||||||||||||||||||||||||||\"\n        }\n      }\n    }\n  }\n}\n```\n\n## Architecture Overview\n\n### Conversion Flow\n\n```mermaid\nflowchart LR\n    A[\"Incoming message\"] --\u003e B[\"Parse rows by line separator\"]\n    B --\u003e C[\"Split fields by field separator\"]\n    C --\u003e D[\"Apply input tag options\"]\n    D --\u003e E[\"Build parsed tag map\"]\n    E --\u003e F[\"Resolve output templates and links\"]\n    F --\u003e G[\"Generate rows by input order or configured positions\"]\n    G --\u003e H[\"Apply aliases\"]\n    H --\u003e I[\"Optional JS post-processing\"]\n    I --\u003e J[\"Result\"]\n```\n\n### Config Structure\n\n```mermaid\nflowchart TB\n    A[\"Config file\"] --\u003e B[\"Modification block\"]\n    B --\u003e C[\"Separators\"]\n    B --\u003e D[\"Types\"]\n    B --\u003e E[\"Aliases\"]\n    B --\u003e F[\"tags_info\"]\n    F --\u003e G[\"positions\"]\n    F --\u003e H[\"tags\"]\n    H --\u003e I[\"linked\"]\n    H --\u003e J[\"fields_number\"]\n    H --\u003e K[\"template\"]\n    H --\u003e L[\"options\"]\n```\n\n### Conversion Modes\n\n```mermaid\nflowchart LR\n    A[\"Input-driven conversion\"] --\u003e B[\"Walk input rows in original order\"]\n    B --\u003e C[\"Map each seen input tag to one output row\"]\n\n    D[\"Position-driven conversion\"] --\u003e E[\"Walk output positions from config\"]\n    E --\u003e F[\"Repeat each output tag by linked input count\"]\n```\n\n## Supported Mapping Features\n\n- Custom line, field, component, and component-array separators.\n- Output generation by input order or by explicit configured positions.\n- Template links like `\u003cTAG-3\u003e` and component links like `\u003cTAG-3.1\u003e`.\n- Default literals with `??value`.\n- Aliases for extracting stable values from the converted result.\n- Trusted JavaScript post-processing via `Result.UseScript`.\n\n### Supported Options\n\n- `autofill`: append empty trailing fields while parsing an input row until it matches the tag `fields_number`.\n\n## Validation Model\n\nValidation now happens in two layers:\n\n1. `Modification.Validate()`\n   - checks required separators\n   - rejects separator conflicts\n   - validates positions keys and references\n   - validates known options\n   - validates template field count and link/default syntax\n2. `NewConverterParams()`\n   - validates the selected input/output pair together\n   - rejects output templates that reference unknown input tags\n   - rejects links that point outside known input field ranges when `fields_number` is explicit\n\nThis means invalid mappings fail earlier, before conversion starts.\n\n## Concurrency And Safety\n\n- `Converter` is safe for concurrent `Convert` calls on the same instance.\n- `Result` is mutable and is not guaranteed safe for concurrent mutation.\n- JavaScript hooks are trusted-code only. There is no built-in sandbox or timeout.\n\n## Public API Snapshot\n\n- Construction: `NewConverterParams`, `NewConverter`\n- Converter options: `WithUsingPositions`, `WithUsingAliases`\n- Execution: `Convert`, `ParseMsg`, `ParseInput`, `IndetifyMsg`\n- Result helpers: `FindTag`, `ApplyAliases`, `UseScript`, `SwapRows`, `SetRow`\n- Field helpers: `Components`, `Array`, `ComponentsChecked`, `ArrayChecked`\n\n## Limitations\n\n- Designed for ASCII-oriented messages and simple string-based separators.\n- Template semantics are intentionally narrow: deterministic field mapping, not workflow orchestration.\n- Component validation can only be checked at runtime because input payload shape may vary per message.\n- JavaScript support is for controlled operational environments, not end-user scripting.\n\n## CLI\n\nA minimal CLI is published with each release as `hl7conv`. It is built from `cmd/hl7conv` and uses the same library API.\n\n```text\nhl7conv \u003ccommand\u003e [flags]\n\nCommands:\n  convert         Convert a message using a config and an input/output block pair.\n  identify        Identify a message type by matching parsed tags against configured Types.\n  validate-config Validate a JSON config file and optionally a single modification block.\n  version         Print version.\n```\n\nExamples:\n\n```bash\n# convert a message read from a file, position-driven, with aliases\nhl7conv convert \\\n  -config ./examples/config.json \\\n  -in astm_hbl -out mindray_hbl \\\n  -input ./message.txt \\\n  -positions -aliases\n\n# validate config and a specific block\nhl7conv validate-config -config ./examples/config.json -block astm_hbl\n\n# identify message type\ncat ./message.txt | hl7conv identify \\\n  -config ./examples/config.json \\\n  -in astm_hbl -out mindray_hbl\n```\n\nBuild locally:\n\n```bash\ngo build -o hl7conv ./cmd/hl7conv\n```\n\n## Alternatives\n\n`hl7-converter` deliberately occupies a small slot. It is not a replacement for full integration platforms or full HL7 toolkits.\n\n- **Mirth Connect / NextGen Connect.** Full integration server with channels, queues, persistence, retries, transformers and a UI. Use it when you need an integration platform. Use `hl7-converter` when you need an embeddable mapping engine inside your own Go service.\n- **HAPI HL7v2 (Java).** Comprehensive HL7v2 parser and model with strict structures. Use it when you need full HL7v2 conformance, ACK handling, and a Java stack. Use `hl7-converter` when your reality is closer to ASTM-like or HL7-ish row formats and you want config-driven mapping in Go.\n- **FHIR-oriented converters and mappers (FHIR Mapping Language, Microsoft FHIR Converter).** Aimed at producing FHIR resources, often with rich resource semantics and bundle handling. Use them when the target is FHIR. Use `hl7-converter` when both sides are row-and-tag based and you need deterministic field mapping without leaving Go.\n\nIn short: pick `hl7-converter` when the mapping is deterministic, row-based, must live in Go, and the only thing you really need is a small, testable transformation step.\n\n## Testing And Benchmarks\n\nRun the full test suite:\n\n```bash\ngo test ./...\n```\n\nRun with the race detector:\n\n```bash\ngo test -race ./...\n```\n\nRun benchmarks:\n\n```bash\ngo test -bench=. ./...\n```\n\nThe repository includes:\n\n- unit tests for config validation, template parsing, conversion modes, aliases, and field helpers\n- concurrency tests for shared `Converter` usage\n- fuzz coverage for `Convert`\n- benchmarks for realistic message payloads\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsingl3focus%2Fhl7-converter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsingl3focus%2Fhl7-converter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsingl3focus%2Fhl7-converter/lists"}