Skip to content

Commit bb69fdc

Browse files
author
Rob Tjalma
authored
Merge pull request #132 from com-pas/add-scl-validator
Added Validator Plugin to use CoMPAS SCL Validator Service.
2 parents c6cdd9f + daad95f commit bb69fdc

File tree

9 files changed

+133
-5
lines changed

9 files changed

+133
-5
lines changed

public/js/plugins.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ export const officialPlugins = [
9191
requireDoc: true,
9292
position: 'top'
9393
},
94+
{
95+
name: 'Validate using OCL',
96+
src: '/src/validators/ValidateSchemaWithCompas.js',
97+
icon: 'rule_folder',
98+
default: true,
99+
kind: 'validator',
100+
},
94101
{
95102
name: 'Validate project',
96103
src: '/src/validators/ValidateSchema.js',

src/Hosting.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ interface MenuItem {
3636
}
3737

3838
interface Validator {
39-
validate: () => Promise<void>;
39+
validate: (manual?: boolean) => Promise<void>;
4040
}
4141

4242
interface MenuPlugin {
@@ -148,7 +148,7 @@ export function Hosting<
148148
(<unknown>(
149149
(<List>ae.target).items[ae.detail.index].lastElementChild
150150
))
151-
)).validate()
151+
)).validate(true)
152152
)
153153
);
154154
},
@@ -235,7 +235,7 @@ export function Hosting<
235235
.querySelector('mwc-list')!
236236
.items.filter(item => item.className === 'validator')
237237
.map(item =>
238-
(<Validator>(<unknown>item.lastElementChild)).validate()
238+
(<Validator>(<unknown>item.lastElementChild)).validate(false)
239239
)
240240
).then();
241241
this.dispatchEvent(newPendingStateEvent(this.validated));
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {CompasSettings} from "../compas/CompasSettings.js";
2+
import {handleError, handleResponse, parseXml} from "./foundation.js";
3+
4+
export const SVS_NAMESPACE = 'https://www.lfenergy.org/compas/SclValidatorService/v1';
5+
6+
export function CompasSclValidatorService() {
7+
function getCompasSettings() {
8+
return CompasSettings().compasSettings;
9+
}
10+
11+
return {
12+
validateSCL(type: string, doc: Document): Promise<Document> {
13+
const saaUrl = getCompasSettings().sclValidatorServiceUrl + '/validate/v1/' + type;
14+
return fetch(saaUrl, {
15+
method: 'POST',
16+
headers: {
17+
'Content-Type': 'application/xml'
18+
},
19+
body: `<?xml version="1.0" encoding="UTF-8"?>
20+
<svs:SclValidateRequest xmlns:svs="${SVS_NAMESPACE}">
21+
<svs:SclData><![CDATA[${new XMLSerializer().serializeToString(doc.documentElement)}]]></svs:SclData>
22+
</svs:SclValidateRequest>`
23+
}).catch(handleError)
24+
.then(handleResponse)
25+
.then(parseXml);
26+
},
27+
}
28+
}

src/compas/CompasSettings.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {dispatchEventOnOpenScd} from "./foundation.js";
1010

