@jeniex/utils 1.0.6 → 1.0.8

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
@@ -50,9 +50,9 @@ else {
50
50
  infoObject = { script: { name: document.title } };
51
51
  }
52
52
  const scriptName = infoObject.script.name;
53
- /** The identifier of the script to be used in logging */
53
+ /** The identifier of the script to be used in logging. */
54
54
  const logId = `[${scriptName}]:`;
55
- /** The initial tab URL on the script run */
55
+ /** The initial tab URL on the script run. */
56
56
  const tabURL = window.location.href;
57
57
 
58
58
  function alert(message) {
@@ -69,6 +69,90 @@ function prompt(message, _default) {
69
69
  return window.prompt(`[ ${scriptName} ]\n\n${message}`, _default);
70
70
  }
71
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
+
72
156
  function $(selectors, parent) {
73
157
  const element = (parent ?? document).querySelector(ensureJoin(selectors));
74
158
  if (element === null) {
@@ -84,6 +168,91 @@ function $$(selectors, parent) {
84
168
  return elements;
85
169
  }
86
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 fails.
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
+
87
256
  function createFlagMessage(flag) {
88
257
  const { message: messageHeader, values, type } = flag;
89
258
  let message = messageHeader;
@@ -161,11 +330,18 @@ async function getOptions(flags) {
161
330
 
162
331
  exports.$ = $;
163
332
  exports.$$ = $$;
333
+ exports.addStyle = addStyle;
164
334
  exports.alert = alert;
165
335
  exports.asserted = asserted;
166
336
  exports.confirm = confirm;
167
337
  exports.ensureJoin = ensureJoin;
338
+ exports.fish = fish;
339
+ exports.fishResponse = fishResponse;
340
+ exports.fishX = fishX;
341
+ exports.fishXResponse = fishXResponse;
168
342
  exports.getOptions = getOptions;
343
+ exports.getSearchParam = getSearchParam;
344
+ exports.imageLoad = imageLoad;
169
345
  exports.isFalsy = isFalsy;
170
346
  exports.isNotNullish = isNotNullish;
171
347
  exports.isNullish = isNullish;
@@ -173,7 +349,9 @@ exports.isString = isString;
173
349
  exports.isTruthy = isTruthy;
174
350
  exports.logId = logId;
175
351
  exports.noop = noop;
352
+ exports.pageLoad = pageLoad;
176
353
  exports.prompt = prompt;
177
354
  exports.scriptName = scriptName;
355
+ exports.setSearchParam = setSearchParam;
178
356
  exports.sleep = sleep;
179
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
- /** The identifier of the script to be used in logging */
65
+ /** The identifier of the script to be used in logging. */
29
66
  declare const logId: string;
30
- /** The initial tab URL on the script run */
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 fails.
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
@@ -48,9 +48,9 @@ else {
48
48
  infoObject = { script: { name: document.title } };
49
49
  }
50
50
  const scriptName = infoObject.script.name;
51
- /** The identifier of the script to be used in logging */
51
+ /** The identifier of the script to be used in logging. */
52
52
  const logId = `[${scriptName}]:`;
53
- /** The initial tab URL on the script run */
53
+ /** The initial tab URL on the script run. */
54
54
  const tabURL = window.location.href;
55
55
 
56
56
  function alert(message) {
@@ -67,6 +67,90 @@ function prompt(message, _default) {
67
67
  return window.prompt(`[ ${scriptName} ]\n\n${message}`, _default);
68
68
  }
69
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
+
70
154
  function $(selectors, parent) {
71
155
  const element = (parent ?? document).querySelector(ensureJoin(selectors));
72
156
  if (element === null) {
@@ -82,6 +166,91 @@ function $$(selectors, parent) {
82
166
  return elements;
83
167
  }
84
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 fails.
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
+
85
254
  function createFlagMessage(flag) {
86
255
  const { message: messageHeader, values, type } = flag;
87
256
  let message = messageHeader;
@@ -157,4 +326,4 @@ async function getOptions(flags) {
157
326
  return options;
158
327
  }
159
328
 
160
- 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.6",
3
+ "version": "1.0.8",
4
4
  "author": "JenieX",
5
5
  "homepage": "https://github.com/JenieX/utils",
6
6
  "type": "module",