@api-client/core 0.5.15 → 0.5.18

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 (43) hide show
  1. package/build/browser.d.ts +1 -0
  2. package/build/browser.js +1 -0
  3. package/build/browser.js.map +1 -1
  4. package/build/index.d.ts +1 -0
  5. package/build/index.js +1 -0
  6. package/build/index.js.map +1 -1
  7. package/build/src/lib/parsers/UriTemplate.d.ts +18 -3
  8. package/build/src/lib/parsers/UriTemplate.js +27 -6
  9. package/build/src/lib/parsers/UriTemplate.js.map +1 -1
  10. package/build/src/lib/parsers/UrlProcessor.d.ts +255 -0
  11. package/build/src/lib/parsers/UrlProcessor.js +687 -0
  12. package/build/src/lib/parsers/UrlProcessor.js.map +1 -0
  13. package/build/src/models/HttpProject.d.ts +85 -32
  14. package/build/src/models/HttpProject.js +181 -80
  15. package/build/src/models/HttpProject.js.map +1 -1
  16. package/build/src/models/ProjectFolder.d.ts +43 -6
  17. package/build/src/models/ProjectFolder.js +37 -12
  18. package/build/src/models/ProjectFolder.js.map +1 -1
  19. package/build/src/models/ProjectItem.d.ts +13 -6
  20. package/build/src/models/ProjectItem.js +24 -4
  21. package/build/src/models/ProjectItem.js.map +1 -1
  22. package/build/src/models/ProjectParent.d.ts +1 -42
  23. package/build/src/models/ProjectParent.js +1 -84
  24. package/build/src/models/ProjectParent.js.map +1 -1
  25. package/build/src/models/transformers/PostmanBackupTransformer.js +0 -1
  26. package/build/src/models/transformers/PostmanBackupTransformer.js.map +1 -1
  27. package/build/src/models/transformers/PostmanV21Transformer.js +0 -1
  28. package/build/src/models/transformers/PostmanV21Transformer.js.map +1 -1
  29. package/build/src/models/transformers/PostmanV2Transformer.js +0 -1
  30. package/build/src/models/transformers/PostmanV2Transformer.js.map +1 -1
  31. package/build/src/runtime/node/ProjectRequestRunner.js +1 -1
  32. package/build/src/runtime/node/ProjectRequestRunner.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/lib/parsers/UriTemplate.ts +34 -11
  35. package/src/lib/parsers/UrlProcessor.ts +799 -0
  36. package/src/models/HttpProject.ts +236 -99
  37. package/src/models/ProjectFolder.ts +68 -17
  38. package/src/models/ProjectItem.ts +33 -11
  39. package/src/models/ProjectParent.ts +1 -110
  40. package/src/models/transformers/PostmanBackupTransformer.ts +0 -1
  41. package/src/models/transformers/PostmanV21Transformer.ts +0 -1
  42. package/src/models/transformers/PostmanV2Transformer.ts +0 -1
  43. package/src/runtime/node/ProjectRequestRunner.ts +1 -1
