@labdigital/commercetools-mock 1.4.0 → 1.6.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 (129) hide show
  1. package/README.md +5 -4
  2. package/dist/index.cjs +116 -18
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +30 -7
  5. package/dist/index.d.ts +30 -7
  6. package/dist/index.js +116 -18
  7. package/dist/index.js.map +1 -1
  8. package/package.json +4 -3
  9. package/src/constants.ts +2 -2
  10. package/src/ctMock.ts +176 -176
  11. package/src/exceptions.ts +10 -10
  12. package/src/helpers.ts +26 -26
  13. package/src/index.test.ts +173 -173
  14. package/src/index.ts +3 -3
  15. package/src/lib/expandParser.ts +19 -19
  16. package/src/lib/haversine.test.ts +13 -13
  17. package/src/lib/haversine.ts +14 -14
  18. package/src/lib/masking.ts +15 -15
  19. package/src/lib/parser.ts +2 -2
  20. package/src/lib/predicateParser.test.ts +204 -204
  21. package/src/lib/predicateParser.ts +398 -398
  22. package/src/lib/projectionSearchFilter.test.ts +168 -168
  23. package/src/lib/projectionSearchFilter.ts +272 -269
  24. package/src/lib/proxy.ts +8 -8
  25. package/src/oauth/errors.ts +4 -4
  26. package/src/oauth/helpers.ts +6 -6
  27. package/src/oauth/server.ts +103 -101
  28. package/src/oauth/store.ts +27 -27
  29. package/src/priceSelector.test.ts +68 -68
  30. package/src/priceSelector.ts +70 -70
  31. package/src/product-projection-search.ts +296 -296
  32. package/src/projectAPI.test.ts +3 -3
  33. package/src/projectAPI.ts +46 -46
  34. package/src/repositories/abstract.ts +190 -190
  35. package/src/repositories/associate-role.ts +10 -7
  36. package/src/repositories/attribute-group.ts +63 -8
  37. package/src/repositories/business-unit.ts +10 -7
  38. package/src/repositories/cart-discount.ts +134 -134
  39. package/src/repositories/cart.ts +517 -514
  40. package/src/repositories/category.ts +170 -167
  41. package/src/repositories/channel.ts +114 -111
  42. package/src/repositories/custom-object.ts +66 -63
  43. package/src/repositories/customer-group.ts +72 -69
  44. package/src/repositories/customer.ts +93 -79
  45. package/src/repositories/discount-code.ts +171 -168
  46. package/src/repositories/errors.ts +15 -15
  47. package/src/repositories/extension.ts +79 -76
  48. package/src/repositories/helpers.ts +180 -180
  49. package/src/repositories/index.ts +39 -39
  50. package/src/repositories/inventory-entry.ts +98 -95
  51. package/src/repositories/my-order.ts +11 -11
  52. package/src/repositories/order-edit.ts +29 -29
  53. package/src/repositories/order.test.ts +191 -191
  54. package/src/repositories/order.ts +393 -389
  55. package/src/repositories/payment.ts +155 -155
  56. package/src/repositories/product-discount.ts +149 -149
  57. package/src/repositories/product-projection.ts +116 -52
  58. package/src/repositories/product-selection.ts +31 -31
  59. package/src/repositories/product-type.ts +156 -156
  60. package/src/repositories/product.ts +600 -597
  61. package/src/repositories/project.ts +136 -135
  62. package/src/repositories/quote-request.ts +19 -19
  63. package/src/repositories/quote.ts +19 -19
  64. package/src/repositories/review.ts +24 -24
  65. package/src/repositories/shipping-method.ts +217 -217
  66. package/src/repositories/shopping-list.ts +49 -49
  67. package/src/repositories/staged-quote.ts +20 -20
  68. package/src/repositories/standalone-price.ts +72 -61
  69. package/src/repositories/state.ts +84 -84
  70. package/src/repositories/store.ts +114 -114
  71. package/src/repositories/subscription.ts +40 -40
  72. package/src/repositories/tax-category.ts +98 -98
  73. package/src/repositories/type.ts +157 -157
  74. package/src/repositories/zone.ts +71 -71
  75. package/src/server.ts +2 -2
  76. package/src/services/abstract.ts +173 -173
  77. package/src/services/attribute-group.ts +16 -0
  78. package/src/services/cart-discount.ts +8 -8
  79. package/src/services/cart.test.ts +409 -409
  80. package/src/services/cart.ts +50 -50
  81. package/src/services/category.test.ts +25 -25
  82. package/src/services/category.ts +8 -8
  83. package/src/services/channel.ts +8 -8
  84. package/src/services/custom-object.test.ts +184 -184
  85. package/src/services/custom-object.ts +48 -48
  86. package/src/services/customer-group.ts +8 -8
  87. package/src/services/customer.test.ts +151 -129
  88. package/src/services/customer.ts +27 -27
  89. package/src/services/discount-code.ts +8 -8
  90. package/src/services/extension.ts +8 -8
  91. package/src/services/index.ts +52 -44
  92. package/src/services/inventory-entry.test.ts +162 -162
  93. package/src/services/inventory-entry.ts +8 -8
  94. package/src/services/my-cart.test.ts +78 -78
  95. package/src/services/my-cart.ts +28 -28
  96. package/src/services/my-customer.test.ts +44 -44
  97. package/src/services/my-customer.ts +53 -53
  98. package/src/services/my-order.ts +20 -20
  99. package/src/services/my-payment.test.ts +65 -65
  100. package/src/services/my-payment.ts +8 -8
  101. package/src/services/order.test.ts +527 -527
  102. package/src/services/order.ts +31 -31
  103. package/src/services/payment.test.ts +65 -65
  104. package/src/services/payment.ts +8 -8
  105. package/src/services/product-discount.ts +8 -8
  106. package/src/services/product-projection.test.ts +492 -428
  107. package/src/services/product-projection.ts +32 -18
  108. package/src/services/product-type.test.ts +56 -56
  109. package/src/services/product-type.ts +8 -8
  110. package/src/services/product.test.ts +510 -510
  111. package/src/services/product.ts +8 -8
  112. package/src/services/project.ts +34 -34
  113. package/src/services/shipping-method.test.ts +81 -81
  114. package/src/services/shipping-method.ts +12 -12
  115. package/src/services/shopping-list.ts +8 -8
  116. package/src/services/standalone-price.test.ts +256 -256
  117. package/src/services/standalone-price.ts +8 -8
  118. package/src/services/state.test.ts +42 -42
  119. package/src/services/state.ts +8 -8
  120. package/src/services/store.test.ts +57 -57
  121. package/src/services/store.ts +8 -8
  122. package/src/services/subscription.ts +8 -8
  123. package/src/services/tax-category.test.ts +61 -61
  124. package/src/services/tax-category.ts +8 -8
  125. package/src/services/type.ts +8 -8
  126. package/src/services/zone.ts +8 -8
  127. package/src/storage/abstract.ts +58 -58
  128. package/src/storage/in-memory.ts +419 -419
  129. package/src/types.ts +82 -82
