@etsoo/shared 1.2.80 → 1.2.81

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.
@@ -11,6 +11,10 @@ on:
11
11
  # release:
12
12
  # types: [created]
13
13
 
14
+ permissions:
15
+ id-token: write # Required for OIDC
16
+ contents: read
17
+
14
18
  jobs:
15
19
  # Publish to NPM
16
20
  publish-npm:
@@ -44,6 +48,4 @@ jobs:
44
48
 
45
49
  # Publish to npm
46
50
  # For scoped package, make it public for free service
47
- - run: npm publish --access public
48
- env:
49
- NODE_AUTH_TOKEN: ${{ secrets.ETSOONpmToken }}
51
+ - run: npm publish
@@ -328,6 +328,16 @@ test("Tests for mergeClasses", () => {
328
328
  expect(Utils.mergeClasses("a", "", "b ", undefined, "c")).toBe("a b c");
329
329
  });
330
330
 
331
+ test("Tests for formatName", () => {
332
+ expect(Utils.formatName("青岛亿速思维网络科技有限公司", 6)).toBe(
333
+ "青岛亿速思维"
334
+ );
335
+ expect(Utils.formatName("亿速思维(中国)网络科技有限公司", 6)).toBe(
336
+ "亿速思维(中国)"
337
+ );
338
+ expect(Utils.formatName("John Smith", 6)).toBe("John Smith");
339
+ });
340
+
331
341
  test("Tests for getNestedValue", () => {
332
342
  const obj = { jsonData: { photoSize: [200, 100], supportResizing: true } };
333
343
  expect(Utils.getNestedValue(obj, "jsonData.supportResizing")).toBeTruthy();
@@ -132,6 +132,14 @@ export declare namespace Utils {
132
132
  export function excludeAsync<T extends {
133
133
  [P in D]: IdType;
134
134
  }, D extends string = "id">(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]): Promise<T[] | undefined>;
135
+ /**
136
+ * Format name
137
+ * @param name Input name
138
+ * @param maxChars Max chars
139
+ * @param maxParts Max parts (optional)
140
+ * @returns Formatted name
141
+ */
142
+ export function formatName(name: string, maxChars: number, maxParts?: number): string;
135
143
  /**
136
144
  * Format inital character to lower case or upper case
137
145
  * @param input Input string
package/lib/cjs/Utils.js CHANGED
@@ -207,6 +207,63 @@ var Utils;
207
207
  return exclude(result, field, ...excludedValues);
208
208
  }
209
209
  Utils.excludeAsync = excludeAsync;
210
+ /**
211
+ * Format name
212
+ * @param name Input name
213
+ * @param maxChars Max chars
214
+ * @param maxParts Max parts (optional)
215
+ * @returns Formatted name
216
+ */
217
+ function formatName(name, maxChars, maxParts) {
218
+ name = name.trim();
219
+ const parts = name.split(/\s+/);
220
+ const max = maxParts ?? Math.floor(maxChars / 3);
221
+ const effectiveMax = max < 2 ? 2 : max;
222
+ if (parts.length >= effectiveMax) {
223
+ return parts.slice(0, effectiveMax).join(" ");
224
+ }
225
+ else if (name.length > maxChars) {
226
+ let endIndex = maxChars;
227
+ const brackets = {
228
+ "(": ")",
229
+ "(": ")",
230
+ "[": "]"
231
+ };
232
+ // Count unmatched brackets for each type
233
+ for (const [start, end] of Object.entries(brackets)) {
234
+ let count = 0;
235
+ // Count opening and closing brackets in the substring
236
+ for (let i = 0; i < maxChars; i++) {
237
+ if (name[i] === start)
238
+ count++;
239
+ else if (name[i] === end)
240
+ count--;
241
+ }
242
+ if (count > 0) {
243
+ // Find matching end brackets
244
+ for (let i = maxChars; i < name.length && count > 0; i++) {
245
+ if (name[i] === start) {
246
+ count++;
247
+ }
248
+ else if (name[i] === end) {
249
+ count--;
250
+ if (count === 0) {
251
+ endIndex = i + 1;
252
+ }
253
+ }
254
+ }
255
+ if (count === 0) {
256
+ return name.substring(0, endIndex);
257
+ }
258
+ }
259
+ }
260
+ return name.substring(0, endIndex);
261
+ }
262
+ else {
263
+ return name;
264
+ }
265
+ }
266
+ Utils.formatName = formatName;
210
267
  /**
211
268
  * Format inital character to lower case or upper case
212
269
  * @param input Input string
@@ -578,7 +635,7 @@ var Utils;
578
635
  Utils.setLabels = (source, labels, reference) => {
579
636
  Object.keys(source).forEach((key) => {
580
637
  // Reference key
581
- const labelKey = reference == null ? key : reference[key] ?? key;
638
+ const labelKey = reference == null ? key : (reference[key] ?? key);
582
639
  // Label
583
640
  const label = labels[labelKey];
584
641
  if (label != null) {
@@ -63,5 +63,5 @@ export interface IStorage {
63
63
  * @param key Key name
64
64
  * @param data Data, null for removal
65
65
  */
66
- setPersistedData(key: string, data: unknown): void;
66
+ setPersistedData<T>(key: string, data: T): void;
67
67
  }
@@ -65,5 +65,5 @@ export declare class WindowStorage implements IStorage {
65
65
  * @param key Key name
66
66
  * @param data Data, null for removal
67
67
  */
68
- setPersistedData(key: string, data: unknown): void;
68
+ setPersistedData<T>(key: string, data: T): void;
69
69
  }
@@ -132,6 +132,14 @@ export declare namespace Utils {
132
132
  export function excludeAsync<T extends {
133
133
  [P in D]: IdType;
134
134
  }, D extends string = "id">(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]): Promise<T[] | undefined>;
135
+ /**
136
+ * Format name
137
+ * @param name Input name
138
+ * @param maxChars Max chars
139
+ * @param maxParts Max parts (optional)
140
+ * @returns Formatted name
141
+ */
142
+ export function formatName(name: string, maxChars: number, maxParts?: number): string;
135
143
  /**
136
144
  * Format inital character to lower case or upper case
137
145
  * @param input Input string
package/lib/mjs/Utils.js CHANGED
@@ -204,6 +204,63 @@ export var Utils;
204
204
  return exclude(result, field, ...excludedValues);
205
205
  }
206
206
  Utils.excludeAsync = excludeAsync;
207
+ /**
208
+ * Format name
209
+ * @param name Input name
210
+ * @param maxChars Max chars
211
+ * @param maxParts Max parts (optional)
212
+ * @returns Formatted name
213
+ */
214
+ function formatName(name, maxChars, maxParts) {
215
+ name = name.trim();
216
+ const parts = name.split(/\s+/);
217
+ const max = maxParts ?? Math.floor(maxChars / 3);
218
+ const effectiveMax = max < 2 ? 2 : max;
219
+ if (parts.length >= effectiveMax) {
220
+ return parts.slice(0, effectiveMax).join(" ");
221
+ }
222
+ else if (name.length > maxChars) {
223
+ let endIndex = maxChars;
224
+ const brackets = {
225
+ "(": ")",
226
+ "(": ")",
227
+ "[": "]"
228
+ };
229
+ // Count unmatched brackets for each type
230
+ for (const [start, end] of Object.entries(brackets)) {
231
+ let count = 0;
232
+ // Count opening and closing brackets in the substring
233
+ for (let i = 0; i < maxChars; i++) {
234
+ if (name[i] === start)
235
+ count++;
236
+ else if (name[i] === end)
237
+ count--;
238
+ }
239
+ if (count > 0) {
240
+ // Find matching end brackets
241
+ for (let i = maxChars; i < name.length && count > 0; i++) {
242
+ if (name[i] === start) {
243
+ count++;
244
+ }
245
+ else if (name[i] === end) {
246
+ count--;
247
+ if (count === 0) {
248
+ endIndex = i + 1;
249
+ }
250
+ }
251
+ }
252
+ if (count === 0) {
253
+ return name.substring(0, endIndex);
254
+ }
255
+ }
256
+ }
257
+ return name.substring(0, endIndex);
258
+ }
259
+ else {
260
+ return name;
261
+ }
262
+ }
263
+ Utils.formatName = formatName;
207
264
  /**
208
265
  * Format inital character to lower case or upper case
209
266
  * @param input Input string
@@ -575,7 +632,7 @@ export var Utils;
575
632
  Utils.setLabels = (source, labels, reference) => {
576
633
  Object.keys(source).forEach((key) => {
577
634
  // Reference key
578
- const labelKey = reference == null ? key : reference[key] ?? key;
635
+ const labelKey = reference == null ? key : (reference[key] ?? key);
579
636
  // Label
580
637
  const label = labels[labelKey];
581
638
  if (label != null) {
@@ -63,5 +63,5 @@ export interface IStorage {
63
63
  * @param key Key name
64
64
  * @param data Data, null for removal
65
65
  */
66
- setPersistedData(key: string, data: unknown): void;
66
+ setPersistedData<T>(key: string, data: T): void;
67
67
  }
