DEV Community

Murahashi [Matt] Kenichi
Murahashi [Matt] Kenichi

Posted on • Edited on

2 1

Let's build browser engine! in typescript vol7 Selector matching

for selector matching, I create some shortcut.

test("element id found", () => {
  expect(new ElementData("no mean", new Map([["id", "target"]])).id()).toEqual("target");
});

test("element id not found", () => {
  expect(new ElementData("no mean", new Map([["no mean", "no mean"]])).id()).toBeNull();
});
Enter fullscreen mode Exit fullscreen mode
export class ElementData {
  (snip)

  id(): string | null {
    return this.attributes.get("id") || null;
  }
}
Enter fullscreen mode Exit fullscreen mode
test("element class 1 found", () => {
  expect(new ElementData("no mean", new Map([["class", "target1"]])).classes()).toEqual(
    new Set(["target1"])
  );
});

test("element class 2 found", () => {
  expect(new ElementData("no mean", new Map([["class", "target1 target2"]])).classes()).toEqual(
    new Set(["target1", "target2"])
  );
});

test("element class 0 found", () => {
  expect(new ElementData("no mean", new Map([])).classes()).toEqual(new Set([]));
});
Enter fullscreen mode Exit fullscreen mode
export class ElementData {
  (snip)

  classes(): Set<string> {
    const classes = this.attributes.get("class");
    if (!classes) {
      return new Set([]);
    }
    return new Set(classes.split(" "));
  }
}
Enter fullscreen mode Exit fullscreen mode

selector matching. using this simple selector.

test("matches simple selector", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("no mean", new Map([])),
      new SimpleSelector(null, null, [])
    )
  ).toBe(true);
});

test("matches simple selector different tag", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("other", new Map([])),
      new SimpleSelector("some", null, [])
    )
  ).toBe(false);
});

test("matches simple selector same tag", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("target", new Map([])),
      new SimpleSelector("target", null, [])
    )
  ).toBe(true);
});

test("matches simple selector different id", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("no mean1", new Map([["id", "other"]])),
      new SimpleSelector(null, "some", [])
    )
  ).toBe(false);
});

test("matches simple selector same id", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("no mean1", new Map([["id", "target"]])),
      new SimpleSelector(null, "target", [])
    )
  ).toBe(true);
});

test("matches simple selector different class", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("no mean1", new Map([["class", "other1 other2"]])),
      new SimpleSelector(null, null, ["some1", "some2"])
    )
  ).toBe(false);
});

test("matches simple selector same class", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("no mean1", new Map([["class", "target1 other2"]])),
      new SimpleSelector(null, null, ["target1", "some2"])
    )
  ).toBe(true);
});

test("matches simple selector same tag, other id", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("same", new Map([["id", "other"]])),
      new SimpleSelector("same", "some", [])
    )
  ).toBe(false);
});

test("matches simple selector same tag, same id, different class", () => {
  expect(
    matchesSimpleSelector(
      new ElementData("same", new Map([["id", "same"], ["class", "other1 other2"]])),
      new SimpleSelector("same", "same", ["some1", "some2"])
    )
  ).toBe(false);
});
Enter fullscreen mode Exit fullscreen mode
// returns true if there are no none-match
export function matchesSimpleSelector(elem: ElementData, selector: SimpleSelector): boolean {
  const tagName = selector.tagName;
  if (tagName && tagName !== elem.tagName) {
    return false;
  }

  const id = selector.id;
  if (id && id !== elem.id()) {
    return false;
  }

  const classes = selector.classValue;
  if (classes.length !== 0) {
    let included = false;
    for (let className of classes) {
      if (elem.classes().has(className)) {
        included = true;
        break;
      }
    }
    if (!included) {
      return false;
    }
  }

  return true;
}
Enter fullscreen mode Exit fullscreen mode
test("matches no none-match", () => {
  expect(
    matches(
      new ElementData("no mean", new Map([])),
      new Selector.Simple(new SimpleSelector(null, null, []))
    )
  ).toBe(true);
});

test("matches none-match", () => {
  expect(
    matches(
      new ElementData("no mean", new Map([])),
      new Selector.Simple(new SimpleSelector(null, "some", []))
    )
  ).toBe(false);
});

test("matches match", () => {
  expect(
    matches(
      new ElementData("no mean", new Map([["id", "target"]])),
      new Selector.Simple(new SimpleSelector(null, "target", []))
    )
  ).toBe(true);
});
Enter fullscreen mode Exit fullscreen mode
export function matches(elem: ElementData, selector: Selector): boolean {
  switch (selector.format) {
    case Selector.Format.Simple:
      return matchesSimpleSelector(elem, selector.selector);
  }
}
Enter fullscreen mode Exit fullscreen mode

references

series

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay