Skip to content

Commit dffb8c5

Browse files
committed
fix(tLN): Make supervision removal only remove Val textContent (closes #129)
1 parent 0ce54df commit dffb8c5

File tree

3 files changed

+46
-49
lines changed

3 files changed

+46
-49
lines changed

tDataSet/removeDataSet.spec.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ import { removeDataSet } from "./removeDataSet.js";
1010
describe("Utility function to remove DataSet element", () => {
1111
const dataSet = findElement(
1212
withSubscriptionSupervision,
13-
"DataSet",
13+
"DataSet"
1414
) as Element;
1515
const edits = removeDataSet({ node: dataSet });
1616
const extRefs = Array.from(
1717
dataSet.ownerDocument.querySelectorAll(
18-
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"], ExtRef[srcCBName="someGse3"]',
19-
),
18+
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"], ExtRef[srcCBName="someGse3"]'
19+
)
2020
);
21-
const doi = extRefs[0].ownerDocument.querySelector(
22-
'LN[lnClass="LGOS"][inst="1"] > DOI',
21+
const val = extRefs[0].ownerDocument.querySelector(
22+
'LN[lnClass="LGOS"][inst="1"] > DOI[name="GoCBRef"] > DAI[name="setSrcRef"] > Val'
2323
)!;
24-
const ln = extRefs[0].ownerDocument.querySelector(
25-
'LN[lnClass="LGOS"][inst="2"]',
24+
const val2 = extRefs[0].ownerDocument.querySelector(
25+
'LN[lnClass="LGOS"][inst="2"] > DOI[name="GoCBRef"] > DAI[name="setSrcRef"] > Val'
2626
);
2727

2828
it("returns empty string when remove.node is not DataSet", () =>
29-
expect(removeDataSet({ node: doi })).to.be.empty);
29+
expect(removeDataSet({ node: val })).to.be.empty);
3030

3131
it("removes DataSet also removes/updates dependant data", () =>
3232
expect(edits.length).to.equal(10));
@@ -42,8 +42,8 @@ describe("Utility function to remove DataSet element", () => {
4242
});
4343

4444
it("including the subscriber supervision", () => {
45-
expect((edits[5] as Remove).node).to.equal(doi);
46-
expect((edits[6] as Remove).node).to.equal(ln);
45+
expect((edits[5] as Remove).node).to.equal(val!.firstChild);
46+
expect((edits[6] as Remove).node).to.equal(val2!.firstChild);
4747
});
4848

4949
it("including control Block updates", () => {

tExtRef/unsubscribe.spec.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function findElements(str: string, selector: string): Element[] {
1313
return Array.from(
1414
new DOMParser()
1515
.parseFromString(str, "application/xml")
16-
.querySelectorAll(selector),
16+
.querySelectorAll(selector)
1717
);
1818
}
1919

@@ -70,7 +70,7 @@ describe("Function allowing to unsubscribe multiple external references", () =>
7070
it("does not remove ICT defined Ed2.1 attributes", () => {
7171
const extRef = findElement(
7272
laterBindingExtRefs,
73-
'ExtRef[intAddr="someOtherIntAddr"]',
73+
'ExtRef[intAddr="someOtherIntAddr"]'
7474
)!;
7575
const edits = unsubscribe([extRef]);
7676

@@ -89,16 +89,15 @@ describe("Function allowing to unsubscribe multiple external references", () =>
8989
it("per default remove subscription LGOS supervision as well", () => {
9090
const extRefs = findElements(
9191
withSubscriptionSupervision,
92-
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"]',
92+
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"]'
9393
);
9494
const edits = unsubscribe(extRefs);
95-
const doi = extRefs[0].ownerDocument.querySelector(
96-
'LN[lnClass="LGOS"][inst="1"] > DOI',
95+
const val = extRefs[0].ownerDocument.querySelector(
96+
'LN[lnClass="LGOS"][inst="1"] > DOI[name="GoCBRef"] > DAI[name="setSrcRef"] > Val'
9797
);
98-
const ln = extRefs[0].ownerDocument.querySelector(
99-
'LN[lnClass="LGOS"][inst="2"]',
98+
const val2 = extRefs[0].ownerDocument.querySelector(
99+
'LN[lnClass="LGOS"][inst="2"] > DOI[name="GoCBRef"] > DAI[name="setSrcRef"] > Val'
100100
);
101-
102101
expect(edits.length).to.equal(5);
103102
expect(edits[0]).to.satisfies(isRemove);
104103
expect((edits[0] as Remove).node).to.equal(extRefs[0]);
@@ -107,15 +106,15 @@ describe("Function allowing to unsubscribe multiple external references", () =>
107106
expect(edits[2]).to.satisfies(isUpdate);
108107
expect((edits[2] as Update).element).to.equal(extRefs[2]);
109108
expect(edits[3]).to.satisfies(isRemove);
110-
expect((edits[3] as Remove).node).to.equal(doi);
109+
expect((edits[3] as Remove).node).to.equal(val!.firstChild);
111110
expect(edits[4]).to.satisfies(isRemove);
112-
expect((edits[4] as Remove).node).to.equal(ln);
111+
expect((edits[4] as Remove).node).to.equal(val2!.firstChild);
113112
});
114113

115114
it("with ignoreSupervision do not remove subscription LGOS supervision", () => {
116115
const extRefs = findElements(
117116
withSubscriptionSupervision,
118-
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"]',
117+
'ExtRef[srcCBName="someGse"], ExtRef[srcCBName="someGse2"]'
119118
);
120119
const edits = unsubscribe(extRefs, { ignoreSupervision: true });
121120

@@ -131,7 +130,7 @@ describe("Function allowing to unsubscribe multiple external references", () =>
131130
it("does not remove subscription supervision with remaining connections", () => {
132131
const extRef = findElement(
133132
withSubscriptionSupervision,
134-
'ExtRef[srcCBName="someGse"]',
133+
'ExtRef[srcCBName="someGse"]'
135134
)!;
136135
const edits = unsubscribe([extRef]);
137136

@@ -143,7 +142,7 @@ describe("Function allowing to unsubscribe multiple external references", () =>
143142
it("does not remove subscription supervision without missing object reference", () => {
144143
const extRef = findElement(
145144
withSubscriptionSupervision,
146-
'ExtRef[srcCBName="someGse3"]',
145+
'ExtRef[srcCBName="someGse3"]'
147146
)!;
148147
const edits = unsubscribe([extRef]);
149148

@@ -155,10 +154,10 @@ describe("Function allowing to unsubscribe multiple external references", () =>
155154
it("makes sure to remove subscription LSVS supervision as well", () => {
156155
const extRefs = findElements(
157156
withSubscriptionSupervision,
158-
'ExtRef[srcCBName="someSmv"]',
157+
'ExtRef[srcCBName="someSmv"]'
159158
);
160-
const doi = extRefs[0].ownerDocument.querySelector(
161-
'LN[lnClass="LSVS"][inst="1"] > DOI',
159+
const val = extRefs[0].ownerDocument.querySelector(
160+
'LN[lnClass="LSVS"][inst="1"] > DOI[name="SvCBRef"] > DAI[name="setSrcRef"] > Val'
162161
);
163162
const edits = unsubscribe(extRefs);
164163

@@ -170,13 +169,13 @@ describe("Function allowing to unsubscribe multiple external references", () =>
170169
expect(edits[2]).to.satisfies(isRemove);
171170
expect((edits[2] as Remove).node).to.equal(extRefs[1].parentElement);
172171
expect(edits[3]).to.satisfies(isRemove);
173-
expect((edits[3] as Remove).node).to.equal(doi);
172+
expect((edits[3] as Remove).node).to.equal(val?.firstChild);
174173
});
175174

176175
it("with ignoreSupervision do not remove subscription LGOS supervision", () => {
177176
const extRefs = findElements(
178177
withSubscriptionSupervision,
179-
'ExtRef[srcCBName="someSmv"]',
178+
'ExtRef[srcCBName="someSmv"]'
180179
);
181180
const edits = unsubscribe(extRefs, { ignoreSupervision: true });
182181

@@ -192,7 +191,7 @@ describe("Function allowing to unsubscribe multiple external references", () =>
192191
it("with pServT present, serviceType is removed", () => {
193192
const extRefs = findElements(
194193
laterBindingExtRefs,
195-
'ExtRef[intAddr="someOtherIntAddr"]',
194+
'ExtRef[intAddr="someOtherIntAddr"]'
196195
);
197196
const edits = unsubscribe(extRefs, { ignoreSupervision: true });
198197

@@ -204,14 +203,14 @@ describe("Function allowing to unsubscribe multiple external references", () =>
204203
it("without pServT, serviceType is not removed", () => {
205204
const extRefs = findElements(
206205
laterBindingExtRefs,
207-
'ExtRef[intAddr="someIntAddr"]',
206+
'ExtRef[intAddr="someIntAddr"]'
208207
)[0];
209208
const edits = unsubscribe([extRefs], { ignoreSupervision: true });
210209

211210
expect(edits.length).to.equal(1);
212211
expect((edits[0] as Update).element).to.equal(extRefs);
213212
expect((edits[0] as Update).attributes).to.not.have.own.property(
214-
"serviceType",
213+
"serviceType"
215214
);
216215
});
217216
});

tLN/removeSubscriptionSupervision.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,41 +10,39 @@ type GroupedExtRefs = {
1010
subscriberIed: Element;
1111
};
1212

13-
/** @returns Element to remove the subscription supervision */
13+
/** @returns Element to remove the subscription supervision control block reference */
1414
function removableSupervisionElement(
1515
ctrlBlock: Element,
16-
subscriberIed: Element,
16+
subscriberIed: Element
1717
): Element | null {
1818
const supervisionType = ctrlBlock.tagName === "GSEControl" ? "LGOS" : "LSVS";
1919

2020
const valElement = Array.from(
2121
subscriberIed.querySelectorAll(
22-
`LN[lnClass="${supervisionType}"] > DOI > DAI > Val`,
23-
),
22+
`LN[lnClass="${supervisionType}"] > DOI > DAI > Val`
23+
)
2424
).find((val) => val.textContent === controlBlockObjRef(ctrlBlock));
2525
if (!valElement) return null;
2626

27-
const ln = valElement.closest("LN")!;
28-
const doi = valElement.closest("DOI")!;
27+
const textContentNode = Array.from(valElement.childNodes).find(
28+
(child) => child.nodeType === Node.TEXT_NODE
29+
) as Element;
2930

30-
// do not remove logical nodes `LGOS`, `LSVS` unless privately tagged
31-
const canRemoveLn = ln.querySelector(
32-
':scope > Private[type="OpenSCD.create"]',
33-
);
34-
35-
return canRemoveLn ? ln : doi;
31+
return textContentNode ?? null;
3632
}
3733

3834
/** @returns Whether `DA` with name `setSrcRef` can edited by SCL editor */
3935
function isSupervisionEditable(
4036
ctrlBlock: Element,
41-
subscriberIed: Element,
37+
subscriberIed: Element
4238
): boolean {
4339
const supervisionElement = removableSupervisionElement(
4440
ctrlBlock,
45-
subscriberIed,
41+
subscriberIed
4642
);
47-
const supervisionLn = supervisionElement?.closest("LN") ?? null;
43+
if (!supervisionElement) return false;
44+
45+
const supervisionLn = supervisionElement.parentElement?.closest("LN") ?? null;
4846
if (!supervisionLn) return false;
4947

5048
return isSrcRefEditable(supervisionLn);
@@ -80,7 +78,7 @@ function isControlBlockSubscribed(extRefs: Element[]): boolean {
8078
otherExtRef.getAttribute("srcLDInst") === srcLDInst &&
8179
otherExtRef.getAttribute("srcLNClass") === srcLNClass &&
8280
otherExtRef.getAttribute("iedName") === iedName &&
83-
otherExtRef.getAttribute("serviceType") === serviceType,
81+
otherExtRef.getAttribute("serviceType") === serviceType
8482
);
8583
}
8684

@@ -92,7 +90,7 @@ function cannotRemoveSupervision(extRefGroup: GroupedExtRefs): boolean {
9290
}
9391

9492
function groupPerControlBlock(
95-
extRefs: Element[],
93+
extRefs: Element[]
9694
): Record<string, GroupedExtRefs> {
9795
const groupedExtRefs: Record<string, GroupedExtRefs> = {};
9896
extRefs.forEach((extRef) => {
@@ -130,7 +128,7 @@ export function removeSubscriptionSupervision(extRefs: Element[]): Remove[] {
130128

131129
return removableSupervisionElement(
132130
extRefGroup.ctrlBlock,
133-
extRefGroup.subscriberIed,
131+
extRefGroup.subscriberIed
134132
)!;
135133
})
136134
.filter((element) => element) as Element[]

0 commit comments

Comments
 (0)