@@ -65,5 +65,5 @@ export declare class WindowStorage implements IStorage {
65
65
  * @param key Key name
66
66
  * @param data Data, null for removal
67
67
  */
68
- setPersistedData(key: string, data: unknown): void;
68
+ setPersistedData<T>(key: string, data: T): void;
69
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/shared",
3
- "version": "1.2.80",
3
+ "version": "1.2.81",
4
4
  "description": "TypeScript shared utilities and functions",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -36,10 +36,10 @@
36
36
  },
37
37
  "homepage": "https://github.com/ETSOO/Shared#readme",
38
38
  "devDependencies": {
39
- "@types/node": "^24.10.1",
40
- "@vitejs/plugin-react": "^5.1.1",
41
- "jsdom": "^27.2.0",
39
+ "@types/node": "^25.5.0",
40
+ "@vitejs/plugin-react": "^6.0.1",
41
+ "jsdom": "^29.0.1",
42
42
  "typescript": "^5.9.3",
43
- "vitest": "^4.0.10"
43
+ "vitest": "^4.1.2"
44
44
  }
45
45
  }
package/src/Utils.ts CHANGED
@@ -355,6 +355,70 @@ export namespace Utils {
355
355
  return exclude(result, field, ...excludedValues);
356
356
  }
357
357
 
