@api-client/core 0.17.6 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/build/src/amf/ApiSchemaGenerator.d.ts +2 -2
  2. package/build/src/amf/ApiSchemaGenerator.d.ts.map +1 -1
  3. package/build/src/amf/ApiSchemaGenerator.js.map +1 -1
  4. package/build/src/amf/ApiSchemaValues.d.ts.map +1 -1
  5. package/build/src/amf/ApiSchemaValues.js +8 -1
  6. package/build/src/amf/ApiSchemaValues.js.map +1 -1
  7. package/build/src/amf/shape/ShapeBase.d.ts +1 -1
  8. package/build/src/amf/shape/ShapeBase.d.ts.map +1 -1
  9. package/build/src/amf/shape/ShapeBase.js.map +1 -1
  10. package/build/src/amf/shape/ShapeJsonSchemaGenerator.d.ts +1 -1
  11. package/build/src/amf/shape/ShapeJsonSchemaGenerator.d.ts.map +1 -1
  12. package/build/src/amf/shape/ShapeJsonSchemaGenerator.js +7 -1
  13. package/build/src/amf/shape/ShapeJsonSchemaGenerator.js.map +1 -1
  14. package/build/src/amf/shape/ShapeXmlSchemaGenerator.d.ts +1 -1
  15. package/build/src/amf/shape/ShapeXmlSchemaGenerator.d.ts.map +1 -1
  16. package/build/src/amf/shape/ShapeXmlSchemaGenerator.js +8 -2
  17. package/build/src/amf/shape/ShapeXmlSchemaGenerator.js.map +1 -1
  18. package/build/src/mocking/RandExp.d.ts +55 -0
  19. package/build/src/mocking/RandExp.d.ts.map +1 -0
  20. package/build/src/mocking/RandExp.js +302 -0
  21. package/build/src/mocking/RandExp.js.map +1 -0
  22. package/build/src/mocking/lib/ret.d.ts +16 -0
  23. package/build/src/mocking/lib/ret.d.ts.map +1 -0
  24. package/build/src/mocking/lib/ret.js +284 -0
  25. package/build/src/mocking/lib/ret.js.map +1 -0
  26. package/build/src/modeling/Bindings.d.ts +0 -4
  27. package/build/src/modeling/Bindings.d.ts.map +1 -1
  28. package/build/src/modeling/Bindings.js.map +1 -1
  29. package/build/src/modeling/DomainEntity.js +3 -3
  30. package/build/src/modeling/DomainEntity.js.map +1 -1
  31. package/build/src/modeling/DomainProperty.d.ts +18 -0
  32. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  33. package/build/src/modeling/DomainProperty.js +31 -0
  34. package/build/src/modeling/DomainProperty.js.map +1 -1
  35. package/build/src/modeling/Semantics.d.ts.map +1 -1
  36. package/build/src/modeling/Semantics.js +2 -1
  37. package/build/src/modeling/Semantics.js.map +1 -1
  38. package/build/src/modeling/amf/ShapeGenerator.js +3 -3
  39. package/build/src/modeling/amf/ShapeGenerator.js.map +1 -1
  40. package/build/src/modeling/types.d.ts +4 -0
  41. package/build/src/modeling/types.d.ts.map +1 -1
  42. package/build/src/modeling/types.js.map +1 -1
  43. package/build/tsconfig.tsbuildinfo +1 -1
  44. package/data/models/example-generator-api.json +19 -19
  45. package/package.json +2 -2
  46. package/src/amf/ApiSchemaGenerator.ts +2 -2
  47. package/src/amf/ApiSchemaValues.ts +8 -1
  48. package/src/amf/shape/ShapeBase.ts +1 -1
  49. package/src/amf/shape/ShapeJsonSchemaGenerator.ts +7 -2
  50. package/src/amf/shape/ShapeXmlSchemaGenerator.ts +8 -3
  51. package/src/mocking/RandExp.ts +335 -0
  52. package/src/mocking/lib/ret.ts +279 -0
  53. package/src/modeling/Bindings.ts +0 -4
  54. package/src/modeling/DomainEntity.ts +3 -3
  55. package/src/modeling/DomainProperty.ts +33 -0
  56. package/src/modeling/Semantics.ts +2 -1
  57. package/src/modeling/amf/ShapeGenerator.ts +3 -3
  58. package/src/modeling/types.ts +4 -0
  59. package/tests/unit/modeling/amf/shape_generator.spec.ts +3 -8
  60. package/tests/unit/modeling/domain_property.spec.ts +335 -0