@@ -0,0 +1,687 @@
1
+ /* eslint-disable class-methods-use-this */
2
+ /* eslint-disable max-classes-per-file */
3
+ import { UrlEncoder } from './UrlEncoder.js';
4
+ class Tokenizer {
5
+ tokens;
6
+ /**
7
+ * This is set to the next token to be read.
8
+ */
9
+ index = 0;
10
+ size;
11
+ get ended() {
12
+ return this.index === this.size - 1;
13
+ }
14
+ constructor(tokens) {
15
+ this.tokens = tokens;
16
+ this.size = tokens.length;
17
+ }
18
+ /**
19
+ * Reads characters until one of the passed characters (not included).
20
+ * @param chars The list of characters to search for.
21
+ * @returns The string between the current index and the found character or the end of tokens.
22
+ */
23
+ untilChar(...chars) {
24
+ const { tokens, index, size } = this;
25
+ let result = '';
26
+ for (let i = index; i < size; i++) {
27
+ const token = tokens[i];
28
+ this.index = i;
29
+ if (chars.includes(token)) {
30
+ return result;
31
+ }
32
+ result += token;
33
+ }
34
+ return result;
35
+ }
36
+ /**
37
+ * Reads the next token and changes the state.
38
+ * @returns The next token.
39
+ */
40
+ next() {
41
+ const { ended, tokens } = this;
42
+ if (ended) {
43
+ return undefined;
44
+ }
45
+ const next = tokens[this.index];
46
+ this.index += 1;
47
+ return next;
48
+ }
49
+ /**
50
+ * Reads the next character without changing the state.
51
+ */
52
+ getNext() {
53
+ const { ended, tokens, index } = this;
54
+ if (ended) {
55
+ return undefined;
56
+ }
57
+ return tokens[index + 1];
58
+ }
59
+ }
60
+ var PartType;
61
+ (function (PartType) {
62
+ /**
63
+ * Literal string, we do not process these
64
+ */
65
+ PartType[PartType["literal"] = 0] = "literal";
66
+ /**
67
+ * URI template expression
68
+ */
69
+ PartType[PartType["template"] = 1] = "template";
70
+ /**
71
+ * query parameter
72
+ */
73
+ PartType[PartType["param"] = 2] = "param";
74
+ })(PartType || (PartType = {}));
75
+ var State;
76
+ (function (State) {
77
+ /**
78
+ * Processing a literal
79
+ */
80
+ State[State["literal"] = 0] = "literal";
81
+ /**
82
+ * Processing a query parameter
83
+ */
84
+ State[State["param"] = 1] = "param";
85
+ /**
86
+ * Processing a template expression
87
+ */
88
+ State[State["expression"] = 2] = "expression";
89
+ })(State || (State = {}));
90
+ var DataType;
91
+ (function (DataType) {
92
+ // undefined/null
93
+ DataType[DataType["nil"] = 0] = "nil";
94
+ // string
95
+ DataType[DataType["string"] = 1] = "string";
96
+ // object
97
+ DataType[DataType["object"] = 2] = "object";
98
+ // array
99
+ DataType[DataType["array"] = 3] = "array";
100
+ })(DataType || (DataType = {}));
101
+ class SearchParams {
102
+ /**
103
+ * A reference to the URL processor's parts.
104
+ */
105
+ parts = [];
106
+ constructor(parts) {
107
+ this.parts = parts;
108
+ }
109
+ /**
110
+ * Iterates over each query parameter, in order.
111
+ */
112
+ *[Symbol.iterator]() {
113
+ for (const part of this.parts) {
114
+ if (part.type === PartType.param) {
115
+ yield part;
116
+ }
117
+ }
118
+ }
119
+ /**
120
+ * Reads parts, in order, that are query parameters.
121
+ */
122
+ list() {
123
+ return this.parts.filter(i => i.type === PartType.param);
124
+ }
125
+ /**
126
+ * Adds a new query parameter to the list.
127
+ *
128
+ * @param name The name of the parameter.
129
+ * @param value The value of the parameter.
130
+ */
131
+ append(name, value = '') {
132
+ const part = {
133
+ type: PartType.param,
134
+ expression: `${name}=${value}`,
135
+ name,
136
+ value,
137
+ enabled: true,
138
+ };
139
+ this.parts.push(part);
140
+ }
141
+ /**
142
+ * Replaces the param part in the parts list.
143
+ *
144
+ * @param index The index of the parameter as returned by the `getParameters()` method.
145
+ * @param param The param to set.
146
+ */
147
+ update(index, param) {
148
+ if (param.type !== PartType.param) {
149
+ throw new Error(`Invalid query parameter definition`);
150
+ }
151
+ // eslint-disable-next-line no-param-reassign
152
+ param.expression = `${param.name}=${param.value || ''}`;
153
+ let current = 0;
154
+ for (let i = 0, len = this.parts.length; i < len; i++) {
155
+ const part = this.parts[i];
156
+ if (part.type === PartType.param) {
157
+ if (current === index) {
158
+ this.parts[i] = param;
159
+ return;
160
+ }
161
+ current += 1;
162
+ }
163
+ }
164
+ throw new Error(`Missing query parameter at position ${index}.`);
165
+ }
166
+ /**
167
+ * Replaces all parameters with the name with the passed value.
168
+ * It insets the param at the first occurrence of the current param in the parts list.
169
+ * If not exists, it adds it as a last.
170
+ *
171
+ * @param name The name of the parameter
172
+ * @param value the value of the parameter
173
+ */
174
+ set(name, value) {
175
+ let firstIndex = -1;
176
+ for (let i = this.parts.length - 1; i >= 0; i--) {
177
+ const part = this.parts[i];
178
+ if (part.type === PartType.param) {
179
+ const typed = part;
180
+ if (typed.name === name) {
181
+ this.parts.splice(i, 1);
182
+ firstIndex = i;
183
+ }
184
+ }
185
+ }
186
+ const part = {
187
+ type: PartType.param,
188
+ expression: `${name}=${value}`,
189
+ name,
190
+ value,
191
+ enabled: true,
192
+ };
193
+ if (firstIndex === -1) {
194
+ this.parts.push(part);
195
+ }
196
+ else {
197
+ this.parts.splice(firstIndex, 0, part);
198
+ }
199
+ }
200
+ /**
201
+ * Removes a query parameter from the parameters list.
202
+ *
203
+ * @param index The index of the parameter as returned by the `getParameters()` method.
204
+ */
205
+ delete(index) {
206
+ let current = 0;
207
+ for (let i = 0, len = this.parts.length; i < len; i++) {
208
+ const part = this.parts[i];
209
+ if (part.type === PartType.param) {
210
+ if (current === index) {
211
+ this.parts.splice(i, 1);
212
+ return;
213
+ }
214
+ current += 1;
215
+ }
216
+ }
217
+ throw new Error(`Missing query parameter at position ${index}.`);
218
+ }
219
+ /**
220
+ * Toggles the enabled state of the parameter.
221
+ *
222
+ * @param index The index of the parameter as returned by the `getParameters()` method.
223
+ * @param enabled The enabled state of the parameter.
224
+ */
225
+ toggle(index, enabled) {
226
+ const params = this.list();
227
+ const param = params[index];
228
+ if (!param) {
229
+ throw new Error(`Missing query parameter at position ${index}.`);
230
+ }
231
+ param.enabled = enabled;
232
+ }
233
+ }
234
+ /**
235
+ * A class that parses a string a treats it as a value that may include
236
+ * URI templates and request parameters.
237
+ *
238
+ * It can be used by the UI libraries to manipulate the URL templates and query parameters.
239
+ */
240
+ export class UrlProcessor {
241
+ /**
242
+ * The source expression.
243
+ * It is immutable for the entire manipulation process of the URI.
244
+ * Any modification is on the parts level and the `expand()` and `toString()`
245
+ * function only rely on the `parts`.
246
+ */
247
+ expression;
248
+ /**
249
+ * The tokenizer object
250
+ */
251
+ tokens;
252
+ /**
253
+ * An ordered list of parts of the expression.
254
+ */
255
+ parts = [];
256
+ /**
257
+ * A helper class to manipulate query parameters on the parser.
258
+ */
259
+ search;
260
+ constructor(expression) {
261
+ this.expression = expression;
262
+ this.tokens = new Tokenizer(expression);
263
+ this.search = new SearchParams(this.parts);
264
+ this._parse();
265
+ }
266
+ /**
267
+ * Creates an URI leaving the template expressions are they are (without expanding them).
268
+ */
269
+ toString() {
270
+ let result = '';
271
+ this.parts.forEach((part) => {
272
+ if (part.type === PartType.literal) {
273
+ result += part.expression;
274
+ }
275
+ else if (part.type === PartType.template) {
276
+ result += `{${part.expression}}`;
277
+ }
278
+ else {
279
+ const typed = part;
280
+ if (!typed.enabled) {
281
+ return;
282
+ }
283
+ if (result.includes('?')) {
284
+ result += '&';
285
+ }
286
+ else {
287
+ result += '?';
288
+ }
289
+ result += part.expression;
290
+ }
291
+ });
292
+ return result;
293
+ }
294
+ /**
295
+ * Creates a URI with expanded template values.
296
+ *
297
+ * @param map The variables to evaluate.
298
+ * @param opts Processing options.
299
+ */
300
+ expand(map, opts = {}) {
301
+ let result = '';
302
+ for (const part of this.parts) {
303
+ if (part.type === PartType.literal) {
304
+ result += part.expression;
305
+ }
306
+ else if (part.type === PartType.param) {
307
+ const typed = part;
308
+ if (!typed.enabled) {
309
+ continue;
310
+ }
311
+ if (result.includes('?')) {
312
+ result += '&';
313
+ }
314
+ else {
315
+ result += '?';
316
+ }
317
+ result += part.expression;
318
+ }
319
+ else {
320
+ result += this._expandExpression(part, map, opts);
321
+ }
322
+ }
323
+ return result;
324
+ }
325
+ _expandExpression(part, map, opts) {
326
+ const { operator, variables } = part;
327
+ const buffer = [];
328
+ for (const variable of variables) {
329
+ const data = this._getData(map, variable.name);
330
+ if (data.type === DataType.nil && opts.strict) {
331
+ throw new Error(`Missing expansion value for variable "${variable.name}"`);
332
+ }
333
+ if (data.type === DataType.nil && opts.ignoreMissing) {
334
+ buffer.push(part.expression);
335
+ continue;
336
+ }
337
+ if (!data.values.length) {
338
+ if (data.type !== DataType.nil) {
339
+ // Empty object / array. We still append the separator.
340
+ buffer.push('');
341
+ }
342
+ continue;
343
+ }
344
+ if (data.type > DataType.string && variable.maxLength) {
345
+ if (opts.strict) {
346
+ throw new Error(`Invalid expression: Prefix modifier not applicable to variable "${variable.name}"`);
347
+ }
348
+ // we ignore invalid values.
349
+ continue;
350
+ }
351
+ if (operator.named) {
352
+ buffer.push(this._expandNamedExpression(data, operator, variable));
353
+ }
354
+ else {
355
+ buffer.push(this._expandUnNamedExpression(data, operator, variable));
356
+ }
357
+ }
358
+ if (buffer.length) {
359
+ return (operator.prefix || '') + buffer.join(operator.separator);
360
+ }
361
+ // prefix is not prepended for empty expressions
362
+ return '';
363
+ }
364
+ _expandNamedExpression(data, operator, variable) {
365
+ let result = '';
366
+ const separator = variable.explode && operator.separator || ',';
367
+ const encodeFunction = operator.reserved ? UrlEncoder.encodeReserved : UrlEncoder.strictEncode;
368
+ let name = '';
369
+ if (data.type !== DataType.object && variable.name) {
370
+ name = encodeFunction(variable.name);
371
+ }
372
+ const hasLength = typeof variable.maxLength === 'number';
373
+ data.values.forEach((item, index) => {
374
+ let value;
375
+ if (hasLength) {
376
+ value = encodeFunction(item.value.substring(0, variable.maxLength));
377
+ if (data.type === DataType.object) {
378
+ // apply maxLength to keys of objects as well
379
+ name = encodeFunction(item.name.substring(0, variable.maxLength));
380
+ }
381
+ }
382
+ else {
383
+ // encode value
384
+ value = encodeFunction(item.value);
385
+ if (data.type === DataType.object) {
386
+ // encode name and cache encoded value
387
+ name = encodeFunction(item.name);
388
+ }
389
+ }
390
+ if (result) {
391
+ result += separator;
392
+ }
393
+ if (!variable.explode) {
394
+ if (!index) {
395
+ result += encodeFunction(variable.name) + (operator.emptyNameSeparator || value ? '=' : '');
396
+ }
397
+ if (data.type === DataType.object) {
398
+ result += `${name},`;
399
+ }
400
+ result += value;
401
+ }
402
+ else {
403
+ result += name + (operator.emptyNameSeparator || value ? '=' : '') + value;
404
+ }
405
+ });
406
+ return result;
407
+ }
408
+ _expandUnNamedExpression(data, operator, variable) {
409
+ let result = '';
410
+ const separator = variable.explode && operator.separator || ',';
411
+ const encodeFunction = operator.reserved ? UrlEncoder.encodeReserved : UrlEncoder.strictEncode;
412
+ const hasLength = typeof variable.maxLength === 'number';
413
+ data.values.forEach((item) => {
414
+ let value;
415
+ if (hasLength) {
416
+ value = encodeFunction(item.value.substring(0, variable.maxLength));
417
+ }
418
+ else {
419
+ value = encodeFunction(item.value);
420
+ }
421
+ if (result) {
422
+ result += separator;
423
+ }
424
+ if (data.type === DataType.object) {
425
+ let _name;
426
+ if (hasLength) {
427
+ _name = encodeFunction(item.name.substring(0, variable.maxLength));
428
+ }
429
+ else {
430
+ _name = encodeFunction(item.name || '');
431
+ }
432
+ result += _name;
433
+ if (variable.explode) {
434
+ result += (operator.emptyNameSeparator || value ? '=' : '');
435
+ }
436
+ else {
437
+ result += ',';
438
+ }
439
+ }
440
+ result += value;
441
+ });
442
+ return result;
443
+ }
444
+ _getData(map, name) {
445
+ const result = {
446
+ type: DataType.nil,
447
+ values: [],
448
+ };
449
+ const value = map[name];
450
+ if (value === undefined || value === null) {
451
+ // undefined and null values are to be ignored completely
452
+ return result;
453
+ }
454
+ if (Array.isArray(value)) {
455
+ for (const v of value) {
456
+ // we only allow primitives in the values
457
+ if (this._validExpansionValue(v)) {
458
+ result.values.push({ value: String(v) });
459
+ }
460
+ }
461
+ }
462
+ else if (String(Object.prototype.toString.call(value)) === '[object Object]') {
463
+ Object.keys(value).forEach((k) => {
464
+ const v = value[k];
465
+ if (this._validExpansionValue(v)) {
466
+ result.values.push({ name: k, value: v });
467
+ }
468
+ });
469
+ if (result.values.length) {
470
+ result.type = DataType.object;
471
+ }
472
+ }
473
+ else {
474
+ result.type = DataType.string;
475
+ result.values.push({ value: String(value) });
476
+ }
477
+ return result;
478
+ }
479
+ _validExpansionValue(value) {
480
+ if (value === undefined || value === null) {
481
+ // these are ignored completely
482
+ return false;
483
+ }
484
+ // we only allow primitives in the values
485
+ return ['string', 'number', 'boolean'].includes(typeof value);
486
+ }
487
+ /**
488
+ * Creates an ordered list of parts that describe the passed expression.
489
+ *
490
+ * FIXME: Handle error states like unclosed brackets.
491
+ */
492
+ _parse() {
493
+ const { tokens } = this;
494
+ let state = State.literal;
495
+ // eslint-disable-next-line no-constant-condition
496
+ while (true) {
497
+ let value;
498
+ if (state === State.literal) {
499
+ value = tokens.untilChar('?', '&', '{', '}');
500
+ }
501
+ else if (state === State.param) {
502
+ value = tokens.untilChar('&', '{');
503
+ }
504
+ else {
505
+ value = tokens.untilChar('}');
506
+ }
507
+ const next = tokens.next();
508
+ if (state === State.literal) {
509
+ // when the value is an empty string that means that we entered the expression string
510
+ // and we have a variable or a query parameter as the first character.
511
+ // We don't need to pass a literal in this case.
512
+ if (value !== '') {
513
+ this._addLiteral(value);
514
+ }
515
+ }
516
+ else if (state === State.param) {
517
+ this._addParam(value);
518
+ }
519
+ else {
520
+ this._addTemplate(value);
521
+ }
522
+ if (next === '?' || next === '&') {
523
+ state = State.param;
524
+ }
525
+ else if (next === '{') {
526
+ state = State.expression;
527
+ }
528
+ else if (next === undefined) {
529
+ break;
530
+ }
531
+ else {
532
+ state = State.literal;
533
+ }
534
+ }
535
+ }
536
+ /**
537
+ * Adds a literal part.
538
+ * Literal parts are not processed in any way. They do not contain query parameters
539
+ * or template expressions.
540
+ *
541
+ * @param expression The literal expression.
542
+ */
543
+ _addLiteral(expression) {
544
+ this.parts.push({
545
+ type: PartType.literal,
546
+ expression,
547
+ });
548
+ }
549
+ /**
550
+ * Adds a part that describes a query parameter
551
+ * @param expression The query param as `name=value` or `name` or `name=`
552
+ */
553
+ _addParam(expression) {
554
+ const parts = expression.split('=');
555
+ const part = {
556
+ type: PartType.param,
557
+ expression,
558
+ name: parts[0],
559
+ value: parts[1] || '',
560
+ enabled: true,
561
+ };
562
+ this.parts.push(part);
563
+ }
564
+ /**
565
+ * Adds a part that is a template expression.
566
+ *
567
+ * @param expression The template expression as defined in RFC 6570
568
+ */
569
+ _addTemplate(expression) {
570
+ const ch = expression[0];
571
+ let operator;
572
+ if (ch === '+') {
573
+ // Reserved character strings (no encoding)
574
+ operator = {
575
+ operator: '+',
576
+ separator: ',',
577
+ reserved: true,
578
+ };
579
+ }
580
+ else if (ch === '#') {
581
+ // Fragment identifiers prefixed by '#'
582
+ operator = {
583
+ operator: '#',
584
+ prefix: '#',
585
+ separator: ',',
586
+ reserved: true,
587
+ };
588
+ }
589
+ else if (ch === '.') {
590
+ // Name labels or extensions prefixed by '.'
591
+ operator = {
592
+ operator: '.',
593
+ prefix: '.',
594
+ separator: '.',
595
+ };
596
+ }
597
+ else if (ch === '/') {
598
+ // Path segments prefixed by '/'
599
+ operator = {
600
+ operator: '/',
601
+ prefix: '/',
602
+ separator: '/',
603
+ };
604
+ }
605
+ else if (ch === ';') {
606
+ // Path parameter name or name=value pairs prefixed by ';'
607
+ operator = {
608
+ operator: ';',
609
+ prefix: ';',
610
+ separator: ';',
611
+ named: true,
612
+ };
613
+ }
614
+ else if (ch === '?') {
615
+ // Query component beginning with '?' and consisting
616
+ // of name=value pairs separated by '&'
617
+ operator = {
618
+ operator: '?',
619
+ prefix: '?',
620
+ separator: '&',
621
+ named: true,
622
+ emptyNameSeparator: true,
623
+ };
624
+ }
625
+ else if (ch === '&') {
626
+ // Continuation of query-style &name=value pairs
627
+ // within a literal query component.
628
+ operator = {
629
+ operator: '&',
630
+ prefix: '&',
631
+ separator: '&',
632
+ named: true,
633
+ emptyNameSeparator: true,
634
+ };
635
+ }
636
+ else {
637
+ // The operator characters equals ("="), comma (","), exclamation ("!"),
638
+ // at sign ("@"), and pipe ("|") are reserved for future extensions.
639
+ // this is level1 simple expression
640
+ operator = {
641
+ separator: ',',
642
+ };
643
+ }
644
+ const part = {
645
+ type: PartType.template,
646
+ expression,
647
+ operator,
648
+ variables: this._readVariables(expression, operator.operator),
649
+ };
650
+ this.parts.push(part);
651
+ }
652
+ _readVariables(expression, operator) {
653
+ let name = expression;
654
+ if (operator) {
655
+ name = name.substring(1);
656
+ }
657
+ return name.split(',').map((item) => {
658
+ let maxLength;
659
+ let varName = item;
660
+ let explode = false;
661
+ if (varName.endsWith('*')) {
662
+ explode = true;
663
+ varName = varName.substring(0, varName.length - 1);
664
+ }
665
+ const lengthIndex = varName.indexOf(':');
666
+ if (lengthIndex >= 0) {
667
+ const len = varName.substring(lengthIndex + 1);
668
+ varName = varName.substring(0, lengthIndex);
669
+ if (len) {
670
+ const parsed = Number(len);
671
+ if (Number.isInteger(parsed)) {
672
+ maxLength = parsed;
673
+ }
674
+ }
675
+ }
676
+ const result = {
677
+ name: varName,
678
+ explode,
679
+ };
680
+ if (typeof maxLength === 'number') {
681
+ result.maxLength = maxLength;
682
+ }
683
+ return result;
684
+ });
685
+ }
686
+ }
687
+ //# sourceMappingURL=UrlProcessor.js.map