1111
export type CompasSettingsRecord = {
1212
sclDataServiceUrl: string;
13+
sclValidatorServiceUrl: string;
1314
cimMappingServiceUrl: string;
1415
sclAutoAlignmentServiceUrl: string;
1516
};
@@ -20,6 +21,7 @@ export function CompasSettings() {
2021
get compasSettings(): CompasSettingsRecord {
2122
return {
2223
sclDataServiceUrl: this.getCompasSetting('sclDataServiceUrl'),
24+
sclValidatorServiceUrl: this.getCompasSetting('sclValidatorServiceUrl'),
2325
cimMappingServiceUrl: this.getCompasSetting('cimMappingServiceUrl'),
2426
sclAutoAlignmentServiceUrl: this.getCompasSetting('sclAutoAlignmentServiceUrl'),
2527
};
@@ -28,6 +30,7 @@ export function CompasSettings() {
2830
get defaultSettings(): CompasSettingsRecord {
2931
return {
3032
sclDataServiceUrl: '/compas-scl-data-service',
33+
sclValidatorServiceUrl: '/compas-scl-validator',
3134
cimMappingServiceUrl: '/compas-cim-mapping',
3235
sclAutoAlignmentServiceUrl: '/compas-scl-auto-alignment'
3336
}
@@ -57,6 +60,10 @@ export class CompasSettingsElement extends LitElement {
5760
return <TextFieldBase>this.shadowRoot!.querySelector('mwc-textfield[id="sclDataServiceUrl"]');
5861
}
5962

63+
getSclValidatorServiceUrlField(): TextFieldBase {
64+
return <TextFieldBase>this.shadowRoot!.querySelector('mwc-textfield[id="sclValidatorServiceUrl"]');
65+
}
66+
6067
getCimMappingServiceUrlField(): TextFieldBase {
6168
return <TextFieldBase>this.shadowRoot!.querySelector('mwc-textfield[id="cimMappingServiceUrl"]');
6269
}
@@ -67,6 +74,7 @@ export class CompasSettingsElement extends LitElement {
6774

6875
valid(): boolean {
6976
return this.getSclDataServiceUrlField().checkValidity()
77+
&& this.getSclValidatorServiceUrlField().checkValidity()
7078
&& this.getCimMappingServiceUrlField().checkValidity()
7179
&& this.getSclAutoAlignmentServiceUrlField().checkValidity();
7280
}
@@ -78,6 +86,7 @@ export class CompasSettingsElement extends LitElement {
7886

7987
// Update settings from TextField.
8088
CompasSettings().setCompasSetting('sclDataServiceUrl', this.getSclDataServiceUrlField().value);
89+
CompasSettings().setCompasSetting('sclValidatorServiceUrl', this.getSclValidatorServiceUrlField().value);
8190
CompasSettings().setCompasSetting('cimMappingServiceUrl', this.getCimMappingServiceUrlField().value);
8291
CompasSettings().setCompasSetting('sclAutoAlignmentServiceUrl', this.getSclAutoAlignmentServiceUrlField().value);
8392
return true;
@@ -101,6 +110,10 @@ export class CompasSettingsElement extends LitElement {
101110
label="${translate('compas.settings.sclDataServiceUrl')}"
102111
value="${this.compasSettings.sclDataServiceUrl}" required>
103112
</mwc-textfield>
113+
<mwc-textfield dialogInitialFocus id="sclValidatorServiceUrl"
114+
label="${translate('compas.settings.sclValidatorServiceUrl')}"
115+
value="${this.compasSettings.sclValidatorServiceUrl}" required>
116+
</mwc-textfield>
104117
<mwc-textfield id="cimMappingServiceUrl"
105118
label="${translate('compas.settings.cimMappingServiceUrl')}"
106119
value="${this.compasSettings.cimMappingServiceUrl}" required>

src/translations/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ export const de: Translations = {
635635
settings: {
636636
title: 'CoMPAS Einstellungen',
637637
sclDataServiceUrl: 'CoMPAS SCL Data Service URL',
638+
sclValidatorServiceUrl: 'CoMPAS SCL Validator Service URL',
638639
cimMappingServiceUrl: 'CoMPAS CIM Mapping Service URL',
639640
sclAutoAlignmentServiceUrl: 'CoMPAS SCL Auto Alignment Service URL',
640641
},

src/translations/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ export const en = {
630630
settings: {
631631
title: 'CoMPAS Settings',
632632
sclDataServiceUrl: 'CoMPAS SCL Data Service URL',
633+
sclValidatorServiceUrl: 'CoMPAS SCL Validator Service URL',
633634
cimMappingServiceUrl: 'CoMPAS CIM Mapping Service URL',
634635
sclAutoAlignmentServiceUrl: 'CoMPAS SCL Auto Alignment Service URL',
635636
},
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {LitElement, property} from "lit-element";
2+
3+
import {newIssueEvent} from "../foundation.js";
4+
5+
import {CompasSclValidatorService, SVS_NAMESPACE} from "../compas-services/CompasValidatorService.js";
6+
import {createLogEvent} from "../compas-services/foundation.js";
7+
import {dispatchEventOnOpenScd, getTypeFromDocName} from "../compas/foundation.js";
8+
9+
export default class ValidateTemplates extends LitElement {
10+
@property({ attribute: false })
11+
doc!: XMLDocument;
12+
13+
@property({ type: String })
14+
docName!: string;
15+
16+
@property()
17+
pluginId!: string;
18+
19+
async validate(manual: boolean): Promise<void> {
20+
// We don't want to externally validate every time a save is done. So only start the validation when manually triggered.
21+
if (!manual) {
22+
return;
23+
}
24+
25+
const docType = getTypeFromDocName(this.docName);
26+
await CompasSclValidatorService().validateSCL(docType, this.doc)
27+
.then(document => {
28+
const validationErrors = Array.from(document.querySelectorAll('SclValidateResponse > ValidationErrors') ?? []);
29+
// Check if there are validation errors, if there are we will process them.
30+
if (validationErrors.length > 0) {
31+
validationErrors.forEach(validationError => {
32+
const message = validationError.getElementsByTagNameNS(SVS_NAMESPACE, "Message")!.item(0)!.textContent;
33+
dispatchEventOnOpenScd(
34+
newIssueEvent({
35+
validatorId: this.pluginId,
36+
title: message ?? 'No message'
37+
})
38+
);
39+
})
40+
}
41+
})
42+
.catch(createLogEvent);
43+
}
44+
}

test/integration/__snapshots__/open-scd.test.snap.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ snapshots["open-scd looks like its snapshot"] =
125125
Redo
126126
</span>
127127
</mwc-list-item>
128+
<mwc-list-item
129+
aria-disabled="true"
130+
class="validator"
131+
disabled=""
132+
graphic="icon"
133+
iconid="rule_folder"
134+
mwc-list-item=""
135+
tabindex="-1"
136+
>
137+
<mwc-icon slot="graphic">
138+
rule_folder
139+
</mwc-icon>
140+
<span>
141+
Validate using OCL
142+
</span>
143+
<mwc-linear-progress indeterminate="">
144+
</mwc-linear-progress>
145+
</mwc-list-item>
128146
<mwc-list-item
129147
aria-disabled="true"
130148
class="validator"
@@ -854,6 +872,22 @@ snapshots["open-scd looks like its snapshot"] =
854872
role="separator"
855873
>
856874
</li>
875+
<mwc-check-list-item
876+
aria-disabled="false"
877+
class="official"
878+
graphic="control"
879+
hasmeta=""
880+
left=""
881+
mwc-list-item=""
882+
selected=""
883+
tabindex="-1"
884+
value="/src/validators/ValidateSchemaWithCompas.js"
885+
>
886+
<mwc-icon slot="meta">
887+
rule_folder
888+
</mwc-icon>
889+
Validate using OCL
890+
</mwc-check-list-item>
857891
<mwc-check-list-item
858892
aria-disabled="false"
859893
class="official"

test/unit/Plugging.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@ describe('PluggingElement', () => {
168168
).to.have.property('position');
169169
});
170170
it('adds a new validator kind plugin on add button click', async () => {
171-
expect(element.validators).to.have.lengthOf(2);
171+
expect(element.validators).to.have.lengthOf(3);
172172
src.value = 'http://example.com/plugin.js';
173173
name.value = 'testName';
174174
validatorKindOption.click();
175175
await src.updateComplete;
176176
await name.updateComplete;
177177
primaryAction.click();
178178
await element.updateComplete;
179-
expect(element.validators).to.have.lengthOf(3);
179+
expect(element.validators).to.have.lengthOf(4);
180180
});
181181
});
182182
});

0 commit comments

Comments
 (0)