@glion/lint-profile-segment-order 0.26.0 → 0.27.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/LICENSE +1 -1
- package/README.md +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -14
- package/dist/index.js.map +1 -1
- package/package.json +12 -9
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ import { unified } from "unified";
|
|
|
64
64
|
|
|
65
65
|
const processor = unified().use(hl7v2LintSegmentOrder, {
|
|
66
66
|
definition: ({ tree }) =>
|
|
67
|
-
value(tree, "MSH
|
|
67
|
+
value(tree, "MSH.4")?.value === "SITE_A" ? ADT_A01_SITE : undefined,
|
|
68
68
|
});
|
|
69
69
|
```
|
|
70
70
|
|
|
@@ -123,7 +123,7 @@ declare const hl7v2LintSegmentOrder: Plugin<[SegmentOrderOptions?], Root>;
|
|
|
123
123
|
export default hl7v2LintSegmentOrder;
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
All messages use `ruleId: "segment-order"` and `source: "hl7v2-lint"`. The rule reports each edit of the repair with the fewest edits, as `repair` in `@glion/profiles` finds it. A missing segment's message names the segment groups it belongs in, and has `place` a point, where the segment would be inserted, `ancestors` the nodes that hold that point, and `expected` the segment ID. A slot the schema fills with any segment (`Hxx`) or any Z-segment (`anyZSegment`) is described in words and has no `expected`. An unexpected segment's message
|
|
126
|
+
All messages use `ruleId: "segment-order"` and `source: "hl7v2-lint"`. The rule reports each edit of the repair with the fewest edits, as `repair` in `@glion/profiles` finds it. A missing segment's message names the segment groups it belongs in, and has `place` a point, where the segment would be inserted, `ancestors` the nodes that hold that point, and `expected` the segment ID. A slot the schema fills with any segment (`Hxx`) or any Z-segment (`anyZSegment`) is described in words and has no `expected`. An unexpected segment's message describes the segment without naming it, and has `place` the segment's position, `ancestors` the segment and its ancestors, and `actual` the segment ID.
|
|
127
127
|
|
|
128
128
|
The rule reports at most 20 edits for a message, or 21 when the 21st is the out-of-place segment standing where the 20th, a missing one, belongs, then one message with the count of the rest. A message of more than 1,000 segments is not repaired: the rule reports the first segment that does not fit, with `actual` its ID and `expected` the segment IDs valid there, or, when the message ends early, the end of the message with `expected` the segment IDs valid next. Its `note` says why only that one is reported.
|
|
129
129
|
|
|
@@ -205,7 +205,7 @@ PID|2||PATID5678^^^HOSP^MR||DOE^JOHN||19750101|M
|
|
|
205
205
|
Reported message:
|
|
206
206
|
|
|
207
207
|
```
|
|
208
|
-
|
|
208
|
+
The segment is out of place; the event schema does not allow it at this point.
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
An unexpected segment is reported on itself. A segment in place of a required one is reported as unexpected, and the required one as missing.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,IAAI,EAAW,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EACV,WAAW,EAIZ,MAAM,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,IAAI,EAAW,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EACV,WAAW,EAIZ,MAAM,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAsFnC,uEAAuE;AACvE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,KAAK,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;OAOG;IACH,UAAU,CAAC,EACP,WAAW,GACX,CAAC,CACC,OAAO,EAAE,mBAAmB,KACzB,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC;IACrE;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAqKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,QAAA,MAAM,qBAAqB,+DAoD1B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -42,10 +42,7 @@ const messages = {
|
|
|
42
42
|
missingSegment: (segmentId) => `Segment \`${segmentId}\` is missing; the event schema requires it at this point.`,
|
|
43
43
|
missingSegmentInGroup: (segmentId, groups) => `Segment \`${segmentId}\` of segment group \`${groups}\` is missing; the event schema requires it at this point.`,
|
|
44
44
|
moreEdits: (count, reported) => `The message has ${pluralize("more missing or out-of-place segment", count, true)}; the rule reports the first ${reported}.`,
|
|
45
|
-
|
|
46
|
-
unexpectedEmptySegmentIdInGroup: (groups) => `A segment with an empty Segment ID is out of place; the event schema does not allow it at this point in segment group \`${groups}\`.`,
|
|
47
|
-
unexpectedSegment: (segmentId) => `Segment \`${segmentId}\` is out of place; the event schema does not allow it at this point.`,
|
|
48
|
-
unexpectedSegmentInGroup: (segmentId, groups) => `Segment \`${segmentId}\` is out of place; the event schema does not allow it at this point in segment group \`${groups}\`.`
|
|
45
|
+
unexpectedSegment: "The segment is out of place; the event schema does not allow it at this point."
|
|
49
46
|
};
|
|
50
47
|
const notes = {
|
|
51
48
|
notRepairedEnd: (segmentCount) => `The message has ${counts.format(segmentCount)} segments; above ${counts.format(MAX_REPAIRED_SEGMENTS)}, the rule reports only where the message ends, not every missing or out-of-place segment.`,
|
|
@@ -58,9 +55,9 @@ const notes = {
|
|
|
58
55
|
* which the events store resolves through the version's event map.
|
|
59
56
|
*/
|
|
60
57
|
const schemaOf = async (tree) => {
|
|
61
|
-
const version = value(tree, "MSH
|
|
58
|
+
const version = value(tree, "MSH.12.1")?.value;
|
|
62
59
|
if (!version) return;
|
|
63
|
-
const id = value(tree, "MSH
|
|
60
|
+
const id = value(tree, "MSH.9.3")?.value || `${value(tree, "MSH.9.1")?.value ?? ""}_${value(tree, "MSH.9.2")?.value ?? ""}`;
|
|
64
61
|
return await profiles.events.load(version, id);
|
|
65
62
|
};
|
|
66
63
|
/** The reason for a missing segment, by the slot the schema names. */
|
|
@@ -72,12 +69,6 @@ const missingReason = (segment, path) => {
|
|
|
72
69
|
default: return path.length === 0 ? messages.missingSegment(segment) : messages.missingSegmentInGroup(segment, groups);
|
|
73
70
|
}
|
|
74
71
|
};
|
|
75
|
-
/** The reason for an out-of-place segment, by its ID and where it was read. */
|
|
76
|
-
const unexpectedReason = (segment, path) => {
|
|
77
|
-
const groups = path.join(" > ");
|
|
78
|
-
if (segment === "") return path.length === 0 ? messages.unexpectedEmptySegmentId : messages.unexpectedEmptySegmentIdInGroup(groups);
|
|
79
|
-
return path.length === 0 ? messages.unexpectedSegment(segment) : messages.unexpectedSegmentInGroup(segment, groups);
|
|
80
|
-
};
|
|
81
72
|
/**
|
|
82
73
|
* How many edits to report: `MAX_REPORTED_EDITS`, or one more when the last
|
|
83
74
|
* of those is a missing segment and the next is the out-of-place segment
|
|
@@ -112,7 +103,7 @@ const reportEdits = (file, tree, segments, edits) => {
|
|
|
112
103
|
case "unexpected": {
|
|
113
104
|
const at = segments[edit.index];
|
|
114
105
|
if (!at) throw new Error(`repair() reported an unexpected segment at index ${edit.index} of a ${segments.length}-segment message. This is a bug; please report it.`);
|
|
115
|
-
const message = file.message(
|
|
106
|
+
const message = file.message(messages.unexpectedSegment, {
|
|
116
107
|
ancestors: at.ancestors,
|
|
117
108
|
place: at.node.position
|
|
118
109
|
});
|
|
@@ -131,7 +122,7 @@ const reportFirstMisfit = (file, tree, segments, result, note) => {
|
|
|
131
122
|
case "mismatched": {
|
|
132
123
|
const at = segments[result.index];
|
|
133
124
|
if (!at) throw new Error(`runner() reported a mismatch at index ${result.index} of a ${segments.length}-segment message. This is a bug; please report it.`);
|
|
134
|
-
const message = file.message(
|
|
125
|
+
const message = file.message(messages.unexpectedSegment, {
|
|
135
126
|
ancestors: at.ancestors,
|
|
136
127
|
place: at.node.position
|
|
137
128
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Nodes, Root, Segment } from \"@glion/ast\";\nimport type {\n EventSchema,\n RepairEdit,\n RunnerIncomplete,\n RunnerMismatched,\n} from \"@glion/profiles\";\nimport { profiles, repair, runner } from \"@glion/profiles\";\nimport { value } from \"@glion/util-query\";\nimport { SKIP, visit } from \"@glion/util-visit\";\nimport pluralize from \"pluralize\";\nimport { lintRule } from \"unified-lint-rule\";\nimport type { VFile } from \"vfile\";\n\n/**\n * The most segments a message may have for the rule to report every missing\n * and out-of-place segment. A longer message gets the first segment that does\n * not fit. The repair's memory grows with segments × program size; at the\n * largest bundled program (454 instructions), 1,000 segments take about 4 MB.\n */\nconst MAX_REPAIRED_SEGMENTS = 1000;\n\n/**\n * The most edits reported for one message, before a count of the rest; one\n * more when the last is a missing segment and the next the out-of-place\n * segment standing where it belongs.\n */\nconst MAX_REPORTED_EDITS = 20;\n\n/** The name an event schema gives a slot that any segment fills. */\nconst ANY_SEGMENT = \"Hxx\";\n\n/** The name an event schema gives a slot that any Z-segment fills. */\nconst ANY_Z_SEGMENT = \"anyZSegment\";\n\nconst segmentIds = new Intl.ListFormat(\"en\", { type: \"disjunction\" });\n\nconst counts = new Intl.NumberFormat(\"en\");\n\n/** A segment ID the event schema names, as a message writes it. */\nconst written = (id: string): string => {\n switch (id) {\n case ANY_SEGMENT: {\n return \"any segment\";\n }\n case ANY_Z_SEGMENT: {\n return \"any Z-segment\";\n }\n default: {\n return `\\`${id}\\``;\n }\n }\n};\n\n/** The segment IDs a slot takes, without the any-segment slots. */\nconst segmentIdsOnly = (ids: readonly string[]): string[] =>\n ids.filter((id) => id !== ANY_SEGMENT && id !== ANY_Z_SEGMENT);\n\nconst messages = {\n endsBeforeComplete: (expected: readonly string[]) =>\n `The message ends before its event schema is complete; the event schema requires ${segmentIds.format(expected.map(written))} next.`,\n missingAnySegment:\n \"A segment is missing; the event schema requires a segment with any Segment ID at this point.\",\n missingAnySegmentInGroup: (groups: string) =>\n `A segment of segment group \\`${groups}\\` is missing; the event schema requires a segment with any Segment ID at this point.`,\n missingAnyZSegment:\n \"A Z-segment is missing; the event schema requires a Z-segment at this point.\",\n missingAnyZSegmentInGroup: (groups: string) =>\n `A Z-segment of segment group \\`${groups}\\` is missing; the event schema requires a Z-segment at this point.`,\n missingSegment: (segmentId: string) =>\n `Segment \\`${segmentId}\\` is missing; the event schema requires it at this point.`,\n missingSegmentInGroup: (segmentId: string, groups: string) =>\n `Segment \\`${segmentId}\\` of segment group \\`${groups}\\` is missing; the event schema requires it at this point.`,\n moreEdits: (count: number, reported: number) =>\n `The message has ${pluralize(\"more missing or out-of-place segment\", count, true)}; the rule reports the first ${reported}.`,\n unexpectedEmptySegmentId:\n \"A segment with an empty Segment ID is out of place; the event schema does not allow it at this point.\",\n unexpectedEmptySegmentIdInGroup: (groups: string) =>\n `A segment with an empty Segment ID is out of place; the event schema does not allow it at this point in segment group \\`${groups}\\`.`,\n unexpectedSegment: (segmentId: string) =>\n `Segment \\`${segmentId}\\` is out of place; the event schema does not allow it at this point.`,\n unexpectedSegmentInGroup: (segmentId: string, groups: string) =>\n `Segment \\`${segmentId}\\` is out of place; the event schema does not allow it at this point in segment group \\`${groups}\\`.`,\n} as const;\n\nconst notes = {\n notRepairedEnd: (segmentCount: number) =>\n `The message has ${counts.format(segmentCount)} segments; above ${counts.format(MAX_REPAIRED_SEGMENTS)}, the rule reports only where the message ends, not every missing or out-of-place segment.`,\n notRepairedMisfit: (segmentCount: number) =>\n `The message has ${counts.format(segmentCount)} segments; above ${counts.format(MAX_REPAIRED_SEGMENTS)}, the rule reports only the first segment that does not fit, not every missing or out-of-place segment.`,\n unrepairedEnd:\n \"The rule could not list every missing or out-of-place segment in this message, so it reports only where the message ends. This is a bug; please report it.\",\n unrepairedMisfit:\n \"The rule could not list every missing or out-of-place segment in this message, so it reports only the first segment that does not fit. This is a bug; please report it.\",\n} as const;\n\n/** The notes a report of the first segment that does not fit carries. */\ninterface MisfitNotes {\n /** When a segment does not fit. */\n misfit: string;\n /** When the message ends before its event schema is complete. */\n end: string;\n}\n\n/** The message a `definition` function chooses an event schema for. */\nexport interface SegmentOrderContext {\n tree: Root;\n file: VFile;\n}\n\n/**\n * Options for the segment order lint rule.\n */\nexport interface SegmentOrderOptions {\n /**\n * The event schema to validate against, or a function that returns the\n * one to use for a message. Default: the schema MSH-9 names.\n *\n * When the function returns `undefined`, the rule uses the schema MSH-9\n * names. Return the same object for every message that uses a schema: a\n * new object is compiled on its first run.\n */\n definition?:\n | EventSchema\n | ((\n context: SegmentOrderContext\n ) => EventSchema | undefined | Promise<EventSchema | undefined>);\n /**\n * Whether a Z-segment (a segment ID that starts with `Z`) that the event\n * schema does not name fits at any position. HL7v2 allows local Z-segments\n * in any message and segment group (v2.5.1 §2.11). When `false`, the rule\n * reports such a segment as unexpected. Default: `true`.\n */\n allowZSegments?: boolean;\n}\n\n/**\n * The event schema MSH-12 and MSH-9 name: MSH-9.3, or MSH-9.1 and MSH-9.2,\n * which the events store resolves through the version's event map.\n */\nconst schemaOf = async (tree: Root): Promise<EventSchema | undefined> => {\n const version = value(tree, \"MSH-12.1\")?.value;\n if (!version) {\n return;\n }\n const id =\n value(tree, \"MSH-9.3\")?.value ||\n `${value(tree, \"MSH-9.1\")?.value ?? \"\"}_${value(tree, \"MSH-9.2\")?.value ?? \"\"}`;\n return await profiles.events.load(version, id);\n};\n\n/** A segment of the message, and its ancestors, inclusive. */\ninterface Located {\n node: Segment;\n ancestors: Nodes[];\n}\n\n/** The reason for a missing segment, by the slot the schema names. */\nconst missingReason = (segment: string, path: readonly string[]): string => {\n const groups = path.join(\" > \");\n switch (segment) {\n case ANY_SEGMENT: {\n return path.length === 0\n ? messages.missingAnySegment\n : messages.missingAnySegmentInGroup(groups);\n }\n case ANY_Z_SEGMENT: {\n return path.length === 0\n ? messages.missingAnyZSegment\n : messages.missingAnyZSegmentInGroup(groups);\n }\n default: {\n return path.length === 0\n ? messages.missingSegment(segment)\n : messages.missingSegmentInGroup(segment, groups);\n }\n }\n};\n\n/** The reason for an out-of-place segment, by its ID and where it was read. */\nconst unexpectedReason = (segment: string, path: readonly string[]): string => {\n const groups = path.join(\" > \");\n if (segment === \"\") {\n return path.length === 0\n ? messages.unexpectedEmptySegmentId\n : messages.unexpectedEmptySegmentIdInGroup(groups);\n }\n return path.length === 0\n ? messages.unexpectedSegment(segment)\n : messages.unexpectedSegmentInGroup(segment, groups);\n};\n\n/**\n * How many edits to report: `MAX_REPORTED_EDITS`, or one more when the last\n * of those is a missing segment and the next is the out-of-place segment\n * standing where it belongs.\n */\nconst reportedCount = (edits: readonly RepairEdit[]): number => {\n const last = edits[MAX_REPORTED_EDITS - 1];\n const next = edits[MAX_REPORTED_EDITS];\n const splitsPair =\n last?.type === \"missing\" &&\n next?.type === \"unexpected\" &&\n next.index === last.index;\n return splitsPair ? MAX_REPORTED_EDITS + 1 : MAX_REPORTED_EDITS;\n};\n\n/**\n * Reports each edit of the repair, up to `reportedCount()`, then a count of\n * the rest.\n */\nconst reportEdits = (\n file: VFile,\n tree: Root,\n segments: readonly Located[],\n edits: readonly RepairEdit[]\n): void => {\n const reported = reportedCount(edits);\n for (const edit of edits.slice(0, reported)) {\n switch (edit.type) {\n case \"missing\": {\n const reason = missingReason(edit.segment, edit.path);\n const next = segments[edit.index];\n const message = next\n ? file.message(reason, {\n ancestors: next.ancestors.slice(0, -1),\n place: next.node.position?.start,\n })\n : file.message(reason, {\n ancestors: [tree],\n place: tree.position?.end,\n });\n const expected = segmentIdsOnly([edit.segment]);\n if (expected.length > 0) {\n message.expected = expected;\n }\n break;\n }\n case \"unexpected\": {\n const at = segments[edit.index];\n if (!at) {\n throw new Error(\n `repair() reported an unexpected segment at index ${edit.index} of a ${segments.length}-segment message. This is a bug; please report it.`\n );\n }\n const message = file.message(\n unexpectedReason(edit.segment, edit.path),\n { ancestors: at.ancestors, place: at.node.position }\n );\n message.actual = edit.segment;\n break;\n }\n }\n }\n if (edits.length > reported) {\n file.message(messages.moreEdits(edits.length - reported, reported), {\n ancestors: [tree],\n place: tree.position,\n });\n }\n};\n\n/** Reports the first segment that does not fit, as the runner found it. */\nconst reportFirstMisfit = (\n file: VFile,\n tree: Root,\n segments: readonly Located[],\n result: RunnerMismatched | RunnerIncomplete,\n note: MisfitNotes\n): void => {\n switch (result.type) {\n case \"mismatched\": {\n const at = segments[result.index];\n if (!at) {\n throw new Error(\n `runner() reported a mismatch at index ${result.index} of a ${segments.length}-segment message. This is a bug; please report it.`\n );\n }\n const message = file.message(\n at.node.name === \"\"\n ? messages.unexpectedEmptySegmentId\n : messages.unexpectedSegment(at.node.name),\n { ancestors: at.ancestors, place: at.node.position }\n );\n message.actual = at.node.name;\n const expected = segmentIdsOnly(result.expected);\n if (expected.length > 0) {\n message.expected = expected;\n }\n message.note = note.misfit;\n break;\n }\n case \"incomplete\": {\n const message = file.message(\n messages.endsBeforeComplete(result.expected),\n { ancestors: [tree], place: tree.position?.end }\n );\n const expected = segmentIdsOnly(result.expected);\n if (expected.length > 0) {\n message.expected = expected;\n }\n message.note = note.end;\n break;\n }\n }\n};\n\n/**\n * Lint rule that validates HL7v2 segment order against event schema\n * profiles.\n *\n * Verifies each segment appears in the order the event schema defines.\n *\n * **Resolution**: If no `definition` is provided, the rule resolves the\n * schema from MSH-12 (version) and MSH-9.3 (event schema), or MSH-9.1\n * and MSH-9.2 when MSH-9.3 is empty. If the schema is unavailable, the rule\n * reports nothing.\n *\n * **Behavior**: When the segments do not fit the schema, reports each edit of\n * the repair with the fewest: each segment the schema requires and the message\n * does not have, at the point it would be inserted, with `expected` its ID; and\n * each segment the message has and the schema does not allow there, on that\n * segment, with `actual` its ID. Reports at most 20 edits, or 21 when the 21st\n * is the out-of-place segment standing where the 20th, a missing one, belongs,\n * then one message with the count of the rest. A message of more than 1,000\n * segments gets one report: the first segment that does not fit, with\n * `expected` the segment IDs valid there, or the end of the message when it\n * ends early. A Z-segment the schema does not name is allowed anywhere unless\n * `allowZSegments` is `false`.\n *\n * @example\n * ```typescript\n * // With the schema MSH-9 names:\n * unified().use(hl7v2LintSegmentOrder);\n *\n * // With a schema of your own:\n * unified().use(hl7v2LintSegmentOrder, {\n * definition: {\n * elements: [\n * { name: \"MSH\", optional: false, repeating: false, type: \"segment\" },\n * { name: \"PID\", optional: false, repeating: false, type: \"segment\" },\n * ],\n * id: \"ADT_SITE\",\n * },\n * });\n *\n * // With a schema chosen per message, and the one MSH-9 names otherwise:\n * unified().use(hl7v2LintSegmentOrder, {\n * definition: ({ tree }) =>\n * isSiteMessage(tree) ? SITE_STRUCTURE : undefined,\n * });\n * ```;\n */\nconst hl7v2LintSegmentOrder = lintRule<Root, SegmentOrderOptions>(\n {\n origin: \"hl7v2-lint:segment-order\",\n url: \"https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-segment-order#readme\",\n },\n async (tree, file, options) => {\n const definition = options?.definition;\n const chosen =\n typeof definition === \"function\"\n ? await definition({ file, tree })\n : definition;\n const schema = chosen ?? (await schemaOf(tree));\n\n if (!schema) {\n return;\n }\n\n const segments: Located[] = [];\n visit(tree, \"segment\", (node, parents) => {\n segments.push({ ancestors: [...parents, node], node });\n return SKIP;\n });\n\n const input = segments.map(({ node }) => node.name);\n const runOptions = { allowZSegments: options?.allowZSegments };\n const result = runner(schema, input, runOptions);\n switch (result.type) {\n case \"matched\": {\n return;\n }\n case \"mismatched\":\n case \"incomplete\": {\n if (segments.length > MAX_REPAIRED_SEGMENTS) {\n reportFirstMisfit(file, tree, segments, result, {\n end: notes.notRepairedEnd(segments.length),\n misfit: notes.notRepairedMisfit(segments.length),\n });\n return;\n }\n const edits = repair(schema, input, runOptions);\n if (edits.length === 0) {\n reportFirstMisfit(file, tree, segments, result, {\n end: notes.unrepairedEnd,\n misfit: notes.unrepairedMisfit,\n });\n return;\n }\n reportEdits(file, tree, segments, edits);\n }\n }\n }\n);\n\nexport default hl7v2LintSegmentOrder;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Nodes, Root, Segment } from \"@glion/ast\";\nimport type {\n EventSchema,\n RepairEdit,\n RunnerIncomplete,\n RunnerMismatched,\n} from \"@glion/profiles\";\nimport { profiles, repair, runner } from \"@glion/profiles\";\nimport { value } from \"@glion/util-query\";\nimport { SKIP, visit } from \"@glion/util-visit\";\nimport pluralize from \"pluralize\";\nimport { lintRule } from \"unified-lint-rule\";\nimport type { VFile } from \"vfile\";\n\n/**\n * The most segments a message may have for the rule to report every missing\n * and out-of-place segment. A longer message gets the first segment that does\n * not fit. The repair's memory grows with segments × program size; at the\n * largest bundled program (454 instructions), 1,000 segments take about 4 MB.\n */\nconst MAX_REPAIRED_SEGMENTS = 1000;\n\n/**\n * The most edits reported for one message, before a count of the rest; one\n * more when the last is a missing segment and the next the out-of-place\n * segment standing where it belongs.\n */\nconst MAX_REPORTED_EDITS = 20;\n\n/** The name an event schema gives a slot that any segment fills. */\nconst ANY_SEGMENT = \"Hxx\";\n\n/** The name an event schema gives a slot that any Z-segment fills. */\nconst ANY_Z_SEGMENT = \"anyZSegment\";\n\nconst segmentIds = new Intl.ListFormat(\"en\", { type: \"disjunction\" });\n\nconst counts = new Intl.NumberFormat(\"en\");\n\n/** A segment ID the event schema names, as a message writes it. */\nconst written = (id: string): string => {\n switch (id) {\n case ANY_SEGMENT: {\n return \"any segment\";\n }\n case ANY_Z_SEGMENT: {\n return \"any Z-segment\";\n }\n default: {\n return `\\`${id}\\``;\n }\n }\n};\n\n/** The segment IDs a slot takes, without the any-segment slots. */\nconst segmentIdsOnly = (ids: readonly string[]): string[] =>\n ids.filter((id) => id !== ANY_SEGMENT && id !== ANY_Z_SEGMENT);\n\nconst messages = {\n endsBeforeComplete: (expected: readonly string[]) =>\n `The message ends before its event schema is complete; the event schema requires ${segmentIds.format(expected.map(written))} next.`,\n missingAnySegment:\n \"A segment is missing; the event schema requires a segment with any Segment ID at this point.\",\n missingAnySegmentInGroup: (groups: string) =>\n `A segment of segment group \\`${groups}\\` is missing; the event schema requires a segment with any Segment ID at this point.`,\n missingAnyZSegment:\n \"A Z-segment is missing; the event schema requires a Z-segment at this point.\",\n missingAnyZSegmentInGroup: (groups: string) =>\n `A Z-segment of segment group \\`${groups}\\` is missing; the event schema requires a Z-segment at this point.`,\n missingSegment: (segmentId: string) =>\n `Segment \\`${segmentId}\\` is missing; the event schema requires it at this point.`,\n missingSegmentInGroup: (segmentId: string, groups: string) =>\n `Segment \\`${segmentId}\\` of segment group \\`${groups}\\` is missing; the event schema requires it at this point.`,\n moreEdits: (count: number, reported: number) =>\n `The message has ${pluralize(\"more missing or out-of-place segment\", count, true)}; the rule reports the first ${reported}.`,\n unexpectedSegment:\n \"The segment is out of place; the event schema does not allow it at this point.\",\n} as const;\n\nconst notes = {\n notRepairedEnd: (segmentCount: number) =>\n `The message has ${counts.format(segmentCount)} segments; above ${counts.format(MAX_REPAIRED_SEGMENTS)}, the rule reports only where the message ends, not every missing or out-of-place segment.`,\n notRepairedMisfit: (segmentCount: number) =>\n `The message has ${counts.format(segmentCount)} segments; above ${counts.format(MAX_REPAIRED_SEGMENTS)}, the rule reports only the first segment that does not fit, not every missing or out-of-place segment.`,\n unrepairedEnd:\n \"The rule could not list every missing or out-of-place segment in this message, so it reports only where the message ends. This is a bug; please report it.\",\n unrepairedMisfit:\n \"The rule could not list every missing or out-of-place segment in this message, so it reports only the first segment that does not fit. This is a bug; please report it.\",\n} as const;\n\n/** The notes a report of the first segment that does not fit carries. */\ninterface MisfitNotes {\n /** When a segment does not fit. */\n misfit: string;\n /** When the message ends before its event schema is complete. */\n end: string;\n}\n\n/** The message a `definition` function chooses an event schema for. */\nexport interface SegmentOrderContext {\n tree: Root;\n file: VFile;\n}\n\n/**\n * Options for the segment order lint rule.\n */\nexport interface SegmentOrderOptions {\n /**\n * The event schema to validate against, or a function that returns the\n * one to use for a message. Default: the schema MSH-9 names.\n *\n * When the function returns `undefined`, the rule uses the schema MSH-9\n * names. Return the same object for every message that uses a schema: a\n * new object is compiled on its first run.\n */\n definition?:\n | EventSchema\n | ((\n context: SegmentOrderContext\n ) => EventSchema | undefined | Promise<EventSchema | undefined>);\n /**\n * Whether a Z-segment (a segment ID that starts with `Z`) that the event\n * schema does not name fits at any position. HL7v2 allows local Z-segments\n * in any message and segment group (v2.5.1 §2.11). When `false`, the rule\n * reports such a segment as unexpected. Default: `true`.\n */\n allowZSegments?: boolean;\n}\n\n/**\n * The event schema MSH-12 and MSH-9 name: MSH-9.3, or MSH-9.1 and MSH-9.2,\n * which the events store resolves through the version's event map.\n */\nconst schemaOf = async (tree: Root): Promise<EventSchema | undefined> => {\n const version = value(tree, \"MSH.12.1\")?.value;\n // Stryker disable next-line ConditionalExpression,BlockStatement: the events store loads no schema for an empty or absent version either\n if (!version) {\n return;\n }\n const id =\n value(tree, \"MSH.9.3\")?.value ||\n // Stryker disable next-line StringLiteral: with MSH-9.1 or MSH-9.2 absent, no event schema or event map entry matches the ID either way\n `${value(tree, \"MSH.9.1\")?.value ?? \"\"}_${value(tree, \"MSH.9.2\")?.value ?? \"\"}`;\n return await profiles.events.load(version, id);\n};\n\n/** A segment of the message, and its ancestors, inclusive. */\ninterface Located {\n node: Segment;\n ancestors: Nodes[];\n}\n\n/** The reason for a missing segment, by the slot the schema names. */\nconst missingReason = (segment: string, path: readonly string[]): string => {\n const groups = path.join(\" > \");\n switch (segment) {\n case ANY_SEGMENT: {\n return path.length === 0\n ? messages.missingAnySegment\n : messages.missingAnySegmentInGroup(groups);\n }\n case ANY_Z_SEGMENT: {\n return path.length === 0\n ? messages.missingAnyZSegment\n : messages.missingAnyZSegmentInGroup(groups);\n }\n default: {\n return path.length === 0\n ? messages.missingSegment(segment)\n : messages.missingSegmentInGroup(segment, groups);\n }\n }\n};\n\n/**\n * How many edits to report: `MAX_REPORTED_EDITS`, or one more when the last\n * of those is a missing segment and the next is the out-of-place segment\n * standing where it belongs.\n */\nconst reportedCount = (edits: readonly RepairEdit[]): number => {\n const last = edits[MAX_REPORTED_EDITS - 1];\n const next = edits[MAX_REPORTED_EDITS];\n const splitsPair =\n // Stryker disable next-line ConditionalExpression: an unexpected edit consumes its segment, so the edit after it never shares its index\n last?.type === \"missing\" &&\n next?.type === \"unexpected\" &&\n next.index === last.index;\n return splitsPair ? MAX_REPORTED_EDITS + 1 : MAX_REPORTED_EDITS;\n};\n\n/**\n * Reports each edit of the repair, up to `reportedCount()`, then a count of\n * the rest.\n */\nconst reportEdits = (\n file: VFile,\n tree: Root,\n segments: readonly Located[],\n edits: readonly RepairEdit[]\n): void => {\n const reported = reportedCount(edits);\n for (const edit of edits.slice(0, reported)) {\n switch (edit.type) {\n case \"missing\": {\n const reason = missingReason(edit.segment, edit.path);\n const next = segments[edit.index];\n const message = next\n ? file.message(reason, {\n ancestors: next.ancestors.slice(0, -1),\n place: next.node.position?.start,\n })\n : file.message(reason, {\n ancestors: [tree],\n place: tree.position?.end,\n });\n const expected = segmentIdsOnly([edit.segment]);\n if (expected.length > 0) {\n message.expected = expected;\n }\n break;\n }\n case \"unexpected\": {\n const at = segments[edit.index];\n // Stryker disable all: repair() reports unexpected segments at indexes inside the message, so this guard never fires\n if (!at) {\n throw new Error(\n `repair() reported an unexpected segment at index ${edit.index} of a ${segments.length}-segment message. This is a bug; please report it.`\n );\n }\n // Stryker restore all\n const message = file.message(messages.unexpectedSegment, {\n ancestors: at.ancestors,\n place: at.node.position,\n });\n message.actual = edit.segment;\n break;\n }\n }\n }\n if (edits.length > reported) {\n file.message(messages.moreEdits(edits.length - reported, reported), {\n ancestors: [tree],\n place: tree.position,\n });\n }\n};\n\n/** Reports the first segment that does not fit, as the runner found it. */\nconst reportFirstMisfit = (\n file: VFile,\n tree: Root,\n segments: readonly Located[],\n result: RunnerMismatched | RunnerIncomplete,\n note: MisfitNotes\n): void => {\n switch (result.type) {\n case \"mismatched\": {\n const at = segments[result.index];\n // Stryker disable all: runner() reports a mismatch at an index inside the message, so this guard never fires\n if (!at) {\n throw new Error(\n `runner() reported a mismatch at index ${result.index} of a ${segments.length}-segment message. This is a bug; please report it.`\n );\n }\n // Stryker restore all\n const message = file.message(messages.unexpectedSegment, {\n ancestors: at.ancestors,\n place: at.node.position,\n });\n message.actual = at.node.name;\n const expected = segmentIdsOnly(result.expected);\n if (expected.length > 0) {\n message.expected = expected;\n }\n message.note = note.misfit;\n break;\n }\n case \"incomplete\": {\n const message = file.message(\n messages.endsBeforeComplete(result.expected),\n { ancestors: [tree], place: tree.position?.end }\n );\n const expected = segmentIdsOnly(result.expected);\n if (expected.length > 0) {\n message.expected = expected;\n }\n message.note = note.end;\n break;\n }\n }\n};\n\n/**\n * Lint rule that validates HL7v2 segment order against event schema\n * profiles.\n *\n * Verifies each segment appears in the order the event schema defines.\n *\n * **Resolution**: If no `definition` is provided, the rule resolves the\n * schema from MSH-12 (version) and MSH-9.3 (event schema), or MSH-9.1\n * and MSH-9.2 when MSH-9.3 is empty. If the schema is unavailable, the rule\n * reports nothing.\n *\n * **Behavior**: When the segments do not fit the schema, reports each edit of\n * the repair with the fewest: each segment the schema requires and the message\n * does not have, at the point it would be inserted, with `expected` its ID; and\n * each segment the message has and the schema does not allow there, on that\n * segment, with `actual` its ID. Reports at most 20 edits, or 21 when the 21st\n * is the out-of-place segment standing where the 20th, a missing one, belongs,\n * then one message with the count of the rest. A message of more than 1,000\n * segments gets one report: the first segment that does not fit, with\n * `expected` the segment IDs valid there, or the end of the message when it\n * ends early. A Z-segment the schema does not name is allowed anywhere unless\n * `allowZSegments` is `false`.\n *\n * @example\n * ```typescript\n * // With the schema MSH-9 names:\n * unified().use(hl7v2LintSegmentOrder);\n *\n * // With a schema of your own:\n * unified().use(hl7v2LintSegmentOrder, {\n * definition: {\n * elements: [\n * { name: \"MSH\", optional: false, repeating: false, type: \"segment\" },\n * { name: \"PID\", optional: false, repeating: false, type: \"segment\" },\n * ],\n * id: \"ADT_SITE\",\n * },\n * });\n *\n * // With a schema chosen per message, and the one MSH-9 names otherwise:\n * unified().use(hl7v2LintSegmentOrder, {\n * definition: ({ tree }) =>\n * isSiteMessage(tree) ? SITE_STRUCTURE : undefined,\n * });\n * ```;\n */\nconst hl7v2LintSegmentOrder = lintRule<Root, SegmentOrderOptions>(\n {\n origin: \"hl7v2-lint:segment-order\",\n url: \"https://github.com/rethinkhealth/glion/tree/main/packages/lint-profile-segment-order#readme\",\n },\n async (tree, file, options) => {\n const definition = options?.definition;\n const chosen =\n typeof definition === \"function\"\n ? await definition({ file, tree })\n : definition;\n const schema = chosen ?? (await schemaOf(tree));\n\n if (!schema) {\n return;\n }\n\n const segments: Located[] = [];\n visit(tree, \"segment\", (node, parents) => {\n segments.push({ ancestors: [...parents, node], node });\n return SKIP;\n });\n\n const input = segments.map(({ node }) => node.name);\n const runOptions = { allowZSegments: options?.allowZSegments };\n const result = runner(schema, input, runOptions);\n switch (result.type) {\n // Stryker disable next-line ConditionalExpression,BlockStatement,StringLiteral: a matched message reaches no report either way: repair() finds no edits for it and reportFirstMisfit has no arm for it\n case \"matched\": {\n return;\n }\n case \"mismatched\":\n case \"incomplete\": {\n if (segments.length > MAX_REPAIRED_SEGMENTS) {\n reportFirstMisfit(file, tree, segments, result, {\n end: notes.notRepairedEnd(segments.length),\n misfit: notes.notRepairedMisfit(segments.length),\n });\n return;\n }\n const edits = repair(schema, input, runOptions);\n if (edits.length === 0) {\n reportFirstMisfit(file, tree, segments, result, {\n end: notes.unrepairedEnd,\n misfit: notes.unrepairedMisfit,\n });\n return;\n }\n reportEdits(file, tree, segments, edits);\n }\n }\n }\n);\n\nexport default hl7v2LintSegmentOrder;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glion/lint-profile-segment-order",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"description": "Lints the segment order of an HL7v2 message against its message structure",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"health",
|
|
@@ -36,12 +36,14 @@
|
|
|
36
36
|
"pluralize": "8.0.0",
|
|
37
37
|
"unified-lint-rule": "3.0.1",
|
|
38
38
|
"vfile": "6.0.3",
|
|
39
|
-
"@glion/ast": "0.
|
|
40
|
-
"@glion/profiles": "0.
|
|
41
|
-
"@glion/util-query": "0.
|
|
42
|
-
"@glion/util-visit": "0.
|
|
39
|
+
"@glion/ast": "0.27.1",
|
|
40
|
+
"@glion/profiles": "0.27.1",
|
|
41
|
+
"@glion/util-query": "0.27.1",
|
|
42
|
+
"@glion/util-visit": "0.27.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@stryker-mutator/core": "10.0.0",
|
|
46
|
+
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
45
47
|
"@types/node": "25.6.0",
|
|
46
48
|
"@types/pluralize": "^0.0.33",
|
|
47
49
|
"@vitest/coverage-v8": "4.1.11",
|
|
@@ -50,9 +52,9 @@
|
|
|
50
52
|
"typescript": "6.0.3",
|
|
51
53
|
"unified": "^11.0.5",
|
|
52
54
|
"vitest": "4.1.11",
|
|
53
|
-
"@glion/builder": "0.
|
|
55
|
+
"@glion/builder": "0.27.1",
|
|
54
56
|
"@glion/check-readme": "0.18.0",
|
|
55
|
-
"@glion/parser": "0.
|
|
57
|
+
"@glion/parser": "0.27.1",
|
|
56
58
|
"@glion/testing": "0.18.0",
|
|
57
59
|
"@glion/tsconfig": "0.18.0"
|
|
58
60
|
},
|
|
@@ -63,9 +65,10 @@
|
|
|
63
65
|
"build": "tsdown && tsc --emitDeclarationOnly",
|
|
64
66
|
"check-types": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json",
|
|
65
67
|
"check:readme": "glion-check-readme",
|
|
68
|
+
"mutate": "stryker run",
|
|
69
|
+
"publint": "publint --strict",
|
|
66
70
|
"test": "vitest run",
|
|
67
71
|
"test:coverage": "vitest run --coverage",
|
|
68
|
-
"test:watch": "vitest"
|
|
69
|
-
"publint": "publint --strict"
|
|
72
|
+
"test:watch": "vitest"
|
|
70
73
|
}
|
|
71
74
|
}
|