Skip to content

Commit f4bf72d

Browse files
use local npm packages in bfd-model-idr
1 parent 4f04ad2 commit f4bf72d

19 files changed

Lines changed: 1968 additions & 90 deletions

.github/workflows/build-release.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -291,18 +291,6 @@ jobs:
291291
with:
292292
node-version: "22"
293293

294-
- name: Install Sushi
295-
run: |
296-
npm install -g fsh-sushi
297-
sushi build
298-
echo "Installed + run sushi"
299-
working-directory: apps/bfd-model-idr/sushi
300-
301-
- name: Install fhirpath
302-
run: |
303-
npm install fhirpath
304-
working-directory: apps/bfd-model-idr
305-
306294
- name: Install uv
307295
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
308296
with:

.github/workflows/ci-pipeline-synthetic.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,13 @@ jobs:
2929
with:
3030
java-version: "25"
3131
distribution: "corretto"
32-
- name: Install dependencies
33-
run: npm install -g fsh-sushi && npm install fhirpath
34-
working-directory: apps/bfd-model-idr
3532
- name: Sync UV in bfd-model-idr
3633
run: uv sync
3734
working-directory: apps/bfd-model-idr
3835
- name: Build sushi
3936
run: |
4037
cd ${{ github.workspace }}/apps/bfd-model-idr
41-
sushi build ./sushi
38+
npm run sushi-build
4239
- name: Generate v3 Data Dictionary
4340
run: uv run gen_dd.py
4441
working-directory: apps/bfd-model-idr