@@ -2,7 +2,10 @@
2
2
  * This module implements the commercetools product projection filter expression.
3
3
  */
4
4
 
5
- import type { ProductProjection, ProductVariant } from '@commercetools/platform-sdk'
5
+ import type {
6
+ ProductProjection,
7
+ ProductVariant,
8
+ } from '@commercetools/platform-sdk'
6
9
  import { nestedLookup } from '../helpers.js'
7
10
  import type { Writable } from '../types.js'
8
11
  import { Lexer, Parser } from './parser.js'
@@ -10,48 +13,48 @@ import { Lexer, Parser } from './parser.js'
10
13
  type MatchFunc = (target: any) => boolean
11
14
 
12
15
  type ProductProjectionFilter = (
13
- p: Writable<ProductProjection>,
14
- markMatchingVariants: boolean
16
+ p: Writable<ProductProjection>,
17
+ markMatchingVariants: boolean
15
18
  ) => boolean
16
19
 
17
20
  type TypeSymbol = {
18
- type: 'Symbol'
19
- kind: 'int' | 'string' | 'any'
20
- value: any
21
+ type: 'Symbol'
22
+ kind: 'int' | 'string' | 'any'
23
+ value: any
21
24
  }
22
25
 
23
26
  type RangeExpressionSet = {
24
- source: string
25
- type: 'RangeExpression'
26
- children?: RangeExpression[]
27
+ source: string
28
+ type: 'RangeExpression'
29
+ children?: RangeExpression[]
27
30
  }
28
31
 
