Skip to content

Commit 462f62d

Browse files
committed
chore: work in progress
1 parent 572f02b commit 462f62d

File tree

8 files changed

+873
-516
lines changed

8 files changed

+873
-516
lines changed

XMLEditor.spec.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import {
1010
undoRedoTestCases,
1111
} from "./testHelpers.js";
1212

13+
import { Commit, EditV2, Transactor } from "@omicronenergy/oscd-api";
14+
1315
import {
14-
Commit,
15-
EditV2,
16-
isSetAttributes,
1716
isSetTextContent,
18-
Transactor,
19-
} from "@omicronenergy/oscd-api";
17+
isSetAttributes,
18+
} from "@omicronenergy/oscd-api/utils.js";
2019

2120
import { XMLEditor } from "./XMLEditor.js";
2221

handleEdit.spec.ts

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@ import {
1515
} from "./testHelpers.js";
1616

1717
import { EditV2, Insert } from "@omicronenergy/oscd-api";
18+
import { isEditV2 } from "@omicronenergy/oscd-api/utils.js";
19+
1820
import { handleEdit } from "./handleEdit.js";
1921

2022
import { assert, property } from "fast-check";
2123

24+
it("fails at distinguishing EditV2", () => {
25+
expect(isEditV2([{ node: "notanode", parent: "notanode", reference: 42 }])).to
26+
.be.false;
27+
});
28+
2229
describe("handleEdit", () => {
2330
let sclDoc: XMLDocument;
2431

@@ -190,29 +197,37 @@ describe("handleEdit", () => {
190197
testDocs.chain(([{ nodes }]) => setAttributes(nodes)),
191198
(edit) => {
192199
handleEdit(edit);
193-
const attributesHandledCorrectly = Object.entries(edit.attributes)
194-
.filter(([name]) => xmlAttributeName.test(name))
195-
.map((entry) => entry as [string, string | null])
196-
.every(
197-
([name, value]) => edit.element.getAttribute(name) === value,
198-
);
199-
const attributesNSHandledCorrectly = Object.entries(
200-
edit.attributesNS,
201-
)
202-
.map((entry) => entry as [string, Record<string, string | null>])
203-
.every(([ns, attributes]) => {
204-
const unprefixedAttributes = Object.fromEntries(
205-
Object.entries(attributes)
206-
.filter(([name]) => xmlAttributeName.test(name))
207-
.map((entry) => entry as [string, string | null])
208-
.map(([name, value]) => [name.split(":", 2).pop(), value])
209-
.filter(([name]) => name),
210-
);
211-
return Object.entries(unprefixedAttributes).every(
212-
([name, value]) =>
213-
edit.element.getAttributeNS(ns, name!) === value,
214-
);
215-
});
200+
const attributesHandledCorrectly = edit.attributes
201+
? Object.entries(edit.attributes)
202+
.filter(([name]) => xmlAttributeName.test(name))
203+
.map((entry) => entry as [string, string | null])
204+
.every(
205+
([name, value]) =>
206+
edit.element.getAttribute(name) === value,
207+
)
208+
: true;
209+
const attributesNSHandledCorrectly = edit.attributesNS
210+
? Object.entries(edit.attributesNS)
211+
.map(
212+
(entry) => entry as [string, Record<string, string | null>],
213+
)
214+
.every(([ns, attributes]) => {
215+
const unprefixedAttributes = Object.fromEntries(
216+
Object.entries(attributes)
217+
.filter(([name]) => xmlAttributeName.test(name))
218+
.map((entry) => entry as [string, string | null])
219+
.map(([name, value]) => [
220+
name.split(":", 2).pop(),
221+
value,
222+
])
223+
.filter(([name]) => name),
224+
);
225+
return Object.entries(unprefixedAttributes).every(
226+
([name, value]) =>
227+
edit.element.getAttributeNS(ns, name!) === value,
228+
);
229+
})
230+
: true;
216231
return attributesHandledCorrectly && attributesNSHandledCorrectly;
217232
},
218233
),
@@ -242,7 +257,7 @@ describe("handleEdit", () => {
242257
const ed = handleEdit(a);
243258
undoEdits.unshift(ed);
244259
});
245-
if (edits.length) handleEdit(undoEdits);
260+
handleEdit(undoEdits);
246261
expect(doc1).to.satisfy((doc: XMLDocument) =>
247262
doc.isEqualNode(oldDoc1),
248263
);
@@ -252,6 +267,10 @@ describe("handleEdit", () => {
252267
return true;
253268
},
254269
),
270+
{
271+
seed: 1017362841,
272+
path: "1",
273+
},
255274
)).timeout(20000);
256275

257276
it("changes the document the same way when redoing undone edits", () =>

handleEdit.ts

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import {
22
EditV2,
33
Insert,
4-
isComplex,
5-
isInsert,
6-
isRemove,
7-
isSetAttributes,
8-
isSetTextContent,
94
Remove,
105
SetAttributes,
116
SetTextContent,
127
} from "@omicronenergy/oscd-api";
138

9+
import {
10+
isComplexEditV2,
11+
isInsert,
12+
isRemove,
13+
isSetAttributes,
14+
isSetTextContent,
15+
} from "@omicronenergy/oscd-api/utils.js";
16+
1417
function handleSetTextContent({
1518
element,
1619
textContent,
@@ -32,65 +35,69 @@ function handleSetTextContent({
3235

3336
function handleSetAttributes({
3437
element,
35-
attributes,
36-
attributesNS,
38+
attributes = {},
39+
attributesNS = {},
3740
}: SetAttributes): SetAttributes {
3841
const oldAttributes = { ...attributes };
3942
const oldAttributesNS = { ...attributesNS };
4043

4144
// save element's non-prefixed attributes for undo
42-
Object.keys(attributes)
43-
.reverse()
44-
.forEach((name) => {
45-
oldAttributes[name] = element.getAttribute(name);
46-
});
45+
if (attributes)
46+
Object.keys(attributes)
47+
.reverse()
48+
.forEach((name) => {
49+
oldAttributes[name] = element.getAttribute(name);
50+
});
4751

4852
// change element's non-prefixed attributes
49-
for (const entry of Object.entries(attributes)) {
50-
try {
51-
const [name, value] = entry as [string, string | null];
52-
if (value === null) element.removeAttribute(name);
53-
else element.setAttribute(name, value);
54-
} catch (_e) {
55-
// undo nothing if update didn't work on this attribute
56-
delete oldAttributes[entry[0]];
53+
if (attributes)
54+
for (const entry of Object.entries(attributes)) {
55+
try {
56+
const [name, value] = entry as [string, string | null];
57+
if (value === null) element.removeAttribute(name);
58+
else element.setAttribute(name, value);
59+
} catch (_e) {
60+
// undo nothing if update didn't work on this attribute
61+
delete oldAttributes[entry[0]];
62+
}
5763
}
58-
}
5964

6065
// save element's namespaced attributes for undo
61-
Object.entries(attributesNS).forEach(([ns, attrs]) => {
62-
Object.keys(attrs!)
63-
.reverse()
64-
.forEach((name) => {
65-
oldAttributesNS[ns] = {
66-
...oldAttributesNS[ns],
67-
[name]: element.getAttributeNS(ns, name.split(":").pop()!),
68-
};
66+
if (attributesNS)
67+
Object.entries(attributesNS).forEach(([ns, attrs]) => {
68+
Object.keys(attrs!)
69+
.reverse()
70+
.forEach((name) => {
71+
oldAttributesNS[ns] = {
72+
...oldAttributesNS[ns],
73+
[name]: element.getAttributeNS(ns, name.split(":").pop()!),
74+
};
75+
});
76+
Object.keys(attrs!).forEach((name) => {
77+
delete oldAttributesNS[ns]![name];
6978
});
70-
Object.keys(attrs!).forEach((name) => {
71-
delete oldAttributesNS[ns]![name];
7279
});
73-
});
7480

7581
// change element's namespaced attributes
76-
for (const nsEntry of Object.entries(attributesNS)) {
77-
const [ns, attrs] = nsEntry as [
78-
string,
79-
Partial<Record<string, string | null>>,
80-
];
81-
for (const entry of Object.entries(attrs)) {
82-
try {
83-
const [name, value] = entry as [string, string | null];
84-
if (value === null) {
85-
element.removeAttributeNS(ns, name.split(":").pop()!);
86-
} else {
87-
element.setAttributeNS(ns, name, value);
82+
if (attributesNS)
83+
for (const nsEntry of Object.entries(attributesNS)) {
84+
const [ns, attrs] = nsEntry as [
85+
string,
86+
Partial<Record<string, string | null>>,
87+
];
88+
for (const entry of Object.entries(attrs)) {
89+
try {
90+
const [name, value] = entry as [string, string | null];
91+
if (value === null) {
92+
element.removeAttributeNS(ns, name.split(":").pop()!);
93+
} else {
94+
element.setAttributeNS(ns, name, value);
95+
}
96+
} catch (_e) {
97+
delete oldAttributesNS[ns]![entry[0]];
8898
}
89-
} catch (_e) {
90-
delete oldAttributesNS[ns]![entry[0]];
9199
}
92100
}
93-
}
94101

95102
return {
96103
element,
@@ -141,13 +148,11 @@ export function handleEdit(edit: EditV2): EditV2 {
141148
if (isRemove(edit)) return handleRemove(edit);
142149
if (isSetAttributes(edit)) return handleSetAttributes(edit);
143150
if (isSetTextContent(edit)) return handleSetTextContent(edit);
144-
if (isComplex(edit))
151+
if (isComplexEditV2(edit))
145152
return edit
146153
.map((edit) => handleEdit(edit))
147154
.reverse()
148155
.flat(Infinity as 1);
149156

150-
console.error(`Invalid edit provided: ${edit}`);
151-
152157
return [];
153158
}

oscd-editor.ts

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
11
export {
2+
Commit,
3+
CommitOptions,
24
EditV2,
35
Insert,
46
Remove,
57
SetAttributes,
68
SetTextContent,
7-
isComplex,
8-
isEditV2,
9-
isInsert,
10-
isRemove,
11-
isSetAttributes,
12-
isSetTextContent,
9+
TransactedCallback,
10+
Transactor,
1311
} from "@omicronenergy/oscd-api";
1412

15-
export { Edit, Update, isEdit } from "@omicronenergy/oscd-api";
16-
1713
export { handleEdit } from "./handleEdit.js";
1814

19-
export {
20-
complexEdit,
21-
edit,
22-
remove,
23-
setAttributes,
24-
setTextContent,
25-
simpleEdit,
26-
} from "./testHelpers.js";
27-
2815
export { XMLEditor } from "./XMLEditor.js";
29-
30-
export type {
31-
Commit,
32-
CommitOptions,
33-
Transactor,
34-
TransactedCallback,
35-
} from "@omicronenergy/oscd-api";

0 commit comments

Comments
 (0)