Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
extend validation to xml
Browse files Browse the repository at this point in the history
  • Loading branch information
oliveregger committed Apr 21, 2022
1 parent 84cf512 commit f00d125
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matchbox",
"version": "1.3.0",
"version": "1.4.0",
"license": "MIT",
"scripts": {
"ng": "ng",
Expand Down
15 changes: 12 additions & 3 deletions src/app/operation-outcome/operation-outcome.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
<mat-card-header>
<mat-card-title>{{ title }}</mat-card-title>
</mat-card-header>
<div *ngIf="operationOutcome">
<div *ngFor="let issue of operationOutcome.issue" class="issue">
<div *ngIf="outcome">
<div *ngFor="let issue of outcome.issue" class="issue">
<a class="{{ issue.severity }}" (click)="scroll(getLineNo(issue))"
>{{ getLineFromExtension(issue) }}: {{ getLocation(issue) }}</a
>:<br />
{{ issue.diagnostics }}
<ng-container *ngIf="hasSliceInfo(issue) == false">
{{ issue.diagnostics }}
</ng-container>
<ng-container *ngIf="hasSliceInfo(issue)">
<ol>
<li *ngFor="let sliceInfo of getSliceInfo(issue)" class="issue">
{{ sliceInfo }}
</li>
</ol>
</ng-container>
</div>
</div>
<div
Expand Down
4 changes: 0 additions & 4 deletions src/app/operation-outcome/operation-outcome.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
background: #cc3300; /* color */
}

.fatal {
background: #cc3300; /* color */
}

