browser-extension-utils 0.1.19 → 0.2.1

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/lib/index.d.ts CHANGED
@@ -68,15 +68,24 @@ export function removeEventListener(
68
68
  type: string | Record<string, unknown>
69
69
  ): void
70
70
 
71
- export function getAttribute(element: HTMLElement, name: string): string
71
+ export function getAttribute(
72
+ // eslint-disable-next-line @typescript-eslint/ban-types
73
+ element: HTMLElement | null | undefined,
74
+ name: string
75
+ ): string | undefined
72
76
 
73
77
  export function setAttribute(
74
- element: HTMLElement,
78
+ // eslint-disable-next-line @typescript-eslint/ban-types
79
+ element: HTMLElement | null | undefined,
75
80
  name: string,
76
81
  value: string
77
82
  ): void
78
83
 
79
- export function removeAttribute(element: HTMLElement, name: string): void
84
+ export function removeAttribute(
85
+ // eslint-disable-next-line @typescript-eslint/ban-types
86
+ element: HTMLElement | null | undefined,
87
+ name: string
88
+ ): void
80
89
 
81
90
  export function setAttributes(
82
91
  element: HTMLElement,
@@ -89,20 +98,34 @@ export function addAttribute(
89
98
  value: string
90
99
  ): void
91
100
 
92
- export function addClass(element: HTMLElement, className: string): void
101
+ export function addClass(
102
+ // eslint-disable-next-line @typescript-eslint/ban-types
103
+ element: HTMLElement | null | undefined,
104
+ className: string
105
+ ): void
93
106
 
94
- export function removeClass(element: HTMLElement, className: string): void
107
+ export function removeClass(
108
+ // eslint-disable-next-line @typescript-eslint/ban-types
109
+ element: HTMLElement | null | undefined,
110
+ className: string
111
+ ): void
95
112
 
96
- export function hasClass(element: HTMLElement, className: string): boolean
113
+ export function hasClass(
114
+ // eslint-disable-next-line @typescript-eslint/ban-types
115
+ element: HTMLElement | null | undefined,
116
+ className: string
117
+ ): boolean
97
118
 
98
119
  export type SetStyle = (
99
- element: HTMLElement,
120
+ // eslint-disable-next-line @typescript-eslint/ban-types
121
+ element: HTMLElement | null | undefined,
100
122
  style: string | Record<string, unknown>,
101
123
  overwrite?: boolean
102
124
  ) => void
103
125
 
104
126
  export function setStyle(
105
- element: HTMLElement,
127
+ // eslint-disable-next-line @typescript-eslint/ban-types
128
+ element: HTMLElement | null | undefined,
106
129
  style: string | Record<string, unknown>,
107
130
  overwrite?: boolean
108
131
  ): void
@@ -119,11 +142,19 @@ export function isUrl(text: string | undefined): boolean
119
142
  export function throttle(func: Function, interval: number): Function
120
143
 
121
144
  export type MenuCallback = (event?: MouseEvent | KeyboardEvent) => void
145
+ export type RegisterMenuCommandOptions = {
146
+ id?: string
147
+ title?: string
148
+ autoClose?: boolean
149
+ // O - Tampermonkey
150
+ // X - Violentmonkey
151
+ accessKey?: string
152
+ }
122
153
  export function registerMenuCommand(
123
154
  name: string,
124
155
  callback: MenuCallback,
125
- accessKey?: string
126
- ): void
156
+ options?: RegisterMenuCommandOptions
157
+ ): string | undefined
127
158
 
128
159
  export function extendHistoryApi(): void
129
160
 