29
32
  type FilterExpressionSet = {
30
- source: string
31
- type: 'FilterExpression'
32
- children?: FilterExpression[]
33
+ source: string
34
+ type: 'FilterExpression'
35
+ children?: FilterExpression[]
33
36
  }
34
37
 
35
38
  type TermExpressionSet = {
36
- source: string
37
- type: 'TermExpression'
39
+ source: string
40
+ type: 'TermExpression'
38
41
  }
39
42
 
40
43
  type ExpressionSet =
41
- | RangeExpressionSet
42
- | FilterExpressionSet
43
- | TermExpressionSet
44
+ | RangeExpressionSet
45
+ | FilterExpressionSet
46
+ | TermExpressionSet
44
47
 
45
48
  export type RangeExpression = {
46
- type: 'RangeExpression'
47
- start?: number
48
- stop?: number
49
- match: (obj: any) => boolean
49
+ type: 'RangeExpression'
50
+ start?: number
51
+ stop?: number
52
+ match: (obj: any) => boolean
50
53
  }
51
54
 
52
55
  export type FilterExpression = {
53
- type: 'FilterExpression'
54
- match: (obj: any) => boolean
56
+ type: 'FilterExpression'
57
+ match: (obj: any) => boolean
55
58
  }
56
59
 
57
60
  /**
@@ -59,273 +62,273 @@ export type FilterExpression = {
59
62
  * NOTE: The filter can alter the resources in-place (FIXME)
60
63
  */
61
64
  export const parseFilterExpression = (
62
- filter: string
65
+ filter: string
63
66
  ): ProductProjectionFilter => {
64
- const exprFunc = generateMatchFunc(filter)
65
- const [source] = filter.split(':', 1)
67
+ const exprFunc = generateMatchFunc(filter)
68
+ const [source] = filter.split(':', 1)
66
69
 
67
- if (source.startsWith('variants.')) {
68
- return filterVariants(source, exprFunc)
69
- }
70
- return filterProduct(source, exprFunc)
70
+ if (source.startsWith('variants.')) {
71
+ return filterVariants(source, exprFunc)
72
+ }
73
+ return filterProduct(source, exprFunc)
71
74
  }
72
75
 
73
76
  const getLexer = (value: string) =>
74
- new Lexer(value)
75
- .token('MISSING', /missing(?![-_a-z0-9]+)/i)
76
- .token('EXISTS', /exists(?![-_a-z0-9]+)/i)
77
- .token('RANGE', /range(?![-_a-z0-9]+)/i)
78
- .token('TO', /to(?![-_a-z0-9]+)/i)
79
- .token('IDENTIFIER', /[-_.a-z]+/i)
80
-
81
- .token('FLOAT', /\d+\.\d+/)
82
- .token('INT', /\d+/)
83
- .token('STRING', /"((?:\\.|[^"\\])*)"/)
84
- .token('STRING', /'((?:\\.|[^'\\])*)'/)
85
-
86
- .token('COMMA', ',')
87
- .token('STAR', '*')
88
- .token('(', '(')
89
- .token(':', ':')
90
- .token(')', ')')
91
- .token('"', '"')
92
- .token('WS', /\s+/, true) // skip
77
+ new Lexer(value)
78
+ .token('MISSING', /missing(?![-_a-z0-9]+)/i)
79
+ .token('EXISTS', /exists(?![-_a-z0-9]+)/i)
80
+ .token('RANGE', /range(?![-_a-z0-9]+)/i)
81
+ .token('TO', /to(?![-_a-z0-9]+)/i)
82
+ .token('IDENTIFIER', /[-_.a-z]+/i)
83
+
84
+ .token('FLOAT', /\d+\.\d+/)
85
+ .token('INT', /\d+/)
86
+ .token('STRING', /"((?:\\.|[^"\\])*)"/)
87
+ .token('STRING', /'((?:\\.|[^'\\])*)'/)
88
+
89
+ .token('COMMA', ',')
90
+ .token('STAR', '*')
91
+ .token('(', '(')
92
+ .token(':', ':')
93
+ .token(')', ')')
94
+ .token('"', '"')
95
+ .token('WS', /\s+/, true) // skip
93
96
 
