Skip to content

Commit

Permalink
feat: add Edit and EditV2 type guards
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobVogelsang committed Oct 27, 2024
1 parent 898c4e3 commit 7d5f002
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 3 deletions.
45 changes: 45 additions & 0 deletions editv1.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { expect } from "@open-wc/testing";

import { isEdit, Update } from "./editv1.js";
import { Insert, Remove, SetAttributes, SetTextContent } from "./editv2.js";

const element = new DOMParser().parseFromString(
"<SCL />",
"application/xml",
)!.documentElement;

const update: Update = { element, attributes: {} };
const insert: Insert = { parent: element, node: element, reference: null };
const remove: Remove = { node: element };
const setAttributes: SetAttributes = {
element,
attributes: {},
attributesNS: {},
};
const setTextContent: SetTextContent = { element, textContent: "" };

describe("type guard functions for editv1", () => {
it("returns false on invalid Edit type", () =>
expect("invalid edit").to.not.satisfy(isEdit));

it("returns false on Update", () => expect(update).to.satisfy(isEdit));

it("returns true for Insert", () => expect(insert).to.satisfy(isEdit));

it("returns true for Remove", () => expect(remove).to.satisfy(isEdit));

it("returns false for SetAttributes", () =>
expect(setAttributes).to.not.satisfy(isEdit));

it("returns true for SetTextContent", () =>
expect(setTextContent).to.not.satisfy(isEdit));

it("returns false on mixed edit and editV2 array", () =>
expect([update, setAttributes]).to.not.satisfy(isEdit));

it("returns true on edit array", () =>
expect([update, remove, insert]).to.satisfy(isEdit));

it("returns false on editV2 array", () =>
expect([setAttributes, remove, insert, setTextContent]).to.not.satisfy(isEdit));
});
17 changes: 16 additions & 1 deletion editv1.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isSetAttributes } from "./editv2";

/** Intent to `parent.insertBefore(node, reference)` */
export type Insert = {
parent: Node;
Expand Down Expand Up @@ -39,7 +41,10 @@ export function isNamespaced(
}

export function isUpdate(edit: Edit): edit is Update {
return (edit as Update).element !== undefined;
return (
(edit as Update).element !== undefined &&
(edit as Update).attributes !== undefined
);
}

export function isRemove(edit: Edit): edit is Remove {
Expand All @@ -49,3 +54,13 @@ export function isRemove(edit: Edit): edit is Remove {
}

export type EditEvent<E extends Edit = Edit> = CustomEvent<E>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isEdit(edit: any): edit is Edit {
if (isComplex(edit)) return !edit.some((e) => !isEdit(e));

return (
!isSetAttributes(edit) &&
(isUpdate(edit) || isInsert(edit) || isRemove(edit))
);
}
53 changes: 53 additions & 0 deletions editv2.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { expect } from "@open-wc/testing";

import { Update } from "./editv1.js";
import {
Insert,
isEditV2,
Remove,
SetAttributes,
SetTextContent,
} from "./editv2.js";

const element = new DOMParser().parseFromString(
"<SCL />",
"application/xml",
)!.documentElement;

const update: Update = { element, attributes: {} };
const insert: Insert = { parent: element, node: element, reference: null };
const remove: Remove = { node: element };
const setAttributes: SetAttributes = {
element,
attributes: {},
attributesNS: {},
};
const setTextContent: SetTextContent = { element, textContent: "" };

describe("type guard functions for editv2", () => {
it("returns false on invalid Edit type", () =>
expect("invalid edit").to.not.satisfy(isEditV2));

it("returns false on Update", () => expect(update).to.not.satisfy(isEditV2));

it("returns true for Insert", () => expect(insert).to.satisfy(isEditV2));

it("returns true for Remove", () => expect(remove).to.satisfy(isEditV2));

it("returns true for SetAttributes", () =>
expect(setAttributes).to.satisfy(isEditV2));

it("returns true for SetTextContent", () =>
expect(setTextContent).to.satisfy(isEditV2));

it("returns false on mixed edit and editV2 array", () =>
expect([update, setAttributes]).to.not.satisfy(isEditV2));

it("returns false on edit array", () =>
expect([update, update]).to.not.satisfy(isEditV2));

it("returns true on editV2 array", () =>
expect([setAttributes, remove, insert, setTextContent]).to.satisfy(
isEditV2,
));
});
23 changes: 21 additions & 2 deletions editv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export function isComplex(edit: EditV2): edit is EditV2[] {
}

export function isSetTextContent(edit: EditV2): edit is SetTextContent {
return "element" in edit && "textContent" in edit;
return (
(edit as SetTextContent).element !== undefined &&
(edit as SetTextContent).textContent !== undefined
);
}

export function isRemove(edit: EditV2): edit is Remove {
Expand All @@ -46,7 +49,11 @@ export function isRemove(edit: EditV2): edit is Remove {
}

export function isSetAttributes(edit: EditV2): edit is SetAttributes {
return "element" in edit && "attributesNS" in edit && "attributes" in edit;
return (
(edit as SetAttributes).element !== undefined &&
(edit as SetAttributes).attributes !== undefined &&
(edit as SetAttributes).attributesNS !== undefined
);
}

export function isInsert(edit: EditV2): edit is Insert {
Expand All @@ -56,3 +63,15 @@ export function isInsert(edit: EditV2): edit is Insert {
(edit as Insert).reference !== undefined
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isEditV2(edit: any): edit is EditV2 {
if (isComplex(edit)) return !edit.some((e) => !isEditV2(e));

return (
isSetAttributes(edit) ||
isSetTextContent(edit) ||
isInsert(edit) ||
isRemove(edit)
);
}

0 comments on commit 7d5f002

Please sign in to comment.