.error {
background: #ff9966; /* color */
}
Expand Down
98 changes: 67 additions & 31 deletions src/app/operation-outcome/operation-outcome.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import * as ace from 'ace-builds';
})
export class OperationOutcomeComponent implements AfterViewInit, OnInit {
@Input() title: string;
@Input() json: string;
@Input() operationOutcome: fhir.r4.OperationOutcome;
outcome: fhir.r4.OperationOutcome;

@ViewChild('editor') private editor: ElementRef<HTMLElement>;

content: string;

jsonLines: string[];
padNo: number;

Expand All @@ -39,39 +40,49 @@ export class OperationOutcomeComponent implements AfterViewInit, OnInit {
this.aceEditor.setOption('useWorker', false);
this.aceEditor.setTheme('ace/theme/chrome');
this.aceEditor.session.setMode('ace/mode/json');
this.aceEditor.session.setValue(this.json);
this.aceEditor.session.setValue(this.content);
this.aceEditor.setReadOnly(true);
this.aceEditor.on('change', () => {
console.log(this.aceEditor.getValue());
});
this.operationOutcome.issue?.sort(
(issue1, issue2) => this.getLineNo(issue1) - this.getLineNo(issue2)
);
this.operationOutcome.issue?.forEach((issue) =>
this.aceEditor
.getSession()
.addMarker(
new ace.Range(
this.getLineNo(issue) - 1,
0,
this.getLineNo(issue) - 1,
1
),
this.getLineAceClass(issue),
'fullLine',
true
)
);
this.updateAnnotations();
}

updateAnnotations() {
const annotations: ace.Ace.Annotation[] = [];
this.operationOutcome.issue?.forEach((issue) =>
annotations.push({
row: this.getLineNo(issue) - 1,
column: 0,
text: issue.diagnostics, // Or the Json reply from the parser
type: this.getErrorType(issue), // also "warning" and "information"
})
);
this.aceEditor.session.setAnnotations(annotations);
if (this.outcome && this.aceEditor) {
const prevMarkers = this.aceEditor.session.getMarkers();
if (prevMarkers) {
const prevMarkersArr = Object.keys(prevMarkers);
for (let item of prevMarkersArr) {
this.aceEditor.session.removeMarker(prevMarkers[item].id);
}
}
this.outcome.issue?.forEach((issue) =>
this.aceEditor
.getSession()
.addMarker(
new ace.Range(
this.getLineNo(issue) - 1,
0,
this.getLineNo(issue) - 1,
1
),
this.getLineAceClass(issue),
'fullLine',
true
)
);
this.outcome.issue?.forEach((issue) =>
annotations.push({
row: this.getLineNo(issue) - 1,
column: 0,
text: issue.diagnostics, // Or the Json reply from the parser
type: this.getErrorType(issue), // also "warning" and "information"
})
);
this.aceEditor.session.setAnnotations(annotations);
}
}

getErrorType(issue: fhir.r4.OperationOutcomeIssue): string {
Expand All @@ -88,8 +99,21 @@ export class OperationOutcomeComponent implements AfterViewInit, OnInit {
return '';
}

@Input() set json(value: string) {
this.content = value;
this.ngAfterViewInit();
}

@Input() set operationOutcome(value: fhir.r4.OperationOutcome) {
this.outcome = value;
this.outcome.issue?.sort(
(issue1, issue2) => this.getLineNo(issue1) - this.getLineNo(issue2)
);
this.ngAfterViewInit();
}

getJson(): String {
return this.json;
return this.content;
}

getLineAceClass(issue: fhir.r4.OperationOutcomeIssue): string {
Expand All @@ -103,6 +127,18 @@ export class OperationOutcomeComponent implements AfterViewInit, OnInit {
return 0;
}

hasSliceInfo(issue: fhir.r4.OperationOutcomeIssue): boolean {
return issue?.diagnostics?.indexOf('Slice info:') >= 0;
}

getSliceInfo(issue: fhir.r4.OperationOutcomeIssue): string[] {
let slice = issue?.diagnostics
.substring(issue?.diagnostics?.indexOf('Slice info: 1.)') + 15)
.trimLeft();
let regexp = new RegExp('[\\d]+[\\.][\\)]');
return slice.split(regexp);
}

getLineFromExtension(issue: fhir.r4.OperationOutcomeIssue): string {
if (issue.extension?.length > 0) {
return 'L' + issue.extension[0].valueInteger;
Expand Down
78 changes: 65 additions & 13 deletions src/app/validate/validate.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ interface ITarEntry {
class ValidationEntry {
name: string; // "package/package.json",
json: string;
mimetype: string;
operationOutcome: fhir.r4.OperationOutcome;
profiles: string[];

constructor(name: string, json: string) {
constructor(name: string, json: string, mimetype: string) {
this.name = name;
this.json = json;
this.mimetype = mimetype;
}

getErrors(): number {
Expand Down Expand Up @@ -120,7 +122,10 @@ export class ValidateComponent implements OnInit {
(<fhir.r4.CapabilityStatementRestResource>entry).type ===
this.resourceName
);
return [resCap.profile, ...resCap.supportedProfile];
if (resCap != null) {
return [resCap.profile, ...resCap.supportedProfile];
}
return null;
}

addFile(droppedBlob: IDroppedBlob) {
Expand All @@ -131,20 +136,47 @@ export class ValidateComponent implements OnInit {
) {
this.addJson(droppedBlob.blob);
}
if (
droppedBlob.contentType === 'application/xml' ||
droppedBlob.name.endsWith('.xml')
) {
this.addXml(droppedBlob.blob);
}
if (droppedBlob.name.endsWith('.tgz')) {
this.addPackage(droppedBlob.blob);
}
this.validationInProgress -= 1;
}

addXml(file) {
const reader = new FileReader();
reader.readAsText(file);
const dataSource = this.dataSource;
reader.onload = () => {
// need to run CD since file load runs outside of zone
this.cd.markForCheck();
let entry = new ValidationEntry(
file.name,
<string>reader.result,
'application/fhir+xml'
);
dataSource.data.push(entry);
this.validate(entry);
};
}

addJson(file) {
const reader = new FileReader();
reader.readAsText(file);
const dataSource = this.dataSource;
reader.onload = () => {
// need to run CD since file load runs outside of zone
this.cd.markForCheck();
let entry = new ValidationEntry(file.name, <string>reader.result);
let entry = new ValidationEntry(
file.name,
<string>reader.result,
'application/fhir+json'
);
dataSource.data.push(entry);
this.validate(entry);
};
Expand Down Expand Up @@ -219,7 +251,8 @@ export class ValidateComponent implements OnInit {
JSON.parse(decoder.decode(extractedFile.buffer)),
null,
2
)
),
'application/fhir+json'
);
dataSource.data.push(entry);
pointer.validate(entry);
Expand Down Expand Up @@ -261,7 +294,7 @@ export class ValidateComponent implements OnInit {
options: {
headers: {
accept: 'application/fhir+json;fhirVersion=4.0',
'content-type': 'application/fhir+json;fhirVersion=4.0',
'content-type': row.mimetype,
},
},
})
Expand All @@ -285,13 +318,31 @@ export class ValidateComponent implements OnInit {
if (row) {
this.operationOutcome = row.operationOutcome;
this.json = row.json;
const res = <fhir.r4.Resource>JSON.parse(this.json);
if (res?.resourceType) {
this.resourceName = res.resourceType;
this.resourceId = res.id;
} else {
this.resourceName = '';
this.resourceId = '';
this.resourceName = '';
this.resourceId = '';
if (row.mimetype === 'application/fhir+json') {
const res = <fhir.r4.Resource>JSON.parse(this.json);
if (res?.resourceType) {
this.resourceName = res.resourceType;
this.resourceId = res.id;
}
}
if (row.mimetype === 'application/fhir+xml') {
let pos = this.json.indexOf('<?') + 1;
let posLeft = this.json.indexOf('<', pos);
let posRight = this.json.indexOf('>', pos);
if (posLeft < posRight) {
let tag = this.json.substring(posLeft + 1, posRight - 1);
let posTag = tag.indexOf(' xmlns');
if (posTag > 0) {
tag = tag.substring(0, posTag);
}
posTag = tag.indexOf(':');
if (posTag > 0) {
tag = tag.substring(posTag + 1);
}
this.resourceName = tag;
}
}
} else {
this.operationOutcome = undefined;
Expand All @@ -312,7 +363,8 @@ export class ValidateComponent implements OnInit {
onValidate() {
let entry = new ValidationEntry(
this.selectedEntry.name,
this.selectedEntry.json
this.selectedEntry.json,
this.selectedEntry.mimetype
);
this.dataSource.data.push(entry);
this.validate(entry);
Expand Down

0 comments on commit f00d125

Please sign in to comment.