mod2dom 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Makefile CHANGED
@@ -8,7 +8,7 @@ prod:
8
8
  @npm run buildprod
9
9
 
10
10
  test:
11
- @npm run test
11
+ @npm run test -- --slowTestThreshold 5 --retry 2 --logHeapUsage --reporter verbose
12
12
 
13
13
  updateMinor:
14
14
  npm version minor
@@ -1,7 +1,14 @@
1
- import { defineConfig } from "vitest/config"
1
+ import { defineConfig } from "vitest/config";
2
+ import path from "path";
2
3
 
3
4
  export default defineConfig({
4
- test: {
5
- environment: "jsdom"
6
- }
5
+ resolve: {
6
+ alias: {
7
+ "@utils": path.resolve(__dirname, "../src/utils"),
8
+ },
9
+ },
10
+
11
+ test: {
12
+ environment: "jsdom",
13
+ },
7
14
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mod2dom",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,17 +1,57 @@
1
- const mapAsync = async (array: Array<any>, callback: (item: any) => Promise<void>) => {
2
- const newArray = new Array();
3
- for (const item of array) {
4
- newArray.push(await callback(item));
1
+ import { mapAsync } from "@utils";
2
+
3
+ export class CLItem {
4
+ raw: ClipboardItem
5
+
6
+ constructor(item: ClipboardItem) {
7
+ this.raw = item;
8
+ }
9
+
10
+ get text() {
11
+ return (async () => {
12
+ if (this.raw.types[0]?.match(/text\/.+/g)) {
13
+ return await (await this.raw.getType(this.raw.types[0])).text();
14
+ } else {
15
+ return undefined;
16
+ }
17
+ })();
18
+ }
19
+
20
+ get type() {
21
+ return this.raw.types[0];
22
+ }
23
+
24
+ get types() {
25
+ return this.raw.types;
5
26
  }
6
27
  }
7
28
 
8
29
  export const clipboard = {
9
- readAll: async function readAll() {
30
+ ClipboardItem: CLItem,
31
+
32
+ raw: async function raw(): Promise<Array<CLItem>> {
10
33
  const r = await navigator.clipboard.read();
11
- return await mapAsync(r, async (l) => {
12
- const blob = await l.getType("text/plain");
13
- const text = await blob.text();
14
- return text;
15
- });
16
- }
34
+
35
+ return r.map((l) => new this.ClipboardItem(l));
36
+ },
37
+
38
+ readAll: async function readAll() {
39
+ const r = await this.raw();
40
+
41
+ return (await mapAsync(r, async (l) => {
42
+ return await l.text;
43
+ })).filter((v) => v !== undefined);
44
+ },
45
+
46
+ read: async function read() {
47
+ return (await this.readAll()).at(-1);
48
+ },
49
+
50
+ write: async function write(text: string) {
51
+ return await navigator.clipboard.writeText(text);
52
+ },
53
+
54
+ writeRaw: async function write(...raw: ClipboardItems) {
55
+ return await navigator.clipboard.write(raw);
56
+ },
17
57
  }
package/src/types.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export type DNode = Document | HTMLElement | Element | Node;
2
2
  export type { QueryType, QueryOption, QueryOptions } from "./query.js";
3
+ export { CLItem } from "./localServices/clipboard.js";
@@ -0,0 +1,7 @@
1
+ export const mapAsync = async (array: Array<any>, callback: (item: any) => Promise<void>) => {
2
+ const newArray = new Array();
3
+ for (const item of array) {
4
+ newArray.push(await callback(item));
5
+ }
6
+ return newArray;
7
+ }
@@ -0,0 +1,61 @@
1
+ import { describe, it, vi, beforeEach, expect } from "vitest";
2
+ import { clipboard } from "../../src/localServices/clipboard.js";
3
+ import { CLItem } from "../../src/localServices/clipboard.js";
4
+
5
+ describe("read", () => {
6
+ describe("text", () => {
7
+ let navigatorMock = {
8
+ clipboard: {
9
+ read: vi.fn()
10
+ }
11
+ }
12
+ let makeClipboardItemMock = (types: any, blob: any) => {
13
+ return {
14
+ types: types,
15
+ getType: vi.fn().mockResolvedValue(blob)
16
+ };
17
+ }
18
+ beforeEach(() => {
19
+ vi.resetAllMocks();
20
+
21
+ vi.stubGlobal("navigator", navigatorMock);
22
+ })
23
+
24
+
25
+ it("Normal Read (1)", async () => {
26
+ const mockBlob = new Blob(["hello world"], {
27
+ type: "text/plain",
28
+ });
29
+
30
+ const mockClipboardItem = makeClipboardItemMock(["text/plain"], mockBlob);
31
+ navigatorMock.clipboard.read.mockResolvedValue([mockClipboardItem]);
32
+
33
+ const result = await clipboard.read();
34
+
35
+ expect(mockClipboardItem.getType).toHaveBeenCalledOnce();
36
+ expect(navigatorMock.clipboard.read).toHaveBeenCalledOnce();
37
+ expect(result).toBe("hello world");
38
+ });
39
+
40
+ it("Normal Read (2)", async () => {
41
+ const wrongBlob = new Blob(["wrong"], {
42
+ type: "text/plain"
43
+ });
44
+ const wrongClipboardItem = makeClipboardItemMock(["text/plain"], wrongBlob);
45
+
46
+ const mockBlob = new Blob(["hello world"], {
47
+ type: "text/html",
48
+ });
49
+
50
+ const mockClipboardItem = makeClipboardItemMock(["text/html"], mockBlob);
51
+ navigatorMock.clipboard.read.mockResolvedValue([wrongClipboardItem, mockClipboardItem]);
52
+
53
+ const result = await clipboard.read();
54
+
55
+ expect(wrongClipboardItem.getType).toHaveBeenCalledOnce();
56
+ expect(mockClipboardItem.getType).toHaveBeenCalledOnce();
57
+ expect(navigatorMock.clipboard.read).toHaveBeenCalledOnce();
58
+ expect(result).toBe("hello world");
59
+ });
60
+ })
61
+ })
@@ -3,7 +3,7 @@ import { DOMParser } from "../../src/index";
3
3
  import { TagName as IDName, Element, ClassName } from "../../src/query";
4
4
 
5
5
  describe("invalidClass.empty.none", () => {
6
- it("finds an element", () => {
6
+ it("fails to find an element", () => {
7
7
  document.body.innerHTML = `
8
8
  <div>
9
9
  <button id="x" class="test">Hello, World!</button>
@@ -22,7 +22,7 @@ describe("invalidClass.empty.none", () => {
22
22
  });
23
23
 
24
24
  describe("invalidClass.empty.whitespace", () => {
25
- it("finds an element", () => {
25
+ it("fails to find an element", () => {
26
26
  document.body.innerHTML = `
27
27
  <div>
28
28
  <button id="x" class="test">Hello, World!</button>
@@ -41,7 +41,7 @@ describe("invalidClass.empty.whitespace", () => {
41
41
  });
42
42
 
43
43
  describe("invalidClass.character(1)", () => {
44
- it("finds an element", () => {
44
+ it("fails to find an element", () => {
45
45
  document.body.innerHTML = `
46
46
  <div>
47
47
  <button id="x" class="test">Hello, World!</button>
@@ -60,7 +60,7 @@ describe("invalidClass.character(1)", () => {
60
60
  });
61
61
 
62
62
  describe("invalidClass.character(2)", () => {
63
- it("finds an element", () => {
63
+ it("fails to find an element", () => {
64
64
  document.body.innerHTML = `
65
65
  <div>
66
66
  <button id="x" class="test">Hello, World!</button>
@@ -10,6 +10,16 @@ describe("findTheButton", () => {
10
10
 
11
11
  const btn = DOMParser.find(Element('button', {}, IDName("x"), ClassName("test")));
12
12
 
13
+ expect(btn?.textContent).toBe("Hello, World!")
14
+ });
15
+
16
+ it("finds an element based on an array query", () => {
17
+ document.body.innerHTML = `
18
+ <button id="x" class="test">Hello, World!</button>
19
+ `
20
+
21
+ const btn = DOMParser.find([Element('button', {}, IDName("x"), ClassName("test"))]);
22
+
13
23
  expect(btn?.textContent).toBe("Hello, World!")
14
24
  })
15
25
  });
package/tsconfig.json CHANGED
@@ -40,7 +40,11 @@
40
40
  "isolatedModules": true,
41
41
  "noUncheckedSideEffectImports": true,
42
42
  "moduleDetection": "force",
43
- "skipLibCheck": true
43
+ "skipLibCheck": true,
44
+ "paths": {
45
+ "@utils": ["./src/utils/index.ts"],
46
+ "@/*": ["./src/*"]
47
+ }
44
48
  },
45
49
 
46
50
  "include": [