diff --git a/describe.spec.ts b/describe.spec.ts
index 6b0e7b9c..8222f419 100644
--- a/describe.spec.ts
+++ b/describe.spec.ts
@@ -14,15 +14,15 @@ const testScl = new DOMParser().parseFromString(
-
-
-
+
+
-
+
+
@@ -114,13 +114,9 @@ const baseEnumType = testScl.querySelector("#someID")!;
const diffEnumType = testScl.querySelector("#someDiffID")!;
const equalEnumType = testScl.querySelector("#someOtherID")!;
-const baseLN = testScl.querySelector(`LN[lnType="baseXCBR"]`)!;
-const equalLN = testScl.querySelector(`LN[lnType="equalXCBR"]`)!;
-const diffLN = testScl.querySelector(`LN[lnType="diffXCBR"]`)!;
-
-const baseLN0 = testScl.querySelector(`LDevice[inst="ldInst1"]>LN0`)!;
-const equalLN0 = testScl.querySelector(`LDevice[inst="ldInst2"]>LN0`)!;
-const diffLN0 = testScl.querySelector(`LDevice[inst="ldInst3"]>LN0`)!;
+const baseLDevice = testScl.querySelector(`LDevice[inst="ldInst1"]`)!;
+const equalLDevice = testScl.querySelector(`LDevice[inst="ldInst2"]`)!;
+const diffLDevice = testScl.querySelector(`LDevice[inst="ldInst3"]`)!;
describe("Describe SCL elements function", () => {
it("returns undefined with missing describe function", () =>
@@ -139,23 +135,13 @@ describe("Describe SCL elements function", () => {
JSON.stringify(describeSclElement(equalEnumType)),
));
- it("returns same description with semantically equal LN0's", () =>
- expect(JSON.stringify(describeSclElement(baseLN0))).to.equal(
- JSON.stringify(describeSclElement(equalLN0)),
- ));
-
- it("returns different description with unequal LN0 elements", () =>
- expect(JSON.stringify(describeSclElement(baseLN0))).to.not.equal(
- JSON.stringify(describeSclElement(diffLN0)),
- ));
-
- it("returns same description with semantically equal LN's", () =>
- expect(JSON.stringify(describeSclElement(baseLN))).to.equal(
- JSON.stringify(describeSclElement(equalLN)),
+ it("returns same description with semantically equal LDevice's", () =>
+ expect(JSON.stringify(describeSclElement(baseLDevice))).to.equal(
+ JSON.stringify(describeSclElement(equalLDevice)),
));
- it("returns different description with unequal LN elements", () =>
- expect(JSON.stringify(describeSclElement(baseLN))).to.not.equal(
- JSON.stringify(describeSclElement(diffLN)),
+ it("returns different description with unequal LDevice elements", () =>
+ expect(JSON.stringify(describeSclElement(baseLDevice))).to.not.equal(
+ JSON.stringify(describeSclElement(diffLDevice)),
));
});
diff --git a/describe.ts b/describe.ts
index f65f066d..c5da5b88 100644
--- a/describe.ts
+++ b/describe.ts
@@ -3,6 +3,7 @@ import { Text, TextDescription } from "./describe/Text.js";
import { EnumType, EnumTypeDescription } from "./describe/EnumType.js";
import { DAType, DATypeDescription } from "./describe/DAType.js";
import { DOType, DOTypeDescription } from "./describe/DOType.js";
+import { LDevice, LDeviceDescription } from "./describe/LDevice.js";
import { LNodeType, LNodeTypeDescription } from "./describe/LNodeType.js";
import { LN, LNDescription } from "./describe/LN.js";
import { LN0, LN0Description } from "./describe/LN0.js";
@@ -16,7 +17,8 @@ export type Description =
| DOTypeDescription
| LNodeTypeDescription
| LNDescription
- | LN0Description;
+ | LN0Description
+ | LDeviceDescription;
const sclElementDescriptors: Partial<
Record Description | undefined>
> = {
@@ -28,6 +30,7 @@ const sclElementDescriptors: Partial<
LNodeType,
LN,
LN0,
+ LDevice,
};
export function describe(element: Element): Description | undefined {
diff --git a/describe/LDevice.spec.ts b/describe/LDevice.spec.ts
new file mode 100644
index 00000000..9604560d
--- /dev/null
+++ b/describe/LDevice.spec.ts
@@ -0,0 +1,294 @@
+import { expect } from "chai";
+import { LDevice } from "./LDevice.js";
+
+const scl = new DOMParser().parseFromString(
+ `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ on
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.10
+ 30.30
+ 20.20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test
+
+
+
+
+
+
+
+
+
+ 10.10
+ 30.30
+ 20.20
+
+
+
+ Some AccessControl Own Namespace thingy!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+ on
+
+
+
+
+ on
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 60.60
+ 10.10
+ 40.10
+
+
+
+
+ 30.30
+ 10.10
+ 20.20
+
+
+
+ on
+ test
+ off
+
+
+ on
+ test
+
+
+ `,
+ "application/xml",
+);
+
+/*
+const missingLnType = scl.querySelector('*[desc="missingLnType"]')!;
+const invalidLnType = scl.querySelector('*[desc="invalidLnType"]')!;
+const invalidLnTypeDescription = scl.querySelector(
+ '*[desc="invalidLnTypeDescription"]'
+)!; */
+
+const baseLDevice = scl.querySelector(`LDevice[inst="lDevice1"]`)!;
+const equalLDevice = scl.querySelector('LDevice[inst="lDevice2"]')!;
+const diffLDevice = scl.querySelector('LDevice[inst="lDevice3"]')!;
+const missingLLN0 = scl.querySelector('LDevice[inst="lDevice4"]')!;
+const missingLnType = scl.querySelector('LDevice[inst="lDevice5"]')!;
+const invalidLnType = scl.querySelector('LDevice[inst="lDevice6"]')!;
+const missingInst = scl.querySelector('LDevice[inst="lDevice7"]')!;
+const undefinedLN = scl.querySelector('LDevice[inst="lDevice8"]')!;
+
+describe("Description for SCL schema type LDevice", () => {
+ it("returns undefined with missing lnType attribute", () =>
+ expect(LDevice(missingLLN0)).to.be.undefined);
+
+ it("returns undefined with missing lnType attribute", () =>
+ expect(LDevice(missingLnType)).to.be.undefined);
+
+ it("returns undefined with invalid lnType attribute", () =>
+ expect(LDevice(invalidLnType)).to.be.undefined);
+
+ it("returns undefined with missing lnType attribute", () =>
+ expect(LDevice(missingInst)).to.be.undefined);
+
+ it("returns undefined with at least one undefined LNDescription", () =>
+ expect(LDevice(undefinedLN)).to.be.undefined);
+
+ it("return ldName attribute if present", () =>
+ expect(LDevice(diffLDevice)?.ldName).to.equal("ldName"));
+
+ it("return AccessControl child as a string if present", () =>
+ expect(LDevice(diffLDevice)?.accessControl).to.equal(
+ `Some AccessControl Own Namespace thingy!`,
+ ));
+
+ it("returns same description with semantically equal LDevice's", () =>
+ expect(JSON.stringify(LDevice(baseLDevice))).to.equal(
+ JSON.stringify(LDevice(equalLDevice)),
+ ));
+
+ it("returns different description with unequal LDevice elements", () =>
+ expect(JSON.stringify(LDevice(baseLDevice))).to.not.equal(
+ JSON.stringify(LDevice(diffLDevice)),
+ ));
+});
diff --git a/describe/LDevice.ts b/describe/LDevice.ts
new file mode 100644
index 00000000..48b99b0b
--- /dev/null
+++ b/describe/LDevice.ts
@@ -0,0 +1,63 @@
+import { LN0, LN0Description } from "./LN0.js";
+import { LN, LNDescription } from "./LN.js";
+import { NamingDescription, describeNaming } from "./Naming.js";
+import { sortRecord } from "../utils.js";
+
+export interface LDeviceDescription extends NamingDescription {
+ /** LDevice attribute ldName */
+ ldName?: string;
+ /** LDevice child LN0 */
+ ln0: LN0Description;
+ /** LDevice children LN */
+ lns: Record;
+ /** LDevice child AccessControl */
+ accessControl?: string;
+}
+
+export function LDevice(element: Element): LDeviceDescription | undefined {
+ const ln0 = element.querySelector(":scope > LN0");
+ if (!ln0) return;
+
+ const ln0Description = LN0(ln0);
+ if (!ln0Description) return;
+
+ const lns: Record = {};
+ let existUndefinedLns = false;
+ Array.from(element.children)
+ .filter((child) => child.tagName === "LN")
+ .forEach((ln) => {
+ const prefix = ln.getAttribute("prefix");
+ const lnClass = ln.getAttribute("lnClass");
+ const inst = ln.getAttribute("inst");
+ if (!lnClass || !inst) {
+ existUndefinedLns = true;
+ return;
+ }
+
+ const id = `${prefix ? prefix : ""}${lnClass}${inst}`;
+
+ const lnDescription = LN(ln);
+ if (!lnDescription) {
+ existUndefinedLns = true;
+ return;
+ }
+
+ lns[id] = lnDescription;
+ });
+
+ if (existUndefinedLns) return;
+
+ const lDeviceDescription: LDeviceDescription = {
+ ...describeNaming(element),
+ ln0: ln0Description,
+ lns: sortRecord(lns) as Record,
+ };
+
+ const ldName = element.getAttribute("ldName");
+ if (ldName) lDeviceDescription.ldName = ldName;
+
+ const accessControl = element.querySelector(":scope > AccessControl");
+ if (accessControl) lDeviceDescription.accessControl = accessControl.outerHTML;
+
+ return lDeviceDescription;
+}
diff --git a/utils.ts b/utils.ts
index 2ab18c85..407f14ae 100644
--- a/utils.ts
+++ b/utils.ts
@@ -1,6 +1,7 @@
import { DADescription } from "./describe/DADescription.js";
import { DODescription } from "./describe/DODescription.js";
import { GSEControlDescription } from "./describe/GSEControl.js";
+import { LNDescription } from "./describe/LN.js";
import { LogControlDescription } from "./describe/LogControl.js";
import { NamingDescription } from "./describe/Naming.js";
import { ReportControlDescription } from "./describe/ReportControl.js";
@@ -10,6 +11,7 @@ import { SampledValueControlDescription } from "./describe/SampledValueControl.j
type SortedObjects =
| DADescription
| GSEControlDescription
+ | LNDescription
| LogControlDescription
| NamingDescription
| SampledValueControlDescription