@ibiliaze/stringman 3.18.0 → 3.20.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/dist/index.d.ts +16 -0
- package/dist/index.js +73 -1
- package/package.json +2 -2
- package/src/index.ts +76 -0
package/dist/index.d.ts
CHANGED
|
@@ -141,6 +141,18 @@ export declare const isVideoUrl: (url: string) => boolean;
|
|
|
141
141
|
* @throws Error if no endpoint returns a valid IP.
|
|
142
142
|
*/
|
|
143
143
|
export declare const getPublicIP: () => Promise<string>;
|
|
144
|
+
/**
|
|
145
|
+
* Convert an unknown value into a stable string key for deduping.
|
|
146
|
+
*/
|
|
147
|
+
export declare const valueKey: (v: unknown) => string;
|
|
148
|
+
/**
|
|
149
|
+
* Dedupe an array by a key (dot-path supported), preserving the item type.
|
|
150
|
+
*
|
|
151
|
+
* - keepFirst=true => first wins
|
|
152
|
+
* - keepFirst=false => last wins
|
|
153
|
+
* - keepNoKey=true => keep items where key is missing/invalid (kept in original order, before deduped items)
|
|
154
|
+
*/
|
|
155
|
+
export declare const dedupeBy: <T>(arr: T[] | undefined, key: keyof T, { keepFirst, keepNoKey }?: DedupeByOptions) => T[];
|
|
144
156
|
export declare const invalidPw: (password: string, passwordLength?: number) => string | void;
|
|
145
157
|
export declare const b36: (n: number) => string;
|
|
146
158
|
export declare const luhn36: (s: string) => string;
|
|
@@ -170,3 +182,7 @@ export declare const crypto: {
|
|
|
170
182
|
export declare const order: {
|
|
171
183
|
createNumericOrderId: () => string;
|
|
172
184
|
};
|
|
185
|
+
type DedupeByOptions = {
|
|
186
|
+
keepFirst?: boolean;
|
|
187
|
+
keepNoKey?: boolean;
|
|
188
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.order = exports.crypto = exports.ticket = exports.luhn36 = exports.b36 = exports.invalidPw = exports.getPublicIP = exports.isVideoUrl = exports.getRandomString = exports.extractImageSrcs = exports.select = exports.query = exports.getCloudinaryPublicId = exports.dp = exports.megaTrim = exports.superTrim = void 0;
|
|
17
|
+
exports.order = exports.crypto = exports.ticket = exports.luhn36 = exports.b36 = exports.invalidPw = exports.dedupeBy = exports.valueKey = exports.getPublicIP = exports.isVideoUrl = exports.getRandomString = exports.extractImageSrcs = exports.select = exports.query = exports.getCloudinaryPublicId = exports.dp = exports.megaTrim = exports.superTrim = void 0;
|
|
18
18
|
__exportStar(require("./seat"), exports);
|
|
19
19
|
const ticket_1 = require("./ticket");
|
|
20
20
|
const order_1 = require("./order");
|
|
@@ -244,6 +244,78 @@ const getPublicIP = async () => {
|
|
|
244
244
|
throw new Error('Public IP unavailable');
|
|
245
245
|
};
|
|
246
246
|
exports.getPublicIP = getPublicIP;
|
|
247
|
+
/**
|
|
248
|
+
* Convert an unknown value into a stable string key for deduping.
|
|
249
|
+
*/
|
|
250
|
+
const valueKey = (v) => {
|
|
251
|
+
try {
|
|
252
|
+
if (v == null)
|
|
253
|
+
return '';
|
|
254
|
+
if (typeof v === 'string')
|
|
255
|
+
return v;
|
|
256
|
+
const key = String(v);
|
|
257
|
+
if (key === '[object Object]')
|
|
258
|
+
return '';
|
|
259
|
+
return key;
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
console.error('valueKey(): failed to normalise value:', v, e);
|
|
263
|
+
return '';
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
exports.valueKey = valueKey;
|
|
267
|
+
/**
|
|
268
|
+
* Dedupe an array by a key (dot-path supported), preserving the item type.
|
|
269
|
+
*
|
|
270
|
+
* - keepFirst=true => first wins
|
|
271
|
+
* - keepFirst=false => last wins
|
|
272
|
+
* - keepNoKey=true => keep items where key is missing/invalid (kept in original order, before deduped items)
|
|
273
|
+
*/
|
|
274
|
+
const dedupeBy = (arr = [], key, { keepFirst = true, keepNoKey = true } = {}) => {
|
|
275
|
+
try {
|
|
276
|
+
if (!Array.isArray(arr)) {
|
|
277
|
+
console.error('dedupeBy(): expected an array, got:', arr);
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
if (typeof key !== 'string')
|
|
281
|
+
throw new Error('Key is not a string');
|
|
282
|
+
// Build a getter for a "dot.path" key like "user.id"
|
|
283
|
+
const getKey = (obj) => {
|
|
284
|
+
try {
|
|
285
|
+
return key.split('.').reduce((acc, k) => acc?.[k], obj);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
// Map preserves insertion order, which gives stable output ordering for "first wins"
|
|
292
|
+
const map = new Map();
|
|
293
|
+
const noKey = [];
|
|
294
|
+
for (const item of arr) {
|
|
295
|
+
const raw = getKey(item);
|
|
296
|
+
const k = (0, exports.valueKey)(raw);
|
|
297
|
+
if (!k) {
|
|
298
|
+
if (keepNoKey)
|
|
299
|
+
noKey.push(item);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (keepFirst) {
|
|
303
|
+
if (!map.has(k))
|
|
304
|
+
map.set(k, item);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
map.set(k, item); // last wins
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const deduped = Array.from(map.values());
|
|
311
|
+
return keepNoKey ? noKey.concat(deduped) : deduped;
|
|
312
|
+
}
|
|
313
|
+
catch (e) {
|
|
314
|
+
console.error('dedupeBy(): failed:', e);
|
|
315
|
+
return Array.isArray(arr) ? arr : [];
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
exports.dedupeBy = dedupeBy;
|
|
247
319
|
const invalidPw = (password, passwordLength = 8) => {
|
|
248
320
|
try {
|
|
249
321
|
if (password.length < passwordLength)
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibiliaze/stringman",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"pub": "npm publish --access public",
|
|
10
|
-
"git": "git add .; git commit -m 'changes'; git tag -a 3.
|
|
10
|
+
"git": "git add .; git commit -m 'changes'; git tag -a 3.20.0 -m '3.20.0'; git push origin 3.20.0; git push",
|
|
11
11
|
"push": "npm run build; npm run git; npm run pub"
|
|
12
12
|
},
|
|
13
13
|
"author": "Ibi Hasanli",
|
package/src/index.ts
CHANGED
|
@@ -230,6 +230,77 @@ export const getPublicIP = async (): Promise<string> => {
|
|
|
230
230
|
throw new Error('Public IP unavailable');
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Convert an unknown value into a stable string key for deduping.
|
|
235
|
+
*/
|
|
236
|
+
export const valueKey = (v: unknown): string => {
|
|
237
|
+
try {
|
|
238
|
+
if (v == null) return '';
|
|
239
|
+
if (typeof v === 'string') return v;
|
|
240
|
+
|
|
241
|
+
const key = String(v);
|
|
242
|
+
if (key === '[object Object]') return '';
|
|
243
|
+
|
|
244
|
+
return key;
|
|
245
|
+
} catch (e) {
|
|
246
|
+
console.error('valueKey(): failed to normalise value:', v, e);
|
|
247
|
+
return '';
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Dedupe an array by a key (dot-path supported), preserving the item type.
|
|
253
|
+
*
|
|
254
|
+
* - keepFirst=true => first wins
|
|
255
|
+
* - keepFirst=false => last wins
|
|
256
|
+
* - keepNoKey=true => keep items where key is missing/invalid (kept in original order, before deduped items)
|
|
257
|
+
*/
|
|
258
|
+
export const dedupeBy = <T>(arr: T[] = [], key: keyof T, { keepFirst = true, keepNoKey = true }: DedupeByOptions = {}): T[] => {
|
|
259
|
+
try {
|
|
260
|
+
if (!Array.isArray(arr)) {
|
|
261
|
+
console.error('dedupeBy(): expected an array, got:', arr);
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (typeof key !== 'string') throw new Error('Key is not a string');
|
|
266
|
+
|
|
267
|
+
// Build a getter for a "dot.path" key like "user.id"
|
|
268
|
+
const getKey = (obj: any): unknown => {
|
|
269
|
+
try {
|
|
270
|
+
return key.split('.').reduce((acc, k) => acc?.[k], obj);
|
|
271
|
+
} catch {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// Map preserves insertion order, which gives stable output ordering for "first wins"
|
|
277
|
+
const map = new Map<string, T>();
|
|
278
|
+
const noKey: T[] = [];
|
|
279
|
+
|
|
280
|
+
for (const item of arr) {
|
|
281
|
+
const raw = getKey(item);
|
|
282
|
+
const k = valueKey(raw);
|
|
283
|
+
|
|
284
|
+
if (!k) {
|
|
285
|
+
if (keepNoKey) noKey.push(item);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (keepFirst) {
|
|
290
|
+
if (!map.has(k)) map.set(k, item);
|
|
291
|
+
} else {
|
|
292
|
+
map.set(k, item); // last wins
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const deduped = Array.from(map.values());
|
|
297
|
+
return keepNoKey ? noKey.concat(deduped) : deduped;
|
|
298
|
+
} catch (e) {
|
|
299
|
+
console.error('dedupeBy(): failed:', e);
|
|
300
|
+
return Array.isArray(arr) ? arr : [];
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
233
304
|
export const invalidPw = (password: string, passwordLength: number = 8): string | void => {
|
|
234
305
|
try {
|
|
235
306
|
if (password.length < passwordLength) return `Password must be at least ${passwordLength} characters`;
|
|
@@ -292,3 +363,8 @@ export const crypto = {
|
|
|
292
363
|
};
|
|
293
364
|
|
|
294
365
|
export const order = { createNumericOrderId };
|
|
366
|
+
|
|
367
|
+
type DedupeByOptions = {
|
|
368
|
+
keepFirst?: boolean;
|
|
369
|
+
keepNoKey?: boolean;
|
|
370
|
+
};
|