@the-cascade-protocol/cli 0.2.4 → 0.3.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/dist/commands/convert.d.ts +8 -5
- package/dist/commands/convert.d.ts.map +1 -1
- package/dist/commands/convert.js +55 -7
- package/dist/commands/convert.js.map +1 -1
- package/dist/commands/pod/helpers.d.ts +2 -0
- package/dist/commands/pod/helpers.d.ts.map +1 -1
- package/dist/commands/pod/helpers.js +62 -1
- package/dist/commands/pod/helpers.js.map +1 -1
- package/dist/commands/pod/import.d.ts +20 -0
- package/dist/commands/pod/import.d.ts.map +1 -0
- package/dist/commands/pod/import.js +382 -0
- package/dist/commands/pod/import.js.map +1 -0
- package/dist/commands/pod/index.d.ts.map +1 -1
- package/dist/commands/pod/index.js +2 -0
- package/dist/commands/pod/index.js.map +1 -1
- package/dist/commands/reconcile.d.ts +32 -0
- package/dist/commands/reconcile.d.ts.map +1 -0
- package/dist/commands/reconcile.js +116 -0
- package/dist/commands/reconcile.js.map +1 -0
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/fhir-converter/cascade-to-fhir-admin.d.ts +13 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-admin.d.ts.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-admin.js +70 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-admin.js.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-clinical.d.ts +36 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-clinical.d.ts.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-clinical.js +407 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-clinical.js.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-demographics.d.ts +15 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-demographics.d.ts.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-demographics.js +115 -0
- package/dist/lib/fhir-converter/cascade-to-fhir-demographics.js.map +1 -0
- package/dist/lib/fhir-converter/cascade-to-fhir.d.ts +9 -3
- package/dist/lib/fhir-converter/cascade-to-fhir.d.ts.map +1 -1
- package/dist/lib/fhir-converter/cascade-to-fhir.js +69 -290
- package/dist/lib/fhir-converter/cascade-to-fhir.js.map +1 -1
- package/dist/lib/fhir-converter/converters-clinical-admin.d.ts +16 -0
- package/dist/lib/fhir-converter/converters-clinical-admin.d.ts.map +1 -0
- package/dist/lib/fhir-converter/converters-clinical-admin.js +166 -0
- package/dist/lib/fhir-converter/converters-clinical-admin.js.map +1 -0
- package/dist/lib/fhir-converter/converters-clinical.d.ts +28 -0
- package/dist/lib/fhir-converter/converters-clinical.d.ts.map +1 -1
- package/dist/lib/fhir-converter/converters-clinical.js +436 -11
- package/dist/lib/fhir-converter/converters-clinical.js.map +1 -1
- package/dist/lib/fhir-converter/converters-demographics.d.ts.map +1 -1
- package/dist/lib/fhir-converter/converters-demographics.js +4 -5
- package/dist/lib/fhir-converter/converters-demographics.js.map +1 -1
- package/dist/lib/fhir-converter/converters-passthrough.d.ts +29 -0
- package/dist/lib/fhir-converter/converters-passthrough.d.ts.map +1 -0
- package/dist/lib/fhir-converter/converters-passthrough.js +86 -0
- package/dist/lib/fhir-converter/converters-passthrough.js.map +1 -0
- package/dist/lib/fhir-converter/fhir-to-cascade.d.ts +8 -4
- package/dist/lib/fhir-converter/fhir-to-cascade.d.ts.map +1 -1
- package/dist/lib/fhir-converter/fhir-to-cascade.js +41 -10
- package/dist/lib/fhir-converter/fhir-to-cascade.js.map +1 -1
- package/dist/lib/fhir-converter/import-manifest.d.ts +40 -0
- package/dist/lib/fhir-converter/import-manifest.d.ts.map +1 -0
- package/dist/lib/fhir-converter/import-manifest.js +66 -0
- package/dist/lib/fhir-converter/import-manifest.js.map +1 -0
- package/dist/lib/fhir-converter/index.d.ts +33 -13
- package/dist/lib/fhir-converter/index.d.ts.map +1 -1
- package/dist/lib/fhir-converter/index.js +53 -17
- package/dist/lib/fhir-converter/index.js.map +1 -1
- package/dist/lib/fhir-converter/types.d.ts +12 -1
- package/dist/lib/fhir-converter/types.d.ts.map +1 -1
- package/dist/lib/fhir-converter/types.js +67 -2
- package/dist/lib/fhir-converter/types.js.map +1 -1
- package/dist/lib/output.d.ts +5 -0
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +6 -1
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/reconciler.d.ts +45 -0
- package/dist/lib/reconciler.d.ts.map +1 -0
- package/dist/lib/reconciler.js +397 -0
- package/dist/lib/reconciler.js.map +1 -0
- package/dist/shapes/checkup.shapes.ttl +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cascade pod import <pod-dir> <files...>
|
|
3
|
+
*
|
|
4
|
+
* Import FHIR JSON or Cascade Turtle files into a Cascade Pod.
|
|
5
|
+
*
|
|
6
|
+
* Converts FHIR to Cascade Turtle if needed, optionally reconciles multiple
|
|
7
|
+
* inputs, routes records by type to the correct pod data files, updates type
|
|
8
|
+
* indexes, and appends ldp:contains references to index.ttl.
|
|
9
|
+
*
|
|
10
|
+
* Options:
|
|
11
|
+
* --source-system <name> Tag all records with this system name
|
|
12
|
+
* --no-reconcile Skip reconciliation even with multiple files
|
|
13
|
+
* --trust <scores> Trust scores e.g. hospital=0.95,clinic=0.85
|
|
14
|
+
* --dry-run Preview without writing any files
|
|
15
|
+
* --report <file> Write import report JSON to file
|
|
16
|
+
* --passthrough <mode> Passthrough mode: full|minimal (default: full)
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'fs/promises';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import { Parser } from 'n3';
|
|
21
|
+
import { printResult, printError, printVerbose } from '../../lib/output.js';
|
|
22
|
+
import { convert } from '../../lib/fhir-converter/index.js';
|
|
23
|
+
import { quadsToTurtle } from '../../lib/fhir-converter/types.js';
|
|
24
|
+
import { runReconciliation } from '../../lib/reconciler.js';
|
|
25
|
+
import { DATA_TYPES, resolvePodDir, fileExists, } from './helpers.js';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Turtle parsing helper: returns map from subject URI -> Quad[]
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
async function parseTurtleToQuads(turtle) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const parser = new Parser({ format: 'Turtle' });
|
|
32
|
+
const bySubject = new Map();
|
|
33
|
+
parser.parse(turtle, (error, quad) => {
|
|
34
|
+
if (error) {
|
|
35
|
+
reject(error);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!quad) {
|
|
39
|
+
resolve(bySubject);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const subj = quad.subject.value;
|
|
43
|
+
if (!bySubject.has(subj))
|
|
44
|
+
bySubject.set(subj, []);
|
|
45
|
+
bySubject.get(subj).push(quad);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Route a subject's rdf:type to a DATA_TYPES key
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
function routeTypeKey(quads) {
|
|
53
|
+
const rdfTypeIri = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
|
|
54
|
+
const typeQuad = quads.find(q => q.predicate.value === rdfTypeIri);
|
|
55
|
+
const typeIri = typeQuad?.object.value ?? '';
|
|
56
|
+
// Exact match first
|
|
57
|
+
for (const [key, info] of Object.entries(DATA_TYPES)) {
|
|
58
|
+
if (info.isFhirPassthroughBucket)
|
|
59
|
+
continue;
|
|
60
|
+
if (info.rdfTypes.includes(typeIri))
|
|
61
|
+
return key;
|
|
62
|
+
}
|
|
63
|
+
// FHIR passthrough: type starts with http://hl7.org/fhir/
|
|
64
|
+
if (typeIri.startsWith('http://hl7.org/fhir/'))
|
|
65
|
+
return 'fhir-passthrough';
|
|
66
|
+
// Unknown type: fallback to fhir-passthrough
|
|
67
|
+
return 'fhir-passthrough';
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Shorten a full IRI to a prefixed form for type registrations
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
const PREFIX_MAP = {
|
|
73
|
+
'https://ns.cascadeprotocol.org/core/v1#': 'cascade',
|
|
74
|
+
'https://ns.cascadeprotocol.org/health/v1#': 'health',
|
|
75
|
+
'https://ns.cascadeprotocol.org/clinical/v1#': 'clinical',
|
|
76
|
+
'https://ns.cascadeprotocol.org/coverage/v1#': 'coverage',
|
|
77
|
+
'http://hl7.org/fhir/': 'fhir',
|
|
78
|
+
};
|
|
79
|
+
function shortenForTurtle(iri) {
|
|
80
|
+
for (const [ns, prefix] of Object.entries(PREFIX_MAP)) {
|
|
81
|
+
if (iri.startsWith(ns))
|
|
82
|
+
return `${prefix}:${iri.slice(ns.length)}`;
|
|
83
|
+
}
|
|
84
|
+
return `<${iri}>`;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Build a TypeRegistration block
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
function buildTypeRegistration(key, info) {
|
|
90
|
+
const forClass = shortenForTurtle(info.rdfTypes[0]);
|
|
91
|
+
const instance = `</${info.directory}/${info.filename}>`;
|
|
92
|
+
return `\n<#${key}> a solid:TypeRegistration ;\n solid:forClass ${forClass} ;\n solid:instance ${instance} .\n`;
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Determine which type index a DATA_TYPE entry should register in
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
function typeIndexForInfo(info) {
|
|
98
|
+
return info.directory === 'clinical' ? 'publicTypeIndex.ttl' : 'privateTypeIndex.ttl';
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Append to type index file (string manipulation to preserve comments)
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
async function appendTypeRegistration(indexPath, key, info, dryRun) {
|
|
104
|
+
const content = await fs.readFile(indexPath, 'utf-8');
|
|
105
|
+
// Check if already registered (by key name)
|
|
106
|
+
if (content.includes(`<#${key}>`) || content.includes(`/${info.filename}`)) {
|
|
107
|
+
return false; // already present
|
|
108
|
+
}
|
|
109
|
+
const block = buildTypeRegistration(key, info);
|
|
110
|
+
if (!dryRun) {
|
|
111
|
+
await fs.appendFile(indexPath, block, 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Append ldp:contains reference to index.ttl
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
async function appendIndexContains(indexPath, relPath, dryRun) {
|
|
119
|
+
const content = await fs.readFile(indexPath, 'utf-8');
|
|
120
|
+
if (content.includes(relPath)) {
|
|
121
|
+
return false; // already present
|
|
122
|
+
}
|
|
123
|
+
// Append a simple ldp:contains statement
|
|
124
|
+
const line = `\n<> <http://www.w3.org/ns/ldp#contains> <${relPath}> .\n`;
|
|
125
|
+
if (!dryRun) {
|
|
126
|
+
await fs.appendFile(indexPath, line, 'utf-8');
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Command registration
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
export function registerImportSubcommand(pod, program) {
|
|
134
|
+
pod
|
|
135
|
+
.command('import')
|
|
136
|
+
.description('Import FHIR JSON or Cascade Turtle files into a pod')
|
|
137
|
+
.argument('<pod-dir>', 'Path to the Cascade Pod directory')
|
|
138
|
+
.argument('<files...>', 'FHIR JSON or Cascade Turtle files to import')
|
|
139
|
+
.option('--source-system <name>', 'Tag all imported records with this system name')
|
|
140
|
+
.option('--no-reconcile', 'Skip reconciliation even when importing multiple files')
|
|
141
|
+
.option('--trust <scores>', 'Trust scores e.g. hospital=0.95,clinic=0.85')
|
|
142
|
+
.option('--dry-run', 'Preview the import without writing any files')
|
|
143
|
+
.option('--report <file>', 'Write import report JSON to this file')
|
|
144
|
+
.option('--passthrough <mode>', 'Passthrough mode: full or minimal (default: full)', 'full')
|
|
145
|
+
.action(async (podDirArg, files, options) => {
|
|
146
|
+
const globalOpts = program.opts();
|
|
147
|
+
const podDir = resolvePodDir(podDirArg);
|
|
148
|
+
const dryRun = options.dryRun ?? false;
|
|
149
|
+
const passthroughMinimal = options.passthrough === 'minimal';
|
|
150
|
+
// --- Step 1: Validate pod dir ---
|
|
151
|
+
const indexTtlPath = path.join(podDir, 'index.ttl');
|
|
152
|
+
if (!(await fileExists(indexTtlPath))) {
|
|
153
|
+
printError(`Pod not found at ${podDir} (no index.ttl). Run 'cascade pod init' first.`, globalOpts);
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (dryRun) {
|
|
158
|
+
printVerbose('Dry-run mode: no files will be written.', globalOpts);
|
|
159
|
+
}
|
|
160
|
+
// Parse trust scores
|
|
161
|
+
const trustScores = {};
|
|
162
|
+
if (options.trust) {
|
|
163
|
+
for (const pair of options.trust.split(',')) {
|
|
164
|
+
const [sys, score] = pair.split('=');
|
|
165
|
+
if (sys && score)
|
|
166
|
+
trustScores[sys] = parseFloat(score);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// --- Step 2: Convert / collect inputs ---
|
|
170
|
+
const reconcilerInputs = [];
|
|
171
|
+
const sourceReport = [];
|
|
172
|
+
const allWarnings = [];
|
|
173
|
+
for (const filePath of files) {
|
|
174
|
+
const absPath = path.resolve(process.cwd(), filePath);
|
|
175
|
+
let content;
|
|
176
|
+
try {
|
|
177
|
+
content = await fs.readFile(absPath, 'utf-8');
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
printError(`Cannot read file: ${absPath}`, globalOpts);
|
|
181
|
+
process.exitCode = 1;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const systemName = options.sourceSystem ?? path.basename(filePath, path.extname(filePath));
|
|
185
|
+
const trimmed = content.trim();
|
|
186
|
+
const warnings = [];
|
|
187
|
+
let turtleContent;
|
|
188
|
+
let resourceCount = 0;
|
|
189
|
+
// Detect FHIR JSON vs Turtle
|
|
190
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
191
|
+
// FHIR JSON
|
|
192
|
+
printVerbose(`Converting FHIR JSON: ${filePath}`, globalOpts);
|
|
193
|
+
const result = await convert(content, 'fhir', 'cascade', 'turtle', systemName, passthroughMinimal);
|
|
194
|
+
if (!result.success) {
|
|
195
|
+
printError(`Failed to convert ${filePath}: ${result.errors.join(', ')}`, globalOpts);
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
turtleContent = result.output;
|
|
200
|
+
resourceCount = result.resourceCount;
|
|
201
|
+
warnings.push(...result.warnings);
|
|
202
|
+
allWarnings.push(...result.warnings.map(w => `${filePath}: ${w}`));
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// Assume Turtle
|
|
206
|
+
printVerbose(`Reading Turtle: ${filePath}`, globalOpts);
|
|
207
|
+
turtleContent = content;
|
|
208
|
+
// Count subjects as rough resource count
|
|
209
|
+
try {
|
|
210
|
+
const quadsMap = await parseTurtleToQuads(turtleContent);
|
|
211
|
+
resourceCount = quadsMap.size;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
resourceCount = 0;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
reconcilerInputs.push({ content: turtleContent, systemName });
|
|
218
|
+
sourceReport.push({ file: filePath, system: systemName, resourceCount, warnings });
|
|
219
|
+
}
|
|
220
|
+
// --- Step 3: Reconcile or concatenate ---
|
|
221
|
+
let mergedTurtle;
|
|
222
|
+
let reconciliationSummary;
|
|
223
|
+
const shouldReconcile = options.reconcile !== false && reconcilerInputs.length > 1;
|
|
224
|
+
if (shouldReconcile) {
|
|
225
|
+
printVerbose(`Reconciling ${reconcilerInputs.length} inputs...`, globalOpts);
|
|
226
|
+
const reconcileResult = await runReconciliation(reconcilerInputs, {
|
|
227
|
+
trustScores,
|
|
228
|
+
labTolerance: 0.05,
|
|
229
|
+
});
|
|
230
|
+
mergedTurtle = reconcileResult.turtle;
|
|
231
|
+
reconciliationSummary = reconcileResult.report.summary;
|
|
232
|
+
printVerbose(`Reconciliation complete. Final records: ${reconcileResult.report.summary.finalRecordCount}`, globalOpts);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
mergedTurtle = reconcilerInputs.map(i => i.content).join('\n\n');
|
|
236
|
+
}
|
|
237
|
+
// --- Step 4: Parse merged Turtle into quads grouped by subject ---
|
|
238
|
+
let subjectQuads;
|
|
239
|
+
try {
|
|
240
|
+
subjectQuads = await parseTurtleToQuads(mergedTurtle);
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
244
|
+
printError(`Failed to parse merged Turtle: ${msg}`, globalOpts);
|
|
245
|
+
process.exitCode = 1;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// --- Step 5: Route subjects to DATA_TYPES buckets ---
|
|
249
|
+
const buckets = new Map(); // key -> list of subject quad arrays
|
|
250
|
+
for (const [, quads] of subjectQuads) {
|
|
251
|
+
const key = routeTypeKey(quads);
|
|
252
|
+
if (!buckets.has(key))
|
|
253
|
+
buckets.set(key, []);
|
|
254
|
+
buckets.get(key).push(quads);
|
|
255
|
+
}
|
|
256
|
+
// --- Step 6 & 7: For each bucket, serialize and merge into pod files ---
|
|
257
|
+
const filesWritten = [];
|
|
258
|
+
const typeCounts = {};
|
|
259
|
+
const newFiles = []; // relative paths (for index.ttl updates)
|
|
260
|
+
for (const [typeKey, subjectQArrays] of buckets) {
|
|
261
|
+
const info = DATA_TYPES[typeKey];
|
|
262
|
+
if (!info) {
|
|
263
|
+
allWarnings.push(`Unknown type key: ${typeKey} — skipping`);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const targetFile = path.join(podDir, info.directory, info.filename);
|
|
267
|
+
const relPath = `${info.directory}/${info.filename}`;
|
|
268
|
+
// Serialize new quads
|
|
269
|
+
const allNewQuads = subjectQArrays.flat();
|
|
270
|
+
const newTurtle = await quadsToTurtle(allNewQuads);
|
|
271
|
+
let finalTurtle;
|
|
272
|
+
let recordsAdded = subjectQArrays.length;
|
|
273
|
+
let isNewFile = true;
|
|
274
|
+
if (await fileExists(targetFile)) {
|
|
275
|
+
isNewFile = false;
|
|
276
|
+
// Merge: parse existing, combine unique subjects
|
|
277
|
+
let existingQuads;
|
|
278
|
+
try {
|
|
279
|
+
const existing = await fs.readFile(targetFile, 'utf-8');
|
|
280
|
+
existingQuads = await parseTurtleToQuads(existing);
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
existingQuads = new Map();
|
|
284
|
+
}
|
|
285
|
+
// Add new subjects (dedup by subject URI)
|
|
286
|
+
let addedCount = 0;
|
|
287
|
+
for (const [subjectUri, quads] of subjectQuads) {
|
|
288
|
+
if (routeTypeKey(quads) === typeKey && !existingQuads.has(subjectUri)) {
|
|
289
|
+
existingQuads.set(subjectUri, quads);
|
|
290
|
+
addedCount++;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
recordsAdded = addedCount;
|
|
294
|
+
const mergedQuads = Array.from(existingQuads.values()).flat();
|
|
295
|
+
finalTurtle = await quadsToTurtle(mergedQuads);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
finalTurtle = newTurtle;
|
|
299
|
+
}
|
|
300
|
+
if (!dryRun) {
|
|
301
|
+
await fs.mkdir(path.dirname(targetFile), { recursive: true });
|
|
302
|
+
await fs.writeFile(targetFile, finalTurtle, 'utf-8');
|
|
303
|
+
}
|
|
304
|
+
typeCounts[typeKey] = (typeCounts[typeKey] ?? 0) + recordsAdded;
|
|
305
|
+
filesWritten.push({ path: targetFile, recordsAdded, type: typeKey });
|
|
306
|
+
if (isNewFile) {
|
|
307
|
+
newFiles.push(relPath);
|
|
308
|
+
}
|
|
309
|
+
printVerbose(` ${dryRun ? '[dry-run] ' : ''}${isNewFile ? 'Created' : 'Updated'} ${relPath} (+${recordsAdded} records)`, globalOpts);
|
|
310
|
+
}
|
|
311
|
+
// --- Step 8: Update type indexes ---
|
|
312
|
+
const settingsDir = path.join(podDir, 'settings');
|
|
313
|
+
const publicIndexPath = path.join(settingsDir, 'publicTypeIndex.ttl');
|
|
314
|
+
const privateIndexPath = path.join(settingsDir, 'privateTypeIndex.ttl');
|
|
315
|
+
for (const [typeKey] of buckets) {
|
|
316
|
+
const info = DATA_TYPES[typeKey];
|
|
317
|
+
if (!info)
|
|
318
|
+
continue;
|
|
319
|
+
const indexFile = typeIndexForInfo(info);
|
|
320
|
+
const indexPath = indexFile === 'publicTypeIndex.ttl' ? publicIndexPath : privateIndexPath;
|
|
321
|
+
if (await fileExists(indexPath)) {
|
|
322
|
+
const appended = await appendTypeRegistration(indexPath, typeKey, info, dryRun);
|
|
323
|
+
if (appended) {
|
|
324
|
+
printVerbose(` ${dryRun ? '[dry-run] ' : ''}Added type registration for ${typeKey} to ${indexFile}`, globalOpts);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// --- Step 9: Update index.ttl for new files ---
|
|
329
|
+
for (const relPath of newFiles) {
|
|
330
|
+
if (await fileExists(indexTtlPath)) {
|
|
331
|
+
const appended = await appendIndexContains(indexTtlPath, relPath, dryRun);
|
|
332
|
+
if (appended) {
|
|
333
|
+
printVerbose(` ${dryRun ? '[dry-run] ' : ''}Added ${relPath} to index.ttl`, globalOpts);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// --- Step 10: Summary and report ---
|
|
338
|
+
const totalRecordsImported = Object.values(typeCounts).reduce((a, b) => a + b, 0);
|
|
339
|
+
const importReport = {
|
|
340
|
+
importedAt: new Date().toISOString(),
|
|
341
|
+
podDir,
|
|
342
|
+
sources: sourceReport,
|
|
343
|
+
reconciliation: shouldReconcile
|
|
344
|
+
? { enabled: true, summary: reconciliationSummary }
|
|
345
|
+
: { enabled: false },
|
|
346
|
+
filesWritten,
|
|
347
|
+
typeCounts,
|
|
348
|
+
totalRecordsImported,
|
|
349
|
+
warnings: allWarnings,
|
|
350
|
+
dryRun,
|
|
351
|
+
};
|
|
352
|
+
if (options.report && !dryRun) {
|
|
353
|
+
await fs.writeFile(options.report, JSON.stringify(importReport, null, 2), 'utf-8');
|
|
354
|
+
printVerbose(`Import report written to: ${options.report}`, globalOpts);
|
|
355
|
+
}
|
|
356
|
+
if (globalOpts.json) {
|
|
357
|
+
printResult(importReport, globalOpts);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
if (dryRun) {
|
|
361
|
+
console.log(`\n[dry-run] Import preview for pod: ${podDir}`);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
console.log(`\nImport complete: ${podDir}`);
|
|
365
|
+
}
|
|
366
|
+
console.log(` Sources: ${sourceReport.length} file(s)`);
|
|
367
|
+
console.log(` Records imported: ${totalRecordsImported}`);
|
|
368
|
+
console.log(` Files written: ${filesWritten.length}`);
|
|
369
|
+
if (allWarnings.length > 0) {
|
|
370
|
+
console.log(` Warnings: ${allWarnings.length}`);
|
|
371
|
+
for (const w of allWarnings) {
|
|
372
|
+
console.log(` - ${w}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
for (const [type, count] of Object.entries(typeCounts)) {
|
|
376
|
+
if (count > 0)
|
|
377
|
+
console.log(` ${type}: +${count}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/commands/pod/import.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pod/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pod/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQzD"}
|
|
@@ -19,11 +19,13 @@ import { registerInitSubcommand } from './init.js';
|
|
|
19
19
|
import { registerQuerySubcommand } from './query.js';
|
|
20
20
|
import { registerExportSubcommand } from './export.js';
|
|
21
21
|
import { registerInfoSubcommand } from './info.js';
|
|
22
|
+
import { registerImportSubcommand } from './import.js';
|
|
22
23
|
export function registerPodCommand(program) {
|
|
23
24
|
const pod = program.command('pod').description('Manage Cascade Pod structures');
|
|
24
25
|
registerInitSubcommand(pod, program);
|
|
25
26
|
registerQuerySubcommand(pod, program);
|
|
26
27
|
registerExportSubcommand(pod, program);
|
|
27
28
|
registerInfoSubcommand(pod, program);
|
|
29
|
+
registerImportSubcommand(pod, program);
|
|
28
30
|
}
|
|
29
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/pod/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/pod/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC;IAEhF,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACrC,uBAAuB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtC,wBAAwB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACvC,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACrC,wBAAwB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cascade reconcile <file1> <file2> [file3...] [options]
|
|
3
|
+
*
|
|
4
|
+
* Reconcile Cascade Protocol Turtle files from multiple sources into a
|
|
5
|
+
* single normalized record set.
|
|
6
|
+
*
|
|
7
|
+
* Detects and resolves:
|
|
8
|
+
* - Exact duplicates (same record from multiple systems)
|
|
9
|
+
* - Near-duplicates (same record, minor value drift)
|
|
10
|
+
* - Status conflicts (active vs resolved)
|
|
11
|
+
* - Value conflicts (same test, different result)
|
|
12
|
+
*
|
|
13
|
+
* Adds reconciliation provenance to the merged output:
|
|
14
|
+
* cascade:reconciliationStatus "canonical" | "merged" | "conflict-resolved" | "unresolved-conflict"
|
|
15
|
+
* cascade:mergedFrom <source-uri1>, <source-uri2>, ...
|
|
16
|
+
* cascade:mergedSources "system-a, system-b"
|
|
17
|
+
* cascade:conflictResolution "trust_priority" | "merge_values"
|
|
18
|
+
*
|
|
19
|
+
* Options:
|
|
20
|
+
* --output <file> Write merged Turtle to file (default: stdout)
|
|
21
|
+
* --report <file> Write JSON transformation report to file
|
|
22
|
+
* --trust <system=score,...> Set trust scores (e.g. hospital=0.95,specialist=0.85)
|
|
23
|
+
* --lab-tolerance <number> Numeric tolerance for lab value matching (default: 0.05)
|
|
24
|
+
* --json Output report as JSON to stdout
|
|
25
|
+
*
|
|
26
|
+
* Examples:
|
|
27
|
+
* cascade reconcile primary-care.ttl specialist.ttl hospital.ttl --output merged.ttl --report report.json
|
|
28
|
+
* cascade reconcile *.ttl --trust hospital=0.95
|
|
29
|
+
*/
|
|
30
|
+
import { Command } from 'commander';
|
|
31
|
+
export declare function registerReconcileCommand(program: Command): void;
|
|
32
|
+
//# sourceMappingURL=reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/commands/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyF/D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cascade reconcile <file1> <file2> [file3...] [options]
|
|
3
|
+
*
|
|
4
|
+
* Reconcile Cascade Protocol Turtle files from multiple sources into a
|
|
5
|
+
* single normalized record set.
|
|
6
|
+
*
|
|
7
|
+
* Detects and resolves:
|
|
8
|
+
* - Exact duplicates (same record from multiple systems)
|
|
9
|
+
* - Near-duplicates (same record, minor value drift)
|
|
10
|
+
* - Status conflicts (active vs resolved)
|
|
11
|
+
* - Value conflicts (same test, different result)
|
|
12
|
+
*
|
|
13
|
+
* Adds reconciliation provenance to the merged output:
|
|
14
|
+
* cascade:reconciliationStatus "canonical" | "merged" | "conflict-resolved" | "unresolved-conflict"
|
|
15
|
+
* cascade:mergedFrom <source-uri1>, <source-uri2>, ...
|
|
16
|
+
* cascade:mergedSources "system-a, system-b"
|
|
17
|
+
* cascade:conflictResolution "trust_priority" | "merge_values"
|
|
18
|
+
*
|
|
19
|
+
* Options:
|
|
20
|
+
* --output <file> Write merged Turtle to file (default: stdout)
|
|
21
|
+
* --report <file> Write JSON transformation report to file
|
|
22
|
+
* --trust <system=score,...> Set trust scores (e.g. hospital=0.95,specialist=0.85)
|
|
23
|
+
* --lab-tolerance <number> Numeric tolerance for lab value matching (default: 0.05)
|
|
24
|
+
* --json Output report as JSON to stdout
|
|
25
|
+
*
|
|
26
|
+
* Examples:
|
|
27
|
+
* cascade reconcile primary-care.ttl specialist.ttl hospital.ttl --output merged.ttl --report report.json
|
|
28
|
+
* cascade reconcile *.ttl --trust hospital=0.95
|
|
29
|
+
*/
|
|
30
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
31
|
+
import { basename } from 'node:path';
|
|
32
|
+
import { printResult, printError, printVerbose } from '../lib/output.js';
|
|
33
|
+
import { runReconciliation } from '../lib/reconciler.js';
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Command registration
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
export function registerReconcileCommand(program) {
|
|
38
|
+
program
|
|
39
|
+
.command('reconcile')
|
|
40
|
+
.description('Reconcile Cascade RDF from multiple sources into a normalized record set')
|
|
41
|
+
.argument('<files...>', 'Cascade Turtle files to reconcile (2 or more)')
|
|
42
|
+
.option('--output <file>', 'Write merged Turtle output to file (default: stdout)')
|
|
43
|
+
.option('--report <file>', 'Write JSON transformation report to file')
|
|
44
|
+
.option('--trust <scores>', 'Source trust scores: system1=0.9,system2=0.85')
|
|
45
|
+
.option('--lab-tolerance <number>', 'Lab value match tolerance as fraction (default: 0.05)', '0.05')
|
|
46
|
+
.action(async (files, options) => {
|
|
47
|
+
const globalOpts = program.opts();
|
|
48
|
+
if (files.length < 2) {
|
|
49
|
+
printError('reconcile requires at least 2 input files', globalOpts);
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const trustScores = {};
|
|
54
|
+
if (options.trust) {
|
|
55
|
+
for (const pair of options.trust.split(',')) {
|
|
56
|
+
const [sys, score] = pair.split('=');
|
|
57
|
+
if (sys && score)
|
|
58
|
+
trustScores[sys] = parseFloat(score);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const labTolerance = parseFloat(options.labTolerance);
|
|
62
|
+
printVerbose(`Reconciling ${files.length} files`, globalOpts);
|
|
63
|
+
printVerbose(`Trust scores: ${JSON.stringify(trustScores)}`, globalOpts);
|
|
64
|
+
// Read all files
|
|
65
|
+
const inputs = [];
|
|
66
|
+
for (const filePath of files) {
|
|
67
|
+
let turtle;
|
|
68
|
+
try {
|
|
69
|
+
turtle = readFileSync(filePath, 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
printError(`Cannot read file: ${filePath}`, globalOpts);
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const systemName = basename(filePath, '.ttl').replace(/_/g, '-');
|
|
77
|
+
inputs.push({ content: turtle, systemName, file: filePath });
|
|
78
|
+
printVerbose(` Loading ${filePath} (system: ${systemName})`, globalOpts);
|
|
79
|
+
}
|
|
80
|
+
const result = await runReconciliation(inputs.map(i => ({ content: i.content, systemName: i.systemName })), { trustScores, labTolerance });
|
|
81
|
+
// Output
|
|
82
|
+
if (options.output) {
|
|
83
|
+
writeFileSync(options.output, result.turtle);
|
|
84
|
+
console.error(`Merged Turtle written to: ${options.output}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log(result.turtle);
|
|
88
|
+
}
|
|
89
|
+
const reportData = {
|
|
90
|
+
generatedAt: new Date().toISOString(),
|
|
91
|
+
sources: result.report.sources,
|
|
92
|
+
summary: result.report.summary,
|
|
93
|
+
transformations: result.report.transformations,
|
|
94
|
+
unresolvedConflicts: result.report.unresolvedConflicts,
|
|
95
|
+
};
|
|
96
|
+
if (options.report) {
|
|
97
|
+
writeFileSync(options.report, JSON.stringify(reportData, null, 2));
|
|
98
|
+
console.error(`Report written to: ${options.report}`);
|
|
99
|
+
}
|
|
100
|
+
// Summary to stderr
|
|
101
|
+
const { summary } = result.report;
|
|
102
|
+
console.error(`\nReconciliation summary:`);
|
|
103
|
+
console.error(` Input records: ${summary.totalInputRecords}`);
|
|
104
|
+
console.error(` Exact duplicates: -${summary.exactDuplicatesRemoved}`);
|
|
105
|
+
console.error(` Near-duplicates: ~${summary.nearDuplicatesMerged} merged`);
|
|
106
|
+
console.error(` Conflicts resolved: ${summary.conflictsResolved}`);
|
|
107
|
+
if (summary.conflictsUnresolved > 0) {
|
|
108
|
+
console.error(` Unresolved: ${summary.conflictsUnresolved}`);
|
|
109
|
+
}
|
|
110
|
+
console.error(` Final records: ${summary.finalRecordCount}`);
|
|
111
|
+
if (globalOpts.json) {
|
|
112
|
+
printResult(reportData, globalOpts);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/commands/reconcile.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -18,13 +18,12 @@
|
|
|
18
18
|
import { Command } from 'commander';
|
|
19
19
|
import { registerValidateCommand } from './commands/validate.js';
|
|
20
20
|
import { registerConvertCommand } from './commands/convert.js';
|
|
21
|
+
import { registerReconcileCommand } from './commands/reconcile.js';
|
|
21
22
|
import { registerPodCommand } from './commands/pod/index.js';
|
|
22
23
|
import { registerConformanceCommand } from './commands/conformance.js';
|
|
23
24
|
import { registerServeCommand } from './commands/serve.js';
|
|
24
25
|
import { registerCapabilitiesCommand } from './commands/capabilities.js';
|
|
25
|
-
import
|
|
26
|
-
const require = createRequire(import.meta.url);
|
|
27
|
-
const pkg = require('../package.json');
|
|
26
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
28
27
|
const program = new Command();
|
|
29
28
|
program
|
|
30
29
|
.name('cascade')
|
|
@@ -35,6 +34,7 @@ program
|
|
|
35
34
|
// Register all commands
|
|
36
35
|
registerValidateCommand(program);
|
|
37
36
|
registerConvertCommand(program);
|
|
37
|
+
registerReconcileCommand(program);
|
|
38
38
|
registerPodCommand(program);
|
|
39
39
|
registerConformanceCommand(program);
|
|
40
40
|
registerServeCommand(program);
|
|
@@ -44,6 +44,8 @@ program.addHelpText('after', `
|
|
|
44
44
|
Examples:
|
|
45
45
|
cascade validate record.ttl
|
|
46
46
|
cascade convert --from fhir --to cascade patient.json
|
|
47
|
+
cascade convert --from fhir --to cascade --source-system primary-care patient.json
|
|
48
|
+
cascade reconcile system-a.ttl system-b.ttl system-c.ttl --output merged.ttl --report report.json
|
|
47
49
|
cascade pod init ./my-pod
|
|
48
50
|
cascade capabilities
|
|
49
51
|
cascade capabilities --json
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAExD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,sBAAsB,CAAC;KACnC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,MAAM,CAAC,WAAW,EAAE,gBAAgB,EAAE,KAAK,CAAC;KAC5C,MAAM,CAAC,QAAQ,EAAE,2CAA2C,EAAE,KAAK,CAAC,CAAC;AAExE,wBAAwB;AACxB,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAClC,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,0BAA0B,CAAC,OAAO,CAAC,CAAC;AACpC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,2BAA2B,CAAC,OAAO,CAAC,CAAC;AAErC,iCAAiC;AACjC,OAAO,CAAC,WAAW,CACjB,OAAO,EACP;;;;;;;;;CASD,CACA,CAAC;AAEF,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cascade -> FHIR reverse converters for administrative/financial types.
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* coverage:ClaimRecord -> Claim
|
|
6
|
+
* coverage:BenefitStatement -> ExplanationOfBenefit
|
|
7
|
+
*/
|
|
8
|
+
type PV = Map<string, string[]>;
|
|
9
|
+
type FhirResource = Record<string, any>;
|
|
10
|
+
export declare function restoreClaimRecord(pv: PV, _warnings: string[]): FhirResource;
|
|
11
|
+
export declare function restoreBenefitStatement(pv: PV, _warnings: string[]): FhirResource;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cascade-to-fhir-admin.d.ts.map
|