@jsarc/qust 0.0.0 → 0.0.1-beta.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.
package/README.md CHANGED
@@ -328,18 +328,18 @@ const url = buildSearchUrl("/products", filters);
328
328
 
329
329
  ```typescript
330
330
  // Dans une application web
331
- const currentQuery = window.location.search;
331
+ const currentQuery = (window as any).location.search;
332
332
  const params = qust.parse(currentQuery);
333
333
 
334
334
  // Utilisation avec React/Vue/Angular
335
335
  function useQueryParams() {
336
336
  const [params, setParams] = useState(() => {
337
- return qust.parse(window.location.search);
337
+ return qust.parse((window as any).location.search);
338
338
  });
339
339
 
340
340
  const updateParams = (newParams: any) => {
341
341
  const query = qust.stringify({ ...params, ...newParams });
342
- window.history.pushState({}, '', `?\${query}`);
342
+ (window as any).history.pushState({}, '', `?\${query}`);
343
343
  setParams(qust.parse(query));
344
344
  };
345
345
 
@@ -376,11 +376,11 @@ class FormState {
376
376
  skipEmptyString: true,
377
377
  skipNull: true
378
378
  });
379
- window.location.hash = query;
379
+ (window as any).location.hash = query;
380
380
  }
381
381
 
382
382
  loadFromUrl() {
383
- const query = window.location.hash.substring(1);
383
+ const query = (window as any).location.hash.substring(1);
384
384
  this.state = qust.parse(`?\${query}`) || {};
385
385
  }
386
386
  }
package/index.ts CHANGED
@@ -353,7 +353,7 @@ const globalFunct = (function(global: any) {
353
353
 
354
354
  static exposeToGlobal(): void {
355
355
  if (typeof window !== "undefined") {
356
- window.Qust = Qust;
356
+ (window as any).Qust = Qust;
357
357
  }
358
358
  }
359
359
  }
@@ -370,8 +370,8 @@ const globalFunct = (function(global: any) {
370
370
  };
371
371
 
372
372
  if (typeof window !== "undefined") {
373
- window.Qust = Qust;
374
- window.qust = qust;
373
+ (window as any).Qust = Qust;
374
+ (window as any).qust = qust;
375
375
  }
376
376
 
377
377
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.0.0",
6
+ "version": "0.0.1-beta.0.1",
7
7
  "description": "Qust est une bibliothèque TypeScript ultra-légère et performante pour la sérialisation et désérialisation d'objets en chaînes de requête (query strings). Elle offre une API simple et puissante pour manipuler les paramètres d'URL avec support des types complexes, des tableaux, des objets imbriqués et des options avancées.",
8
8
  "main": "index.ts",
9
9
  "keywords": [],
package/qust.ts ADDED
@@ -0,0 +1,429 @@
1
+ // @ts-nocheck
2
+
3
+ interface Window {
4
+ default: typeof defaultElementGF;
5
+ Qust: any;
6
+ qust: any;
7
+ __bundledModules: any;
8
+ }
9
+
10
+ interface QustOptions {
11
+ arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
12
+ arraySeparator?: string;
13
+ skipNull?: boolean;
14
+ skipEmptyString?: boolean;
15
+ encode?: boolean;
16
+ decode?: boolean;
17
+ depth?: number;
18
+ }
19
+
20
+
21
+ type Primitive = string | number | boolean | null | undefined;
22
+
23
+ type QueryValue = Primitive | Primitive[] | { [key: string]: QueryValue };
24
+
25
+ type QueryObject = { [key: string]: QueryValue };
26
+
27
+ const globalFunct = (function(global: any) {
28
+ 'use strict';
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ const DEFAULT_OPTIONS: Required<QustOptions> = {
39
+ arrayFormat: 'bracket',
40
+ arraySeparator: ',',
41
+ skipNull: true,
42
+ skipEmptyString: false,
43
+ encode: true,
44
+ decode: true,
45
+ depth: 10
46
+ };
47
+
48
+ class Qust {
49
+ private options: Required<QustOptions>;
50
+
51
+ constructor(options: QustOptions = {}) {
52
+ this.options = { ...DEFAULT_OPTIONS, ...options };
53
+ }
54
+
55
+ stringify(obj: QueryObject): string {
56
+ if (!obj || typeof obj !== 'object') {
57
+ return '';
58
+ }
59
+
60
+ const parts: string[] = [];
61
+ this.processObject('', obj, parts, 0);
62
+
63
+ return parts.length > 0 ? `?${parts.join('&')}` : '';
64
+ }
65
+
66
+ parse<T = QueryObject>(queryString: string): T {
67
+ if (!queryString || typeof queryString !== 'string') {
68
+ return {} as T;
69
+ }
70
+
71
+ const cleanString = queryString.startsWith('?')
72
+ ? queryString.slice(1)
73
+ : queryString;
74
+
75
+ if (!cleanString) {
76
+ return {} as T;
77
+ }
78
+
79
+ const result: QueryObject = {};
80
+ const pairs = cleanString.split('&');
81
+
82
+ for (const pair of pairs) {
83
+ if (!pair) continue;
84
+
85
+ const [encodedKey, encodedValue] = pair.split('=');
86
+
87
+ if (!encodedKey) continue;
88
+
89
+ const key = this.options.decode
90
+ ? decodeURIComponent(encodedKey)
91
+ : encodedKey;
92
+
93
+ const value = this.options.decode && encodedValue !== undefined
94
+ ? decodeURIComponent(encodedValue)
95
+ : encodedValue;
96
+
97
+ this.setValue(result, key, value);
98
+ }
99
+
100
+ return this.transformArrays(result) as T;
101
+ }
102
+
103
+ private processObject(
104
+ prefix: string,
105
+ value: QueryValue,
106
+ parts: string[],
107
+ depth: number
108
+ ): void {
109
+ if (depth > this.options.depth) {
110
+ console.warn('Qust: Profondeur maximale atteinte, arrêt de la récursion');
111
+ return;
112
+ }
113
+
114
+ if (value === null || value === undefined) {
115
+ if (!this.options.skipNull) {
116
+ parts.push(this.encodeKey(prefix));
117
+ }
118
+ return;
119
+ }
120
+
121
+ if (typeof value === 'string' && value === '' && this.options.skipEmptyString) {
122
+ return;
123
+ }
124
+
125
+ if (Array.isArray(value)) {
126
+ this.processArray(prefix, value, parts, depth + 1);
127
+ return;
128
+ }
129
+
130
+ if (typeof value === 'object' && !this.isPrimitive(value)) {
131
+ for (const [key, val] of Object.entries(value)) {
132
+ const newPrefix = prefix ? `${prefix}[${key}]` : key;
133
+ this.processObject(newPrefix, val, parts, depth + 1);
134
+ }
135
+ return;
136
+ }
137
+
138
+ const encodedKey = this.encodeKey(prefix);
139
+ const encodedValue = this.options.encode && typeof value === 'string'
140
+ ? encodeURIComponent(value)
141
+ : String(value);
142
+
143
+ parts.push(`${encodedKey}=${encodedValue}`);
144
+ }
145
+
146
+ private processArray(
147
+ prefix: string,
148
+ array: Primitive[],
149
+ parts: string[],
150
+ depth: number
151
+ ): void {
152
+ if (array.length === 0) return;
153
+
154
+ const encodedKey = this.encodeKey(prefix);
155
+
156
+ switch (this.options.arrayFormat) {
157
+ case 'comma':
158
+ const values = array
159
+ .map(item => this.options.encode && typeof item === 'string'
160
+ ? encodeURIComponent(item)
161
+ : String(item)
162
+ )
163
+ .join(this.options.arraySeparator);
164
+ parts.push(`${encodedKey}=${values}`);
165
+ break;
166
+
167
+ case 'index':
168
+ array.forEach((item, index) => {
169
+ const arrayPrefix = `${prefix}[${index}]`;
170
+ this.processObject(arrayPrefix, item, parts, depth);
171
+ });
172
+ break;
173
+
174
+ case 'separator':
175
+ array.forEach(item => {
176
+ const encodedValue = this.options.encode && typeof item === 'string'
177
+ ? encodeURIComponent(item)
178
+ : String(item);
179
+ parts.push(`${encodedKey}=${encodedValue}`);
180
+ });
181
+ break;
182
+
183
+ case 'none':
184
+ array.forEach(item => {
185
+ this.processObject(prefix, item, parts, depth);
186
+ });
187
+ break;
188
+
189
+ case 'bracket':
190
+ default:
191
+ array.forEach(item => {
192
+ const arrayPrefix = `${prefix}[]`;
193
+ this.processObject(arrayPrefix, item, parts, depth);
194
+ });
195
+ break;
196
+ }
197
+ }
198
+
199
+ private encodeKey(key: string): string {
200
+ if (!this.options.encode) {
201
+ return key;
202
+ }
203
+
204
+ const parts: string[] = [];
205
+ let currentPart = '';
206
+
207
+ for (let i = 0; i < key.length; i++) {
208
+ const char = key[i];
209
+
210
+ if (char === '[' || char === ']') {
211
+
212
+ if (currentPart) {
213
+ parts.push(encodeURIComponent(currentPart));
214
+ currentPart = '';
215
+ }
216
+
217
+ parts.push(char);
218
+ } else {
219
+ currentPart += char;
220
+ }
221
+ }
222
+
223
+ if (currentPart) {
224
+ parts.push(encodeURIComponent(currentPart));
225
+ }
226
+
227
+ return parts.join('');
228
+ }
229
+
230
+ private setValue(obj: QueryObject, key: string, value: string | undefined): void {
231
+ const matches = key.match(/([^\[\]]+)|(\[\])/g);
232
+
233
+ if (!matches) {
234
+ if (value !== undefined) {
235
+ obj[key] = this.parseValue(value);
236
+ }
237
+ return;
238
+ }
239
+
240
+ let current: any = obj;
241
+
242
+ for (let i = 0; i < matches.length; i++) {
243
+ const match = matches[i];
244
+ const isLast = i === matches.length - 1;
245
+
246
+ if (match === '[]') {
247
+ if (!Array.isArray(current)) {
248
+ current = [];
249
+ }
250
+
251
+ if (isLast) {
252
+ if (!!value) {
253
+ current.push(this.parseValue(value));
254
+ }
255
+ } else {
256
+ const nextMatch = matches[i + 1];
257
+ const nextIndex = parseInt(nextMatch, 10);
258
+
259
+ if (!isNaN(nextIndex)) {
260
+ if (current[nextIndex] === undefined) {
261
+ current[nextIndex] = {};
262
+ }
263
+ current = current[nextIndex];
264
+ i++;
265
+ } else {
266
+ const newObj = {};
267
+ current.push(newObj);
268
+ current = newObj;
269
+ }
270
+ }
271
+ } else {
272
+ if (isLast) {
273
+ if (value !== undefined) {
274
+ current[match] = this.parseValue(value);
275
+ }
276
+ } else {
277
+ if (current[match] === undefined || typeof current[match] !== 'object') {
278
+ const nextMatch = matches[i + 1];
279
+ current[match] = nextMatch === '[]' ? [] : {};
280
+ }
281
+ current = current[match];
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ private transformArrays(obj: any): any {
288
+ if (Array.isArray(obj)) {
289
+ return obj.map(item =>
290
+ typeof item === 'object' && item !== null
291
+ ? this.transformArrays(item)
292
+ : item
293
+ );
294
+ }
295
+
296
+ if (typeof obj !== 'object' || obj === null) {
297
+ return obj;
298
+ }
299
+
300
+ const result: any = {};
301
+ const keys = Object.keys(obj);
302
+
303
+ const isArrayLike = keys.every(key => {
304
+ const num = parseInt(key, 10);
305
+ return !isNaN(num) && num >= 0 && num.toString() === key;
306
+ });
307
+
308
+ if (isArrayLike && keys.length > 0) {
309
+ const array: any[] = [];
310
+ keys.forEach(key => {
311
+ const index = parseInt(key, 10);
312
+ array[index] = this.transformArrays(obj[key]);
313
+ });
314
+ return array;
315
+ }
316
+
317
+ keys.forEach(key => {
318
+ const value = obj[key];
319
+ result[key] =
320
+ typeof value === 'object' && value !== null
321
+ ? this.transformArrays(value)
322
+ : value;
323
+ });
324
+
325
+ return result;
326
+ }
327
+
328
+ private parseValue(value: string): Primitive {
329
+ if (value === 'true') return true;
330
+ if (value === 'false') return false;
331
+ if (value === 'null') return null;
332
+ if (value === 'undefined') return undefined;
333
+
334
+ const num = Number(value);
335
+ if (!isNaN(num) && value.trim() !== '') return num;
336
+
337
+ return value;
338
+ }
339
+
340
+ private isPrimitive(value: any): boolean {
341
+ return value === null ||
342
+ typeof value !== 'object' &&
343
+ typeof value !== 'function';
344
+ }
345
+
346
+ setOptions(newOptions: Partial<QustOptions>): void {
347
+ this.options = { ...this.options, ...newOptions };
348
+ }
349
+
350
+ getOptions(): Required<QustOptions> {
351
+ return { ...this.options };
352
+ }
353
+
354
+ static exposeToGlobal(): void {
355
+ if (typeof window !== "undefined") {
356
+ (window as any).Qust = Qust;
357
+ }
358
+ }
359
+ }
360
+
361
+ const qust = {
362
+
363
+ stringify(obj: QueryObject, options?: QustOptions): string {
364
+ return new Qust(options).stringify(obj);
365
+ },
366
+
367
+ parse<T = QueryObject>(queryString: string, options?: QustOptions): T {
368
+ return new Qust(options).parse<T>(queryString);
369
+ }
370
+ };
371
+
372
+ if (typeof window !== "undefined") {
373
+ (window as any).Qust = Qust;
374
+ (window as any).qust = qust;
375
+ }
376
+
377
+
378
+
379
+
380
+ const globalFunctModule = {
381
+ default: qust,
382
+ Qust: Qust,
383
+ qust: qust,
384
+ };
385
+
386
+
387
+ const __bundledModules = globalFunctModule;
388
+
389
+ if (typeof global !== 'undefined') {
390
+ (global as any).default = qust;
391
+ (global as any).Qust = Qust;
392
+ (global as any).qust = qust;
393
+ (global as any).__bundledModules = __bundledModules;
394
+ }
395
+
396
+ if (typeof window !== "undefined") {
397
+ (window as any).default = qust;
398
+ (window as any).Qust = Qust;
399
+ (window as any).qust = qust;
400
+ (window as any).__bundledModules = __bundledModules;
401
+ }
402
+
403
+ if (typeof exports !== 'undefined') {
404
+ exports.default = qust;
405
+ exports.Qust = Qust;
406
+ exports.qust = qust;
407
+ }
408
+ return globalFunctModule;
409
+
410
+ })(typeof global !== 'undefined' ? global :
411
+ typeof window !== 'undefined' ? window :
412
+ typeof self !== 'undefined' ? self :
413
+ typeof globalThis !== 'undefined' ? globalThis :
414
+ {});
415
+
416
+ type QustElementTypeGF = typeof globalFunct.Qust;
417
+
418
+ type qustElementTypeGF = typeof globalFunct.qust;
419
+
420
+ type DefaultElementTypeGF = typeof globalFunct.default;
421
+
422
+ const QustElementGF: QustElementTypeGF = globalFunct.Qust;
423
+
424
+ const qustElementGF: qustElementTypeGF = globalFunct.qust;
425
+
426
+ const defaultElementGF: DefaultElementTypeGF = globalFunct.default;
427
+
428
+
429
+
package/ts/index.ts ADDED
@@ -0,0 +1,436 @@
1
+ // @ts-nocheck
2
+
3
+ interface Window {
4
+ default: typeof defaultElementGF;
5
+ Qust: any;
6
+ qust: any;
7
+ __bundledModules: any;
8
+ }
9
+
10
+ interface QustOptions {
11
+ arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
12
+ arraySeparator?: string;
13
+ skipNull?: boolean;
14
+ skipEmptyString?: boolean;
15
+ encode?: boolean;
16
+ decode?: boolean;
17
+ depth?: number;
18
+ }
19
+
20
+
21
+ type Primitive = string | number | boolean | null | undefined;
22
+
23
+ type QueryValue = Primitive | Primitive[] | { [key: string]: QueryValue };
24
+
25
+ type QueryObject = { [key: string]: QueryValue };
26
+
27
+ const globalFunct = (function(global: any) {
28
+ 'use strict';
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ const DEFAULT_OPTIONS: Required<QustOptions> = {
39
+ arrayFormat: 'bracket',
40
+ arraySeparator: ',',
41
+ skipNull: true,
42
+ skipEmptyString: false,
43
+ encode: true,
44
+ decode: true,
45
+ depth: 10
46
+ };
47
+
48
+ class Qust {
49
+ private options: Required<QustOptions>;
50
+
51
+ constructor(options: QustOptions = {}) {
52
+ this.options = { ...DEFAULT_OPTIONS, ...options };
53
+ }
54
+
55
+ stringify(obj: QueryObject): string {
56
+ if (!obj || typeof obj !== 'object') {
57
+ return '';
58
+ }
59
+
60
+ const parts: string[] = [];
61
+ this.processObject('', obj, parts, 0);
62
+
63
+ return parts.length > 0 ? `?${parts.join('&')}` : '';
64
+ }
65
+
66
+ parse<T = QueryObject>(queryString: string): T {
67
+ if (!queryString || typeof queryString !== 'string') {
68
+ return {} as T;
69
+ }
70
+
71
+ const cleanString = queryString.startsWith('?')
72
+ ? queryString.slice(1)
73
+ : queryString;
74
+
75
+ if (!cleanString) {
76
+ return {} as T;
77
+ }
78
+
79
+ const result: QueryObject = {};
80
+ const pairs = cleanString.split('&');
81
+
82
+ for (const pair of pairs) {
83
+ if (!pair) continue;
84
+
85
+ const [encodedKey, encodedValue] = pair.split('=');
86
+
87
+ if (!encodedKey) continue;
88
+
89
+ const key = this.options.decode
90
+ ? decodeURIComponent(encodedKey)
91
+ : encodedKey;
92
+
93
+ const value = this.options.decode && encodedValue !== undefined
94
+ ? decodeURIComponent(encodedValue)
95
+ : encodedValue;
96
+
97
+ this.setValue(result, key, value);
98
+ }
99
+
100
+ return this.transformArrays(result) as T;
101
+ }
102
+
103
+ private processObject(
104
+ prefix: string,
105
+ value: QueryValue,
106
+ parts: string[],
107
+ depth: number
108
+ ): void {
109
+ if (depth > this.options.depth) {
110
+ console.warn('Qust: Profondeur maximale atteinte, arrêt de la récursion');
111
+ return;
112
+ }
113
+
114
+ if (value === null || value === undefined) {
115
+ if (!this.options.skipNull) {
116
+ parts.push(this.encodeKey(prefix));
117
+ }
118
+ return;
119
+ }
120
+
121
+ if (typeof value === 'string' && value === '' && this.options.skipEmptyString) {
122
+ return;
123
+ }
124
+
125
+ if (Array.isArray(value)) {
126
+ this.processArray(prefix, value, parts, depth + 1);
127
+ return;
128
+ }
129
+
130
+ if (typeof value === 'object' && !this.isPrimitive(value)) {
131
+ for (const [key, val] of Object.entries(value)) {
132
+ const newPrefix = prefix ? `${prefix}[${key}]` : key;
133
+ this.processObject(newPrefix, val, parts, depth + 1);
134
+ }
135
+ return;
136
+ }
137
+
138
+ const encodedKey = this.encodeKey(prefix);
139
+ const encodedValue = this.options.encode && typeof value === 'string'
140
+ ? encodeURIComponent(value)
141
+ : String(value);
142
+
143
+ parts.push(`${encodedKey}=${encodedValue}`);
144
+ }
145
+
146
+ private processArray(
147
+ prefix: string,
148
+ array: Primitive[],
149
+ parts: string[],
150
+ depth: number
151
+ ): void {
152
+ if (array.length === 0) return;
153
+
154
+ const encodedKey = this.encodeKey(prefix);
155
+
156
+ switch (this.options.arrayFormat) {
157
+ case 'comma':
158
+ const values = array
159
+ .map(item => this.options.encode && typeof item === 'string'
160
+ ? encodeURIComponent(item)
161
+ : String(item)
162
+ )
163
+ .join(this.options.arraySeparator);
164
+ parts.push(`${encodedKey}=${values}`);
165
+ break;
166
+
167
+ case 'index':
168
+ array.forEach((item, index) => {
169
+ const arrayPrefix = `${prefix}[${index}]`;
170
+ this.processObject(arrayPrefix, item, parts, depth);
171
+ });
172
+ break;
173
+
174
+ case 'separator':
175
+ array.forEach(item => {
176
+ const encodedValue = this.options.encode && typeof item === 'string'
177
+ ? encodeURIComponent(item)
178
+ : String(item);
179
+ parts.push(`${encodedKey}=${encodedValue}`);
180
+ });
181
+ break;
182
+
183
+ case 'none':
184
+ array.forEach(item => {
185
+ this.processObject(prefix, item, parts, depth);
186
+ });
187
+ break;
188
+
189
+ case 'bracket':
190
+ default:
191
+ array.forEach(item => {
192
+ const arrayPrefix = `${prefix}[]`;
193
+ this.processObject(arrayPrefix, item, parts, depth);
194
+ });
195
+ break;
196
+ }
197
+ }
198
+
199
+ private encodeKey(key: string): string {
200
+ if (!this.options.encode) {
201
+ return key;
202
+ }
203
+
204
+ const parts: string[] = [];
205
+ let currentPart = '';
206
+
207
+ for (let i = 0; i < key.length; i++) {
208
+ const char = key[i];
209
+
210
+ if (char === '[' || char === ']') {
211
+
212
+ if (currentPart) {
213
+ parts.push(encodeURIComponent(currentPart));
214
+ currentPart = '';
215
+ }
216
+
217
+ parts.push(char);
218
+ } else {
219
+ currentPart += char;
220
+ }
221
+ }
222
+
223
+ if (currentPart) {
224
+ parts.push(encodeURIComponent(currentPart));
225
+ }
226
+
227
+ return parts.join('');
228
+ }
229
+
230
+ private setValue(obj: QueryObject, key: string, value: string | undefined): void {
231
+ const matches = key.match(/([^\[\]]+)|(\[\])/g);
232
+
233
+ if (!matches) {
234
+ if (value !== undefined) {
235
+ obj[key] = this.parseValue(value);
236
+ }
237
+ return;
238
+ }
239
+
240
+ let current: any = obj;
241
+
242
+ for (let i = 0; i < matches.length; i++) {
243
+ const match = matches[i];
244
+ const isLast = i === matches.length - 1;
245
+
246
+ if (match === '[]') {
247
+ if (!Array.isArray(current)) {
248
+ current = [];
249
+ }
250
+
251
+ if (isLast) {
252
+ if (!!value) {
253
+ current.push(this.parseValue(value));
254
+ }
255
+ } else {
256
+ const nextMatch = matches[i + 1];
257
+ const nextIndex = parseInt(nextMatch, 10);
258
+
259
+ if (!isNaN(nextIndex)) {
260
+ if (current[nextIndex] === undefined) {
261
+ current[nextIndex] = {};
262
+ }
263
+ current = current[nextIndex];
264
+ i++;
265
+ } else {
266
+ const newObj = {};
267
+ current.push(newObj);
268
+ current = newObj;
269
+ }
270
+ }
271
+ } else {
272
+ if (isLast) {
273
+ if (value !== undefined) {
274
+ current[match] = this.parseValue(value);
275
+ }
276
+ } else {
277
+ if (current[match] === undefined || typeof current[match] !== 'object') {
278
+ const nextMatch = matches[i + 1];
279
+ current[match] = nextMatch === '[]' ? [] : {};
280
+ }
281
+ current = current[match];
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ private transformArrays(obj: any): any {
288
+ if (Array.isArray(obj)) {
289
+ return obj.map(item =>
290
+ typeof item === 'object' && item !== null
291
+ ? this.transformArrays(item)
292
+ : item
293
+ );
294
+ }
295
+
296
+ if (typeof obj !== 'object' || obj === null) {
297
+ return obj;
298
+ }
299
+
300
+ const result: any = {};
301
+ const keys = Object.keys(obj);
302
+
303
+ const isArrayLike = keys.every(key => {
304
+ const num = parseInt(key, 10);
305
+ return !isNaN(num) && num >= 0 && num.toString() === key;
306
+ });
307
+
308
+ if (isArrayLike && keys.length > 0) {
309
+ const array: any[] = [];
310
+ keys.forEach(key => {
311
+ const index = parseInt(key, 10);
312
+ array[index] = this.transformArrays(obj[key]);
313
+ });
314
+ return array;
315
+ }
316
+
317
+ keys.forEach(key => {
318
+ const value = obj[key];
319
+ result[key] =
320
+ typeof value === 'object' && value !== null
321
+ ? this.transformArrays(value)
322
+ : value;
323
+ });
324
+
325
+ return result;
326
+ }
327
+
328
+ private parseValue(value: string): Primitive {
329
+ if (value === 'true') return true;
330
+ if (value === 'false') return false;
331
+ if (value === 'null') return null;
332
+ if (value === 'undefined') return undefined;
333
+
334
+ const num = Number(value);
335
+ if (!isNaN(num) && value.trim() !== '') return num;
336
+
337
+ return value;
338
+ }
339
+
340
+ private isPrimitive(value: any): boolean {
341
+ return value === null ||
342
+ typeof value !== 'object' &&
343
+ typeof value !== 'function';
344
+ }
345
+
346
+ setOptions(newOptions: Partial<QustOptions>): void {
347
+ this.options = { ...this.options, ...newOptions };
348
+ }
349
+
350
+ getOptions(): Required<QustOptions> {
351
+ return { ...this.options };
352
+ }
353
+
354
+ static exposeToGlobal(): void {
355
+ if (typeof window !== "undefined") {
356
+ (window as any).Qust = Qust;
357
+ }
358
+ }
359
+ }
360
+
361
+ const qust = {
362
+
363
+ stringify(obj: QueryObject, options?: QustOptions): string {
364
+ return new Qust(options).stringify(obj);
365
+ },
366
+
367
+ parse<T = QueryObject>(queryString: string, options?: QustOptions): T {
368
+ return new Qust(options).parse<T>(queryString);
369
+ }
370
+ };
371
+
372
+ if (typeof window !== "undefined") {
373
+ (window as any).Qust = Qust;
374
+ (window as any).qust = qust;
375
+ }
376
+
377
+
378
+
379
+
380
+ const globalFunctModule = {
381
+ default: qust,
382
+ Qust: Qust,
383
+ qust: qust,
384
+ };
385
+
386
+
387
+ const __bundledModules = globalFunctModule;
388
+
389
+ if (typeof global !== 'undefined') {
390
+ (global as any).default = qust;
391
+ (global as any).Qust = Qust;
392
+ (global as any).qust = qust;
393
+ (global as any).__bundledModules = __bundledModules;
394
+ }
395
+
396
+ if (typeof window !== "undefined") {
397
+ (window as any).default = qust;
398
+ (window as any).Qust = Qust;
399
+ (window as any).qust = qust;
400
+ (window as any).__bundledModules = __bundledModules;
401
+ }
402
+
403
+ if (typeof exports !== 'undefined') {
404
+ exports.default = qust;
405
+ exports.Qust = Qust;
406
+ exports.qust = qust;
407
+ }
408
+ return globalFunctModule;
409
+
410
+ })(typeof global !== 'undefined' ? global :
411
+ typeof window !== 'undefined' ? window :
412
+ typeof self !== 'undefined' ? self :
413
+ typeof globalThis !== 'undefined' ? globalThis :
414
+ {});
415
+
416
+ type QustElementTypeGF = typeof globalFunct.Qust;
417
+
418
+ type qustElementTypeGF = typeof globalFunct.qust;
419
+
420
+ type DefaultElementTypeGF = typeof globalFunct.default;
421
+
422
+ const QustElementGF: QustElementTypeGF = globalFunct.Qust;
423
+
424
+ const qustElementGF: qustElementTypeGF = globalFunct.qust;
425
+
426
+ const defaultElementGF: DefaultElementTypeGF = globalFunct.default;
427
+
428
+ export {
429
+ defaultElementGF as default,
430
+ QustElementGF as Qust,
431
+ qustElementGF as qust,
432
+ };
433
+ export type {
434
+ DefaultElementTypeGF,
435
+ QustElementTypeGF,qustElementTypeGF,
436
+ };
package/ts/qust.ts ADDED
@@ -0,0 +1,429 @@
1
+ // @ts-nocheck
2
+
3
+ interface Window {
4
+ default: typeof defaultElementGF;
5
+ Qust: any;
6
+ qust: any;
7
+ __bundledModules: any;
8
+ }
9
+
10
+ interface QustOptions {
11
+ arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
12
+ arraySeparator?: string;
13
+ skipNull?: boolean;
14
+ skipEmptyString?: boolean;
15
+ encode?: boolean;
16
+ decode?: boolean;
17
+ depth?: number;
18
+ }
19
+
20
+
21
+ type Primitive = string | number | boolean | null | undefined;
22
+
23
+ type QueryValue = Primitive | Primitive[] | { [key: string]: QueryValue };
24
+
25
+ type QueryObject = { [key: string]: QueryValue };
26
+
27
+ const globalFunct = (function(global: any) {
28
+ 'use strict';
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ const DEFAULT_OPTIONS: Required<QustOptions> = {
39
+ arrayFormat: 'bracket',
40
+ arraySeparator: ',',
41
+ skipNull: true,
42
+ skipEmptyString: false,
43
+ encode: true,
44
+ decode: true,
45
+ depth: 10
46
+ };
47
+
48
+ class Qust {
49
+ private options: Required<QustOptions>;
50
+
51
+ constructor(options: QustOptions = {}) {
52
+ this.options = { ...DEFAULT_OPTIONS, ...options };
53
+ }
54
+
55
+ stringify(obj: QueryObject): string {
56
+ if (!obj || typeof obj !== 'object') {
57
+ return '';
58
+ }
59
+
60
+ const parts: string[] = [];
61
+ this.processObject('', obj, parts, 0);
62
+
63
+ return parts.length > 0 ? `?${parts.join('&')}` : '';
64
+ }
65
+
66
+ parse<T = QueryObject>(queryString: string): T {
67
+ if (!queryString || typeof queryString !== 'string') {
68
+ return {} as T;
69
+ }
70
+
71
+ const cleanString = queryString.startsWith('?')
72
+ ? queryString.slice(1)
73
+ : queryString;
74
+
75
+ if (!cleanString) {
76
+ return {} as T;
77
+ }
78
+
79
+ const result: QueryObject = {};
80
+ const pairs = cleanString.split('&');
81
+
82
+ for (const pair of pairs) {
83
+ if (!pair) continue;
84
+
85
+ const [encodedKey, encodedValue] = pair.split('=');
86
+
87
+ if (!encodedKey) continue;
88
+
89
+ const key = this.options.decode
90
+ ? decodeURIComponent(encodedKey)
91
+ : encodedKey;
92
+
93
+ const value = this.options.decode && encodedValue !== undefined
94
+ ? decodeURIComponent(encodedValue)
95
+ : encodedValue;
96
+
97
+ this.setValue(result, key, value);
98
+ }
99
+
100
+ return this.transformArrays(result) as T;
101
+ }
102
+
103
+ private processObject(
104
+ prefix: string,
105
+ value: QueryValue,
106
+ parts: string[],
107
+ depth: number
108
+ ): void {
109
+ if (depth > this.options.depth) {
110
+ console.warn('Qust: Profondeur maximale atteinte, arrêt de la récursion');
111
+ return;
112
+ }
113
+
114
+ if (value === null || value === undefined) {
115
+ if (!this.options.skipNull) {
116
+ parts.push(this.encodeKey(prefix));
117
+ }
118
+ return;
119
+ }
120
+
121
+ if (typeof value === 'string' && value === '' && this.options.skipEmptyString) {
122
+ return;
123
+ }
124
+
125
+ if (Array.isArray(value)) {
126
+ this.processArray(prefix, value, parts, depth + 1);
127
+ return;
128
+ }
129
+
130
+ if (typeof value === 'object' && !this.isPrimitive(value)) {
131
+ for (const [key, val] of Object.entries(value)) {
132
+ const newPrefix = prefix ? `${prefix}[${key}]` : key;
133
+ this.processObject(newPrefix, val, parts, depth + 1);
134
+ }
135
+ return;
136
+ }
137
+
138
+ const encodedKey = this.encodeKey(prefix);
139
+ const encodedValue = this.options.encode && typeof value === 'string'
140
+ ? encodeURIComponent(value)
141
+ : String(value);
142
+
143
+ parts.push(`${encodedKey}=${encodedValue}`);
144
+ }
145
+
146
+ private processArray(
147
+ prefix: string,
148
+ array: Primitive[],
149
+ parts: string[],
150
+ depth: number
151
+ ): void {
152
+ if (array.length === 0) return;
153
+
154
+ const encodedKey = this.encodeKey(prefix);
155
+
156
+ switch (this.options.arrayFormat) {
157
+ case 'comma':
158
+ const values = array
159
+ .map(item => this.options.encode && typeof item === 'string'
160
+ ? encodeURIComponent(item)
161
+ : String(item)
162
+ )
163
+ .join(this.options.arraySeparator);
164
+ parts.push(`${encodedKey}=${values}`);
165
+ break;
166
+
167
+ case 'index':
168
+ array.forEach((item, index) => {
169
+ const arrayPrefix = `${prefix}[${index}]`;
170
+ this.processObject(arrayPrefix, item, parts, depth);
171
+ });
172
+ break;
173
+
174
+ case 'separator':
175
+ array.forEach(item => {
176
+ const encodedValue = this.options.encode && typeof item === 'string'
177
+ ? encodeURIComponent(item)
178
+ : String(item);
179
+ parts.push(`${encodedKey}=${encodedValue}`);
180
+ });
181
+ break;
182
+
183
+ case 'none':
184
+ array.forEach(item => {
185
+ this.processObject(prefix, item, parts, depth);
186
+ });
187
+ break;
188
+
189
+ case 'bracket':
190
+ default:
191
+ array.forEach(item => {
192
+ const arrayPrefix = `${prefix}[]`;
193
+ this.processObject(arrayPrefix, item, parts, depth);
194
+ });
195
+ break;
196
+ }
197
+ }
198
+
199
+ private encodeKey(key: string): string {
200
+ if (!this.options.encode) {
201
+ return key;
202
+ }
203
+
204
+ const parts: string[] = [];
205
+ let currentPart = '';
206
+
207
+ for (let i = 0; i < key.length; i++) {
208
+ const char = key[i];
209
+
210
+ if (char === '[' || char === ']') {
211
+
212
+ if (currentPart) {
213
+ parts.push(encodeURIComponent(currentPart));
214
+ currentPart = '';
215
+ }
216
+
217
+ parts.push(char);
218
+ } else {
219
+ currentPart += char;
220
+ }
221
+ }
222
+
223
+ if (currentPart) {
224
+ parts.push(encodeURIComponent(currentPart));
225
+ }
226
+
227
+ return parts.join('');
228
+ }
229
+
230
+ private setValue(obj: QueryObject, key: string, value: string | undefined): void {
231
+ const matches = key.match(/([^\[\]]+)|(\[\])/g);
232
+
233
+ if (!matches) {
234
+ if (value !== undefined) {
235
+ obj[key] = this.parseValue(value);
236
+ }
237
+ return;
238
+ }
239
+
240
+ let current: any = obj;
241
+
242
+ for (let i = 0; i < matches.length; i++) {
243
+ const match = matches[i];
244
+ const isLast = i === matches.length - 1;
245
+
246
+ if (match === '[]') {
247
+ if (!Array.isArray(current)) {
248
+ current = [];
249
+ }
250
+
251
+ if (isLast) {
252
+ if (!!value) {
253
+ current.push(this.parseValue(value));
254
+ }
255
+ } else {
256
+ const nextMatch = matches[i + 1];
257
+ const nextIndex = parseInt(nextMatch, 10);
258
+
259
+ if (!isNaN(nextIndex)) {
260
+ if (current[nextIndex] === undefined) {
261
+ current[nextIndex] = {};
262
+ }
263
+ current = current[nextIndex];
264
+ i++;
265
+ } else {
266
+ const newObj = {};
267
+ current.push(newObj);
268
+ current = newObj;
269
+ }
270
+ }
271
+ } else {
272
+ if (isLast) {
273
+ if (value !== undefined) {
274
+ current[match] = this.parseValue(value);
275
+ }
276
+ } else {
277
+ if (current[match] === undefined || typeof current[match] !== 'object') {
278
+ const nextMatch = matches[i + 1];
279
+ current[match] = nextMatch === '[]' ? [] : {};
280
+ }
281
+ current = current[match];
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ private transformArrays(obj: any): any {
288
+ if (Array.isArray(obj)) {
289
+ return obj.map(item =>
290
+ typeof item === 'object' && item !== null
291
+ ? this.transformArrays(item)
292
+ : item
293
+ );
294
+ }
295
+
296
+ if (typeof obj !== 'object' || obj === null) {
297
+ return obj;
298
+ }
299
+
300
+ const result: any = {};
301
+ const keys = Object.keys(obj);
302
+
303
+ const isArrayLike = keys.every(key => {
304
+ const num = parseInt(key, 10);
305
+ return !isNaN(num) && num >= 0 && num.toString() === key;
306
+ });
307
+
308
+ if (isArrayLike && keys.length > 0) {
309
+ const array: any[] = [];
310
+ keys.forEach(key => {
311
+ const index = parseInt(key, 10);
312
+ array[index] = this.transformArrays(obj[key]);
313
+ });
314
+ return array;
315
+ }
316
+
317
+ keys.forEach(key => {
318
+ const value = obj[key];
319
+ result[key] =
320
+ typeof value === 'object' && value !== null
321
+ ? this.transformArrays(value)
322
+ : value;
323
+ });
324
+
325
+ return result;
326
+ }
327
+
328
+ private parseValue(value: string): Primitive {
329
+ if (value === 'true') return true;
330
+ if (value === 'false') return false;
331
+ if (value === 'null') return null;
332
+ if (value === 'undefined') return undefined;
333
+
334
+ const num = Number(value);
335
+ if (!isNaN(num) && value.trim() !== '') return num;
336
+
337
+ return value;
338
+ }
339
+
340
+ private isPrimitive(value: any): boolean {
341
+ return value === null ||
342
+ typeof value !== 'object' &&
343
+ typeof value !== 'function';
344
+ }
345
+
346
+ setOptions(newOptions: Partial<QustOptions>): void {
347
+ this.options = { ...this.options, ...newOptions };
348
+ }
349
+
350
+ getOptions(): Required<QustOptions> {
351
+ return { ...this.options };
352
+ }
353
+
354
+ static exposeToGlobal(): void {
355
+ if (typeof window !== "undefined") {
356
+ (window as any).Qust = Qust;
357
+ }
358
+ }
359
+ }
360
+
361
+ const qust = {
362
+
363
+ stringify(obj: QueryObject, options?: QustOptions): string {
364
+ return new Qust(options).stringify(obj);
365
+ },
366
+
367
+ parse<T = QueryObject>(queryString: string, options?: QustOptions): T {
368
+ return new Qust(options).parse<T>(queryString);
369
+ }
370
+ };
371
+
372
+ if (typeof window !== "undefined") {
373
+ (window as any).Qust = Qust;
374
+ (window as any).qust = qust;
375
+ }
376
+
377
+
378
+
379
+
380
+ const globalFunctModule = {
381
+ default: qust,
382
+ Qust: Qust,
383
+ qust: qust,
384
+ };
385
+
386
+
387
+ const __bundledModules = globalFunctModule;
388
+
389
+ if (typeof global !== 'undefined') {
390
+ (global as any).default = qust;
391
+ (global as any).Qust = Qust;
392
+ (global as any).qust = qust;
393
+ (global as any).__bundledModules = __bundledModules;
394
+ }
395
+
396
+ if (typeof window !== "undefined") {
397
+ (window as any).default = qust;
398
+ (window as any).Qust = Qust;
399
+ (window as any).qust = qust;
400
+ (window as any).__bundledModules = __bundledModules;
401
+ }
402
+
403
+ if (typeof exports !== 'undefined') {
404
+ exports.default = qust;
405
+ exports.Qust = Qust;
406
+ exports.qust = qust;
407
+ }
408
+ return globalFunctModule;
409
+
410
+ })(typeof global !== 'undefined' ? global :
411
+ typeof window !== 'undefined' ? window :
412
+ typeof self !== 'undefined' ? self :
413
+ typeof globalThis !== 'undefined' ? globalThis :
414
+ {});
415
+
416
+ type QustElementTypeGF = typeof globalFunct.Qust;
417
+
418
+ type qustElementTypeGF = typeof globalFunct.qust;
419
+
420
+ type DefaultElementTypeGF = typeof globalFunct.default;
421
+
422
+ const QustElementGF: QustElementTypeGF = globalFunct.Qust;
423
+
424
+ const qustElementGF: qustElementTypeGF = globalFunct.qust;
425
+
426
+ const defaultElementGF: DefaultElementTypeGF = globalFunct.default;
427
+
428
+
429
+