@@ -42071,13 +42071,13 @@
42071
42071
  "@id": "#197"
42072
42072
  },
42073
42073
  {
42074
- "@id": "#200"
42074
+ "@id": "#206"
42075
42075
  },
42076
42076
  {
42077
- "@id": "#203"
42077
+ "@id": "#200"
42078
42078
  },
42079
42079
  {
42080
- "@id": "#206"
42080
+ "@id": "#203"
42081
42081
  },
42082
42082
  {
42083
42083
  "@id": "#209"
@@ -42810,9 +42810,6 @@
42810
42810
  "@id": "#219"
42811
42811
  },
42812
42812
  {
42813
- "@id": "#219"
42814
- },
42815
- {
42816
42813
  "@id": "#210"
42817
42814
  },
42818
42815
  {
@@ -42820,6 +42817,9 @@
42820
42817
  },
42821
42818
  {
42822
42819
  "@id": "#216"
42820
+ },
42821
+ {
42822
+ "@id": "#219"
42823
42823
  }
42824
42824
  ],
42825
42825
  "doc:root": false,
@@ -43499,7 +43499,7 @@
43499
43499
  "doc:ExternalDomainElement",
43500
43500
  "doc:DomainElement"
43501
43501
  ],
43502
- "doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
43502
+ "doc:raw": "code: 'J'\ndescription: 'Information and communication'\n",
43503
43503
  "core:mediaType": "application/yaml",
