@glion/lint-profile-table-values 0.25.0 → 0.27.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/LICENSE +1 -1
- package/README.md +10 -10
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -38
- package/dist/index.js.map +1 -1
- package/package.json +11 -8
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Lint rule to validate coded field values against HL7v2 tables.
|
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
Flags coded field values that are not
|
|
7
|
+
Flags coded field values that are not codes of the HL7-defined table referenced by the field's profile. The rule reads the profile context attached by `@glion/annotate-profile-context`, looks up the field's table by its TBL# (such as `HL70003`), and checks the first subcomponent of each repetition against the table's codes. Only `hl7`-type tables are validated; user-defined tables, empty values, and Z-segments are skipped.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -23,7 +23,7 @@ import { reporter } from "vfile-reporter";
|
|
|
23
23
|
|
|
24
24
|
const message = [
|
|
25
25
|
"MSH|^~\\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^A01^ADT_A01|MSG00001|P|2.5",
|
|
26
|
-
"
|
|
26
|
+
"EVN|A01",
|
|
27
27
|
].join("\r");
|
|
28
28
|
|
|
29
29
|
const file = await unified()
|
|
@@ -41,7 +41,7 @@ console.error(reporter([file]));
|
|
|
41
41
|
|
|
42
42
|
A `unified` lint rule plugin. Takes no options.
|
|
43
43
|
|
|
44
|
-
Reads `file.data.profile`. For each
|
|
44
|
+
Reads `file.data.profile`. For each field whose profile declares a `table`, loads the table definition from `ctx.tables`. If the table is HL7-defined, it checks each repetition's first subcomponent value against the table's codes.
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
import type { Plugin } from "unified";
|
|
@@ -53,33 +53,33 @@ export default hl7v2LintTableValues;
|
|
|
53
53
|
|
|
54
54
|
## What it checks
|
|
55
55
|
|
|
56
|
-
This rule flags coded values that are not
|
|
56
|
+
This rule flags coded values that are not codes of the HL7 table referenced by the field's profile. For example, `EVN-1` (Event Type Code) references table `HL70003`, whose v2.5 codes include `A01`, `A02`, and `A03`.
|
|
57
57
|
|
|
58
58
|
### Valid
|
|
59
59
|
|
|
60
|
-
`
|
|
60
|
+
`EVN-1` is `A01`, a code of table `HL70003`:
|
|
61
61
|
|
|
62
62
|
```hl7
|
|
63
63
|
MSH|^~\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^A01^ADT_A01|MSG00001|P|2.5
|
|
64
|
-
|
|
64
|
+
EVN|A01
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
### Invalid
|
|
68
68
|
|
|
69
|
-
`
|
|
69
|
+
`EVN-1` is `ZZZ`, which is not a code of table `HL70003`:
|
|
70
70
|
|
|
71
71
|
```hl7
|
|
72
72
|
MSH|^~\&|SENDER|FAC|RECV|RFAC|20250601120000||ADT^A01^ADT_A01|MSG00001|P|2.5
|
|
73
|
-
|
|
73
|
+
EVN|ZZZ
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
Reported message:
|
|
77
77
|
|
|
78
78
|
```
|
|
79
|
-
|
|
79
|
+
The value is not in table `HL70003` (Event type); the field requires a code from it.
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
The message is placed on the repetition that holds the value. One message is reported per offending repetition, with `actual` set to the value and `expected` to the table's codes.
|
|
83
83
|
|
|
84
84
|
## Part of Glion
|
|
85
85
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import type { Root } from "@glion/ast";
|
|
2
|
+
/**
|
|
3
|
+
* Lint rule that reports a coded value that is not a code of the HL7-defined
|
|
4
|
+
* table its field references.
|
|
5
|
+
*
|
|
6
|
+
* Reads the field and table definitions from `file.data.profile`, so
|
|
7
|
+
* `@glion/annotate-profile-context` MUST run before it. Checks the first
|
|
8
|
+
* subcomponent of each repetition. Fields of `user` tables, empty values, and
|
|
9
|
+
* segments without a profile are not checked.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* unified()
|
|
14
|
+
* .use(hl7v2AnnotateProfileContext)
|
|
15
|
+
* .use(hl7v2LintTableValues);
|
|
16
|
+
* ```;
|
|
17
|
+
*/
|
|
2
18
|
declare const hl7v2LintTableValues: import("unified-lint-rule").Plugin<Root, unknown>;
|
|
3
19
|
export default hl7v2LintTableValues;
|
|
4
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AASvC;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,oBAAoB,mDA6CzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,58 +1,50 @@
|
|
|
1
1
|
import { SKIP, visit } from "@glion/util-visit";
|
|
2
|
-
import { isEmptyNode } from "@glion/utils";
|
|
3
2
|
import { lintRule } from "unified-lint-rule";
|
|
4
3
|
//#region src/index.ts
|
|
4
|
+
const messages = { notInTable: (table, description) => `The value is not in table \`${table}\` (${description}); the field requires a code from it.` };
|
|
5
5
|
/**
|
|
6
|
-
* Lint rule that
|
|
6
|
+
* Lint rule that reports a coded value that is not a code of the HL7-defined
|
|
7
|
+
* table its field references.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Only `hl7`-type tables are validated. `user`-type tables are skipped
|
|
13
|
-
* (they contain site-specific codes).
|
|
14
|
-
*
|
|
15
|
-
* Empty fields are skipped. Segments without a known profile are skipped.
|
|
9
|
+
* Reads the field and table definitions from `file.data.profile`, so
|
|
10
|
+
* `@glion/annotate-profile-context` MUST run before it. Checks the first
|
|
11
|
+
* subcomponent of each repetition. Fields of `user` tables, empty values, and
|
|
12
|
+
* segments without a profile are not checked.
|
|
16
13
|
*
|
|
17
14
|
* @example
|
|
18
15
|
* ```typescript
|
|
19
|
-
* unified()
|
|
16
|
+
* unified()
|
|
17
|
+
* .use(hl7v2AnnotateProfileContext)
|
|
18
|
+
* .use(hl7v2LintTableValues);
|
|
20
19
|
* ```;
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (tableDef?.type !== "hl7") return;
|
|
27
|
-
return {
|
|
28
|
-
fieldProfile,
|
|
29
|
-
tableDef
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
const hl7v2LintTableValues = lintRule({ origin: "hl7v2-lint:table-values" }, (tree, file) => {
|
|
21
|
+
const hl7v2LintTableValues = lintRule({
|
|
22
|
+
origin: "hl7v2-lint:table-values",
|
|
23
|
+
url: "https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-table-values#readme"
|
|
24
|
+
}, (tree, file) => {
|
|
33
25
|
const ctx = file.data.profile;
|
|
34
26
|
if (!ctx) return;
|
|
35
|
-
visit(tree, "
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!tableDef.codes.has(val)) {
|
|
47
|
-
const name = fieldProfile.name ? ` (${fieldProfile.name})` : "";
|
|
48
|
-
file.message(`Field ${segment.name}-${info.sequence}${name} value '${val}' is not in table ${tableDef.id} (${tableDef.description})`, {
|
|
27
|
+
visit(tree, "segment", (segment, ancestors) => {
|
|
28
|
+
const fields = ctx.fields.get(segment.name);
|
|
29
|
+
if (!fields) return SKIP;
|
|
30
|
+
for (const [index, field] of segment.children.entries()) {
|
|
31
|
+
const profile = fields.bySequence.get(index + 1);
|
|
32
|
+
const table = profile?.table && ctx.tables.get(profile.table);
|
|
33
|
+
if (!table || table.type !== "hl7") continue;
|
|
34
|
+
for (const repetition of field.children) {
|
|
35
|
+
const value = repetition.children[0]?.children[0]?.value;
|
|
36
|
+
if (!value || table.codes.has(value)) continue;
|
|
37
|
+
const message = file.message(messages.notInTable(profile.table, table.description), {
|
|
49
38
|
ancestors: [
|
|
50
39
|
...ancestors,
|
|
51
|
-
|
|
40
|
+
segment,
|
|
41
|
+
field,
|
|
52
42
|
repetition
|
|
53
43
|
],
|
|
54
|
-
place: repetition.position ??
|
|
44
|
+
place: repetition.position ?? field.position
|
|
55
45
|
});
|
|
46
|
+
message.actual = value;
|
|
47
|
+
message.expected = [...table.codes.keys()];
|
|
56
48
|
}
|
|
57
49
|
}
|
|
58
50
|
return SKIP;
|
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\";\nimport type { Root
|
|
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\";\nimport type { Root } from \"@glion/ast\";\nimport { SKIP, visit } from \"@glion/util-visit\";\nimport { lintRule } from \"unified-lint-rule\";\n\nconst messages = {\n notInTable: (table: string, description: string) =>\n `The value is not in table \\`${table}\\` (${description}); the field requires a code from it.`,\n} as const;\n\n/**\n * Lint rule that reports a coded value that is not a code of the HL7-defined\n * table its field references.\n *\n * Reads the field and table definitions from `file.data.profile`, so\n * `@glion/annotate-profile-context` MUST run before it. Checks the first\n * subcomponent of each repetition. Fields of `user` tables, empty values, and\n * segments without a profile are not checked.\n *\n * @example\n * ```typescript\n * unified()\n * .use(hl7v2AnnotateProfileContext)\n * .use(hl7v2LintTableValues);\n * ```;\n */\nconst hl7v2LintTableValues = lintRule<Root>(\n {\n origin: \"hl7v2-lint:table-values\",\n url: \"https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-table-values#readme\",\n },\n (tree, file) => {\n const ctx = file.data.profile;\n if (!ctx) {\n return;\n }\n\n visit(tree, \"segment\", (segment, ancestors) => {\n const fields = ctx.fields.get(segment.name);\n if (!fields) {\n return SKIP;\n }\n\n for (const [index, field] of segment.children.entries()) {\n const profile = fields.bySequence.get(index + 1);\n const table = profile?.table && ctx.tables.get(profile.table);\n // `user` tables hold site-specific codes.\n if (!table || table.type !== \"hl7\") {\n continue;\n }\n\n for (const repetition of field.children) {\n const value = repetition.children[0]?.children[0]?.value;\n if (!value || table.codes.has(value)) {\n continue;\n }\n\n const message = file.message(\n messages.notInTable(profile.table, table.description),\n {\n ancestors: [...ancestors, segment, field, repetition],\n place: repetition.position ?? field.position,\n }\n );\n message.actual = value;\n message.expected = [...table.codes.keys()];\n }\n }\n return SKIP;\n });\n }\n);\n\nexport default hl7v2LintTableValues;\n"],"mappings":";;;AAMA,MAAM,WAAW,EACf,aAAa,OAAe,gBAC1B,+BAA+B,MAAM,MAAM,YAAY,wCAC1D;;;;;;;;;;;;;;;;;AAkBD,MAAM,uBAAuB,SAC3B;CACE,QAAQ;CACR,KAAK;CACN,GACA,MAAM,SAAS;CACd,MAAM,MAAM,KAAK,KAAK;AACtB,KAAI,CAAC,IACH;AAGF,OAAM,MAAM,YAAY,SAAS,cAAc;EAC7C,MAAM,SAAS,IAAI,OAAO,IAAI,QAAQ,KAAK;AAC3C,MAAI,CAAC,OACH,QAAO;AAGT,OAAK,MAAM,CAAC,OAAO,UAAU,QAAQ,SAAS,SAAS,EAAE;GACvD,MAAM,UAAU,OAAO,WAAW,IAAI,QAAQ,EAAE;GAChD,MAAM,QAAQ,SAAS,SAAS,IAAI,OAAO,IAAI,QAAQ,MAAM;AAE7D,OAAI,CAAC,SAAS,MAAM,SAAS,MAC3B;AAGF,QAAK,MAAM,cAAc,MAAM,UAAU;IACvC,MAAM,QAAQ,WAAW,SAAS,IAAI,SAAS,IAAI;AACnD,QAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,CAClC;IAGF,MAAM,UAAU,KAAK,QACnB,SAAS,WAAW,QAAQ,OAAO,MAAM,YAAY,EACrD;KACE,WAAW;MAAC,GAAG;MAAW;MAAS;MAAO;MAAW;KACrD,OAAO,WAAW,YAAY,MAAM;KACrC,CACF;AACD,YAAQ,SAAS;AACjB,YAAQ,WAAW,CAAC,GAAG,MAAM,MAAM,MAAM,CAAC;;;AAG9C,SAAO;GACP;EAEL"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glion/lint-profile-table-values",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Lint rule to validate coded field values against HL7v2 tables",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"health",
|
|
@@ -34,11 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"unified-lint-rule": "3.0.1",
|
|
37
|
-
"@glion/ast": "0.
|
|
38
|
-
"@glion/util-visit": "0.
|
|
39
|
-
"@glion/utils": "0.
|
|
37
|
+
"@glion/ast": "0.27.0",
|
|
38
|
+
"@glion/util-visit": "0.27.0",
|
|
39
|
+
"@glion/utils": "0.27.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@stryker-mutator/core": "10.0.0",
|
|
43
|
+
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
42
44
|
"@types/node": "25.6.0",
|
|
43
45
|
"@vitest/coverage-v8": "4.1.11",
|
|
44
46
|
"publint": "0.3.18",
|
|
@@ -47,8 +49,8 @@
|
|
|
47
49
|
"unified": "^11.0.5",
|
|
48
50
|
"vfile": "^6.0.3",
|
|
49
51
|
"vitest": "4.1.11",
|
|
50
|
-
"@glion/annotate-profile-context": "0.
|
|
51
|
-
"@glion/builder": "0.
|
|
52
|
+
"@glion/annotate-profile-context": "0.27.0",
|
|
53
|
+
"@glion/builder": "0.27.0",
|
|
52
54
|
"@glion/check-readme": "0.18.0",
|
|
53
55
|
"@glion/testing": "0.18.0",
|
|
54
56
|
"@glion/tsconfig": "0.18.0"
|
|
@@ -60,9 +62,10 @@
|
|
|
60
62
|
"build": "tsdown && tsc --emitDeclarationOnly",
|
|
61
63
|
"check-types": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json",
|
|
62
64
|
"check:readme": "glion-check-readme",
|
|
65
|
+
"mutate": "stryker run",
|
|
66
|
+
"publint": "publint --strict",
|
|
63
67
|
"test": "vitest run",
|
|
64
68
|
"test:coverage": "vitest run --coverage",
|
|
65
|
-
"test:watch": "vitest"
|
|
66
|
-
"publint": "publint --strict"
|
|
69
|
+
"test:watch": "vitest"
|
|
67
70
|
}
|
|
68
71
|
}
|