@glion/lint-profile-required-components 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Rethink Health
3
+ Copyright (c) 2023 Rethink Health, SUARL
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -77,7 +77,7 @@ PID|1||PATID1234^^^HOSP^MR||DOE^JANE||19800101|F
77
77
  Reported messages:
78
78
 
79
79
  ```
80
- Component `MSH-9.2` (Trigger Event) is empty; it is required.
80
+ The component is empty; it is required.
81
81
  Component `MSH-9.3` (Message Structure) is not present; it is required.
82
82
  ```
83
83
 
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAWvC;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,2BAA2B,mDAwDhC,CAAC;AAEF,eAAe,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { lintRule } from "unified-lint-rule";
4
4
  //#region src/index.ts
5
5
  const messages = {
6
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.`
7
+ emptyComponent: "The component is empty; it is required."
8
8
  };
9
9
  /**
10
10
  * Lint rule that reports a required component that is absent or empty.
@@ -32,13 +32,13 @@ const hl7v2LintRequiredComponents = lintRule({
32
32
  if (datatypes === void 0) return;
33
33
  visit(tree, "field", (field, ancestors) => {
34
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;
35
+ const { data } = field;
36
+ if (data?.id === void 0) return SKIP;
37
+ const datatype = data.datatype && datatypes.get(data.datatype);
38
+ if (!datatype) return SKIP;
39
39
  for (const repetition of field.children) for (const profile of datatype.componentsBySequence.values()) {
40
40
  if (profile.optionality !== Optionality.Required) continue;
41
- const componentId = `${id}.${profile.sequence}`;
41
+ const componentId = `${data.id}.${profile.sequence}`;
42
42
  const component = repetition.children[profile.sequence - 1];
43
43
  if (component === void 0) file.message(messages.absentComponent(componentId, profile.name), {
44
44
  ancestors: [
@@ -48,7 +48,7 @@ const hl7v2LintRequiredComponents = lintRule({
48
48
  ],
49
49
  place: repetition.position
50
50
  });
51
- else if (isEmptyNode(component)) file.message(messages.emptyComponent(componentId, profile.name), {
51
+ else if (isEmptyNode(component)) file.message(messages.emptyComponent, {
52
52
  ancestors: [
53
53
  ...ancestors,
54
54
  field,
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\";\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"}
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: \"The component 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 { data } = field;\n if (data?.id === undefined) {\n return SKIP;\n }\n const datatype = data.datatype && datatypes.get(data.datatype);\n if (!datatype) {\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 = `${data.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, {\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,gBAAgB;CACjB;;;;;;;;;;;;;;;;;;;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,EAAE,SAAS;AACjB,MAAI,MAAM,OAAO,KAAA,EACf,QAAO;EAET,MAAM,WAAW,KAAK,YAAY,UAAU,IAAI,KAAK,SAAS;AAC9D,MAAI,CAAC,SACH,QAAO;AAMT,OAAK,MAAM,cAAc,MAAM,SAC7B,MAAK,MAAM,WAAW,SAAS,qBAAqB,QAAQ,EAAE;AAC5D,OAAI,QAAQ,gBAAgB,YAAY,SACtC;GAGF,MAAM,cAAc,GAAG,KAAK,GAAG,GAAG,QAAQ;GAC1C,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,gBAAgB;IACpC,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.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "Lint rule to validate required components in composite datatype fields",
5
5
  "keywords": [
6
6
  "health",
@@ -34,12 +34,14 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "unified-lint-rule": "3.0.1",
37
- "@glion/annotate-profile-fields": "0.25.0",
38
- "@glion/ast": "0.25.0",
39
- "@glion/util-visit": "0.25.0",
40
- "@glion/utils": "0.25.0"
37
+ "@glion/annotate-profile-fields": "0.27.0",
38
+ "@glion/ast": "0.27.0",
39
+ "@glion/util-visit": "0.27.0",
40
+ "@glion/utils": "0.27.0"
41
41
  },
42
42
  "devDependencies": {
43
+ "@stryker-mutator/core": "10.0.0",
44
+ "@stryker-mutator/vitest-runner": "10.0.0",
43
45
  "@types/node": "25.6.0",
44
46
  "@vitest/coverage-v8": "4.1.11",
45
47
  "publint": "0.3.18",
@@ -48,11 +50,11 @@
48
50
  "unified": "^11.0.5",
49
51
  "vfile": "^6.0.3",
50
52
  "vitest": "4.1.11",
51
- "@glion/annotate-profile-context": "0.25.0",
52
- "@glion/builder": "0.25.0",
53
+ "@glion/annotate-profile-context": "0.27.0",
54
+ "@glion/builder": "0.27.0",
53
55
  "@glion/check-readme": "0.18.0",
54
- "@glion/parser": "0.25.0",
55
- "@glion/profiles": "0.25.0",
56
+ "@glion/parser": "0.27.0",
57
+ "@glion/profiles": "0.27.0",
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
  }