43504
43504
  "sourcemaps:sources": [
43505
43505
  {
@@ -43520,7 +43520,7 @@
43520
43520
  "doc:ExternalDomainElement",
43521
43521
  "doc:DomainElement"
43522
43522
  ],
43523
- "doc:raw": "code: 'J'\ndescription: 'Information and communication'\n",
43523
+ "doc:raw": "code: '7487'\ndescription: 'Financial and insurance activities'\ntype: \"PRIMARY\"\nclassificationCode: 'BE_NACEBEL2008'\nactivityGroupCode: 'ABCDE'\n",
43524
43524
  "core:mediaType": "application/yaml",
43525
43525
  "sourcemaps:sources": [
43526
43526
  {
@@ -43541,7 +43541,7 @@
43541
43541
  "doc:ExternalDomainElement",
43542
43542
  "doc:DomainElement"
43543
43543
  ],
43544
- "doc:raw": "code: '7487'\ndescription: 'Financial and insurance activities'\ntype: \"PRIMARY\"\nclassificationCode: 'BE_NACEBEL2008'\nactivityGroupCode: 'ABCDE'\n",
43544
+ "doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
43545
43545
  "core:mediaType": "application/yaml",
43546
43546
  "sourcemaps:sources": [
43547
43547
  {
@@ -44232,7 +44232,7 @@
44232
44232
  "doc:ExternalDomainElement",
44233
44233
  "doc:DomainElement"
44234
44234
  ],
44235
- "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
44235
+ "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
44236
44236
  "core:mediaType": "application/yaml",
44237
44237
  "sourcemaps:sources": [
44238
44238
  {
@@ -44253,7 +44253,7 @@
44253
44253
  "doc:ExternalDomainElement",
44254
44254
  "doc:DomainElement"
44255
44255
  ],
44256
- "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44256
+ "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
44257
44257
  "core:mediaType": "application/yaml",
44258
44258
  "sourcemaps:sources": [
44259
44259
  {
@@ -44274,7 +44274,7 @@
44274
44274
  "doc:ExternalDomainElement",
44275
44275
  "doc:DomainElement"
44276
44276
  ],
44277
- "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44277
+ "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44278
44278
  "core:mediaType": "application/yaml",
44279
44279
  "sourcemaps:sources": [
44280
44280
  {
@@ -44295,7 +44295,7 @@
44295
44295
  "doc:ExternalDomainElement",
44296
44296
  "doc:DomainElement"
44297
44297
  ],
44298
- "doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
44298
+ "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44299
44299
  "core:mediaType": "application/yaml",
44300
44300
  "sourcemaps:sources": [
44301
44301
  {
@@ -44771,17 +44771,17 @@
44771
44771
  {
44772
44772
  "@id": "#202/source-map/lexical/element_0",
44773
44773
  "sourcemaps:element": "amf://id#202",
44774
- "sourcemaps:value": "[(1,0)-(5,0)]"
44774
+ "sourcemaps:value": "[(1,0)-(3,0)]"
44775
44775
  },
44776
44776
  {
44777
44777
  "@id": "#205/source-map/lexical/element_0",
44778
44778
  "sourcemaps:element": "amf://id#205",
44779
- "sourcemaps:value": "[(1,0)-(3,0)]"
44779
+ "sourcemaps:value": "[(1,0)-(6,0)]"
44780
44780
  },
44781
44781
  {
44782
44782
  "@id": "#208/source-map/lexical/element_0",
44783
44783
  "sourcemaps:element": "amf://id#208",
44784
- "sourcemaps:value": "[(1,0)-(6,0)]"
44784
+ "sourcemaps:value": "[(1,0)-(5,0)]"
44785
44785
  },
44786
44786
  {
44787
44787
  "@id": "#223/source-map/lexical/element_0",
@@ -45121,17 +45121,17 @@
45121
45121
  {
45122
45122
  "@id": "#215/source-map/lexical/element_0",
45123
45123
  "sourcemaps:element": "amf://id#215",
45124
- "sourcemaps:value": "[(1,0)-(7,0)]"
45124
+ "sourcemaps:value": "[(1,0)-(6,0)]"
45125
45125
  },
45126
45126
  {
45127
45127
  "@id": "#218/source-map/lexical/element_0",
45128
45128
  "sourcemaps:element": "amf://id#218",
45129
- "sourcemaps:value": "[(1,0)-(3,0)]"
45129
+ "sourcemaps:value": "[(1,0)-(7,0)]"
45130
45130
  },
45131
45131
  {
45132
45132
  "@id": "#221/source-map/lexical/element_0",
45133
45133
  "sourcemaps:element": "amf://id#221",
45134
- "sourcemaps:value": "[(1,0)-(6,0)]"
45134
+ "sourcemaps:value": "[(1,0)-(3,0)]"
45135
45135
  },
45136
45136
  {
45137
45137
  "@id": "#338/source-map/synthesized-field/element_1",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-client/core",
3
3
  "description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
4
- "version": "0.17.6",
4
+ "version": "0.18.0",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -88,7 +88,7 @@
88
88
  "@esm-bundle/chai": "^4.3.4-fix.0",
89
89
  "@metrichor/jmespath": "^0.3.1",
90
90
  "@pawel-up/data-mock": "^0.4.0",
91
- "@pawel-up/jexl": "^3.0.0",
91
+ "@pawel-up/jexl": "^4.0.1",
92
92
  "@xmldom/xmldom": "^0.9.7",
93
93
  "amf-json-ld-lib": "^0.0.15",
94
94
  "chalk": "^5.4.1",
@@ -1,5 +1,5 @@
1
1
  import { AmfNamespace as ns } from './definitions/Namespace.js'
2
- import { IApiAnyShape, IApiDataExample, IShapeUnion } from './definitions/Shapes.js'
2
+ import { IApiAnyShape, IApiDataExample, IApiPropertyShape, IShapeUnion } from './definitions/Shapes.js'
3
3
  import { ShapeBase, IShapeRenderOptions } from './shape/ShapeBase.js'
4
4
  import { ShapeJsonSchemaGenerator } from './shape/ShapeJsonSchemaGenerator.js'
5
5
  import { ShapeXmlSchemaGenerator } from './shape/ShapeXmlSchemaGenerator.js'
@@ -69,7 +69,7 @@ export class ApiSchemaGenerator {
69
69
  *
70
70
  * @param shape The Shape definition
71
71
  */
72
- generate(shape: IShapeUnion): string | number | boolean | null | undefined {
72
+ generate(shape: IShapeUnion | IApiPropertyShape<IShapeUnion>): string | number | boolean | null | undefined {
73
73
  const { generator } = this
74
74
  if (!generator) {
75
75
  return undefined
@@ -16,6 +16,7 @@ import {
16
16
  IShapeUnion,
17
17
  } from './definitions/Shapes.js'
18
18
  import type { ILoremWordInit, ITypeHashInit, ITypeNumberInit } from '@pawel-up/data-mock/types.js'
19
+ import { RandExp } from '../mocking/RandExp.js'
19
20
 
20
21
  export interface IApiSchemaReadOptions {
21
22
  /**
@@ -275,7 +276,13 @@ export class ApiSchemaValues {
275
276
  }
276
277
 
277
278
  static generateStringValue(schema: IApiScalarShape): string {
278
- const { minLength, maxLength, name = '', format } = schema
279
+ const { minLength, maxLength, name = '', format, pattern } = schema
280
+ if (pattern) {
281
+ // if the pattern is set we generate a random string that matches the pattern.
282
+ // Note, this is not a full regex support, just a simple one.
283
+ const randExp = new RandExp(pattern, undefined, { max: 10 })
284
+ return randExp.gen()
285
+ }
279
286
  const lowerName = name.toLowerCase()
280
287
  // we employ some heuristics to generate content based on the property name.
281
288
  if (lowerName === 'description') {
@@ -138,7 +138,7 @@ export abstract class ShapeBase {
138
138
  * @param schema The Shape definition
139
139
  * @returns The generated example
140
140
  */
141
- abstract generate(schema: IShapeUnion): string | number | boolean | null | undefined
141
+ abstract generate(schema: IShapeUnion | IApiPropertyShape<IShapeUnion>): string | number | boolean | null | undefined
142
142
 
143
143
  /**
144
144
  * Serializes generated values into the final mime type related form.
@@ -20,8 +20,13 @@ export class ShapeJsonSchemaGenerator extends ShapeBase {
20
20
  *
21
21
  * @param schema The Shape definition
22
22
  */
23
- generate(schema: IShapeUnion): string | number | boolean | null | undefined {
24
- const result = this.toObject(schema)
23
+ generate(schema: IShapeUnion | IApiPropertyShape<IShapeUnion>): string | number | boolean | null | undefined {
24
+ let result: string | number | boolean | object | object[] | null | undefined
25
+ if (schema.types.includes(ns.w3.shacl.PropertyShape)) {
26
+ result = this._propertyShapeObject(schema as IApiPropertyShape<IShapeUnion>)
27
+ } else {
28
+ result = this.toObject(schema as IShapeUnion)
29
+ }
25
30
  if (result !== null && typeof result === 'object') {
26
31
  return this.serialize(result)
27
32
  }
@@ -55,9 +55,14 @@ export class ShapeXmlSchemaGenerator extends ShapeBase {
55
55
  *
56
56
  * @param schema The Shape definition
57
57
  */
58
- generate(schema: IShapeUnion): string | undefined {
59
- const value = this.processNode(schema, {}, true)
60
- return value
58
+ generate(schema: IShapeUnion | IApiPropertyShape<IShapeUnion>): string | undefined {
59
+ let result: string | undefined
60
+ if (schema.types.includes(ns.w3.shacl.PropertyShape)) {
61
+ result = this._propertyShapeObject(schema as IApiPropertyShape<IShapeUnion>)
62
+ } else {
63
+ result = this.processNode(schema as IShapeUnion, {}, true)
64
+ }
65
+ return result
61
66
  }
62
67
 
63
68
  /**
@@ -0,0 +1,335 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * randexp v0.4.6
4
+ * Create random strings that match a given regular expression.
5
+ *
6
+ * Copyright (C) 2017 by fent (https://github.com/fent)
7
+ * MIT License
8
+ */
9
+
10
+ import { ret, Token, types } from './lib/ret.js'
11
+
12
+ class DRange {
13
+ low: number
14
+ high: number
15
+ length: number
16
+
17
+ constructor(low: number, high: number) {
18
+ this.low = low
19
+ this.high = high
20
+ this.length = 1 + high - low
21
+ }
22
+
23
+ overlaps(range: DRange): boolean {
24
+ return !(this.high < range.low || this.low > range.high)
25
+ }
26
+
27
+ touches(range: DRange): boolean {
28
+ return !(this.high + 1 < range.low || this.low - 1 > range.high)
29
+ }
30
+
31
+ add(range: DRange): DRange | null {
32
+ if (this.touches(range)) {
33
+ return new DRange(Math.min(this.low, range.low), Math.max(this.high, range.high))
34
+ }
35
+ return null
36
+ }
37
+
38
+ subtract(range: DRange): DRange[] {
39
+ if (!this.overlaps(range)) {
40
+ return [this.clone()]
41
+ }
42
+ if (range.low <= this.low && range.high >= this.high) {
43
+ return []
44
+ }
45
+ if (range.low > this.low && range.high < this.high) {
46
+ return [new DRange(this.low, range.low - 1), new DRange(range.high + 1, this.high)]
47
+ }
48
+ if (range.low <= this.low) {
49
+ return [new DRange(range.high + 1, this.high)]
50
+ }
51
+ // if (range.high >= this.high)
52
+ return [new DRange(this.low, range.low - 1)]
53
+ }
54
+
55
+ toString(): string {
56
+ return this.low === this.high ? String(this.low) : `${this.low}-${this.high}`
57
+ }
58
+
59
+ clone(): DRange {
60
+ return new DRange(this.low, this.high)
61
+ }
62
+ }
63
+
64
+ class DiscontinuousRange {
65
+ ranges: DRange[] = []
66
+ length = 0
67
+
68
+ constructor(low?: number | DiscontinuousRange, high?: number) {
69
+ if (low !== undefined) {
70
+ this.add(low, high)
71
+ }
72
+ }
73
+
74
+ private _setLength(): void {
75
+ this.length = this.ranges.reduce((sum, range) => sum + range.length, 0)
76
+ }
77
+
78
+ add(low: number | DiscontinuousRange | DRange, high?: number): this {
79
+ const addRange = (range: DRange) => {
80
+ const newRanges: DRange[] = []
81
+ let i = 0
82
+ while (i < this.ranges.length && !range.touches(this.ranges[i])) {
83
+ newRanges.push(this.ranges[i].clone())
84
+ i++
85
+ }
86
+ while (i < this.ranges.length && range.touches(this.ranges[i])) {
87
+ range = range.add(this.ranges[i]) as DRange
88
+ i++
89
+ }
90
+ newRanges.push(range)
91
+ while (i < this.ranges.length) {
92
+ newRanges.push(this.ranges[i].clone())
93
+ i++
94
+ }
95
+ this.ranges = newRanges
96
+ this._setLength()
97
+ }
98
+
99
+ if (low instanceof DiscontinuousRange) {
100
+ low.ranges.forEach(addRange)
101
+ } else if (low instanceof DRange) {
102
+ addRange(low)
103
+ } else {
104
+ if (high === undefined) high = low
105
+ addRange(new DRange(low, high))
106
+ }
107
+ return this
108
+ }
109
+
110
+ subtract(low: number | DiscontinuousRange | DRange, high?: number): this {
111
+ const subtractRange = (range: DRange) => {
112
+ const newRanges: DRange[] = []
113
+ let i = 0
114
+ while (i < this.ranges.length && !range.overlaps(this.ranges[i])) {
115
+ newRanges.push(this.ranges[i].clone())
116
+ i++
117
+ }
118
+ while (i < this.ranges.length && range.overlaps(this.ranges[i])) {
119
+ newRanges.push(...this.ranges[i].subtract(range))
120
+ i++
121
+ }
122
+ while (i < this.ranges.length) {
123
+ newRanges.push(this.ranges[i].clone())
124
+ i++
125
+ }
126
+ this.ranges = newRanges
127
+ this._setLength()
128
+ }
129
+
130
+ if (low instanceof DiscontinuousRange) {
131
+ low.ranges.forEach(subtractRange)
132
+ } else if (low instanceof DRange) {
133
+ subtractRange(low)
134
+ } else {
135
+ if (high === undefined) high = low
136
+ subtractRange(new DRange(low, high))
137
+ }
138
+ return this
139
+ }
140
+
141
+ index(i: number): number | null {
142
+ let j = 0
143
+ while (j < this.ranges.length && this.ranges[j].length <= i) {
144
+ i -= this.ranges[j].length
145
+ j++
146
+ }
147
+ if (j >= this.ranges.length) {
148
+ return null
149
+ }
150
+ return this.ranges[j].low + i
151
+ }
152
+
153
+ toString(): string {
154
+ return `[ ${this.ranges.join(', ')} ]`
155
+ }
156
+
157
+ clone(): DiscontinuousRange {
158
+ return new DiscontinuousRange(this)
159
+ }
160
+ }
161
+
162
+ export interface RandExpOptions {
163
+ max?: number
164
+ defaultRange?: DiscontinuousRange
165
+ randInt?: (min: number, max: number) => number
166
+ }
167
+
168
+ export class RandExp {
169
+ max = 10 // Reduced from 100 to 10 for more reasonable string lengths
170
+ defaultRange: DiscontinuousRange = new DiscontinuousRange(32, 126)
171
+ randInt: (min: number, max: number) => number = (min, max) => {
172
+ return min + Math.floor(Math.random() * (max - min + 1))
173
+ }
174
+
175
+ private tokens: Token
176
+ private ignoreCase: boolean
177
+ private multiline: boolean
178
+
179
+ constructor(regexp: RegExp | string, flags?: string, options?: RandExpOptions) {
180
+ this.defaultRange = this.defaultRange.clone()
181
+
182
+ // Apply options if provided
183
+ if (options) {
184
+ if (typeof options.max === 'number') {
185
+ this.max = options.max
186
+ }
187
+ if (options.defaultRange instanceof DiscontinuousRange) {
188
+ this.defaultRange = options.defaultRange
189
+ }
190
+ if (typeof options.randInt === 'function') {
191
+ this.randInt = options.randInt
192
+ }
193
+ }
194
+
195
+ if (regexp instanceof RegExp) {
196
+ this.ignoreCase = regexp.ignoreCase
197
+ this.multiline = regexp.multiline
198
+ this._setDefaults(regexp)
199
+ regexp = regexp.source
200
+ } else if (typeof regexp === 'string') {
201
+ this.ignoreCase = flags?.includes('i') ?? false
202
+ this.multiline = flags?.includes('m') ?? false
203
+ } else {
204
+ throw new Error('Expected a regexp or string')
205
+ }
206
+ this.tokens = ret(regexp)
207
+ }
208
+
209
+ private _setDefaults(regexp: any): void {
210
+ if (typeof regexp.max === 'number') {
211
+ this.max = regexp.max
212
+ }
213
+ if (regexp.defaultRange instanceof DiscontinuousRange) {
214
+ this.defaultRange = regexp.defaultRange
215
+ }
216
+ if (typeof regexp.randInt === 'function') {
217
+ this.randInt = regexp.randInt
218
+ }
219
+ }
220
+
221
+ gen(): string {
222
+ return this._gen(this.tokens, [])
223
+ }
224
+
225
+ private _gen(token: Token, groups: (string | null)[]): string {
226
+ let stack, str, i, l
227
+
228
+ switch (token.type) {
229
+ case types.ROOT:
230
+ case types.GROUP:
231
+ if (token.followedBy || token.notFollowedBy) return ''
232
+
233
+ if (token.remember && token.groupNumber === undefined) {
234
+ token.groupNumber = groups.push(null) - 1
235
+ }
236
+
237
+ stack = token.options ? this._choice(token.options) : token.stack
238
+ str = ''
239
+ for (i = 0, l = stack.length; i < l; i++) {
240
+ str += this._gen(stack[i], groups)
241
+ }
242
+
243
+ if (token.remember) {
244
+ groups[token.groupNumber] = str
245
+ }
246
+ return str
247
+
248
+ case types.POSITION:
249
+ return ''
250
+
251
+ case types.SET: {
252
+ const set = this._processSet(token)
253
+ if (!set.length) return ''
254
+ return String.fromCharCode(this._choice(set) as number)
255
+ }
256
+ case types.REPETITION: {
257
+ const n = this.randInt(token.min, token.max === Infinity ? token.min + this.max : token.max)
258
+ str = ''
259
+ for (i = 0; i < n; i++) {
260
+ str += this._gen(token.value, groups)
261
+ }
262
+ return str
263
+ }
264
+ case types.REFERENCE:
265
+ return groups[token.value - 1] || ''
266
+
267
+ case types.CHAR: {
268
+ const code = this.ignoreCase && this._coin() ? RandExp._toCaseInverse(token.value) : token.value
269
+ return String.fromCharCode(code)
270
+ }
271
+ }
272
+ return ''
273
+ }
274
+
275
+ private _processSet(token: Token): DiscontinuousRange {
276
+ if (token.type === types.CHAR) {
277
+ return new DiscontinuousRange(token.value)
278
+ }
279
+ if (token.type === types.RANGE) {
280
+ return new DiscontinuousRange(token.from, token.to)
281
+ }
282
+
283
+ const dr = new DiscontinuousRange()
284
+ for (const char of token.set) {
285
+ const sub = this._processSet(char)
286
+ dr.add(sub)
287
+ if (this.ignoreCase) {
288
+ for (let j = 0; j < sub.length; j++) {
289
+ const charCode = sub.index(j) as number
290
+ const otherCase = RandExp._toCaseInverse(charCode)
291
+ if (charCode !== otherCase) {
292
+ dr.add(otherCase)
293
+ }
294
+ }
295
+ }
296
+ }
297
+
298
+ return token.not ? this.defaultRange.clone().subtract(dr) : dr
299
+ }
300
+
301
+ private static _toCaseInverse(code: number): number {
302
+ if (code >= 97 && code <= 122) return code - 32
303
+ if (code >= 65 && code <= 90) return code + 32
304
+ return code
305
+ }
306
+
307
+ private _coin(): boolean {
308
+ return this.randInt(0, 1) === 0
309
+ }
310
+
311
+ private _choice(choices: any[] | DiscontinuousRange): any {
312
+ if (choices instanceof DiscontinuousRange) {
313
+ return choices.index(this.randInt(0, choices.length - 1))
314
+ }
315
+ return choices[this.randInt(0, choices.length - 1)]
316
+ }
317
+
318
+ static randexp(regexp: RegExp | string, flags?: string, options?: RandExpOptions): string {
319
+ let randexpInstance
320
+ if ((regexp as any)._randexp === undefined) {
321
+ randexpInstance = new RandExp(regexp, flags, options)
322
+ ;(regexp as any)._randexp = randexpInstance
323
+ } else {
324
+ randexpInstance = (regexp as any)._randexp
325
+ }
326
+ randexpInstance._setDefaults(regexp)
327
+ return randexpInstance.gen()
328
+ }
329
+
330
+ static sugar(): void {
331
+ ;(RegExp.prototype as any).gen = function () {
332
+ return RandExp.randexp(this)
333
+ }
334
+ }
335
+ }