94
97
  const parseFilter = (filter: string): ExpressionSet => {
95
- const lexer = getLexer(filter)
96
- const parser = new Parser(lexer)
97
- .builder()
98
- .nud('IDENTIFIER', 100, (t) => t.token.match)
99
- .led(':', 100, ({ left, bp }) => {
100
- const parsed: any = parser.parse({ terminals: [bp - 1] })
101
- const expressions: RangeExpression[] | FilterExpression[] | TypeSymbol[] =
102
- !Array.isArray(parsed) ? [parsed] : parsed
103
-
104
- // Make sure we only have one type of expression (cannot mix)
105
- const unique = new Set(expressions.map((expr) => expr.type))
106
- if (unique.size > 1) {
107
- throw new Error('Invalid expression')
108
- }
109
-
110
- // Convert plain symbols to a filter expression. For example
111
- // variants.attribute.foobar:4 where 4 is a Symbol should result
112
- // in a comparison
113
- if (expressions.some((expr) => expr.type == 'Symbol')) {
114
- return {
115
- source: left as string,
116
- type: 'FilterExpression',
117
- children: expressions.map((e): FilterExpression => {
118
- if (e.type != 'Symbol') {
119
- throw new Error('Invalid expression')
120
- }
121
-
122
- return {
123
- type: 'FilterExpression',
124
- match: (obj: any): boolean => obj === e.value,
125
- }
126
- }),
127
- }
128
- }
129
-
130
- return {
131
- source: left,
132
- type: expressions[0].type,
133
- children: expressions,
134
- }
135
- })
136
- .nud(
137
- 'STRING',
138
- 20,
139
- (t) =>
140
- ({
141
- type: 'Symbol',
142
- kind: 'string',
143
- // @ts-ignore
144
- value: t.token.groups[1],
145
- } as TypeSymbol)
146
- )
147
- .nud(
148
- 'INT',
149
- 5,
150
- (t) =>
151
- ({
152
- type: 'Symbol',
153
- kind: 'int',
154
- value: parseInt(t.token.match, 10),
155
- } as TypeSymbol)
156
- )
157
- .nud('STAR', 5, (_) => ({
158
- type: 'Symbol',
159
- kind: 'any',
160
- value: null,
161
- }))
162
- .nud(
163
- 'EXISTS',
164
- 10,
165
- ({ bp }) =>
166
- ({
167
- type: 'FilterExpression',
168
- match: (obj: any): boolean => obj !== undefined,
169
- } as FilterExpression)
170
- )
171
- .nud(
172
- 'MISSING',
173
- 10,
174
- ({ bp }) =>
175
- ({
176
- type: 'FilterExpression',
177
- match: (obj: any): boolean => obj === undefined,
178
- } as FilterExpression)
179
- )
180
- .led('COMMA', 200, ({ left, token, bp }) => {
181
- const expr: any = parser.parse({ terminals: [bp - 1] })
182
- if (Array.isArray(expr)) {
183
- return [left, ...expr]
184
- } else {
185
- return [left, expr]
186
- }
187
- })
188
- .nud('(', 100, (t) => {
189
- const expr: any = parser.parse({ terminals: [')'] })
190
- lexer.expect(')')
191
- return expr
192
- })
193
- .bp(')', 0)
194
- .led('TO', 20, ({ left, bp }) => {
195
- const expr: any = parser.parse({ terminals: [bp - 1] })
196
- return {
197
- start: left.value,
198
- stop: expr.value,
199
- }
200
- })
201
- .nud('RANGE', 20, ({ bp }) => {
202
- let ranges: any = parser.parse()
203
-
204
- // If multiple ranges are defined we receive an array of ranges. So let's
205
- // make sure we always have an array
206
- if (!Array.isArray(ranges)) {
207
- ranges = [ranges]
208
- }
209
-
210
- // Return a list of functions which matches the ranges. These functions
211
- // are processed as an OR clause
212
- return ranges.map((range: any) => {
213
- let func: (obj: any) => boolean
214
-
215
- if (range.start !== null && range.stop !== null) {
216
- func = (obj: any): boolean => obj >= range.start && obj <= range.stop
217
- } else if (range.start === null && range.stop !== null) {
218
- func = (obj: any): boolean => obj <= range.stop
219
- } else if (range.start !== null && range.stop === null) {
220
- func = (obj: any): boolean => obj >= range.start
221
- } else {
222
- func = (obj: any): boolean => true
223
- }
224
-
225
- return {
226
- type: 'RangeExpression',
227
- start: range.start,
228
- stop: range.stop,
229
- match: func,
230
- } as RangeExpression
231
- })
232
- })
233
- .build()
234
-
235
- return parser.parse()
98
+ const lexer = getLexer(filter)
99
+ const parser = new Parser(lexer)
100
+ .builder()
101
+ .nud('IDENTIFIER', 100, (t) => t.token.match)
102
+ .led(':', 100, ({ left, bp }) => {
103
+ const parsed: any = parser.parse({ terminals: [bp - 1] })
104
+ const expressions: RangeExpression[] | FilterExpression[] | TypeSymbol[] =
105
+ !Array.isArray(parsed) ? [parsed] : parsed
106
+
107
+ // Make sure we only have one type of expression (cannot mix)
108
+ const unique = new Set(expressions.map((expr) => expr.type))
109
+ if (unique.size > 1) {
110
+ throw new Error('Invalid expression')
111
+ }
112
+
113
+ // Convert plain symbols to a filter expression. For example
114
+ // variants.attribute.foobar:4 where 4 is a Symbol should result
115
+ // in a comparison
116
+ if (expressions.some((expr) => expr.type == 'Symbol')) {
117
+ return {
118
+ source: left as string,
119
+ type: 'FilterExpression',
120
+ children: expressions.map((e): FilterExpression => {
121
+ if (e.type != 'Symbol') {
122
+ throw new Error('Invalid expression')
123
+ }
124
+
125
+ return {
126
+ type: 'FilterExpression',
127
+ match: (obj: any): boolean => obj === e.value,
128
+ }
129
+ }),
130
+ }
131
+ }
132
+
133
+ return {
134
+ source: left,
135
+ type: expressions[0].type,
136
+ children: expressions,
137
+ }
138
+ })
139
+ .nud(
140
+ 'STRING',
141
+ 20,
142
+ (t) =>
143
+ ({
144
+ type: 'Symbol',
145
+ kind: 'string',
146
+ // @ts-ignore
147
+ value: t.token.groups[1],
148
+ }) as TypeSymbol
149
+ )
150
+ .nud(
151
+ 'INT',
152
+ 5,
153
+ (t) =>
154
+ ({
155
+ type: 'Symbol',
156
+ kind: 'int',
157
+ value: parseInt(t.token.match, 10),
158
+ }) as TypeSymbol
159
+ )
160
+ .nud('STAR', 5, (_) => ({
161
+ type: 'Symbol',
162
+ kind: 'any',
163
+ value: null,
164
+ }))
165
+ .nud(
166
+ 'EXISTS',
167
+ 10,
168
+ ({ bp }) =>
169
+ ({
170
+ type: 'FilterExpression',
171
+ match: (obj: any): boolean => obj !== undefined,
172
+ }) as FilterExpression
173
+ )
174
+ .nud(
175
+ 'MISSING',
176
+ 10,
177
+ ({ bp }) =>
178
+ ({
179
+ type: 'FilterExpression',
180
+ match: (obj: any): boolean => obj === undefined,
181
+ }) as FilterExpression
182
+ )
183
+ .led('COMMA', 200, ({ left, token, bp }) => {
184
+ const expr: any = parser.parse({ terminals: [bp - 1] })
185
+ if (Array.isArray(expr)) {
186
+ return [left, ...expr]
187
+ } else {
188
+ return [left, expr]
189
+ }
190
+ })
191
+ .nud('(', 100, (t) => {
192
+ const expr: any = parser.parse({ terminals: [')'] })
193
+ lexer.expect(')')
194
+ return expr
195
+ })
196
+ .bp(')', 0)
197
+ .led('TO', 20, ({ left, bp }) => {
198
+ const expr: any = parser.parse({ terminals: [bp - 1] })
199
+ return {
200
+ start: left.value,
201
+ stop: expr.value,
202
+ }
203
+ })
204
+ .nud('RANGE', 20, ({ bp }) => {
205
+ let ranges: any = parser.parse()
206
+
207
+ // If multiple ranges are defined we receive an array of ranges. So let's
208
+ // make sure we always have an array
209
+ if (!Array.isArray(ranges)) {
210
+ ranges = [ranges]
211
+ }
212
+
213
+ // Return a list of functions which matches the ranges. These functions
214
+ // are processed as an OR clause
215
+ return ranges.map((range: any) => {
216
+ let func: (obj: any) => boolean
217
+
218
+ if (range.start !== null && range.stop !== null) {
219
+ func = (obj: any): boolean => obj >= range.start && obj <= range.stop
220
+ } else if (range.start === null && range.stop !== null) {
221
+ func = (obj: any): boolean => obj <= range.stop
222
+ } else if (range.start !== null && range.stop === null) {
223
+ func = (obj: any): boolean => obj >= range.start
224
+ } else {
225
+ func = (obj: any): boolean => true
226
+ }
227
+
228
+ return {
229
+ type: 'RangeExpression',
230
+ start: range.start,
231
+ stop: range.stop,
232
+ match: func,
233
+ } as RangeExpression
234
+ })
235
+ })
236
+ .build()
237
+
238
+ return parser.parse()
236
239
  }