358
+ /**
359
+ * Format name
360
+ * @param name Input name
361
+ * @param maxChars Max chars
362
+ * @param maxParts Max parts (optional)
363
+ * @returns Formatted name
364
+ */
365
+ export function formatName(
366
+ name: string,
367
+ maxChars: number,
368
+ maxParts?: number
369
+ ): string {
370
+ name = name.trim();
371
+
372
+ const parts = name.split(/\s+/);
373
+
374
+ const max = maxParts ?? Math.floor(maxChars / 3);
375
+ const effectiveMax = max < 2 ? 2 : max;
376
+
377
+ if (parts.length >= effectiveMax) {
378
+ return parts.slice(0, effectiveMax).join(" ");
379
+ } else if (name.length > maxChars) {
380
+ let endIndex = maxChars;
381
+ const brackets: Record<string, string> = {
382
+ "(": ")",
383
+ "(": ")",
384
+ "[": "]"
385
+ };
386
+
387
+ // Count unmatched brackets for each type
388
+ for (const [start, end] of Object.entries(brackets)) {
389
+ let count = 0;
390
+
391
+ // Count opening and closing brackets in the substring
392
+ for (let i = 0; i < maxChars; i++) {
393
+ if (name[i] === start) count++;
394
+ else if (name[i] === end) count--;
395
+ }
396
+
397
+ if (count > 0) {
398
+ // Find matching end brackets
399
+ for (let i = maxChars; i < name.length && count > 0; i++) {
400
+ if (name[i] === start) {
401
+ count++;
402
+ } else if (name[i] === end) {
403
+ count--;
404
+ if (count === 0) {
405
+ endIndex = i + 1;
406
+ }
407
+ }
408
+ }
409
+
410
+ if (count === 0) {
411
+ return name.substring(0, endIndex);
412
+ }
413
+ }
414
+ }
415
+
416
+ return name.substring(0, endIndex);
417
+ } else {
418
+ return name;
419
+ }
420
+ }
421
+
358
422
  /**
359
423
  * Format inital character to lower case or upper case
360
424
  * @param input Input string
@@ -823,7 +887,7 @@ export namespace Utils {
823
887
  ) => {
824
888
  Object.keys(source).forEach((key) => {
825
889
  // Reference key
826
- const labelKey = reference == null ? key : reference[key] ?? key;
890
+ const labelKey = reference == null ? key : (reference[key] ?? key);
827
891
 
828
892
  // Label
829
893
  const label = labels[labelKey];
@@ -963,8 +1027,8 @@ export namespace Utils {
963
1027
  index1 === -1
964
1028
  ? index2
965
1029
  : index2 === -1
966
- ? index1
967
- : Math.min(index1, index2);
1030
+ ? index1
1031
+ : Math.min(index1, index2);
968
1032
  root = path.substring(0, index + 1);
969
1033
  dir = path.substring(0, lastIndex);
970
1034
  if (dir === "") dir = root;
@@ -73,5 +73,5 @@ export interface IStorage {
73
73
  * @param key Key name
74
74
  * @param data Data, null for removal
75
75
  */
76
- setPersistedData(key: string, data: unknown): void;
76
+ setPersistedData<T>(key: string, data: T): void;
77
77
  }
@@ -141,7 +141,7 @@ export class WindowStorage implements IStorage {
141
141
  * @param key Key name
142
142
  * @param data Data, null for removal
143
143
  */
144
- setPersistedData(key: string, data: unknown) {
144
+ setPersistedData<T>(key: string, data: T) {
145
145
  StorageUtils.setLocalData(key, data);
146
146
  }
147
147
  }