@@ -172,3 +203,5 @@ export function parseInt10(
172
203
 
173
204
  // eslint-disable-next-line @typescript-eslint/naming-convention
174
205
  export function createHTML(html: string): string
206
+
207
+ export function compareVersions(v1: string, v2: string): number
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export const doc = document
2
2
 
3
- export const win = window
3
+ export const win = globalThis
4
4
 
5
5
  export const uniq = (array) => [...new Set(array)]
6
6
 
@@ -19,7 +19,7 @@ export const toCamelCase = function (text) {
19
19
  }
20
20
 
21
21
  export const $ = (selectors, element) =>
22
- (element || doc).querySelector(selectors)
22
+ (element || doc).querySelector(selectors) || undefined
23
23
  export const $$ = (selectors, element) => [
24
24
  ...(element || doc).querySelectorAll(selectors),
25
25
  ]
@@ -30,8 +30,8 @@ export const getRootElement = (type) =>
30
30
  type === 1
31
31
  ? doc.head || doc.body || doc.documentElement
32
32
  : type === 2
33
- ? doc.body || doc.documentElement
34
- : doc.documentElement
33
+ ? doc.body || doc.documentElement
34
+ : doc.documentElement
35
35
 
36
36
  export const createElement = (tagName, attributes) =>
37
37
  setAttributes(doc.createElement(tagName), attributes)
@@ -102,7 +102,7 @@ export const removeEventListener = (element, type, listener, options) => {
102
102
  }
103
103
 
104
104
  export const getAttribute = (element, name) =>
105
- element && element.getAttribute ? element.getAttribute(name) : null
105
+ element && element.getAttribute ? element.getAttribute(name) : undefined
106
106
  export const setAttribute = (element, name, value) =>
107
107
  element && element.setAttribute
108
108
  ? element.setAttribute(name, value)
@@ -274,6 +274,7 @@ export const throttle = (func, interval) => {
274
274
  // Polyfill for Object.hasOwn()
275
275
  if (typeof Object.hasOwn !== "function") {
276
276
  Object.hasOwn = (instance, prop) =>
277
+ // eslint-disable-next-line prefer-object-has-own
277
278
  Object.prototype.hasOwnProperty.call(instance, prop)
278
279
  }
279
280
 
@@ -287,19 +288,19 @@ export const extendHistoryApi = () => {
287
288
  history.pushState = function () {
288
289
  // eslint-disable-next-line prefer-rest-params
289
290
  pushState.apply(history, arguments)
290
- window.dispatchEvent(new Event("pushstate"))
291
- window.dispatchEvent(new Event("locationchange"))
291
+ globalThis.dispatchEvent(new Event("pushstate"))
292
+ globalThis.dispatchEvent(new Event("locationchange"))
292
293
  }
293
294
 
294
295
  history.replaceState = function () {
295
296
  // eslint-disable-next-line prefer-rest-params
296
297
  replaceState.apply(history, arguments)
297
- window.dispatchEvent(new Event("replacestate"))
298
- window.dispatchEvent(new Event("locationchange"))
298
+ globalThis.dispatchEvent(new Event("replacestate"))
299
+ globalThis.dispatchEvent(new Event("locationchange"))
299
300
  }
300
301
 
301
- window.addEventListener("popstate", function () {
302
- window.dispatchEvent(new Event("locationchange"))
302
+ globalThis.addEventListener("popstate", function () {
303
+ globalThis.dispatchEvent(new Event("locationchange"))
303
304
  })
304
305
 
305
306
  // Usage example:
@@ -498,3 +499,50 @@ const escapeHTMLPolicy =
498
499
  export const createHTML = (html) => {
499
500
  return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html
500
501
  }
502
+
503
+ /**
504
+ * Compare two semantic version strings
505
+ * @param {string} v1 - First version string (e.g., "1.2.0")
506
+ * @param {string} v2 - Second version string (e.g., "1.1.5")
507
+ * @returns {number} - Returns 1 if v1 > v2, -1 if v1 < v2, 0 if equal
508
+ * @throws {Error} - Throws error for invalid version strings
509
+ */
510
+ export function compareVersions(v1, v2) {
511
+ // Input validation
512
+ if (typeof v1 !== "string" || typeof v2 !== "string") {
513
+ throw new TypeError("Version strings must be of type string")
514
+ }
515
+
516
+ if (!v1.trim() || !v2.trim()) {
517
+ throw new Error("Version strings cannot be empty")
518
+ }
519
+
520
+ // Validate version format (basic semantic versioning)
521
+ const versionRegex = /^\d+(\.\d+)*$/
522
+ if (!versionRegex.test(v1) || !versionRegex.test(v2)) {
523
+ throw new Error(
524
+ "Invalid version format. Use semantic versioning (e.g., '1.2.3')"
525
+ )
526
+ }
527
+
528
+ const v1Parts = v1.split(".").map(Number)
529
+ const v2Parts = v2.split(".").map(Number)
530
+ const maxLength = Math.max(v1Parts.length, v2Parts.length)
531
+
532
+ for (let i = 0; i < maxLength; i++) {
533
+ const num1 = v1Parts[i] || 0 // Use logical OR for cleaner default assignment
534
+ const num2 = v2Parts[i] || 0
535
+
536
+ if (num1 !== num2) {
537
+ return num1 > num2 ? 1 : -1 // Simplified comparison
538
+ }
539
+ }
540
+
541
+ return 0 // Versions are equal
542
+ }
543
+
544
+ // Usage:
545
+ // console.log(compareVersions("1.2.0", "1.1.5")); // Output: 1
546
+ // console.log(compareVersions("1.0", "1.0.0")); // Output: 0
547
+ // console.log(compareVersions("2.0", "1.5.10")); // Output: 1
548
+ // console.log(compareVersions("1.0.0", "1.0.0.1")); // Output: -1
package/lib/userscript.js CHANGED
@@ -71,8 +71,8 @@ export const addStyle = (styleText) =>
71
71
  addElement(null, "style", { textContent: styleText })
72
72
 
73
73
  // Only register menu on top frame
74
- export const registerMenuCommand = (name, callback, accessKey) => {
75
- if (window !== top) {
74
+ export const registerMenuCommand = (name, callback, options) => {
75
+ if (globalThis !== top) {
76
76
  return
77
77
  }
78
78
 
@@ -81,6 +81,6 @@ export const registerMenuCommand = (name, callback, accessKey) => {
81
81
  return
82
82
  }
83
83
 
84
- GM.registerMenuCommand(name, callback, accessKey)
84
+ return GM.registerMenuCommand(name, callback, options)
85
85
  }
86
86
  /* eslint-enable new-cap, camelcase */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-extension-utils",
3
- "version": "0.1.19",
3
+ "version": "0.2.1",
4
4
  "description": "Utilities for developing browser extensions and userscripts",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "homepage": "https://github.com/utags/browser-extension-utils#readme",
31
31
  "devDependencies": {
32
- "prettier": "^3.0.2",
33
- "xo": "^0.56.0"
32
+ "prettier": "^3.5.3",
33
+ "xo": "^0.60.0"
34
34
  },
35
35
  "files": [
36
36
  "lib/",
@@ -38,7 +38,7 @@
38
38
  "README.md"
39
39
  ],
40
40
  "engines": {
41
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
41
+ "node": ">=16.9.0"
42
42
  },
43
43
  "xo": {
44
44
  "space": 2,
@@ -56,7 +56,9 @@
56
56
  "document"
57
57
  ],
58
58
  "rules": {
59
+ "logical-assignment-operators": 0,
59
60
  "prefer-destructuring": 0,
61
+ "unicorn/prevent-abbreviations": 0,
60
62
  "capitalized-comments": 0
61
63
  }
62
64
  }