237
240
 
238
241
  const generateMatchFunc = (filter: string) => {
239
- const result = parseFilter(filter)
240
- if (!result) {
241
- // const lines = filter.split('\n')
242
- // const column = lines[lines.length - 1].length
243
- throw new Error(`Syntax error while parsing '${filter}'.`)
244
- }
245
- if (result.type == 'TermExpression') {
246
- throw new Error(`Syntax error while parsing '${filter}'.`)
247
- }
248
-
249
- return (obj: any) => {
250
- if (!result.children) return false
251
- return result.children.some((c) => c.match(obj))
252
- }
242
+ const result = parseFilter(filter)
243
+ if (!result) {
244
+ // const lines = filter.split('\n')
245
+ // const column = lines[lines.length - 1].length
246
+ throw new Error(`Syntax error while parsing '${filter}'.`)
247
+ }
248
+ if (result.type == 'TermExpression') {
249
+ throw new Error(`Syntax error while parsing '${filter}'.`)
250
+ }
251
+
252
+ return (obj: any) => {
253
+ if (!result.children) return false
254
+ return result.children.some((c) => c.match(obj))
255
+ }
253
256
  }
254
257
 
255
258
  export const generateFacetFunc = (filter: string): ExpressionSet => {
256
- if (!filter.includes(':')) {
257
- return {
258
- source: filter,
259
- type: 'TermExpression',
260
- }
261
- }
262
- return parseFilter(filter)
259
+ if (!filter.includes(':')) {
260
+ return {
261
+ source: filter,
262
+ type: 'TermExpression',
263
+ }
264
+ }
265
+ return parseFilter(filter)
263
266
  }
