@codex-ts/core-lib 1.0.0 → 1.0.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.
Files changed (77) hide show
  1. package/{dist/core-lib/fesm2022/core-lib.mjs → fesm2022/codex-ts-core-lib.mjs} +1 -1
  2. package/fesm2022/codex-ts-core-lib.mjs.map +1 -0
  3. package/package.json +42 -63
  4. package/dist/core-lib/fesm2022/core-lib.mjs.map +0 -1
  5. package/ng-package.json +0 -7
  6. package/src/index.ts +0 -44
  7. package/src/lib/components/base-form.component.ts +0 -328
  8. package/src/lib/components/base-list-page.component.ts +0 -327
  9. package/src/lib/components/base-page.component.ts +0 -33
  10. package/src/lib/components/base-tabbed-form.component.ts +0 -345
  11. package/src/lib/components/formly/core-formly.module.ts +0 -34
  12. package/src/lib/components/formly/field.interface.ts +0 -15
  13. package/src/lib/components/formly/form-field.wrapper.ts +0 -94
  14. package/src/lib/components/formly/formly.constants.ts +0 -14
  15. package/src/lib/components/formly/primeng-formly.module.ts +0 -77
  16. package/src/lib/components/formly/types/checkbox.type.ts +0 -43
  17. package/src/lib/components/formly/types/date.type.ts +0 -88
  18. package/src/lib/components/formly/types/multiselect.type.ts +0 -61
  19. package/src/lib/components/formly/types/numeric-input.type.ts +0 -45
  20. package/src/lib/components/formly/types/radio.type.ts +0 -47
  21. package/src/lib/components/formly/types/select.type.ts +0 -54
  22. package/src/lib/components/formly/types/text-input.type.ts +0 -33
  23. package/src/lib/components/formly/types/textarea.type.ts +0 -37
  24. package/src/lib/constants/app.constants.ts +0 -15
  25. package/src/lib/constants/app.messages.ts +0 -36
  26. package/src/lib/enums/component-context.enum.ts +0 -6
  27. package/src/lib/enums/tabbed-form-type.enum.ts +0 -4
  28. package/src/lib/models/pagination/filter-criteria.interface.ts +0 -19
  29. package/src/lib/models/pagination/page-request.interface.ts +0 -13
  30. package/src/lib/models/pagination/page.interface.ts +0 -9
  31. package/src/lib/models/pagination/sort-criteria.interface.ts +0 -4
  32. package/src/lib/pipes/indian-date.pipe.ts +0 -46
  33. package/src/lib/services/base-crud.service.ts +0 -81
  34. package/src/lib/services/entity-registry.service.ts +0 -51
  35. package/src/lib/services/entity.service.ts +0 -10
  36. package/src/lib/services/enum-registry.service.ts +0 -66
  37. package/src/lib/services/formly-config.service.ts +0 -50
  38. package/src/lib/services/http-utility.service.example.ts +0 -253
  39. package/src/lib/services/http-utility.service.md +0 -175
  40. package/src/lib/services/http-utility.service.ts +0 -389
  41. package/src/lib/services/notification.service.ts +0 -35
  42. package/src/lib/services/reference-data-provider.service.ts +0 -28
  43. package/src/lib/services/utils.service.ts +0 -154
  44. /package/{dist/core-lib/index.d.ts → index.d.ts} +0 -0
  45. /package/{dist/core-lib/lib → lib}/components/base-form.component.d.ts +0 -0
  46. /package/{dist/core-lib/lib → lib}/components/base-list-page.component.d.ts +0 -0
  47. /package/{dist/core-lib/lib → lib}/components/base-page.component.d.ts +0 -0
  48. /package/{dist/core-lib/lib → lib}/components/base-tabbed-form.component.d.ts +0 -0
  49. /package/{dist/core-lib/lib → lib}/components/formly/core-formly.module.d.ts +0 -0
  50. /package/{dist/core-lib/lib → lib}/components/formly/form-field.wrapper.d.ts +0 -0
  51. /package/{dist/core-lib/lib → lib}/components/formly/formly.constants.d.ts +0 -0
  52. /package/{dist/core-lib/lib → lib}/components/formly/types/checkbox.type.d.ts +0 -0
  53. /package/{dist/core-lib/lib → lib}/components/formly/types/date.type.d.ts +0 -0
  54. /package/{dist/core-lib/lib → lib}/components/formly/types/multiselect.type.d.ts +0 -0
  55. /package/{dist/core-lib/lib → lib}/components/formly/types/numeric-input.type.d.ts +0 -0
  56. /package/{dist/core-lib/lib → lib}/components/formly/types/radio.type.d.ts +0 -0
  57. /package/{dist/core-lib/lib → lib}/components/formly/types/select.type.d.ts +0 -0
  58. /package/{dist/core-lib/lib → lib}/components/formly/types/text-input.type.d.ts +0 -0
  59. /package/{dist/core-lib/lib → lib}/components/formly/types/textarea.type.d.ts +0 -0
  60. /package/{dist/core-lib/lib → lib}/constants/app.constants.d.ts +0 -0
  61. /package/{dist/core-lib/lib → lib}/constants/app.messages.d.ts +0 -0
  62. /package/{dist/core-lib/lib → lib}/enums/component-context.enum.d.ts +0 -0
  63. /package/{dist/core-lib/lib → lib}/enums/tabbed-form-type.enum.d.ts +0 -0
  64. /package/{dist/core-lib/lib → lib}/models/pagination/filter-criteria.interface.d.ts +0 -0
  65. /package/{dist/core-lib/lib → lib}/models/pagination/page-request.interface.d.ts +0 -0
  66. /package/{dist/core-lib/lib → lib}/models/pagination/page.interface.d.ts +0 -0
  67. /package/{dist/core-lib/lib → lib}/models/pagination/sort-criteria.interface.d.ts +0 -0
  68. /package/{dist/core-lib/lib → lib}/pipes/indian-date.pipe.d.ts +0 -0
  69. /package/{dist/core-lib/lib → lib}/services/base-crud.service.d.ts +0 -0
  70. /package/{dist/core-lib/lib → lib}/services/entity-registry.service.d.ts +0 -0
  71. /package/{dist/core-lib/lib → lib}/services/entity.service.d.ts +0 -0
  72. /package/{dist/core-lib/lib → lib}/services/enum-registry.service.d.ts +0 -0
  73. /package/{dist/core-lib/lib → lib}/services/formly-config.service.d.ts +0 -0
  74. /package/{dist/core-lib/lib → lib}/services/http-utility.service.d.ts +0 -0
  75. /package/{dist/core-lib/lib → lib}/services/notification.service.d.ts +0 -0
  76. /package/{dist/core-lib/lib → lib}/services/reference-data-provider.service.d.ts +0 -0
  77. /package/{dist/core-lib/lib → lib}/services/utils.service.d.ts +0 -0
