@glion/lint-profile-required-components 0.23.0 → 0.24.0
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 +17 -17
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -39
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @glion/lint-profile-required-components
|
|
2
2
|
|
|
3
|
-
Lint rule
|
|
3
|
+
Lint rule that reports a required component that is missing or empty.
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
Flags
|
|
7
|
+
Flags a component that the HL7v2 standard for the message's version marks `R` (required) when it is missing or empty in a field that has a value. Before v2.5 the standard marks no component as required, so the rule reports nothing for older versions. Empty fields are left to `@glion/lint-profile-required-fields`. It needs the plugins `@glion/annotate-profile-context` and `@glion/annotate-profile-fields` to run before it; `@glion/preset-lint-profile-recommended` includes them.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -16,21 +16,24 @@ npm install @glion/lint-profile-required-components
|
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
import { hl7v2AnnotateProfileContext } from "@glion/annotate-profile-context";
|
|
19
|
-
import {
|
|
19
|
+
import { hl7v2AnnotateProfileFields } from "@glion/annotate-profile-fields";
|
|
20
20
|
import hl7v2LintRequiredComponents from "@glion/lint-profile-required-components";
|
|
21
|
+
import { parseHL7v2 } from "@glion/parser";
|
|
21
22
|
import { unified } from "unified";
|
|
23
|
+
import { VFile } from "vfile";
|
|
22
24
|
import { reporter } from "vfile-reporter";
|
|
23
25
|
|
|
24
26
|
const message = [
|
|
25
|
-
"MSH|^~\\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT
|
|
27
|
+
"MSH|^~\\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^|MSG00001|P|2.5",
|
|
26
28
|
"PID|1||PATID1234^^^HOSP^MR||DOE^JANE||19800101|F",
|
|
27
29
|
].join("\r");
|
|
28
30
|
|
|
29
|
-
const file =
|
|
30
|
-
|
|
31
|
+
const file = new VFile();
|
|
32
|
+
await unified()
|
|
31
33
|
.use(hl7v2AnnotateProfileContext)
|
|
34
|
+
.use(hl7v2AnnotateProfileFields)
|
|
32
35
|
.use(hl7v2LintRequiredComponents)
|
|
33
|
-
.
|
|
36
|
+
.run(parseHL7v2(message), file);
|
|
34
37
|
|
|
35
38
|
console.error(reporter([file]));
|
|
36
39
|
```
|
|
@@ -39,9 +42,7 @@ console.error(reporter([file]));
|
|
|
39
42
|
|
|
40
43
|
### `unified().use(hl7v2LintRequiredComponents)`
|
|
41
44
|
|
|
42
|
-
A `unified` lint rule plugin. Takes no options.
|
|
43
|
-
|
|
44
|
-
Reads `file.data.profile`. For each non-empty field, resolves the datatype definition from the field profile and iterates `dtDef.requiredSequences`. For every field repetition, checks that each required component is present with a non-empty first subcomponent value.
|
|
45
|
+
A `unified` lint rule plugin. Takes no options. Reports one message for each required component that is missing or empty, in each repetition.
|
|
45
46
|
|
|
46
47
|
```ts
|
|
47
48
|
import type { Plugin } from "unified";
|
|
@@ -53,11 +54,11 @@ export default hl7v2LintRequiredComponents;
|
|
|
53
54
|
|
|
54
55
|
## What it checks
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
In a field that has a value, every component marked `R` in the message's version is present and not empty. For example, in v2.5 `MSH-9` (Message Type) requires the message code (`MSH-9.1`), the trigger event (`MSH-9.2`) and the message structure (`MSH-9.3`).
|
|
57
58
|
|
|
58
59
|
### Valid
|
|
59
60
|
|
|
60
|
-
`MSH-9`
|
|
61
|
+
`MSH-9` has all three components:
|
|
61
62
|
|
|
62
63
|
```hl7
|
|
63
64
|
MSH|^~\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^A01^ADT_A01|MSG00001|P|2.5
|
|
@@ -66,21 +67,20 @@ PID|1||PATID1234^^^HOSP^MR||DOE^JANE||19800101|F
|
|
|
66
67
|
|
|
67
68
|
### Invalid
|
|
68
69
|
|
|
69
|
-
`MSH-9.2`
|
|
70
|
+
`MSH-9.2` is empty and `MSH-9.3` is missing:
|
|
70
71
|
|
|
71
72
|
```hl7
|
|
72
73
|
MSH|^~\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^|MSG00001|P|2.5
|
|
73
74
|
PID|1||PATID1234^^^HOSP^MR||DOE^JANE||19800101|F
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
Reported
|
|
77
|
+
Reported messages:
|
|
77
78
|
|
|
78
79
|
```
|
|
79
|
-
|
|
80
|
+
Component `MSH-9.2` (Trigger Event) is empty; it is required.
|
|
81
|
+
Component `MSH-9.3` (Message Structure) is not present; it is required.
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
When the component name is available in the datatype profile it appears in parentheses. One message is reported per missing required component per repetition.
|
|
83
|
-
|
|
84
84
|
## Part of Glion
|
|
85
85
|
|
|
86
86
|
`@glion/lint-profile-required-components` is part of **[Glion]**, the application framework for HL7v2. See the [Glion README] for the full package catalog and architecture.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { Root } from "@glion/ast";
|
|
2
2
|
/**
|
|
3
|
-
* Lint rule that
|
|
3
|
+
* Lint rule that reports a required component that is absent or empty.
|
|
4
4
|
*
|
|
5
|
-
* For each field
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* For each valued field of a composite datatype, checks in every repetition
|
|
6
|
+
* the components whose optionality is `R`. `RE`, `C`, `B`, and `W` are not
|
|
7
|
+
* checked; before v2.5 the standard records no component optionality.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Segments without a known profile (e.g., Z-segments) are silently skipped.
|
|
9
|
+
* Reads `id` and `datatype` from `field.data`, so
|
|
10
|
+
* `@glion/annotate-profile-fields` MUST run before it.
|
|
12
11
|
*
|
|
13
12
|
* @example
|
|
14
13
|
* ```typescript
|
|
15
|
-
* unified()
|
|
14
|
+
* unified()
|
|
15
|
+
* .use(hl7v2AnnotateProfileContext)
|
|
16
|
+
* .use(hl7v2AnnotateProfileFields)
|
|
17
|
+
* .use(hl7v2LintRequiredComponents);
|
|
16
18
|
* ```;
|
|
17
19
|
*/
|
|
18
20
|
declare const hl7v2LintRequiredComponents: import("unified-lint-rule").Plugin<Root, unknown>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYvC;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,2BAA2B,mDAuDhC,CAAC;AAEF,eAAe,2BAA2B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,59 +1,66 @@
|
|
|
1
1
|
import { SKIP, visit } from "@glion/util-visit";
|
|
2
|
-
import { isEmptyNode } from "@glion/utils";
|
|
2
|
+
import { Optionality, isEmptyNode } from "@glion/utils";
|
|
3
3
|
import { lintRule } from "unified-lint-rule";
|
|
4
4
|
//#region src/index.ts
|
|
5
|
+
const messages = {
|
|
6
|
+
absentComponent: (component, name) => `Component \`${component}\` (${name}) is not present; it is required.`,
|
|
7
|
+
emptyComponent: (component, name) => `Component \`${component}\` (${name}) is empty; it is required.`
|
|
8
|
+
};
|
|
5
9
|
/**
|
|
6
|
-
* Lint rule that
|
|
10
|
+
* Lint rule that reports a required component that is absent or empty.
|
|
7
11
|
*
|
|
8
|
-
* For each field
|
|
9
|
-
*
|
|
10
|
-
*
|
|
12
|
+
* For each valued field of a composite datatype, checks in every repetition
|
|
13
|
+
* the components whose optionality is `R`. `RE`, `C`, `B`, and `W` are not
|
|
14
|
+
* checked; before v2.5 the standard records no component optionality.
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Segments without a known profile (e.g., Z-segments) are silently skipped.
|
|
16
|
+
* Reads `id` and `datatype` from `field.data`, so
|
|
17
|
+
* `@glion/annotate-profile-fields` MUST run before it.
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
17
20
|
* ```typescript
|
|
18
|
-
* unified()
|
|
21
|
+
* unified()
|
|
22
|
+
* .use(hl7v2AnnotateProfileContext)
|
|
23
|
+
* .use(hl7v2AnnotateProfileFields)
|
|
24
|
+
* .use(hl7v2LintRequiredComponents);
|
|
19
25
|
* ```;
|
|
20
26
|
*/
|
|
21
|
-
const hl7v2LintRequiredComponents = lintRule({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
file.message(
|
|
27
|
+
const hl7v2LintRequiredComponents = lintRule({
|
|
28
|
+
origin: "hl7v2-lint:required-components",
|
|
29
|
+
url: "https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-required-components#readme"
|
|
30
|
+
}, (tree, file) => {
|
|
31
|
+
const datatypes = file.data.profile?.datatypes;
|
|
32
|
+
if (datatypes === void 0) return;
|
|
33
|
+
visit(tree, "field", (field, ancestors) => {
|
|
34
|
+
if (isEmptyNode(field)) return SKIP;
|
|
35
|
+
const id = field.data?.id;
|
|
36
|
+
const datatypeId = field.data?.datatype;
|
|
37
|
+
const datatype = datatypeId === void 0 ? void 0 : datatypes.get(datatypeId);
|
|
38
|
+
if (id === void 0 || datatype === void 0) return SKIP;
|
|
39
|
+
for (const repetition of field.children) for (const profile of datatype.componentsBySequence.values()) {
|
|
40
|
+
if (profile.optionality !== Optionality.Required) continue;
|
|
41
|
+
const componentId = `${id}.${profile.sequence}`;
|
|
42
|
+
const component = repetition.children[profile.sequence - 1];
|
|
43
|
+
if (component === void 0) file.message(messages.absentComponent(componentId, profile.name), {
|
|
44
|
+
ancestors: [
|
|
45
|
+
...ancestors,
|
|
46
|
+
field,
|
|
47
|
+
repetition
|
|
48
|
+
],
|
|
49
|
+
place: repetition.position
|
|
50
|
+
});
|
|
51
|
+
else if (isEmptyNode(component)) file.message(messages.emptyComponent(componentId, profile.name), {
|
|
46
52
|
ancestors: [
|
|
47
53
|
...ancestors,
|
|
48
|
-
|
|
54
|
+
field,
|
|
49
55
|
repetition,
|
|
50
|
-
|
|
56
|
+
component
|
|
51
57
|
],
|
|
52
|
-
place: component
|
|
58
|
+
place: component.position
|
|
53
59
|
});
|
|
54
60
|
}
|
|
55
|
-
|
|
56
|
-
}
|
|
61
|
+
return SKIP;
|
|
62
|
+
});
|
|
63
|
+
});
|
|
57
64
|
//#endregion
|
|
58
65
|
export { hl7v2LintRequiredComponents as default };
|
|
59
66
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["// oxlint-disable-next-line no-unused-vars -- triggers VFile DataMap augmentation\nimport type { ProfileContext } from \"@glion/annotate-profile-context\";\
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["// oxlint-disable-next-line no-unused-vars -- triggers VFile DataMap augmentation\nimport type { ProfileContext } from \"@glion/annotate-profile-context\";\n// oxlint-disable-next-line no-unused-vars -- triggers FieldData augmentation\nimport type { hl7v2AnnotateProfileFields } from \"@glion/annotate-profile-fields\";\nimport type { Root } from \"@glion/ast\";\nimport { SKIP, visit } from \"@glion/util-visit\";\nimport { isEmptyNode, Optionality } from \"@glion/utils\";\nimport { lintRule } from \"unified-lint-rule\";\n\nconst messages = {\n absentComponent: (component: string, name: string) =>\n `Component \\`${component}\\` (${name}) is not present; it is required.`,\n emptyComponent: (component: string, name: string) =>\n `Component \\`${component}\\` (${name}) is empty; it is required.`,\n} as const;\n\n/**\n * Lint rule that reports a required component that is absent or empty.\n *\n * For each valued field of a composite datatype, checks in every repetition\n * the components whose optionality is `R`. `RE`, `C`, `B`, and `W` are not\n * checked; before v2.5 the standard records no component optionality.\n *\n * Reads `id` and `datatype` from `field.data`, so\n * `@glion/annotate-profile-fields` MUST run before it.\n *\n * @example\n * ```typescript\n * unified()\n * .use(hl7v2AnnotateProfileContext)\n * .use(hl7v2AnnotateProfileFields)\n * .use(hl7v2LintRequiredComponents);\n * ```;\n */\nconst hl7v2LintRequiredComponents = lintRule<Root>(\n {\n origin: \"hl7v2-lint:required-components\",\n url: \"https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-required-components#readme\",\n },\n (tree, file) => {\n const datatypes = file.data.profile?.datatypes;\n if (datatypes === undefined) {\n return;\n }\n\n visit(tree, \"field\", (field, ancestors) => {\n // A component's R applies only when its field is present; an empty\n // field is left to `@glion/lint-profile-required-fields`.\n if (isEmptyNode(field)) {\n return SKIP;\n }\n\n const id = field.data?.id;\n const datatypeId = field.data?.datatype;\n const datatype =\n datatypeId === undefined ? undefined : datatypes.get(datatypeId);\n if (id === undefined || datatype === undefined) {\n return SKIP;\n }\n\n // Loop over the datatype's components, not the message's: a component\n // left out of the message has no node to visit. A primitive datatype\n // has no components.\n for (const repetition of field.children) {\n for (const profile of datatype.componentsBySequence.values()) {\n if (profile.optionality !== Optionality.Required) {\n continue;\n }\n\n const componentId = `${id}.${profile.sequence}`;\n const component = repetition.children[profile.sequence - 1];\n\n if (component === undefined) {\n // Reported on the repetition, the closest node the message has.\n file.message(messages.absentComponent(componentId, profile.name), {\n ancestors: [...ancestors, field, repetition],\n place: repetition.position,\n });\n } else if (isEmptyNode(component)) {\n file.message(messages.emptyComponent(componentId, profile.name), {\n ancestors: [...ancestors, field, repetition, component],\n place: component.position,\n });\n }\n }\n }\n return SKIP;\n });\n }\n);\n\nexport default hl7v2LintRequiredComponents;\n"],"mappings":";;;;AASA,MAAM,WAAW;CACf,kBAAkB,WAAmB,SACnC,eAAe,UAAU,MAAM,KAAK;CACtC,iBAAiB,WAAmB,SAClC,eAAe,UAAU,MAAM,KAAK;CACvC;;;;;;;;;;;;;;;;;;;AAoBD,MAAM,8BAA8B,SAClC;CACE,QAAQ;CACR,KAAK;CACN,GACA,MAAM,SAAS;CACd,MAAM,YAAY,KAAK,KAAK,SAAS;AACrC,KAAI,cAAc,KAAA,EAChB;AAGF,OAAM,MAAM,UAAU,OAAO,cAAc;AAGzC,MAAI,YAAY,MAAM,CACpB,QAAO;EAGT,MAAM,KAAK,MAAM,MAAM;EACvB,MAAM,aAAa,MAAM,MAAM;EAC/B,MAAM,WACJ,eAAe,KAAA,IAAY,KAAA,IAAY,UAAU,IAAI,WAAW;AAClE,MAAI,OAAO,KAAA,KAAa,aAAa,KAAA,EACnC,QAAO;AAMT,OAAK,MAAM,cAAc,MAAM,SAC7B,MAAK,MAAM,WAAW,SAAS,qBAAqB,QAAQ,EAAE;AAC5D,OAAI,QAAQ,gBAAgB,YAAY,SACtC;GAGF,MAAM,cAAc,GAAG,GAAG,GAAG,QAAQ;GACrC,MAAM,YAAY,WAAW,SAAS,QAAQ,WAAW;AAEzD,OAAI,cAAc,KAAA,EAEhB,MAAK,QAAQ,SAAS,gBAAgB,aAAa,QAAQ,KAAK,EAAE;IAChE,WAAW;KAAC,GAAG;KAAW;KAAO;KAAW;IAC5C,OAAO,WAAW;IACnB,CAAC;YACO,YAAY,UAAU,CAC/B,MAAK,QAAQ,SAAS,eAAe,aAAa,QAAQ,KAAK,EAAE;IAC/D,WAAW;KAAC,GAAG;KAAW;KAAO;KAAY;KAAU;IACvD,OAAO,UAAU;IAClB,CAAC;;AAIR,SAAO;GACP;EAEL"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glion/lint-profile-required-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Lint rule to validate required components in composite datatype fields",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"health",
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"unified-lint-rule": "3.0.1",
|
|
37
|
-
"@glion/
|
|
38
|
-
"@glion/
|
|
39
|
-
"@glion/
|
|
37
|
+
"@glion/annotate-profile-fields": "0.24.0",
|
|
38
|
+
"@glion/ast": "0.24.0",
|
|
39
|
+
"@glion/util-visit": "0.24.0",
|
|
40
|
+
"@glion/utils": "0.24.0"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/node": "25.6.0",
|
|
@@ -47,10 +48,11 @@
|
|
|
47
48
|
"unified": "^11.0.5",
|
|
48
49
|
"vfile": "^6.0.3",
|
|
49
50
|
"vitest": "4.1.11",
|
|
50
|
-
"@glion/annotate-profile-context": "0.
|
|
51
|
-
"@glion/builder": "0.
|
|
51
|
+
"@glion/annotate-profile-context": "0.24.0",
|
|
52
|
+
"@glion/builder": "0.24.0",
|
|
52
53
|
"@glion/check-readme": "0.18.0",
|
|
53
|
-
"@glion/
|
|
54
|
+
"@glion/parser": "0.24.0",
|
|
55
|
+
"@glion/profiles": "0.24.0",
|
|
54
56
|
"@glion/testing": "0.18.0",
|
|
55
57
|
"@glion/tsconfig": "0.18.0"
|
|
56
58
|
},
|