264
267
 
265
268
  const filterProduct =
266
- (source: string, exprFunc: MatchFunc): ProductProjectionFilter =>
267
- (p: ProductProjection, markMatchingVariants: boolean): boolean => {
268
- const value = nestedLookup(p, source)
269
- return exprFunc(value)
270
- }
269
+ (source: string, exprFunc: MatchFunc): ProductProjectionFilter =>
270
+ (p: ProductProjection, markMatchingVariants: boolean): boolean => {
271
+ const value = nestedLookup(p, source)
272
+ return exprFunc(value)
273
+ }
271
274
 
272
275
  const filterVariants =
273
- (source: string, exprFunc: MatchFunc): ProductProjectionFilter =>
274
- (p: ProductProjection, markMatchingVariants: boolean): boolean => {
275
- const [, ...paths] = source.split('.')
276
- const path = paths.join('.')
277
-
278
- const variants = getVariants(p) as Writable<ProductVariant>[]
279
- for (const variant of variants) {
280
- const value = resolveVariantValue(variant, path)
281
-
282
- if (exprFunc(value)) {
283
- // If markMatchingVariants parameter is true those ProductVariants that
284
- // match the search query have the additional field isMatchingVariant
285
- // set to true. For the other variants in the same product projection
286
- // this field is set to false.
287
- if (markMatchingVariants) {
288
- variants.forEach((v) => (v.isMatchingVariant = false))
289
- variant.isMatchingVariant = true
290
- }
291
- return true
292
- }
293
- }
294
-
295
- return false
296
- }
276
+ (source: string, exprFunc: MatchFunc): ProductProjectionFilter =>
277
+ (p: ProductProjection, markMatchingVariants: boolean): boolean => {
278
+ const [, ...paths] = source.split('.')
279
+ const path = paths.join('.')
280
+
281
+ const variants = getVariants(p) as Writable<ProductVariant>[]
282
+ for (const variant of variants) {
283
+ const value = resolveVariantValue(variant, path)
284
+
285
+ if (exprFunc(value)) {
286
+ // If markMatchingVariants parameter is true those ProductVariants that
287
+ // match the search query have the additional field isMatchingVariant
288
+ // set to true. For the other variants in the same product projection
289
+ // this field is set to false.
290
+ if (markMatchingVariants) {
291
+ variants.forEach((v) => (v.isMatchingVariant = false))
292
+ variant.isMatchingVariant = true
293
+ }
294
+ return true
295
+ }
296
+ }
297
+
298
+ return false
299
+ }
297
300
 
