@jeniex/utils 1.0.5 → 1.0.7

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/browser/index.cjs CHANGED
@@ -41,8 +41,9 @@ async function sleep(milliSeconds) {
41
41
  let infoObject;
42
42
  if (typeof GM !== 'undefined') {
43
43
  infoObject = GM.info;
44
+ // eslint-disable-next-line unicorn/no-negated-condition
44
45
  }
45
- else if (typeof GM_info === 'undefined') {
46
+ else if (typeof GM_info !== 'undefined') {
46
47
  infoObject = GM_info;
47
48
  }
48
49
  else {
@@ -68,6 +69,90 @@ function prompt(message, _default) {
68
69
  return window.prompt(`[ ${scriptName} ]\n\n${message}`, _default);
69
70
  }
70
71
 
72
+ async function fishResponse(url, options) {
73
+ const response = await fetch(url, options);
74
+ if (!response.ok) {
75
+ throw new Error(`Request to ${response.url} ended with ${response.status} status.`);
76
+ }
77
+ return response;
78
+ }
79
+
80
+ // Note: to set the 'cookie' header, you have to set 'anonymous' to true.
81
+ async function fishXResponse(url, fishOptions) {
82
+ const { method, anonymous, headers, body, timeOut, onProgress } = fishOptions ?? {};
83
+ return new Promise((resolve, reject) => {
84
+ GM.xmlHttpRequest({
85
+ url,
86
+ method: method ?? 'GET',
87
+ headers,
88
+ anonymous,
89
+ data: body,
90
+ responseType: 'blob',
91
+ timeout: timeOut,
92
+ onprogress: onProgress,
93
+ onload({ response, statusText, status, finalUrl }) {
94
+ const ok = status >= 200 && status < 300;
95
+ if (!ok) {
96
+ reject(new Error(`Request to ${url} ended with ${status} status.`));
97
+ return;
98
+ }
99
+ const properResponse = new Response(response, {
100
+ statusText,
101
+ status,
102
+ });
103
+ Object.defineProperty(properResponse, 'url', { value: finalUrl });
104
+ resolve(properResponse);
105
+ },
106
+ onerror({ status }) {
107
+ reject(new Error(`Request to ${url} ended with ${status} status.`));
108
+ },
109
+ });
110
+ });
111
+ }
112
+
113
+ async function fishBlob(url, options, x) {
114
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
115
+ return response.blob();
116
+ }
117
+
118
+ async function fishBuffer(url, options, x) {
119
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
120
+ return response.arrayBuffer();
121
+ }
122
+
123
+ async function fishDocument(url, options, x) {
124
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
125
+ const responseText = await response.text();
126
+ const parser = new DOMParser();
127
+ return parser.parseFromString(responseText, 'text/html');
128
+ }
129
+
130
+ async function fishJson(url, options, x) {
131
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
132
+ return response.json();
133
+ }
134
+
135
+ async function fishText(url, options, x) {
136
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
137
+ return response.text();
138
+ }
139
+
140
+ // https://httpbin.org/anything
141
+ const fish = {
142
+ blob: async (url, options) => fishBlob(url, options),
143
+ buffer: async (url, options) => fishBuffer(url, options),
144
+ document: async (url, options) => fishDocument(url, options),
145
+ json: async (url, options) => fishJson(url, options),
146
+ text: async (url, options) => fishText(url, options),
147
+ };
148
+ const fishX = {
149
+ blob: async (url, options) => fishBlob(url, options, true),
150
+ buffer: async (url, options) => fishBuffer(url, options, true),
151
+ document: async (url, options) => fishDocument(url, options, true),
152
+ json: async (url, options) => fishJson(url, options, true),
153
+ text: async (url, options) => fishText(url, options, true),
154
+ };
155
+
71
156
  function $(selectors, parent) {
72
157
  const element = (parent ?? document).querySelector(ensureJoin(selectors));
73
158
  if (element === null) {
@@ -83,6 +168,91 @@ function $$(selectors, parent) {
83
168
  return elements;
84
169
  }
85
170
 
171
+ /**
172
+ * @param key The name of the param in the search query.
173
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
174
+ */
175
+ function getSearchParam(key, fullURL) {
176
+ const { search } = new URL(fullURL ?? window.location.href);
177
+ const searchParams = new URLSearchParams(search);
178
+ const value = searchParams.get(key);
179
+ if (value === null) {
180
+ return undefined;
181
+ }
182
+ return value;
183
+ }
184
+ /**
185
+ *
186
+ * @param key The name of the param that is to be in the search query.
187
+ * @param value Its value.
188
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
189
+ */
190
+ function setSearchParam(key, value, fullURL) {
191
+ const updatedURL = [];
192
+ const { origin, pathname, search, hash } = new URL(fullURL ?? window.location.href);
193
+ const searchParams = new URLSearchParams(search);
194
+ searchParams.set(key, value);
195
+ updatedURL.push(origin, pathname, '?', searchParams.toString());
196
+ if (hash !== '') {
197
+ updatedURL.push(hash);
198
+ }
199
+ return updatedURL.join('');
200
+ }
201
+
202
+ function addStyle(css, parent = document.documentElement) {
203
+ const style = document.createElement('style');
204
+ style.setAttribute('type', 'text/css');
205
+ style.textContent = css;
206
+ parent.append(style);
207
+ return style;
208
+ }
209
+
210
+ /**
211
+ * Waits for image to fully load or throws an error if it failed.
212
+ */
213
+ async function imageLoad(img) {
214
+ return new Promise((resolve, reject) => {
215
+ if (img.complete) {
216
+ resolve();
217
+ return;
218
+ }
219
+ let onLoad;
220
+ let onError;
221
+ const removeListeners = () => {
222
+ img.removeEventListener('load', onLoad);
223
+ img.removeEventListener('error', onError);
224
+ };
225
+ onLoad = () => {
226
+ removeListeners();
227
+ resolve();
228
+ };
229
+ onError = () => {
230
+ removeListeners();
231
+ reject(new Error('Image failed to load'));
232
+ };
233
+ img.addEventListener('load', onLoad);
234
+ img.addEventListener('error', onError);
235
+ });
236
+ }
237
+
238
+ /**
239
+ * Waits for the page to load.
240
+ * @param completely Whether or not to wait for resources to load as well.
241
+ */
242
+ async function pageLoad(completely) {
243
+ return new Promise((resolve) => {
244
+ if (document.readyState === 'complete') {
245
+ resolve();
246
+ return;
247
+ }
248
+ if (completely === true) {
249
+ window.addEventListener('load', () => resolve());
250
+ return;
251
+ }
252
+ document.addEventListener('DOMContentLoaded', () => resolve());
253
+ });
254
+ }
255
+
86
256
  function createFlagMessage(flag) {
87
257
  const { message: messageHeader, values, type } = flag;
88
258
  let message = messageHeader;
@@ -160,11 +330,18 @@ async function getOptions(flags) {
160
330
 
161
331
  exports.$ = $;
162
332
  exports.$$ = $$;
333
+ exports.addStyle = addStyle;
163
334
  exports.alert = alert;
164
335
  exports.asserted = asserted;
165
336
  exports.confirm = confirm;
166
337
  exports.ensureJoin = ensureJoin;
338
+ exports.fish = fish;
339
+ exports.fishResponse = fishResponse;
340
+ exports.fishX = fishX;
341
+ exports.fishXResponse = fishXResponse;
167
342
  exports.getOptions = getOptions;
343
+ exports.getSearchParam = getSearchParam;
344
+ exports.imageLoad = imageLoad;
168
345
  exports.isFalsy = isFalsy;
169
346
  exports.isNotNullish = isNotNullish;
170
347
  exports.isNullish = isNullish;
@@ -172,7 +349,9 @@ exports.isString = isString;
172
349
  exports.isTruthy = isTruthy;
173
350
  exports.logId = logId;
174
351
  exports.noop = noop;
352
+ exports.pageLoad = pageLoad;
175
353
  exports.prompt = prompt;
176
354
  exports.scriptName = scriptName;
355
+ exports.setSearchParam = setSearchParam;
177
356
  exports.sleep = sleep;
178
357
  exports.tabURL = tabURL;
@@ -19,17 +19,67 @@ declare function alert(message?: string): void;
19
19
  declare function confirm(message: string): boolean;
20
20
  declare function prompt(message: string, _default?: string): string | null;
21
21
 
22
+ type Method = 'CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE';
23
+ interface FishXOptions {
24
+ method?: Method;
25
+ anonymous?: boolean;
26
+ headers?: Record<string, string>;
27
+ body?: Blob | FormData | string;
28
+ timeOut?: number;
29
+ onProgress?: (response: VMScriptResponseObject<Blob>) => Promise<void> | void;
30
+ }
31
+ interface Fish<T> {
32
+ blob: (url: string, options: T) => Promise<Blob>;
33
+ buffer: (url: string, options: T) => Promise<ArrayBuffer>;
34
+ document: (url: string, options: T) => Promise<Document>;
35
+ json: (url: string, options: T) => Promise<object>;
36
+ text: (url: string, options: T) => Promise<string>;
37
+ }
38
+
39
+ declare function fishResponse(url: string, options?: RequestInit): Promise<Response>;
40
+
41
+ declare function fishXResponse(url: string, fishOptions?: FishXOptions): Promise<Response>;
42
+
43
+ declare const fish: Fish<RequestInit>;
44
+ declare const fishX: Fish<FishXOptions>;
45
+
22
46
  type Parent = Document | HTMLElement;
23
47
  type Selectors = string[] | string;
24
48
  declare function $<T = HTMLElement>(selectors: Selectors, parent?: Parent): T;
25
49
  declare function $$<T extends Element = HTMLElement>(selectors: Selectors, parent?: Parent): NodeListOf<T>;
26
50
 
51
+ /**
52
+ * @param key The name of the param in the search query.
53
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
54
+ */
55
+ declare function getSearchParam(key: string, fullURL?: string): string | undefined;
56
+ /**
57
+ *
58
+ * @param key The name of the param that is to be in the search query.
59
+ * @param value Its value.
60
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
61
+ */
62
+ declare function setSearchParam(key: string, value: string, fullURL?: string): string;
63
+
27
64
  declare const scriptName: string;
28
65
  /** The identifier of the script to be used in logging */
29
66
  declare const logId: string;
30
67
  /** The initial tab URL on the script run */
31
68
  declare const tabURL: string;
32
69
 
70
+ declare function addStyle(css: string, parent?: HTMLElement): HTMLStyleElement;
71
+
72
+ /**
73
+ * Waits for image to fully load or throws an error if it failed.
74
+ */
75
+ declare function imageLoad(img: HTMLImageElement): Promise<void>;
76
+
77
+ /**
78
+ * Waits for the page to load.
79
+ * @param completely Whether or not to wait for resources to load as well.
80
+ */
81
+ declare function pageLoad(completely: boolean): Promise<void>;
82
+
33
83
  interface FlagBase {
34
84
  name: string;
35
85
  message: string;
@@ -56,4 +106,4 @@ type Options = Record<string, FlagValue>;
56
106
 
57
107
  declare function getOptions(flags: Flag[]): Promise<Options>;
58
108
 
59
- export { $, $$, Flag, Fn, Nullable, alert, asserted, confirm, ensureJoin, getOptions, isFalsy, isNotNullish, isNullish, isString, isTruthy, logId, noop, prompt, scriptName, sleep, tabURL };
109
+ export { $, $$, Flag, Fn, Nullable, addStyle, alert, asserted, confirm, ensureJoin, fish, fishResponse, fishX, fishXResponse, getOptions, getSearchParam, imageLoad, isFalsy, isNotNullish, isNullish, isString, isTruthy, logId, noop, pageLoad, prompt, scriptName, setSearchParam, sleep, tabURL };
package/browser/index.js CHANGED
@@ -39,8 +39,9 @@ async function sleep(milliSeconds) {
39
39
  let infoObject;
40
40
  if (typeof GM !== 'undefined') {
41
41
  infoObject = GM.info;
42
+ // eslint-disable-next-line unicorn/no-negated-condition
42
43
  }
43
- else if (typeof GM_info === 'undefined') {
44
+ else if (typeof GM_info !== 'undefined') {
44
45
  infoObject = GM_info;
45
46
  }
46
47
  else {
@@ -66,6 +67,90 @@ function prompt(message, _default) {
66
67
  return window.prompt(`[ ${scriptName} ]\n\n${message}`, _default);
67
68
  }
68
69
 
70
+ async function fishResponse(url, options) {
71
+ const response = await fetch(url, options);
72
+ if (!response.ok) {
73
+ throw new Error(`Request to ${response.url} ended with ${response.status} status.`);
74
+ }
75
+ return response;
76
+ }
77
+
78
+ // Note: to set the 'cookie' header, you have to set 'anonymous' to true.
79
+ async function fishXResponse(url, fishOptions) {
80
+ const { method, anonymous, headers, body, timeOut, onProgress } = fishOptions ?? {};
81
+ return new Promise((resolve, reject) => {
82
+ GM.xmlHttpRequest({
83
+ url,
84
+ method: method ?? 'GET',
85
+ headers,
86
+ anonymous,
87
+ data: body,
88
+ responseType: 'blob',
89
+ timeout: timeOut,
90
+ onprogress: onProgress,
91
+ onload({ response, statusText, status, finalUrl }) {
92
+ const ok = status >= 200 && status < 300;
93
+ if (!ok) {
94
+ reject(new Error(`Request to ${url} ended with ${status} status.`));
95
+ return;
96
+ }
97
+ const properResponse = new Response(response, {
98
+ statusText,
99
+ status,
100
+ });
101
+ Object.defineProperty(properResponse, 'url', { value: finalUrl });
102
+ resolve(properResponse);
103
+ },
104
+ onerror({ status }) {
105
+ reject(new Error(`Request to ${url} ended with ${status} status.`));
106
+ },
107
+ });
108
+ });
109
+ }
110
+
111
+ async function fishBlob(url, options, x) {
112
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
113
+ return response.blob();
114
+ }
115
+
116
+ async function fishBuffer(url, options, x) {
117
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
118
+ return response.arrayBuffer();
119
+ }
120
+
121
+ async function fishDocument(url, options, x) {
122
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
123
+ const responseText = await response.text();
124
+ const parser = new DOMParser();
125
+ return parser.parseFromString(responseText, 'text/html');
126
+ }
127
+
128
+ async function fishJson(url, options, x) {
129
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
130
+ return response.json();
131
+ }
132
+
133
+ async function fishText(url, options, x) {
134
+ const response = await (x ? fishXResponse : fishResponse)(url, options);
135
+ return response.text();
136
+ }
137
+
138
+ // https://httpbin.org/anything
139
+ const fish = {
140
+ blob: async (url, options) => fishBlob(url, options),
141
+ buffer: async (url, options) => fishBuffer(url, options),
142
+ document: async (url, options) => fishDocument(url, options),
143
+ json: async (url, options) => fishJson(url, options),
144
+ text: async (url, options) => fishText(url, options),
145
+ };
146
+ const fishX = {
147
+ blob: async (url, options) => fishBlob(url, options, true),
148
+ buffer: async (url, options) => fishBuffer(url, options, true),
149
+ document: async (url, options) => fishDocument(url, options, true),
150
+ json: async (url, options) => fishJson(url, options, true),
151
+ text: async (url, options) => fishText(url, options, true),
152
+ };
153
+
69
154
  function $(selectors, parent) {
70
155
  const element = (parent ?? document).querySelector(ensureJoin(selectors));
71
156
  if (element === null) {
@@ -81,6 +166,91 @@ function $$(selectors, parent) {
81
166
  return elements;
82
167
  }
83
168
 
169
+ /**
170
+ * @param key The name of the param in the search query.
171
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
172
+ */
173
+ function getSearchParam(key, fullURL) {
174
+ const { search } = new URL(fullURL ?? window.location.href);
175
+ const searchParams = new URLSearchParams(search);
176
+ const value = searchParams.get(key);
177
+ if (value === null) {
178
+ return undefined;
179
+ }
180
+ return value;
181
+ }
182
+ /**
183
+ *
184
+ * @param key The name of the param that is to be in the search query.
185
+ * @param value Its value.
186
+ * @param fullURL If provided, it will be our target, otherwise it is the current location.
187
+ */
188
+ function setSearchParam(key, value, fullURL) {
189
+ const updatedURL = [];
190
+ const { origin, pathname, search, hash } = new URL(fullURL ?? window.location.href);
191
+ const searchParams = new URLSearchParams(search);
192
+ searchParams.set(key, value);
193
+ updatedURL.push(origin, pathname, '?', searchParams.toString());
194
+ if (hash !== '') {
195
+ updatedURL.push(hash);
196
+ }
197
+ return updatedURL.join('');
198
+ }
199
+
200
+ function addStyle(css, parent = document.documentElement) {
201
+ const style = document.createElement('style');
202
+ style.setAttribute('type', 'text/css');
203
+ style.textContent = css;
204
+ parent.append(style);
205
+ return style;
206
+ }
207
+
208
+ /**
209
+ * Waits for image to fully load or throws an error if it failed.
210
+ */
211
+ async function imageLoad(img) {
212
+ return new Promise((resolve, reject) => {
213
+ if (img.complete) {
214
+ resolve();
215
+ return;
216
+ }
217
+ let onLoad;
218
+ let onError;
219
+ const removeListeners = () => {
220
+ img.removeEventListener('load', onLoad);
221
+ img.removeEventListener('error', onError);
222
+ };
223
+ onLoad = () => {
224
+ removeListeners();
225
+ resolve();
226
+ };
227
+ onError = () => {
228
+ removeListeners();
229
+ reject(new Error('Image failed to load'));
230
+ };
231
+ img.addEventListener('load', onLoad);
232
+ img.addEventListener('error', onError);
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Waits for the page to load.
238
+ * @param completely Whether or not to wait for resources to load as well.
239
+ */
240
+ async function pageLoad(completely) {
241
+ return new Promise((resolve) => {
242
+ if (document.readyState === 'complete') {
243
+ resolve();
244
+ return;
245
+ }
246
+ if (completely === true) {
247
+ window.addEventListener('load', () => resolve());
248
+ return;
249
+ }
250
+ document.addEventListener('DOMContentLoaded', () => resolve());
251
+ });
252
+ }
253
+
84
254
  function createFlagMessage(flag) {
85
255
  const { message: messageHeader, values, type } = flag;
86
256
  let message = messageHeader;
@@ -156,4 +326,4 @@ async function getOptions(flags) {
156
326
  return options;
157
327
  }
158
328
 
159
- export { $, $$, alert, asserted, confirm, ensureJoin, getOptions, isFalsy, isNotNullish, isNullish, isString, isTruthy, logId, noop, prompt, scriptName, sleep, tabURL };
329
+ export { $, $$, addStyle, alert, asserted, confirm, ensureJoin, fish, fishResponse, fishX, fishXResponse, getOptions, getSearchParam, imageLoad, isFalsy, isNotNullish, isNullish, isString, isTruthy, logId, noop, pageLoad, prompt, scriptName, setSearchParam, sleep, tabURL };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeniex/utils",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "author": "JenieX",
5
5
  "homepage": "https://github.com/JenieX/utils",
6
6
  "type": "module",