@@ -1,389 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse, HttpEvent } from '@angular/common/http';
3
- import { Observable, throwError, BehaviorSubject, finalize, forkJoin } from 'rxjs';
4
- import { catchError, retry, timeout } from 'rxjs/operators';
5
- import { MessageService } from 'primeng/api';
6
-
7
- /**
8
- * A general-purpose HTTP utility service that provides enhanced HTTP operations
9
- * beyond the standard Angular HttpClient. This service includes features such as:
10
- * - Loading state management
11
- * - Standardized error handling
12
- * - Request timeouts and retries
13
- * - File upload capabilities
14
- * - Batch request handling
15
- */
16
- @Injectable({
17
- providedIn: 'root'
18
- })
19
- export class HttpUtilityService {
20
- private loading = new BehaviorSubject<boolean>(false);
21
- loading$ = this.loading.asObservable();
22
-
23
- constructor(
24
- private http: HttpClient,
25
- private messageService?: MessageService
26
- ) {}
27
-
28
- /**
29
- * Perform a GET request with enhanced options
30
- * @param url The endpoint URL
31
- * @param options Additional request options
32
- * @returns An observable of the response
33
- */
34
- get<T>(url: string, options?: {
35
- params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
36
- headers?: HttpHeaders | Record<string, string | string[]>,
37
- responseType?: 'json',
38
- withCredentials?: boolean,
39
- retries?: number,
40
- timeoutMs?: number
41
- }): Observable<T> {
42
- this.loading.next(true);
43
-
44
- let request$ = this.http.get<T>(url, {
45
- params: options?.params,
46
- headers: options?.headers,
47
- responseType: options?.responseType as 'json',
48
- withCredentials: options?.withCredentials
49
- });
50
-
51
- if (options?.retries) {
52
- request$ = request$.pipe(retry(options.retries));
53
- }
54
-
55
- if (options?.timeoutMs) {
56
- request$ = request$.pipe(timeout(options.timeoutMs));
57
- }
58
-
59
- return request$.pipe(
60
- catchError(this.handleError.bind(this)),
61
- finalize(() => this.loading.next(false))
62
- );
63
- }
64
-
65
- /**
66
- * Perform a POST request with enhanced options
67
- * @param url The endpoint URL
68
- * @param body The request payload
69
- * @param options Additional request options
70
- * @returns An observable of the response
71
- */
72
- post<T>(url: string, body: any, options?: {
73
- params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
74
- headers?: HttpHeaders | Record<string, string | string[]>,
75
- responseType?: 'json',
76
- withCredentials?: boolean,
77
- retries?: number,
78
- timeoutMs?: number
79
- }): Observable<T> {
80
- this.loading.next(true);
81
-
82
- let request$ = this.http.post<T>(url, body, {
83
- params: options?.params,
84
- headers: options?.headers,
85
- responseType: options?.responseType as 'json',
86
- withCredentials: options?.withCredentials
87
- });
88
-
89
- if (options?.retries) {
90
- request$ = request$.pipe(retry(options.retries));
91
- }
92
-
93
- if (options?.timeoutMs) {
94
- request$ = request$.pipe(timeout(options.timeoutMs));
95
- }
96
-
97
- return request$.pipe(
98
- catchError(this.handleError.bind(this)),
99
- finalize(() => this.loading.next(false))
100
- );
101
- }
102
-
103
- /**
104
- * Perform a PUT request with enhanced options
105
- * @param url The endpoint URL
106
- * @param body The request payload
107
- * @param options Additional request options
108
- * @returns An observable of the response
109
- */
110
- put<T>(url: string, body: any, options?: {
111
- params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
112
- headers?: HttpHeaders | Record<string, string | string[]>,
113
- responseType?: 'json',
114
- withCredentials?: boolean,
115
- retries?: number,
116
- timeoutMs?: number
117
- }): Observable<T> {
118
- this.loading.next(true);
119
-
120
- let request$ = this.http.put<T>(url, body, {
121
- params: options?.params,
122
- headers: options?.headers,
123
- responseType: options?.responseType as 'json',
124
- withCredentials: options?.withCredentials
125
- });
126
-
127
- if (options?.retries) {
128
- request$ = request$.pipe(retry(options.retries));
129
- }
130
-
131
- if (options?.timeoutMs) {
132
- request$ = request$.pipe(timeout(options.timeoutMs));
133
- }
134
-
135
- return request$.pipe(
136
- catchError(this.handleError.bind(this)),
137
- finalize(() => this.loading.next(false))
138
- );
139
- }
140
-
141
- /**
142
- * Perform a DELETE request with enhanced options
143
- * @param url The endpoint URL
144
- * @param options Additional request options
145
- * @returns An observable of the response
146
- */
147
- delete<T>(url: string, options?: {
148
- params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
149
- headers?: HttpHeaders | Record<string, string | string[]>,
150
- responseType?: 'json',
151
- withCredentials?: boolean,
152
- retries?: number,
153
- timeoutMs?: number
154
- }): Observable<T> {
155
- this.loading.next(true);
156
-
157
- let request$ = this.http.delete<T>(url, {
158
- params: options?.params,
159
- headers: options?.headers,
160
- responseType: options?.responseType as 'json',
161
- withCredentials: options?.withCredentials
162
- });
163
-
164
- if (options?.retries) {
165
- request$ = request$.pipe(retry(options.retries));
166
- }
167
-
168
- if (options?.timeoutMs) {
169
- request$ = request$.pipe(timeout(options.timeoutMs));
170
- }
171
-
172
- return request$.pipe(
173
- catchError(this.handleError.bind(this)),
174
- finalize(() => this.loading.next(false))
175
- );
176
- }
177
-
178
- /**
179
- * Upload a file with optional additional data
180
- * @param url The upload endpoint URL
181
- * @param file The file to upload
182
- * @param additionalData Additional form data to include
183
- * @param options Additional request options
184
- * @returns An observable of the response
185
- */
186
- uploadFile<T>(url: string, file: File, additionalData?: Record<string, any>, options?: {
187
- headers?: HttpHeaders | Record<string, string | string[]>,
188
- withCredentials?: boolean,
189
- retries?: number,
190
- timeoutMs?: number,
191
- onProgress?: (percentage: number) => void
192
- }): Observable<T> {
193
- this.loading.next(true);
194
-
195
- const formData = new FormData();
196
- formData.append('file', file, file.name);
197
-
198
- if (additionalData) {
199
- Object.keys(additionalData).forEach(key => {
200
- formData.append(key, additionalData[key]);
201
- });
202
- }
203
-
204
- let httpOptions: any = {
205
- headers: options?.headers,
206
- withCredentials: options?.withCredentials
207
- };
208
-
209
- // If progress tracking is requested
210
- if (options?.onProgress) {
211
- httpOptions.reportProgress = true;
212
- httpOptions.observe = 'events';
213
- }
214
-
215
- // Create the request
216
- let request$ = this.http.post<any>(url, formData, httpOptions);
217
-
218
- // Add retries if specified
219
- if (options?.retries) {
220
- request$ = request$.pipe(retry(options.retries));
221
- }
222
-
223
- // Add timeout if specified
224
- if (options?.timeoutMs) {
225
- request$ = request$.pipe(timeout(options.timeoutMs));
226
- }
227
-
228
- // Track progress if a callback is provided
229
- if (options?.onProgress) {
230
- return new Observable<T>(observer => {
231
- request$.subscribe({
232
- next: (event: HttpEvent<any>) => {
233
- if (event.type === 1 && event.total) { // HttpEventType.UploadProgress
234
- const percentDone = Math.round(100 * event.loaded / event.total);
235
- options.onProgress!(percentDone);
236
- } else if (event.type === 4) { // HttpEventType.Response
237
- observer.next(event.body);
238
- observer.complete();
239
- }
240
- },
241
- error: (error) => {
242
- observer.error(this.handleError(error));
243
- this.loading.next(false);
244
- },
245
- complete: () => {
246
- this.loading.next(false);
247
- }
248
- });
249
- });
250
- }
251
-
252
- // Standard request without progress tracking
253
- return request$.pipe(
254
- catchError(this.handleError.bind(this)),
255
- finalize(() => this.loading.next(false))
256
- ) as Observable<T>;
257
- }
258
-
259
- /**
260
- * Execute multiple HTTP requests in parallel
261
- * @param requests Array of HTTP request observables
262
- * @returns An observable that emits when all requests complete
263
- */
264
- batchRequests<T>(requests: Observable<T>[]): Observable<T[]> {
265
- this.loading.next(true);
266
- return forkJoin(requests).pipe(
267
- catchError(this.handleError.bind(this)),
268
- finalize(() => this.loading.next(false))
269
- );
270
- }
271
-
272
- /**
273
- * Download a file from the server
274
- * @param url The file URL
275
- * @param filename Optional filename to save as
276
- * @param options Additional request options
277
- */
278
- downloadFile(url: string, filename?: string, options?: {
279
- params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
280
- headers?: HttpHeaders | Record<string, string | string[]>,
281
- withCredentials?: boolean,
282
- timeoutMs?: number
283
- }): Observable<Blob> {
284
- this.loading.next(true);
285
-
286
- let request$ = this.http.get(url, {
287
- params: options?.params,
288
- headers: options?.headers,
289
- responseType: 'blob',
290
- withCredentials: options?.withCredentials
291
- });
292
-
293
- if (options?.timeoutMs) {
294
- request$ = request$.pipe(timeout(options.timeoutMs));
295
- }
296
-
297
- return request$.pipe(
298
- catchError(this.handleError.bind(this)),
299
- finalize(() => this.loading.next(false))
300
- );
301
- }
302
-
303
- /**
304
- * Create parameter string from an object
305
- * @param params Object containing parameters
306
- * @returns HttpParams object
307
- */
308
- createParams(params: Record<string, any>): HttpParams {
309
- let httpParams = new HttpParams();
310
-
311
- Object.keys(params).forEach(key => {
312
- const value = params[key];
313
- if (value !== undefined && value !== null) {
314
- httpParams = httpParams.append(key, value.toString());
315
- }
316
- });
317
-
318
- return httpParams;
319
- }
320
-
321
- /**
322
- * Standardized error handler for HTTP requests
323
- * @param error The HTTP error
324
- * @returns An observable that errors with the processed error object
325
- */
326
- private handleError(error: HttpErrorResponse) {
327
- console.error('An HTTP error occurred:', error);
328
-
329
- let errorMessage = 'An error occurred';
330
- let errorCode: string | undefined;
331
-
332
- if (error.error instanceof ErrorEvent) {
333
- // Client-side error
334
- errorMessage = error.error.message;
335
- } else {
336
- // Server-side error
337
- errorCode = error.status.toString();
338
-
339
- switch (error.status) {
340
- case 400:
341
- errorMessage = error.error?.message || 'Bad request';
342
- break;
343
- case 401:
344
- errorMessage = 'Unauthorized';
345
- break;
346
- case 403:
347
- errorMessage = 'Access denied';
348
- break;
349
- case 404:
350
- errorMessage = 'Resource not found';
351
- break;
352
- case 408:
353
- errorMessage = 'Request timeout';
354
- break;
355
- case 500:
356
- errorMessage = 'Server error';
357
- break;
358
- case 503:
359
- errorMessage = 'Service unavailable';
360
- break;
361
- default:
362
- errorMessage = error.error?.message || `Error ${error.status}`;
363
- break;
364
- }
365
- }
366
-
367
- this.showError(errorMessage);
368
- return throwError(() => ({
369
- error,
370
- message: errorMessage,
371
- code: errorCode
372
- }));
373
- }
374
-
375
- /**
376
- * Display an error message using the message service
377
- * @param message Error message to display
378
- */
379
- private showError(message: string) {
380
- if (this.messageService) {
381
- this.messageService.add({
382
- severity: 'error',
383
- summary: 'Error',
384
- detail: message,
385
- life: 3000
386
- });
387
- }
388
- }
389
- }
@@ -1,35 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { MessageService } from 'primeng/api';
3
- import { BehaviorSubject } from 'rxjs';
4
-
5
- @Injectable()
6
- export class NotificationService {
7
- private messageSubject = new BehaviorSubject<any>(null);
8
- message$ = this.messageSubject.asObservable();
9
-
10
- constructor(private messageService: MessageService) {}
11
-
12
- showSuccess(message: string) {
13
- const msgObj = {
14
- severity: 'success',
15
- summary: 'Success',
16
- detail: message,
17
- life: 3000
18
- };
19
- this.messageSubject.next(msgObj);
20
- }
21
-
22
- showError(message: string) {
23
- const msgObj = {
24
- severity: 'error',
25
- summary: 'Error',
26
- detail: message,
27
- life: 3000
28
- };
29
- this.messageSubject.next(msgObj);
30
- }
31
-
32
- clearMessage() {
33
- this.messageSubject.next(null);
34
- }
35
- }
@@ -1,28 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
-
3
- @Injectable({
4
- providedIn: 'root'
5
- })
6
- export class ReferenceDataProviderService {
7
-
8
- private endpoints: Record<string, string> = {};
9
-
10
- // Method to set/update endpoints
11
- setEndpoints(endpoints: Record<string, string>) {
12
- this.endpoints = { ...this.endpoints, ...endpoints };
13
- }
14
-
15
- getReferenceEndpoint(entityName: string): string | null {
16
- console.log('getReferenceEndpoint', entityName, this.endpoints);
17
- let endpoint = this.endpoints[entityName];
18
- if (endpoint != null && endpoint.length > 0) {
19
- if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
20
- return endpoint; // Absolute URL
21
- } else {
22
- // Relative URL, assume it's within the application's base context
23
- return endpoint;
24
- }
25
- }
26
- return null;
27
- }
28
- }
@@ -1,154 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { MessageService } from 'primeng/api';
3
-
4
- /**
5
- * A utility service that provides common reusable functionality
6
- * such as UUID validation and error message display
7
- */
8
- @Injectable({
9
- providedIn: 'root'
10
- })
11
- export class UtilsService {
12
- /**
13
- * Validates if a string is a valid UUID
14
- * @param uuid The string to validate
15
- * @returns boolean indicating if the string is a valid UUID
16
- */
17
- isValidUUID(uuid: string): boolean {
18
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19
- return uuidRegex.test(uuid);
20
- }
21
-
22
- /**
23
- * Shows an error message using PrimeNG's MessageService
24
- * @param message The error message to display
25
- * @param messageService The MessageService instance to use
26
- */
27
- showError(message: string, messageService?: MessageService) {
28
- if (messageService) {
29
- messageService.add({
30
- severity: 'error',
31
- summary: 'Error',
32
- detail: message,
33
- life: 3000
34
- });
35
- }
36
- }
37
-
38
- /**
39
- * Shows a success message using PrimeNG's MessageService
40
- * @param message The success message to display
41
- * @param messageService The MessageService instance to use
42
- */
43
- showSuccess(message: string, messageService?: MessageService) {
44
- if (messageService) {
45
- messageService.add({
46
- severity: 'success',
47
- summary: 'Success',
48
- detail: message,
49
- life: 3000
50
- });
51
- }
52
- }
53
-
54
- /**
55
- * Gets the display value for an enum key or array of enum keys
56
- * @param enumType The enum type
57
- * @param key The enum key or array of enum keys
58
- * @returns The display value for the enum key or comma-separated list of display values for array of keys
59
- */
60
- getEnumValue<T>(enumType: T, key: string | string[]): string {
61
- if (!key) return '';
62
-
63
- if (Array.isArray(key)) {
64
- // Handle array of keys - map each to its display value and join with comma
65
- return key.map(k => (enumType as any)[k] || k).join(', ');
66
- }
67
-
68
- // Handle single key
69
- return (enumType as any)[key] || key;
70
- }
71
-
72
- /**
73
- * Gets all values from an enum type for use in formly select fields
74
- * @param enumType The enum type to get values from
75
- * @returns Array of {label, value} pairs for formly select options
76
- */
77
- getEnumValues<T extends { [key: string]: string | number }>(enumType: T): Array<{label: string, value: string}> {
78
- return Object.entries(enumType)
79
- .filter(([key]) => isNaN(Number(key))) // Filter out reverse mappings
80
- .map(([key, value]) => ({
81
- value: key, // enum key as the value
82
- label: value as string // enum value as the label
83
- }));
84
- }
85
-
86
- /**
87
- * Converts a camelCase string to Title Case with spaces
88
- * @param camelCase The camelCase string to convert
89
- * @returns The Title Case string
90
- */
91
- camelCaseToTitleCase(camelCase: string): string {
92
- if (!camelCase) return '';
93
- const spacedString = camelCase.replace(/([a-z])([A-Z])/g, '$1 $2');
94
- return spacedString.charAt(0).toUpperCase() + spacedString.slice(1);
95
- }
96
-
97
- /**
98
- * Converts a string to kebab-case
99
- * @param input The string to convert
100
- * @returns The kebab-case string
101
- */
102
- toKebabCase(input: string): string {
103
- return input
104
- .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
105
- .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2')
106
- .toLowerCase();
107
- }
108
-
109
- /**
110
- * Converts a string to camelCase.
111
- * Example: "loan-application" becomes "loanApplication"
112
- * @param input The string to convert
113
- * @returns The camelCase string
114
- */
115
- toCamelCase(input: string): string {
116
- if (!input) return '';
117
-
118
- // Split by non-alphanumeric chars
119
- const words = input.split(/[^a-zA-Z0-9]/);
120
- const result = [words[0].toLowerCase()];
121
-
122
- // Capitalize first letter of remaining words
123
- for (let i = 1; i < words.length; i++) {
124
- const word = words[i];
125
- if (word) {
126
- result.push(word.charAt(0).toUpperCase() + word.substring(1).toLowerCase());
127
- }
128
- }
129
-
130
- return result.join('');
131
- }
132
-
133
- /**
134
- * Removes double forward slashes from an endpoint string while preserving the protocol
135
- * e.g. "http://localhost:8080//api//v1//users" -> "http://localhost:8080/api/v1/users"
136
- * @param endpoint The endpoint string to clean
137
- * @returns The cleaned endpoint string without double slashes
138
- */
139
- removeDoubleSlashes(endpoint: string): string {
140
- if (!endpoint) return '';
141
-
142
- // Split the URL into protocol and the rest to preserve protocol slashes
143
- const [protocol, ...rest] = endpoint.split('://');
144
-
145
- if (!rest.length) {
146
- // If no protocol is present, just clean the entire string
147
- return endpoint.replace(/\/+/g, '/');
148
- }
149
-
150
- // Clean the path part (after protocol) and reconstruct the URL
151
- const cleanPath = rest.join('://').replace(/\/+/g, '/');
152
- return `${protocol}://${cleanPath}`;
153
- }
154
- }
File without changes