apps/bfd-model-idr/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ sushi/fsh-generated/*
2626
validator_cli.jar
2727
ReferenceTables/source-to-target-mappings
2828
data/*
29-
temp_packages/*
29+
temp_packages/*
30+
node_modules

apps/bfd-model-idr/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ npm --version
2727
brew install npm
2828
```
2929

30-
```sh
31-
npm install -g fsh-sushi fhirpath
32-
```
3330

3431
### Install packages (via uv)
3532

@@ -51,7 +48,7 @@ uv sync
5148
To compile the .fsh files from this folder
5249

5350
```sh
54-
cd sushi && sushi build && cd ..
51+
npm run sushi-build
5552
```
5653

5754
This will generate the StructureDefinition and CodeSystem resources necessary for synthetic data generation. Running compile_resources.py is not necessary to generate synthetic data.

apps/bfd-model-idr/claims_generator.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
CLM_RLT_COND_SGNTR_MBR,
3636
CLM_VAL,
3737
CNTRCT_PBP_NUM,
38-
PRVDR_HSTRY,
3938
PRAUC,
39+
PRVDR_HSTRY,
4040
GeneratorUtil,
4141
RowAdapter,
4242
adapters_to_dicts,
@@ -788,7 +788,7 @@ def generate(
788788

789789
if sushi:
790790
print("Running sushi build")
791-
_, stderr = run_command(["sushi", "build"], cwd="./sushi")
791+
_, stderr = run_command("npm run sushi-build", cwd=".")
792792
if stderr:
793793
print("SUSHI errors:")
794794
print(stderr)
@@ -828,12 +828,12 @@ def generate(
828828

829829
other_util = OtherGeneratorUtil()
830830

831-
generated_provider_histories, generated_type_1_npis, generated_type_2_npis = other_util.gen_provider_history(amount=14, init_provider_historys=files[PRVDR_HSTRY])
832-
833-
out_tables[PRVDR_HSTRY].extend(
834-
generated_provider_histories
831+
generated_provider_histories, generated_type_1_npis, generated_type_2_npis = (
832+
other_util.gen_provider_history(amount=14, init_provider_historys=files[PRVDR_HSTRY])
835833
)
836834

835+
out_tables[PRVDR_HSTRY].extend(generated_provider_histories)
836+
837837
# This table is special in that its data is mostly static and read from a static file, so we
838838
# don't need to do anything fancy with it
839839
out_tables[CLM_ANSI_SGNTR] = other_util.gen_synthetic_clm_ansi_sgntr()
@@ -1051,7 +1051,7 @@ def generate(
10511051
else idx,
10521052
diagnoses=diagnoses,
10531053
init_clm_line=init_clm_line,
1054-
type_1_npis= generated_type_1_npis
1054+
type_1_npis=generated_type_1_npis,
10551055
)
10561056
adj_clms_tbls[CLM_LINE].append(clm_line)
10571057

apps/bfd-model-idr/compile_resources.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import json
33
import subprocess
44
import sys
5-
import requests
65
from pathlib import Path
76

7+
import requests
8+
89
MATCHBOX_SERVER = "http://localhost:8080/matchboxv3"
910

1011

@@ -39,6 +40,7 @@ def get_referenced_maps(compiled_map_path):
3940
print("Error reading map:", e)
4041
return set()
4142

43+
4244
def get_sushi_resources():
4345
try:
4446
sushi_dir = Path(__file__).parent.absolute() / "sushi" / "fsh-generated" / "resources"
@@ -50,6 +52,7 @@ def get_sushi_resources():
5052
print(f"Error getting SUSHI resources: {e}")
5153
return ""
5254

55+
5356
# populate matchbox's tx library
5457
def upload_resources(resource_dir, server_url):
5558
print("Uploading resources to matchbox")
@@ -196,9 +199,10 @@ def main():
196199
script_dir = Path(__file__).parent.absolute()
197200

198201
# Generate Structure Definitions + CodeSystems
199-
if(args.sushi):
202+
if args.sushi:
200203
print("Running sushi build")
201-
stdout, stderr = run_command("sushi build", cwd=script_dir / "sushi")
204+
run_command("npm install", cwd=script_dir)
205+
stdout, stderr = run_command("npm run sushi-build", cwd=script_dir)
202206
print("SUSHI output:")
203207
print(stdout)
204208
if stderr:
@@ -234,14 +238,14 @@ def main():
234238
referenced_maps = get_referenced_maps(compiled_map_path)
235239
map_imports = " ".join([f"-ig {map_file}" for map_file in referenced_maps])
236240

237-
#Augment source file if needed. Currently just for providers.
241+
# Augment source file if needed. Currently just for providers.
238242
(input_file,) = {args.input}
239-
if 'EOB' in input_file:
243+
if "EOB" in input_file:
240244
print("Augmenting input file")
241245
profile_flag = f" {args.profileType}" if args.profileType else ""
242246
augmentation_cmd = f"python augment_sample_resources.py {args.input}{profile_flag}"
243247
stdout, stderr = run_command(augmentation_cmd, cwd=script_dir)
244-
input_file = 'out/temporary-sample.json'
248+
input_file = "out/temporary-sample.json"
245249

246250
print("Executing Transform")
247251
execute_cmd = f"java -jar validator_cli.jar {input_file} -output {args.output} -transform \

apps/bfd-model-idr/gen_dd.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,24 @@
8484
"Pharmacy",
8585
"PriorAuth",
8686
]
87+
88+
89+
def run_subprocess(args: list[str]) -> subprocess.CompletedProcess[bytes]:
90+
return subprocess.run(
91+
args,
92+
cwd=Path().parent,
93+
check=True,
94+
stdout=subprocess.PIPE,
95+
)
96+
97+
98+
run_subprocess(["npm", "install"])
99+
87100
for walk_info in os.walk(dd_support_folder):
88101
files = list(filter(lambda file: ".yaml" in file, walk_info[2]))
89102
for file_name in files:
90103
with Path(str(dd_support_folder) + "/" + str(file_name)).open() as file:
104+
print("Generating", file_name)
91105
data = yaml.safe_load(file)
92106
current_resource_type = file_name[0 : len(file_name) - 5]
93107
for entry in data:
@@ -110,16 +124,13 @@
110124
entry["FHIR Resource"] = "AuditEvent"
111125

112126
# This opportunistically populates examples based upon the samples created from executing FML
113-
result = subprocess.run(
127+
result = run_subprocess(
114128
[
115129
"node",
116130
"eval_fhirpath.js",
117131
json.dumps(sample_resources_by_profile[entry["appliesTo"][0]]),
118132
entry["fhirPath"],
119-
],
120-
cwd=os.path.dirname(__file__),
121-
check=True,
122-
stdout=subprocess.PIPE,
133+
]
123134
)
124135
entry["example"] = json.loads(result.stdout)
125136
if "iif" in entry["fhirPath"] or "union" in entry["fhirPath"]:
@@ -134,20 +145,20 @@
134145

135146
# Populate the element names + missing descriptions
136147
if entry["inputPath"] in structure_def_names_descriptions:
137-
entry["Field Name"] = structure_def_names_descriptions[
138-
entry["inputPath"]
139-
]["name"]
148+
entry["Field Name"] = structure_def_names_descriptions[entry["inputPath"]][
149+
"name"
150+
]
140151
if "definition" in structure_def_names_descriptions[entry["inputPath"]]:
141152
entry["Description"] = structure_def_names_descriptions[
142153
entry["inputPath"]
143-
]["definition"]
144-
#nameOverride and definitionOverride only exist when a field is derived IN fml.
154+
]["definition"]
155+
# nameOverride and definitionOverride only exist when a field is derived IN fml.
145156
if "nameOverride" in entry:
146157
entry["Field Name"] = entry["nameOverride"]
147158
entry["Description"] = entry["definitionOverride"]
148159
elif "Description" not in entry or not entry["Description"]:
149160
raise ValueError(
150-
f"Entry {entry.get("inputPath", 'Unknown')} has no definition. "
161+
f"Entry {entry.get('inputPath', 'Unknown')} has no definition. "
151162
)
152163
entry.pop("inputPath")
153164
dd_df.append(entry)
@@ -156,8 +167,7 @@
156167

157168

158169
def replace_str(input_str):
159-
# Yes, the below is intentional.
160-
if input_str == input_str and len(str(input_str)) > 0:
170+
if isinstance(input_str, str) and len(str(input_str)) > 0:
161171
return "https://bluebutton.cms.gov/fhir/CodeSystem/" + str(input_str).replace("_", "-")
162172
return ""
163173

apps/bfd-model-idr/generator_util.py

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def partition_rows[T](
134134
return bucketed_rows
135135

136136

137-
def run_command(cmd: list[str], cwd: str | None = None):
137+
def run_command(cmd: list[str] | str, cwd: str | None = None):
138138
try:
139139
result = subprocess.run(
140140
cmd, cwd=cwd, shell=True, check=True, text=True, capture_output=True
@@ -182,14 +182,16 @@ def __gen_id(field: str, gen_func: Callable[[], str]) -> str:
182182
def gen_multipart_id(field: str, parts: list[tuple[str, int]]) -> str:
183183
return __gen_id(
184184
field=field,
185-
gen_func=lambda: f"-{
186-
''.join(
187-
[
188-
''.join(random.choices(population=allowed_chars, k=length))
189-
for (allowed_chars, length) in parts
190-
]
191-
)
192-
}",
185+
gen_func=lambda: (
186+
f"-{
187+
''.join(
188+
[
189+
''.join(random.choices(population=allowed_chars, k=length))
190+
for (allowed_chars, length) in parts
191+
]
192+
)
193+
}"
194+
),
193195
)
194196

195197

@@ -336,20 +338,7 @@ def load_code_systems(self):
336338

337339
# Check if the resources directory exists, if not run sushi build
338340
if not Path(relative_path).exists():
339-
print("Running sushi build")
340-
try:
341-
sushi_dir = "./sushi"
342-
result = subprocess.run(
343-
["sushi", "build"], check=True, cwd=sushi_dir, capture_output=True, text=True
344-
)
345-
if result.returncode == 0:
346-
print("Sushi build completed successfully")
347-
else:
348-
print(f"Sushi build failed with error: {result.stderr}")
349-
sys.exit(1)
350-
except Exception as e:
351-
print(f"Error running sushi build: {e}")
352-
sys.exit(1)
341+
run_command("npm run sushi-build")
353342

354343
try:
355344
for path in Path(relative_path).iterdir():
@@ -807,26 +796,26 @@ def generate_bene_lis(self, lis_row: RowAdapter):
807796
self.bene_lis.append(lis_row.kv)
808797

809798
def generate_bene_lis_cmbnd(self, lis_row: RowAdapter):
810-
lis_start_date = self.fake.date_between_dates(
811-
datetime.date(year=2017, month=5, day=20),
812-
datetime.date(year=2021, month=1, day=1),
813-
)
814-
lis_end_date = "9999-12-31"
815-
copmt_lvl_cd = random.choice(self.code_systems["BENE_LIS_COPMT_LVL_CD"])
816-
ptd_prm_pct = random.choice(["025", "050", "075", "100"])
817-
818-
lis_row["IDR_LTST_TRANS_FLG"] = "Y"
819-
lis_row["BENE_CMBND_DEEMD_IND"] = random.choice(["Y", " "])
820-
lis_row["BENE_CMBND_DEEMD_COPMT_LVL_ID"] = copmt_lvl_cd
821-
lis_row["BENE_CMBND_DEEMD_PRM_PCT"] = str(ptd_prm_pct)
822-
lis_row["BENE_CMBND_DEEMD_EFCTV_DT"] = str(lis_start_date)
823-
lis_row["BENE_CMBND_DEEMD_TRMNTN_DT"] = lis_end_date
824-
lis_row["IDR_TRANS_EFCTV_TS"] = str(lis_start_date) + "T00:00:00.000000"
825-
lis_row["IDR_INSRT_TS"] = str(lis_start_date) + "T00:00:00.000000"
826-
lis_row["IDR_UPDT_TS"] = str(lis_start_date) + "T00:00:00.000000"
827-
lis_row["IDR_TRANS_OBSLT_TS"] = "9999-12-31T00:00:00.000000"
828-
829-
self.bene_lis_cmbnd.append(lis_row.kv)
799+
lis_start_date = self.fake.date_between_dates(
800+
datetime.date(year=2017, month=5, day=20),
801+
datetime.date(year=2021, month=1, day=1),
802+
)
803+
lis_end_date = "9999-12-31"
804+
copmt_lvl_cd = random.choice(self.code_systems["BENE_LIS_COPMT_LVL_CD"])
805+
ptd_prm_pct = random.choice(["025", "050", "075", "100"])
806+
807+
lis_row["IDR_LTST_TRANS_FLG"] = "Y"
808+
lis_row["BENE_CMBND_DEEMD_IND"] = random.choice(["Y", " "])
809+
lis_row["BENE_CMBND_DEEMD_COPMT_LVL_ID"] = copmt_lvl_cd
810+
lis_row["BENE_CMBND_DEEMD_PRM_PCT"] = str(ptd_prm_pct)
811+
lis_row["BENE_CMBND_DEEMD_EFCTV_DT"] = str(lis_start_date)
812+
lis_row["BENE_CMBND_DEEMD_TRMNTN_DT"] = lis_end_date
813+
lis_row["IDR_TRANS_EFCTV_TS"] = str(lis_start_date) + "T00:00:00.000000"
814+
lis_row["IDR_INSRT_TS"] = str(lis_start_date) + "T00:00:00.000000"
815+
lis_row["IDR_UPDT_TS"] = str(lis_start_date) + "T00:00:00.000000"
816+
lis_row["IDR_TRANS_OBSLT_TS"] = "9999-12-31T00:00:00.000000"
817+
818+
self.bene_lis_cmbnd.append(lis_row.kv)
830819

831820
def generate_bene_mapd_enrlmt_rx(
832821
self, rx_row: RowAdapter, contract_pbp_sk: str, contract_num: str, pbp_num: str

apps/bfd-model-idr/out/ExplanationOfBenefit-Carrier.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@
9393
"system" : "https://bluebutton.cms.gov/fhir/CodeSystem/CLM-TYPE-CD",
9494
"code" : "72",
9595
"display" : "MEDICARE PART B PROFESSIONAL PHYSICIAN/SUPPLIER CLAIM (DMEPOS)"
96+
},
97+
{
98+
"system" : "https://bluebutton.cms.gov/fhir/CodeSystem/EOB-TYPE",
99+
"code" : "CARRIER"
96100
}]
97101
},
98102
"use" : "claim",

apps/bfd-model-idr/out/ExplanationOfBenefit-DME.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@
9191
"system" : "https://bluebutton.cms.gov/fhir/CodeSystem/CLM-TYPE-CD",
9292
"code" : "82",
9393
"display" : "MEDICARE PART B DME REGIONAL CARRIER (DMERC) CLAIM (DMEPOS)"
94+
},
95+
{
96+
"system" : "https://bluebutton.cms.gov/fhir/CodeSystem/EOB-TYPE",
97+
"code" : "DME"
9498
}]
9599
},
96100
"use" : "claim",

0 commit comments

Comments
 (0)