298
301
  export const resolveVariantValue = (obj: ProductVariant, path: string): any => {
299
- if (path === undefined) {
300
- return obj
301
- }
302
- if (path.startsWith('variants.')) {
303
- path = path.substring(path.indexOf('.') + 1)
304
- }
305
-
306
- if (path.startsWith('attributes.')) {
307
- const [, attrName, ...rest] = path.split('.')
308
- if (!obj.attributes) {
309
- return undefined
310
- }
311
-
312
- for (const attr of obj.attributes) {
313
- if (attr.name === attrName) {
314
- return nestedLookup(attr.value, rest.join('.'))
315
- }
316
- }
317
- }
318
-
319
- if (path === 'price.centAmount') {
320
- return obj.prices && obj.prices.length > 0
321
- ? obj.prices[0].value.centAmount
322
- : undefined
323
- }
324
-
325
- return nestedLookup(obj, path)
302
+ if (path === undefined) {
303
+ return obj
304
+ }
305
+ if (path.startsWith('variants.')) {
306
+ path = path.substring(path.indexOf('.') + 1)
307
+ }
308
+
309
+ if (path.startsWith('attributes.')) {
310
+ const [, attrName, ...rest] = path.split('.')
311
+ if (!obj.attributes) {
312
+ return undefined
313
+ }
314
+
315
+ for (const attr of obj.attributes) {
316
+ if (attr.name === attrName) {
317
+ return nestedLookup(attr.value, rest.join('.'))
318
+ }
319
+ }
320
+ }
321
+
322
+ if (path === 'price.centAmount') {
323
+ return obj.prices && obj.prices.length > 0
324
+ ? obj.prices[0].value.centAmount
325
+ : undefined
326
+ }
327
+
328
+ return nestedLookup(obj, path)
326
329
  }
327
330
 
328
331
  export const getVariants = (p: ProductProjection): ProductVariant[] => [
329
- p.masterVariant,
330
- ...(p.variants ?? []),
332
+ p.masterVariant,
333
+ ...(p.variants ?? []),
331
334
  ]
package/src/lib/proxy.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export const copyHeaders = (headers: Record<string, string>) => {
2
- const validHeaders = ['accept', 'host', 'authorization']
3
- const result: Record<string, string> = {}
2
+ const validHeaders = ['accept', 'host', 'authorization']
3
+ const result: Record<string, string> = {}
4
4
 
5
- Object.entries(headers).forEach(([key, value]) => {
6
- if (validHeaders.includes(key.toLowerCase())) {
7
- result[key] = value
8
- }
9
- })
5
+ Object.entries(headers).forEach(([key, value]) => {
6
+ if (validHeaders.includes(key.toLowerCase())) {
7
+ result[key] = value
8
+ }
9
+ })
10
10
 
11
- return result
11
+ return result
12
12
  }
@@ -1,9 +1,9 @@
1
1
  export interface InvalidClientError {
2
- readonly code: 'invalid_client'
3
- readonly message: string
2
+ readonly code: 'invalid_client'
3
+ readonly message: string
4
4
  }
5
5
 
6
6
  export interface UnsupportedGrantType {
7
- readonly code: 'unsupported_grant_type'
8
- readonly message: string
7
+ readonly code: 'unsupported_grant_type'
8
+ readonly message: string
9
9
  }
@@ -1,10 +1,10 @@
1
1
  import { Request } from 'express'
2
2
 
3
3
  export const getBearerToken = (request: Request): string | undefined => {
4
- const authHeader = request.header('Authorization')
5
- const match = authHeader?.match(/^Bearer\s(?<token>[^\s]+)$/)
6
- if (match) {
7
- return match.groups?.token
8
- }
9
- return undefined
4
+ const authHeader = request.header('Authorization')
5
+ const match = authHeader?.match(/^Bearer\s(?<token>[^\s]+)$/)
6
+ if (match) {
7
+ return match.groups?.token
8
+ }
9
+ return undefined
10
10
  }