Skip to content

Commit 0405921

Browse files
feat(nsdToJson): add CDC support
1 parent 181432e commit 0405921

File tree

8 files changed

+209
-112
lines changed

8 files changed

+209
-112
lines changed

tDataTypeTemplates/nsdToJson.spec.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import {
77
nsd7420,
88
nsd81,
99
} from "../foundation/codecomponents/nsds.js";
10-
import { lnClass74, lnClassData } from "./nsdToJson/testNsdJson.js";
10+
import { cdcData, lnClass74, lnClassData } from "./nsdToJson/testNsdJson.js";
1111

12-
import { nsdToJson } from "./nsdToJson.js";
12+
import { nsdToJson, supportedCdc } from "./nsdToJson.js";
1313

1414
const doc72 = new DOMParser().parseFromString(nsd72, "application/xml");
1515
const doc73 = new DOMParser().parseFromString(nsd73, "application/xml");
@@ -21,6 +21,9 @@ describe("NSD to Json parsing function", () => {
2121
it("return undefined for invalid ln class", () =>
2222
expect(nsdToJson("invalid")).to.be.undefined);
2323

24+
it("return undefined for unsupported CDC", () =>
25+
expect(nsdToJson("ENS")).to.be.undefined);
26+
2427
it("returns object that compares well to static 7-4 ln classes", async () => {
2528
lnClass74.forEach((lnClass) => {
2629
const data = nsdToJson(lnClass)!;
@@ -32,6 +35,17 @@ describe("NSD to Json parsing function", () => {
3235
});
3336
}).timeout(10000);
3437

38+
it("returns object that compares well to static 7-3 ln classes", async () => {
39+
supportedCdc.forEach((cdc) => {
40+
const data = nsdToJson(cdc)!;
41+
const commonDataClass = cdcData[cdc];
42+
43+
Object.keys(commonDataClass).forEach((key) => {
44+
expect(data[key]).to.deep.equal(commonDataClass[key]);
45+
});
46+
});
47+
}).timeout(10000);
48+
3549
it("returns object that compares well to static 7-420 classes", async () => {
3650
const data = nsdToJson("DSTK");
3751
expect(data).to.not.be.undefined;

tDataTypeTemplates/nsdToJson.ts

Lines changed: 117 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,48 @@ type CdcDescription = {
104104

105105
export type LNodeDescription = Record<string, CdcDescription>;
106106

107+
export const supportedCdc = [
108+
"ACD",
109+
"ACT",
110+
"APC",
111+
"ASG",
112+
"BAC",
113+
"BCR",
114+
"BSC",
115+
"CMV",
116+
"DEL",
117+
"DPC",
118+
"DPL",
119+
"HDEL",
120+
"HMV",
121+
"HST",
122+
"HWYE",
123+
"INC",
124+
"INS",
125+
"ISC",
126+
"LPL",
127+
"MV",
128+
"ORG",
129+
"ORS",
130+
"SAV",
131+
"SEC",
132+
"SEQ",
133+
"SPC",
134+
"SPG",
135+
"SPS",
136+
"TCS",
137+
"TSG",
138+
"VSG",
139+
"VSS",
140+
"WYE",
141+
] as const;
142+
const cdcTag = new Set<string>(supportedCdc);
143+
export type SCLTag = (typeof supportedCdc)[number];
144+
145+
export function isSupportedCdc(cdc: string): cdc is SCLTag {
146+
return cdcTag.has(cdc);
147+
}
148+
107149
export type NameSpaceDescription = {
108150
"72"?: XMLDocument;
109151
"73"?: XMLDocument;
@@ -123,7 +165,7 @@ const defaultDoc81 = new DOMParser().parseFromString(nsd81, "application/xml");
123165

124166
/** A utility function that returns a JSON containing the structure of a logical node class
125167
* as described in the IEC 61850-7-4 and IEC 61850-7-420 as JSON
126-
* @param lnClass the logical node class to be constructed
168+
* @param lnClassOrCdc the logical node class to be constructed
127169
* @param nsds user defined NSD files defaulting to
128170
* 8-1: 2003A2
129171
* 7-4: 2007B3
@@ -133,19 +175,13 @@ const defaultDoc81 = new DOMParser().parseFromString(nsd81, "application/xml");
133175
* @returns A JSON object represeting NSD information of a logical node
134176
*/
135177
export function nsdToJson(
136-
lnClass: string,
178+
lnClassOrCdc: string,
137179
nsds?: NameSpaceDescription,
138-
): LNodeDescription | undefined {
180+
): LNodeDescription | CdcChildren | undefined {
181+
139182
const doc74 = nsds && nsds["74"] ? nsds["74"] : defaultDoc74;
140183
const doc7420 = nsds && nsds["7420"] ? nsds["7420"] : defaultDoc7420;
141-
const nsdLnClass74 = doc74.querySelector(`LNClass[name="${lnClass}"]`);
142-
const nsdLnClass7420 = doc7420.querySelector(`LNClass[name="${lnClass}"]`);
143-
144-
const nsdLnClass = nsdLnClass74 || nsdLnClass7420;
145-
if (!nsdLnClass) return undefined;
146-
147-
const lnClassJson: LNodeDescription = {};
148-
184+
149185
function getServiceConstructedAttributes(
150186
serviceDataAttribute: Element,
151187
): Element[] {
@@ -161,18 +197,23 @@ export function nsdToJson(
161197
);
162198
}
163199

164-
function getServiceDataAttributes(dataObject: Element): Element[] {
200+
function getServiceDataAttributesType(type : string | null): Element[] {
165201
const doc81 = nsds && nsds["81"] ? nsds["81"] : defaultDoc81;
166202

167-
const type = dataObject.getAttribute("type");
168203
return Array.from(
169204
doc81
170205
.querySelector(`ServiceCDCs > ServiceCDC[cdc="${type}"]`)
171206
?.querySelectorAll("ServiceDataAttribute") ?? [],
172207
);
173208
}
174209

175-
function getSubDataAttributesType(type: string): Element[] {
210+
function getServiceDataAttributes(dataObject: Element): Element[] {
211+
const type = dataObject.getAttribute("type");
212+
213+
return getServiceDataAttributesType(type);
214+
}
215+
216+
function getSubDataAttributesType(type: string | null): Element[] {
176217
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
177218
const doc72 = nsds && nsds["72"] ? nsds["72"] : defaultDoc72;
178219

@@ -190,27 +231,14 @@ export function nsdToJson(
190231
}
191232

192233
function getSubDataAttributes(dataAttribute: Element): Element[] {
193-
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
194-
const doc72 = nsds && nsds["72"] ? nsds["72"] : defaultDoc72;
195-
196234
const type = dataAttribute.getAttribute("type");
197-
return Array.from(
198-
doc73
199-
.querySelector(`ConstructedAttribute[name="${type}"]`)
200-
?.querySelectorAll(":scope > SubDataAttribute") ?? [],
201-
).concat(
202-
Array.from(
203-
doc72
204-
.querySelector(`ConstructedAttribute[name="${type}"]`)
205-
?.querySelectorAll(":scope > SubDataAttribute") ?? [],
206-
),
207-
);
235+
236+
return getSubDataAttributesType(type)
208237
}
209238

210-
function getDataAttributes(dataObject: Element): Element[] {
239+
function getDataAttributesType(type:string|null): Element[] {
211240
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
212241

213-
const type = dataObject.getAttribute("type");
214242
if (
215243
["CSG", "CURVE", "ENG", "ING", "ASG", "SPG", "TSG", "VSG"].includes(
216244
`${type}`,
@@ -228,16 +256,28 @@ export function nsdToJson(
228256
);
229257
}
230258

231-
function getSubDataObjects(dataObject: Element): Element[] {
232-
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
259+
function getDataAttributes(dataObject: Element): Element[] {
233260
const type = dataObject.getAttribute("type");
261+
262+
return getDataAttributesType(type);
263+
}
264+
265+
function getSubDataObjectsType(type: string | null): Element[] {
266+
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
267+
234268
return Array.from(
235269
doc73
236270
.querySelector(`CDC[name="${type}"]`)
237271
?.querySelectorAll("SubDataObject") ?? [],
238272
);
239273
}
240274

275+
function getSubDataObjects(dataObject: Element): Element[] {
276+
const type = dataObject.getAttribute("type");
277+
278+
return getSubDataObjectsType(type)
279+
}
280+
241281
function getDataObjects(lnClass: Element): Element[] {
242282
const baseClass = lnClass.ownerDocument.querySelector(
243283
`AbstractLNClass[name="${lnClass.getAttribute("base")}"]`,
@@ -579,11 +619,51 @@ export function nsdToJson(
579619
return data;
580620
}
581621

582-
getDataObjects(nsdLnClass).forEach((dataObject) => {
583-
const name = dataObject.getAttribute("name")!;
622+
function CdcChildren(type: string): CdcChildren {
623+
624+
const children: CdcChildren = {};
625+
getSubDataObjectsType(type).forEach((dataObject) => {
626+
const name = dataObject.getAttribute("name")!;
627+
628+
children[name] = nsdDataObject(dataObject);
629+
});
630+
631+
getDataAttributesType(type).forEach((dataAttribute) => {
632+
const name = dataAttribute.getAttribute("name")!;
584633

585-
lnClassJson[name] = nsdDataObject(dataObject);
586-
});
634+
children[name] = nsdDataAttribute(
635+
dataAttribute,
636+
undefined,
637+
undefined,
638+
);
639+
});
640+
641+
getServiceDataAttributesType(type).forEach((serviceDataAttribute) => {
642+
const name = serviceDataAttribute.getAttribute("name")!;
643+
644+
children[name] = nsdServiceDataAttribute(serviceDataAttribute);
645+
});
646+
647+
return children;
648+
}
649+
650+
if (lnClassOrCdc === undefined) return;
651+
else if (isSupportedCdc(lnClassOrCdc))
652+
return CdcChildren(lnClassOrCdc);
653+
else {
654+
const nsdLnClass74 = doc74.querySelector(`LNClass[name="${lnClassOrCdc}"]`);
655+
const nsdLnClass7420 = doc7420.querySelector(`LNClass[name="${lnClassOrCdc}"]`);
656+
657+
const nsdLnClass = nsdLnClass74 || nsdLnClass7420;
658+
if (!nsdLnClass) return undefined;
659+
660+
const lnClassJson: LNodeDescription = {};
661+
getDataObjects(nsdLnClass).forEach((dataObject) => {
662+
const name = dataObject.getAttribute("name")!;
663+
664+
lnClassJson[name] = nsdDataObject(dataObject);
665+
});
587666

588-
return lnClassJson;
667+
return lnClassJson
668+
}
589669
}

tDataTypeTemplates/nsdToJson/testJson/ARIS.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,13 @@
1-
import { acdChildren } from "./ACD.js";
2-
import { actChildren } from "./ACT.js";
3-
import { apcChildren } from "./APC.js";
4-
import { asgChildren } from "./ASG.js";
5-
import { bacChildren } from "./BAC.js";
6-
import { bcrChildren } from "./BCR.js";
7-
import { bscChildren } from "./BSC.js";
81
import { cmvChildren } from "./CMV.js";
9-
import { delChildren } from "./DEL.js";
10-
import { dpcChildren } from "./DPC.js";
11-
import { dplChildren } from "./DPL.js";
12-
import { hdelChildren } from "./HDEL.js";
13-
import { hmvChildren } from "./HMV.js";
14-
import { hstChildren } from "./HST.js";
15-
import { hwyeChildren } from "./HWYE.js";
162
import { incChildren } from "./INC.js";
173
import { ingChildren } from "./ING.js";
184
import { insChildren } from "./INS.js";
195
import { lplChildren } from "./LPL.js";
206
import { mvChildren } from "./MV.js";
217
import { orgChildren } from "./ORG.js";
22-
import { orsChildren } from "./ORS.js";
23-
import { savChildren } from "./SAV.js";
24-
import { secChildren } from "./SEC.js";
25-
import { seqChildren } from "./SEQ.js";
268
import { spcChildren } from "./SPC.js";
279
import { spsChildren } from "./SPS.js";
28-
import { tscChildren } from "./TSC.js";
29-
import { tsgChildren } from "./TSG.js";
30-
import { vsgChildren } from "./VSG.js";
31-
import { vssChildren } from "./VSS.js";
32-
import { wyeChildren } from "./WYE.js";
10+
3311
export const aris = {
3412
Auto: {
3513
tagName: "DataObject",

tDataTypeTemplates/nsdToJson/testJson/FSCH.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { orgChildren } from "./ORG.js";
77
import { spcChildren } from "./SPC.js";
88
import { spsChildren } from "./SPS.js";
99
import { spgChildren } from "./SPG.js";
10-
import { tscChildren } from "./TSC.js";
10+
import { tcsChildren } from "./TCS.js";
1111
import { tsgChildren } from "./TSG.js";
1212

1313
export const fsch = {
@@ -1551,7 +1551,7 @@ export const fsch = {
15511551
descID: "IEC61850_7_4.LNGroupF::FSCH.ActStrTm.desc",
15521552
presCond: "O",
15531553
dsPresCond: "na",
1554-
children: tscChildren,
1554+
children: tcsChildren,
15551555
},
15561556
NxtStrTm: {
15571557
tagName: "DataObject",
@@ -1561,7 +1561,7 @@ export const fsch = {
15611561
mandatory: true,
15621562
presCond: "M",
15631563
dsPresCond: "na",
1564-
children: tscChildren,
1564+
children: tcsChildren,
15651565
},
15661566
SchdEnaErr: {
15671567
tagName: "DataObject",

tDataTypeTemplates/nsdToJson/testJson/IARC.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,11 @@
1-
import { acdChildren } from "./ACD.js";
2-
import { actChildren } from "./ACT.js";
3-
import { apcChildren } from "./APC.js";
4-
import { asgChildren } from "./ASG.js";
5-
import { bacChildren } from "./BAC.js";
6-
import { bcrChildren } from "./BCR.js";
7-
import { bscChildren } from "./BSC.js";
8-
import { cmvChildren } from "./CMV.js";
9-
import { delChildren } from "./DEL.js";
10-
import { dpcChildren } from "./DPC.js";
111
import { dplChildren } from "./DPL.js";
12-
import { hdelChildren } from "./HDEL.js";
13-
import { hmvChildren } from "./HMV.js";
14-
import { hstChildren } from "./HST.js";
15-
import { hwyeChildren } from "./HWYE.js";
16-
import { incChildren } from "./INC.js";
172
import { ingChildren } from "./ING.js";
183
import { insChildren } from "./INS.js";
194
import { lplChildren } from "./LPL.js";
20-
import { mvChildren } from "./MV.js";
215
import { orgChildren } from "./ORG.js";
22-
import { orsChildren } from "./ORS.js";
23-
import { savChildren } from "./SAV.js";
24-
import { secChildren } from "./SEC.js";
25-
import { seqChildren } from "./SEQ.js";
266
import { spcChildren } from "./SPC.js";
277
import { spsChildren } from "./SPS.js";
28-
import { tscChildren } from "./TSC.js";
29-
import { tsgChildren } from "./TSG.js";
30-
import { vsgChildren } from "./VSG.js";
31-
import { vssChildren } from "./VSS.js";
32-
import { wyeChildren } from "./WYE.js";
8+
339
export const iarc = {
3410
EEName: {
3511
tagName: "DataObject",

0 commit comments

Comments
 (0)