@labdigital/commercetools-mock 2.66.0 → 3.0.0-beta.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 (281) hide show
  1. package/README.md +31 -8
  2. package/dist/abstract-BKFcva6S.mjs +1044 -0
  3. package/dist/abstract-BKFcva6S.mjs.map +1 -0
  4. package/dist/config-BcNSzPZz.d.mts +1718 -0
  5. package/dist/index.d.mts +50 -1633
  6. package/dist/index.mjs +3769 -2653
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/storage/sqlite.d.mts +59 -0
  9. package/dist/storage/sqlite.mjs +234 -0
  10. package/dist/storage/sqlite.mjs.map +1 -0
  11. package/package.json +26 -29
  12. package/src/ctMock.ts +125 -136
  13. package/src/helpers.ts +14 -6
  14. package/src/index.ts +5 -0
  15. package/src/lib/masking.ts +4 -5
  16. package/src/lib/product-review-statistics.test.ts +257 -294
  17. package/src/lib/review-statistics.ts +17 -4
  18. package/src/oauth/helpers.ts +7 -4
  19. package/src/oauth/server.test.ts +102 -62
  20. package/src/oauth/server.ts +215 -213
  21. package/src/oauth/store.ts +20 -6
  22. package/src/orderSearch.ts +3 -3
  23. package/src/product-projection-search.ts +38 -20
  24. package/src/product-search-availability.test.ts +31 -52
  25. package/src/product-search.ts +19 -10
  26. package/src/projectAPI.ts +6 -22
  27. package/src/repositories/abstract.ts +182 -48
  28. package/src/repositories/as-associate.test.ts +19 -19
  29. package/src/repositories/associate-role.ts +12 -23
  30. package/src/repositories/attribute-group.test.ts +23 -23
  31. package/src/repositories/attribute-group.ts +6 -4
  32. package/src/repositories/business-unit.test.ts +63 -57
  33. package/src/repositories/business-unit.ts +107 -55
  34. package/src/repositories/cart/actions.ts +96 -65
  35. package/src/repositories/cart/helpers.ts +15 -11
  36. package/src/repositories/cart/index.test.ts +136 -30
  37. package/src/repositories/cart/index.ts +76 -59
  38. package/src/repositories/cart-discount/actions.ts +12 -44
  39. package/src/repositories/cart-discount/index.ts +20 -8
  40. package/src/repositories/category/actions.ts +27 -27
  41. package/src/repositories/category/index.test.ts +13 -9
  42. package/src/repositories/category/index.ts +40 -23
  43. package/src/repositories/channel.test.ts +53 -51
  44. package/src/repositories/channel.ts +12 -22
  45. package/src/repositories/custom-object.ts +34 -25
  46. package/src/repositories/customer/actions.ts +47 -25
  47. package/src/repositories/customer/index.test.ts +11 -11
  48. package/src/repositories/customer/index.ts +65 -35
  49. package/src/repositories/customer-group.test.ts +44 -42
  50. package/src/repositories/customer-group.ts +12 -22
  51. package/src/repositories/discount-code/actions.ts +3 -19
  52. package/src/repositories/discount-code/index.ts +9 -4
  53. package/src/repositories/discount-group/index.ts +8 -3
  54. package/src/repositories/extension.test.ts +27 -27
  55. package/src/repositories/extension.ts +10 -5
  56. package/src/repositories/helpers.ts +126 -47
  57. package/src/repositories/inventory-entry/actions.ts +3 -24
  58. package/src/repositories/inventory-entry/index.ts +19 -11
  59. package/src/repositories/my-customer.ts +13 -12
  60. package/src/repositories/my-order.ts +5 -2
  61. package/src/repositories/order/actions.ts +84 -56
  62. package/src/repositories/order/index.test.ts +36 -31
  63. package/src/repositories/order/index.ts +83 -49
  64. package/src/repositories/order-edit.ts +8 -3
  65. package/src/repositories/payment/actions.ts +64 -44
  66. package/src/repositories/payment/helpers.ts +3 -3
  67. package/src/repositories/payment/index.ts +28 -12
  68. package/src/repositories/product/actions.ts +133 -98
  69. package/src/repositories/product/helpers.ts +29 -16
  70. package/src/repositories/product/index.ts +42 -25
  71. package/src/repositories/product-discount.ts +6 -4
  72. package/src/repositories/product-projection.ts +41 -21
  73. package/src/repositories/product-selection.ts +8 -15
  74. package/src/repositories/product-tailoring.ts +22 -3
  75. package/src/repositories/product-type.ts +45 -4
  76. package/src/repositories/project.ts +57 -13
  77. package/src/repositories/quote/actions.ts +5 -28
  78. package/src/repositories/quote/index.ts +29 -6
  79. package/src/repositories/quote-request/actions.ts +5 -28
  80. package/src/repositories/quote-request/index.test.ts +3 -3
  81. package/src/repositories/quote-request/index.ts +31 -11
  82. package/src/repositories/quote-staged/actions.ts +5 -28
  83. package/src/repositories/quote-staged/index.ts +22 -8
  84. package/src/repositories/recurrence-policy/index.ts +6 -4
  85. package/src/repositories/recurring-order/actions.ts +7 -32
  86. package/src/repositories/recurring-order/index.ts +8 -6
  87. package/src/repositories/review.test.ts +147 -142
  88. package/src/repositories/review.ts +31 -37
  89. package/src/repositories/shipping-method/actions.ts +11 -28
  90. package/src/repositories/shipping-method/index.ts +26 -15
  91. package/src/repositories/shopping-list/actions.ts +21 -31
  92. package/src/repositories/shopping-list/index.ts +44 -22
  93. package/src/repositories/standalone-price.ts +6 -4
  94. package/src/repositories/state.ts +15 -9
  95. package/src/repositories/store.ts +21 -32
  96. package/src/repositories/subscription.test.ts +22 -22
  97. package/src/repositories/subscription.ts +8 -3
  98. package/src/repositories/tax-category/index.ts +8 -3
  99. package/src/repositories/type/actions.ts +21 -3
  100. package/src/repositories/type/index.ts +5 -3
  101. package/src/repositories/zone.test.ts +112 -77
  102. package/src/repositories/zone.ts +5 -3
  103. package/src/schemas/generated/associate-role.ts +13 -0
  104. package/src/schemas/generated/attribute-group.ts +12 -0
  105. package/src/schemas/generated/business-unit.ts +38 -0
  106. package/src/schemas/generated/cart-discount.ts +33 -0
  107. package/src/schemas/generated/cart.ts +61 -0
  108. package/src/schemas/generated/category.ts +25 -0
  109. package/src/schemas/generated/channel.ts +21 -0
  110. package/src/schemas/generated/common.ts +1372 -0
  111. package/src/schemas/generated/custom-object.ts +11 -0
  112. package/src/schemas/generated/customer-group.ts +11 -0
  113. package/src/schemas/generated/customer.ts +47 -0
  114. package/src/schemas/generated/discount-code.ts +25 -0
  115. package/src/schemas/generated/discount-group.ts +13 -0
  116. package/src/schemas/generated/extension.ts +15 -0
  117. package/src/schemas/generated/index.ts +42 -0
  118. package/src/schemas/generated/inventory-entry.ts +20 -0
  119. package/src/schemas/generated/my-quote-request.ts +10 -0
  120. package/src/schemas/generated/order-edit.ts +18 -0
  121. package/src/schemas/generated/order-from-cart.ts +25 -0
  122. package/src/schemas/generated/payment.ts +30 -0
  123. package/src/schemas/generated/product-discount.ts +20 -0
  124. package/src/schemas/generated/product-selection.ts +18 -0
  125. package/src/schemas/generated/product-tailoring.ts +26 -0
  126. package/src/schemas/generated/product-type.ts +12 -0
  127. package/src/schemas/generated/product.ts +37 -0
  128. package/src/schemas/generated/quote-request.ts +19 -0
  129. package/src/schemas/generated/quote.ts +18 -0
  130. package/src/schemas/generated/recurrence-policy.ts +15 -0
  131. package/src/schemas/generated/recurring-order.ts +19 -0
  132. package/src/schemas/generated/review.ts +24 -0
  133. package/src/schemas/generated/shipping-method.ts +24 -0
  134. package/src/schemas/generated/shopping-list.ts +28 -0
  135. package/src/schemas/generated/staged-quote.ts +18 -0
  136. package/src/schemas/generated/standalone-price.ts +32 -0
  137. package/src/schemas/generated/state.ts +20 -0
  138. package/src/schemas/generated/store.ts +23 -0
  139. package/src/schemas/generated/subscription.ts +20 -0
  140. package/src/schemas/generated/tax-category.ts +12 -0
  141. package/src/schemas/generated/type.ts +17 -0
  142. package/src/schemas/generated/zone.ts +12 -0
  143. package/src/schemas/update-request.ts +3 -5
  144. package/src/server.ts +32 -4
  145. package/src/services/abstract.ts +207 -101
  146. package/src/services/as-associate-cart.test.ts +28 -36
  147. package/src/services/as-associate-cart.ts +15 -12
  148. package/src/services/as-associate-order.test.ts +33 -40
  149. package/src/services/as-associate-order.ts +15 -12
  150. package/src/services/as-associate-quote-request.ts +15 -12
  151. package/src/services/as-associate-shopping-list.test.ts +25 -35
  152. package/src/services/as-associate-shopping-list.ts +15 -12
  153. package/src/services/as-associate.test.ts +21 -15
  154. package/src/services/as-associate.ts +23 -22
  155. package/src/services/associate-roles.test.ts +16 -22
  156. package/src/services/associate-roles.ts +2 -2
  157. package/src/services/attribute-group.test.ts +40 -44
  158. package/src/services/attribute-group.ts +2 -2
  159. package/src/services/business-units.test.ts +227 -163
  160. package/src/services/business-units.ts +2 -2
  161. package/src/services/cart-discount.test.ts +253 -187
  162. package/src/services/cart-discount.ts +2 -2
  163. package/src/services/cart.test.ts +833 -832
  164. package/src/services/cart.ts +31 -12
  165. package/src/services/category.test.ts +208 -130
  166. package/src/services/category.ts +2 -2
  167. package/src/services/channel.test.ts +39 -44
  168. package/src/services/channel.ts +2 -2
  169. package/src/services/custom-object.test.ts +103 -79
  170. package/src/services/custom-object.ts +106 -38
  171. package/src/services/customer-group.test.ts +39 -44
  172. package/src/services/customer-group.ts +2 -2
  173. package/src/services/customer.test.ts +357 -292
  174. package/src/services/customer.ts +70 -23
  175. package/src/services/discount-code.test.ts +57 -68
  176. package/src/services/discount-code.ts +2 -2
  177. package/src/services/discount-group.test.ts +111 -134
  178. package/src/services/discount-group.ts +2 -2
  179. package/src/services/draft-validation.test.ts +255 -0
  180. package/src/services/extension.test.ts +39 -44
  181. package/src/services/extension.ts +2 -2
  182. package/src/services/inventory-entry.test.ts +106 -87
  183. package/src/services/inventory-entry.ts +2 -2
  184. package/src/services/my-business-unit.test.ts +82 -112
  185. package/src/services/my-business-unit.ts +25 -19
  186. package/src/services/my-cart.test.ts +46 -41
  187. package/src/services/my-cart.ts +32 -28
  188. package/src/services/my-customer.test.ts +153 -88
  189. package/src/services/my-customer.ts +130 -61
  190. package/src/services/my-order.ts +15 -12
  191. package/src/services/my-payment.test.ts +30 -24
  192. package/src/services/my-payment.ts +2 -2
  193. package/src/services/my-shopping-list.ts +2 -2
  194. package/src/services/order.test.ts +332 -276
  195. package/src/services/order.ts +45 -27
  196. package/src/services/payment.test.ts +31 -29
  197. package/src/services/payment.ts +2 -2
  198. package/src/services/product-discount.test.ts +39 -46
  199. package/src/services/product-discount.ts +2 -2
  200. package/src/services/product-projection.test.ts +176 -166
  201. package/src/services/product-projection.ts +31 -15
  202. package/src/services/product-selection.test.ts +17 -9
  203. package/src/services/product-selection.ts +2 -2
  204. package/src/services/product-type.test.ts +80 -21
  205. package/src/services/product-type.ts +2 -2
  206. package/src/services/product.test.ts +569 -534
  207. package/src/services/product.ts +14 -7
  208. package/src/services/project.test.ts +22 -12
  209. package/src/services/project.ts +28 -13
  210. package/src/services/quote-request.test.ts +36 -39
  211. package/src/services/quote-request.ts +2 -2
  212. package/src/services/quote-staged.ts +2 -2
  213. package/src/services/quote.ts +2 -2
  214. package/src/services/recurrence-policy.test.ts +114 -139
  215. package/src/services/recurrence-policy.ts +2 -2
  216. package/src/services/recurring-order.test.ts +149 -194
  217. package/src/services/recurring-order.ts +2 -2
  218. package/src/services/reviews.test.ts +127 -106
  219. package/src/services/reviews.ts +2 -2
  220. package/src/services/shipping-method.test.ts +96 -125
  221. package/src/services/shipping-method.ts +24 -12
  222. package/src/services/shopping-list.test.ts +183 -141
  223. package/src/services/shopping-list.ts +2 -2
  224. package/src/services/standalone-price.test.ts +60 -46
  225. package/src/services/standalone-price.ts +2 -2
  226. package/src/services/state.test.ts +20 -25
  227. package/src/services/state.ts +2 -2
  228. package/src/services/store.test.ts +26 -45
  229. package/src/services/store.ts +2 -2
  230. package/src/services/subscription.test.ts +39 -44
  231. package/src/services/subscription.ts +2 -2
  232. package/src/services/tax-category.test.ts +33 -36
  233. package/src/services/tax-category.ts +2 -2
  234. package/src/services/type.test.ts +45 -44
  235. package/src/services/type.ts +2 -2
  236. package/src/services/zone.test.ts +40 -44
  237. package/src/services/zone.ts +2 -2
  238. package/src/shipping.ts +41 -11
  239. package/src/storage/abstract.ts +248 -17
  240. package/src/storage/in-memory.ts +147 -290
  241. package/src/storage/sqlite.ts +429 -0
  242. package/src/storage/storage-map.ts +75 -0
  243. package/src/storage/storage.test-helpers.ts +97 -0
  244. package/src/storage/storage.test.ts +802 -0
  245. package/src/testing/associate-role.ts +28 -0
  246. package/src/testing/attribute-group.ts +27 -0
  247. package/src/testing/business-unit.ts +9 -8
  248. package/src/testing/cart-discount.ts +34 -0
  249. package/src/testing/cart.ts +20 -0
  250. package/src/testing/category.ts +25 -0
  251. package/src/testing/channel.ts +23 -0
  252. package/src/testing/custom-object.ts +27 -0
  253. package/src/testing/customer-group.ts +26 -0
  254. package/src/testing/customer.ts +36 -33
  255. package/src/testing/discount-code.ts +29 -0
  256. package/src/testing/discount-group.ts +27 -0
  257. package/src/testing/extension.ts +32 -0
  258. package/src/testing/index.ts +33 -0
  259. package/src/testing/inventory-entry.ts +26 -0
  260. package/src/testing/order.ts +27 -0
  261. package/src/testing/payment.ts +23 -0
  262. package/src/testing/product-discount.ts +33 -0
  263. package/src/testing/product-selection.ts +28 -0
  264. package/src/testing/product-type.ts +27 -0
  265. package/src/testing/product.ts +38 -0
  266. package/src/testing/quote-request.ts +29 -0
  267. package/src/testing/recurrence-policy.ts +33 -0
  268. package/src/testing/recurring-order.ts +32 -0
  269. package/src/testing/review.ts +24 -0
  270. package/src/testing/shipping-method.ts +31 -0
  271. package/src/testing/shopping-list.ts +25 -0
  272. package/src/testing/standalone-price.ts +31 -0
  273. package/src/testing/state.ts +21 -0
  274. package/src/testing/store.ts +26 -0
  275. package/src/testing/subscription.ts +38 -0
  276. package/src/testing/tax-category.ts +27 -0
  277. package/src/testing/type.ts +9 -6
  278. package/src/testing/zone.ts +22 -0
  279. package/src/validate.test.ts +122 -0
  280. package/src/validate.ts +78 -7
  281. package/src/.env +0 -0
@@ -0,0 +1,1044 @@
1
+ import { v4 } from "uuid";
2
+
3
+ //#region src/exceptions.ts
4
+ var CommercetoolsError = class extends Error {
5
+ info;
6
+ statusCode;
7
+ errors;
8
+ constructor(info, statusCode = 400) {
9
+ super(info.message);
10
+ this.info = info;
11
+ this.statusCode = statusCode || 500;
12
+ this.errors = info.errors ?? [];
13
+ }
14
+ };
15
+
16
+ //#endregion
17
+ //#region src/helpers.ts
18
+ const getBaseResourceProperties = (clientId) => {
19
+ const clientInfo = {
20
+ clientId: clientId ?? "",
21
+ isPlatformClient: false
22
+ };
23
+ return {
24
+ id: v4(),
25
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
26
+ lastModifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
27
+ version: 0,
28
+ createdBy: clientInfo,
29
+ lastModifiedBy: clientInfo
30
+ };
31
+ };
32
+ /**
33
+ * Do a nested lookup by using a path. For example `foo.bar.value` will
34
+ * return obj['foo']['bar']['value']
35
+ */
36
+ const nestedLookup = (obj, path) => {
37
+ if (!path || path === "") return obj;
38
+ const parts = path.split(".");
39
+ let val = obj;
40
+ for (let i = 0; i < parts.length; i++) {
41
+ const part = parts[i];
42
+ if (val === void 0) return;
43
+ val = val[part];
44
+ }
45
+ return val;
46
+ };
47
+ const queryParamsArray = (input) => {
48
+ if (input === void 0) return;
49
+ const values = Array.isArray(input) ? input : [input];
50
+ if (values.length < 1) return;
51
+ return values;
52
+ };
53
+ const queryParamsValue = (value) => {
54
+ const values = queryParamsArray(value);
55
+ if (values && values.length > 0) return values[0];
56
+ };
57
+ const cloneObject = (o) => JSON.parse(JSON.stringify(o));
58
+ const mapHeaderType = (outgoingHttpHeaders) => {
59
+ const headersInit = {};
60
+ for (const key in outgoingHttpHeaders) {
61
+ const value = outgoingHttpHeaders[key];
62
+ if (Array.isArray(value)) headersInit[key] = value.join(", ");
63
+ else if (value !== void 0) headersInit[key] = value.toString();
64
+ }
65
+ return headersInit;
66
+ };
67
+ const generateRandomString = (length) => {
68
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
69
+ let result = "";
70
+ for (let i = 0; i < length; i++) {
71
+ const randomIndex = Math.floor(Math.random() * 62);
72
+ result += characters[randomIndex];
73
+ }
74
+ return result;
75
+ };
76
+
77
+ //#endregion
78
+ //#region src/lib/expandParser.ts
79
+ const parseExpandClause = (clause) => {
80
+ const result = {
81
+ element: clause,
82
+ index: void 0,
83
+ rest: void 0
84
+ };
85
+ const pos = clause.indexOf(".");
86
+ if (pos > 0) {
87
+ result.element = clause.substring(0, pos);
88
+ result.rest = clause.substring(pos + 1);
89
+ }
90
+ const match = result.element.match(/\[([^\]+])]/);
91
+ if (match) {
92
+ result.index = match[1] === "*" ? "*" : Number.parseInt(match[1], 10);
93
+ result.element = result.element.substring(0, match.index);
94
+ }
95
+ return result;
96
+ };
97
+
98
+ //#endregion
99
+ //#region vendor/perplex/lexer-state.ts
100
+ /**
101
+ * @private
102
+ */
103
+ var LexerState = class LexerState {
104
+ source;
105
+ position;
106
+ tokenTypes;
107
+ constructor(source, position = 0) {
108
+ this.source = source;
109
+ this.position = position;
110
+ }
111
+ copy() {
112
+ return new LexerState(this.source, this.position);
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ //#region vendor/perplex/token.ts
118
+ /**
119
+ * @typedef {{
120
+ * start: Position,
121
+ * end: Position,
122
+ * }} TokenPosition
123
+ */
124
+ /**
125
+ * Represents a token instance
126
+ */
127
+ var Token = class {
128
+ type;
129
+ match;
130
+ groups;
131
+ start;
132
+ end;
133
+ lexer;
134
+ /**
135
+ * Constructs a token
136
+ * @param {T} type The token type
137
+ * @param {string} match The string that the lexer consumed to create this token
138
+ * @param {string[]} groups Any RegExp groups that accrued during the match
139
+ * @param {number} start The string position where this match started
140
+ * @param {number} end The string position where this match ends
141
+ * @param {Lexer<T>} lexer The parent {@link Lexer}
142
+ */
143
+ constructor(type, match, groups, start, end, lexer) {
144
+ /**
145
+ * The token type
146
+ * @type {T}
147
+ */
148
+ this.type = type;
149
+ /**
150
+ * The string that the lexer consumed to create this token
151
+ * @type {string}
152
+ */
153
+ this.match = match;
154
+ /**
155
+ * Any RegExp groups that accrued during the match
156
+ * @type {string[]}
157
+ */
158
+ this.groups = groups;
159
+ /**
160
+ * The string position where this match started
161
+ * @type {number}
162
+ */
163
+ this.start = start;
164
+ /**
165
+ * The string position where this match ends
166
+ * @type {number}
167
+ */
168
+ this.end = end;
169
+ /**
170
+ * The parent {@link Lexer}
171
+ * @type {Lexer<T>}
172
+ */
173
+ this.lexer = lexer;
174
+ }
175
+ /**
176
+ * Returns the bounds of this token, each in `{line, column}` format
177
+ * @return {TokenPosition}
178
+ */
179
+ strpos() {
180
+ return {
181
+ start: this.lexer.strpos(this.start),
182
+ end: this.lexer.strpos(this.end)
183
+ };
184
+ }
185
+ isEof() {
186
+ return false;
187
+ }
188
+ };
189
+ var EOFToken = class extends Token {
190
+ constructor(lexer) {
191
+ const end = lexer.source.length;
192
+ super(null, "(eof)", [], end, end, lexer);
193
+ }
194
+ isEof() {
195
+ return true;
196
+ }
197
+ };
198
+ /**
199
+ * @private
200
+ */
201
+ const EOF = (lexer) => new EOFToken(lexer);
202
+
203
+ //#endregion
204
+ //#region vendor/perplex/token-types.ts
205
+ function toRegExp(str) {
206
+ return new RegExp(str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"));
207
+ }
208
+ function normalize(regex) {
209
+ if (typeof regex === "string") regex = toRegExp(regex);
210
+ if (!regex.source.startsWith("^")) return new RegExp(`^${regex.source}`, regex.flags);
211
+ else return regex;
212
+ }
213
+ function first(arr, predicate) {
214
+ let i = 0;
215
+ for (const item of arr) {
216
+ const result = predicate(item, i++);
217
+ if (result) return {
218
+ item,
219
+ result
220
+ };
221
+ }
222
+ }
223
+ /**
224
+ * @private
225
+ */
226
+ var TokenTypes = class {
227
+ tokenTypes;
228
+ constructor() {
229
+ this.tokenTypes = [];
230
+ }
231
+ disable(type) {
232
+ return this.enable(type, false);
233
+ }
234
+ enable(type, enabled = true) {
235
+ this.tokenTypes.filter((t) => t.type == type).forEach((t) => t.enabled = enabled);
236
+ return this;
237
+ }
238
+ isEnabled(type) {
239
+ const ttypes = this.tokenTypes.filter((tt) => tt.type == type);
240
+ if (ttypes.length == 0) throw new Error(`Token of type ${type} does not exists`);
241
+ return ttypes[0].enabled;
242
+ }
243
+ peek(source, position) {
244
+ const s = source.substr(position);
245
+ return first(this.tokenTypes.filter((tt) => tt.enabled), (tt) => {
246
+ tt.regex.lastIndex = 0;
247
+ return tt.regex.exec(s);
248
+ });
249
+ }
250
+ token(type, pattern, skip = false) {
251
+ this.tokenTypes.push({
252
+ type,
253
+ regex: normalize(pattern),
254
+ enabled: true,
255
+ skip
256
+ });
257
+ return this;
258
+ }
259
+ };
260
+
261
+ //#endregion
262
+ //#region vendor/perplex/lexer.ts
263
+ /**
264
+ * @typedef {{
265
+ * line: number,
266
+ * column: number,
267
+ * }} Position
268
+ */
269
+ /**
270
+ * Lexes a source-string into tokens.
271
+ *
272
+ * @example
273
+ * const lex = perplex('...')
274
+ * .token('ID', /my-id-regex/)
275
+ * .token('(', /\(/)
276
+ * .token(')', /\)/)
277
+ * .token('WS', /\s+/, true) // true means 'skip'
278
+ *
279
+ * while ((let t = lex.next()).type != 'EOF') {
280
+ * console.log(t)
281
+ * }
282
+ * // alternatively:
283
+ * console.log(lex.toArray())
284
+ * // or:
285
+ * console.log(...lex)
286
+ */
287
+ var Lexer = class {
288
+ _state;
289
+ _tokenTypes;
290
+ /**
291
+ * Creates a new Lexer instance
292
+ * @param {string} [source = ''] The source string to operate on.
293
+ */
294
+ constructor(source = "") {
295
+ this._state = new LexerState(source);
296
+ this._tokenTypes = new TokenTypes();
297
+ }
298
+ /**
299
+ * Gets the current lexer position
300
+ * @return {number} Returns the position
301
+ */
302
+ get position() {
303
+ return this._state.position;
304
+ }
305
+ /**
306
+ * Sets the current lexer position
307
+ * @param {number} i The position to move to
308
+ */
309
+ set position(i) {
310
+ this._state.position = i;
311
+ }
312
+ /**
313
+ * Gets the source the lexer is operating on
314
+ * @return {string} Returns the source
315
+ */
316
+ get source() {
317
+ return this._state.source;
318
+ }
319
+ /**
320
+ * Sets the source the lexer is operating on
321
+ * @param {string} s The source to set
322
+ */
323
+ set source(s) {
324
+ this._state = new LexerState(s);
325
+ }
326
+ /**
327
+ * Attaches this lexer to another lexer's state
328
+ * @param {Lexer<T>} other The other lexer to attach to
329
+ */
330
+ attachTo(other) {
331
+ this._state = other._state;
332
+ }
333
+ /**
334
+ * Disables a token type
335
+ * @param {T} type The token type to disable
336
+ * @return {Lexer<T>}
337
+ */
338
+ disable(type) {
339
+ this._tokenTypes.disable(type);
340
+ return this;
341
+ }
342
+ /**
343
+ * Enables a token type
344
+ * @param {T} type The token type to enalbe
345
+ * @param {?boolean} [enabled=true] Whether to enable/disable the specified token type
346
+ * @return {Lexer<T>}
347
+ */
348
+ enable(type, enabled) {
349
+ this._tokenTypes.enable(type, enabled);
350
+ return this;
351
+ }
352
+ /**
353
+ * Like {@link next}, but throws an exception if the next token is
354
+ * not of the required type.
355
+ * @param {T} type The token type expected from {@link next}
356
+ * @return {Token<T>} Returns the {@link Token} on success
357
+ */
358
+ expect(type) {
359
+ const t = this.next();
360
+ if (t.type != type) {
361
+ const pos = t.strpos();
362
+ throw new Error("Expected " + type + (t ? ", got " + t.type : "") + " at " + pos.start.line + ":" + pos.start.column);
363
+ }
364
+ return t;
365
+ }
366
+ /**
367
+ * Looks up whether a token is enabled.
368
+ * @param tokenType The token type to look up
369
+ * @return {boolean} Returns whether the token is enabled
370
+ */
371
+ isEnabled(tokenType) {
372
+ return this._tokenTypes.isEnabled(tokenType);
373
+ }
374
+ /**
375
+ * Consumes and returns the next {@link Token} in the source string.
376
+ * If there are no more tokens, it returns a {@link Token} of type `$EOF`
377
+ * @return {Token<T>}
378
+ */
379
+ next() {
380
+ try {
381
+ const t = this.peek();
382
+ this._state.position = t.end;
383
+ return t;
384
+ } catch (e) {
385
+ this._state.position = e.end;
386
+ throw e;
387
+ }
388
+ }
389
+ /**
390
+ * Returns the next {@link Token} in the source string, but does
391
+ * not consume it.
392
+ * If there are no more tokens, it returns a {@link Token} of type `$EOF`
393
+ * @param {number} [position=`this.position`] The position at which to start reading
394
+ * @return {Token<T>}
395
+ */
396
+ peek(position = this._state.position) {
397
+ const read = (i = position) => {
398
+ if (i >= this._state.source.length) return EOF(this);
399
+ const n = this._tokenTypes.peek(this._state.source, i);
400
+ if (!n || !n.result) throw new Error(`Unexpected input: ${this._state.source.substring(i, i + 1)} at (${this.strpos(i).line}:${this.strpos(i).column})`);
401
+ return n ? n.item.skip ? read(i + n.result[0].length) : new Token(n.item.type, n.result[0], n.result.map((x) => x), i, i + n.result[0].length, this) : null;
402
+ };
403
+ const t = read();
404
+ if (t) return t;
405
+ let unexpected = this._state.source.substring(position, position + 1);
406
+ try {
407
+ this.peek(position + 1);
408
+ } catch (e) {
409
+ unexpected += e.unexpected;
410
+ }
411
+ const { line, column } = this.strpos(position);
412
+ const e = /* @__PURE__ */ new Error(`Unexpected input: ${unexpected} at (${line}:${column})`);
413
+ e.unexpected = unexpected;
414
+ e.end = position + unexpected.length;
415
+ throw e;
416
+ }
417
+ /**
418
+ * Converts a string-index (relative to the source string) to a line and a column.
419
+ * @param {number} i The index to compute
420
+ * @return {Position}
421
+ */
422
+ strpos(i) {
423
+ let lines = this._state.source.substring(0, i).split(/\r?\n/);
424
+ if (!Array.isArray(lines)) lines = [lines];
425
+ return {
426
+ line: lines.length,
427
+ column: lines[lines.length - 1].length + 1
428
+ };
429
+ }
430
+ /**
431
+ * Converts the token stream to an array of Tokens
432
+ * @return {Token<T>[]} The array of tokens (not including (EOF))
433
+ */
434
+ toArray() {
435
+ return [...this];
436
+ }
437
+ /**
438
+ * Implements the Iterable protocol
439
+ * Iterates lazily over the entire token stream (not including (EOF))
440
+ * @return {Iterator<Token<T>>} Returns an iterator over all remaining tokens
441
+ */
442
+ *[Symbol.iterator]() {
443
+ const oldState = this._state.copy();
444
+ this._state.position = 0;
445
+ let t;
446
+ while (!(t = this.next()).isEof()) yield t;
447
+ this._state = oldState;
448
+ }
449
+ /**
450
+ * Creates a new token type
451
+ * @param {T} type The token type
452
+ * @param {string|RegExp} pattern The pattern to match
453
+ * @param {?boolean} skip Whether this type of token should be skipped
454
+ * @return {Lexer<T>}
455
+ */
456
+ token(type, pattern, skip) {
457
+ this._tokenTypes.token(type, pattern, skip);
458
+ return this;
459
+ }
460
+ /**
461
+ * Creates a keyword
462
+ * @param kwd The keyword to add as a token
463
+ */
464
+ keyword(kwd) {
465
+ return this.token(kwd, new RegExp(`${kwd}(?=\\W|$)`));
466
+ }
467
+ /**
468
+ * Creates an operator
469
+ * @param op The operator to add as a token
470
+ */
471
+ operator(op) {
472
+ const sOp = new String(op).valueOf();
473
+ return this.token(op, sOp);
474
+ }
475
+ };
476
+
477
+ //#endregion
478
+ //#region vendor/pratt/index.ts
479
+ const createStop = () => {
480
+ let stopCalled = false;
481
+ return Object.assign((x) => {
482
+ stopCalled = true;
483
+ return x;
484
+ }, { isStopped() {
485
+ return stopCalled;
486
+ } });
487
+ };
488
+ /**
489
+ * A Pratt parser.
490
+ * @example
491
+ * const lex = new perplex.Lexer('1 + -2 * 3^4')
492
+ * .token('NUM', /\d+/)
493
+ * .token('+', /\+/)
494
+ * .token('-', /-/)
495
+ * .token('*', new RegExp('*'))
496
+ * .token('/', /\//)
497
+ * .token('^', /\^/)
498
+ * .token('(', /\(/)
499
+ * .token(')', /\)/)
500
+ * .token('$SKIP_WS', /\s+/)
501
+ *
502
+ * const parser = new Parser(lex)
503
+ * .builder()
504
+ * .nud('NUM', 100, t => parseInt(t.match))
505
+ * .nud('-', 10, (t, bp) => -parser.parse(bp))
506
+ * .nud('(', 10, (t, bp) => {
507
+ * const expr = parser.parse(bp)
508
+ * lex.expect(')')
509
+ * return expr
510
+ * })
511
+ * .bp(')', 0)
512
+ *
513
+ * .led('^', 20, (left, t, bp) => Math.pow(left, parser.parse(20 - 1)))
514
+ * .led('+', 30, (left, t, bp) => left + parser.parse(bp))
515
+ * .led('-', 30, (left, t, bp) => left - parser.parse(bp))
516
+ * .led('*', 40, (left, t, bp) => left * parser.parse(bp))
517
+ * .led('/', 40, (left, t, bp) => left / parser.parse(bp))
518
+ * .build()
519
+ * parser.parse()
520
+ * // => 161
521
+ */
522
+ var Parser = class {
523
+ lexer;
524
+ _nuds;
525
+ _leds;
526
+ _bps;
527
+ /**
528
+ * Constructs a Parser instance
529
+ * @param {ILexer<T>} lexer The lexer to obtain tokens from
530
+ */
531
+ constructor(lexer) {
532
+ /**
533
+ * The lexer that this parser is operating on.
534
+ * @type {ILexer<T>}
535
+ */
536
+ this.lexer = lexer;
537
+ this._nuds = /* @__PURE__ */ new Map();
538
+ this._leds = /* @__PURE__ */ new Map();
539
+ this._bps = /* @__PURE__ */ new Map();
540
+ }
541
+ _type(tokenOrType) {
542
+ return tokenOrType && typeof tokenOrType.isEof == "function" ? tokenOrType.type : tokenOrType;
543
+ }
544
+ /**
545
+ * Create a {@link ParserBuilder}
546
+ * @return {ParserBuilder<T>} Returns the ParserBuilder
547
+ */
548
+ builder() {
549
+ return new ParserBuilder(this);
550
+ }
551
+ /**
552
+ * Define binding power for a token-type
553
+ * @param {IToken<T>|T} tokenOrType The token type to define the binding power for
554
+ * @returns {number} The binding power of the specified token type
555
+ */
556
+ bp(tokenOrType) {
557
+ if (tokenOrType == null) return Number.NEGATIVE_INFINITY;
558
+ if (tokenOrType && typeof tokenOrType.isEof == "function" && tokenOrType.isEof()) return Number.NEGATIVE_INFINITY;
559
+ const type = this._type(tokenOrType);
560
+ const bp = this._bps.has(type) ? this._bps.get(type) : Number.POSITIVE_INFINITY;
561
+ return typeof bp == "function" ? bp() : bp;
562
+ }
563
+ /**
564
+ * Computes the token's `nud` value and returns it
565
+ * @param {NudInfo<T>} info The info to compute the `nud` from
566
+ * @returns {any} The result of invoking the pertinent `nud` operator
567
+ */
568
+ nud(info) {
569
+ const fn = this._nuds.get(info.token.type);
570
+ if (!fn) {
571
+ const { start } = info.token.strpos();
572
+ throw new Error(`Unexpected token: ${info.token.match} (at ${start.line}:${start.column})`);
573
+ }
574
+ return fn(info);
575
+ }
576
+ /**
577
+ * Computes a token's `led` value and returns it
578
+ * @param {LedInfo<T>} info The info to compute the `led` value for
579
+ * @returns {any} The result of invoking the pertinent `led` operator
580
+ */
581
+ led(info) {
582
+ let fn = this._leds.get(info.token.type);
583
+ if (!fn) {
584
+ const { start } = info.token.strpos();
585
+ throw new Error(`Unexpected token: ${info.token.match} (at ${start.line}:${start.column})`);
586
+ }
587
+ return fn(info);
588
+ }
589
+ /**
590
+ * Kicks off the Pratt parser, and returns the result
591
+ * @param {ParseOpts<T>} opts The parse options
592
+ * @returns {any}
593
+ */
594
+ parse(opts = { terminals: [0] }) {
595
+ const stop = opts.stop = opts.stop || createStop();
596
+ const check = () => {
597
+ if (stop.isStopped()) return false;
598
+ const t = this.lexer.peek();
599
+ const bp = this.bp(t);
600
+ return opts.terminals.reduce((canContinue, rbpOrType) => {
601
+ if (!canContinue) return false;
602
+ if (typeof rbpOrType == "number") return rbpOrType < bp;
603
+ if (typeof rbpOrType == "string") return t.type != rbpOrType;
604
+ }, true);
605
+ };
606
+ const mkinfo = (token) => {
607
+ return {
608
+ token,
609
+ bp: this.bp(token),
610
+ stop,
611
+ ctx: opts.ctx,
612
+ options: opts
613
+ };
614
+ };
615
+ if (!opts.terminals) opts.terminals = [0];
616
+ if (opts.terminals.length == 0) opts.terminals.push(0);
617
+ let left = this.nud(mkinfo(this.lexer.next()));
618
+ while (check()) {
619
+ const operator = this.lexer.next();
620
+ left = this.led(Object.assign(mkinfo(operator), { left }));
621
+ }
622
+ return left;
623
+ }
624
+ };
625
+ /**
626
+ * Builds `led`/`nud` rules for a {@link Parser}
627
+ */
628
+ var ParserBuilder = class {
629
+ _parser;
630
+ /**
631
+ * Constructs a ParserBuilder
632
+ * See also: {@link Parser.builder}
633
+ * @param {Parser<T>} parser The parser
634
+ */
635
+ constructor(parser) {
636
+ this._parser = parser;
637
+ }
638
+ /**
639
+ * Define `nud` for a token type
640
+ * @param {T} tokenType The token type
641
+ * @param {number} bp The binding power
642
+ * @param {NudFunction<T>} fn The function that will parse the token
643
+ * @return {ParserBuilder<T>} Returns this ParserBuilder
644
+ */
645
+ nud(tokenType, bp, fn) {
646
+ this._parser._nuds.set(tokenType, fn);
647
+ this.bp(tokenType, bp);
648
+ return this;
649
+ }
650
+ /**
651
+ * Define `led` for a token type
652
+ * @param {T} tokenType The token type
653
+ * @param {number} bp The binding power
654
+ * @param {LedFunction<T>} fn The function that will parse the token
655
+ * @return {ParserBuilder<T>} Returns this ParserBuilder
656
+ */
657
+ led(tokenType, bp, fn) {
658
+ this._parser._leds.set(tokenType, fn);
659
+ this.bp(tokenType, bp);
660
+ return this;
661
+ }
662
+ /**
663
+ * Define both `led` and `nud` for a token type at once.
664
+ * The supplied `LedFunction` may be called with a null `left`
665
+ * parameter when invoked from a `nud` context.
666
+ * @param {strTng} tokenType The token type
667
+ * @param {number} bp The binding power
668
+ * @param {LedFunction<T>} fn The function that will parse the token
669
+ * @return {ParserBuilder<T>} Returns this ParserBuilder
670
+ */
671
+ either(tokenType, bp, fn) {
672
+ return this.nud(tokenType, bp, (inf) => fn(Object.assign(inf, { left: null }))).led(tokenType, bp, fn);
673
+ }
674
+ /**
675
+ * Define the binding power for a token type
676
+ * @param {T} tokenType The token type
677
+ * @param {BP} bp The binding power
678
+ * @return {ParserBuilder<T>} Returns this ParserBuilder
679
+ */
680
+ bp(tokenType, bp) {
681
+ this._parser._bps.set(tokenType, bp);
682
+ return this;
683
+ }
684
+ /**
685
+ * Returns the parent {@link Parser} instance
686
+ * @returns {Parser<T>}
687
+ */
688
+ build() {
689
+ return this._parser;
690
+ }
691
+ };
692
+
693
+ //#endregion
694
+ //#region src/lib/haversine.ts
695
+ /**
696
+ * Returns the distance between src and dst as meters
697
+ */
698
+ const haversineDistance = (src, dst) => {
699
+ const RADIUS_OF_EARTH_IN_KM = 6371;
700
+ const toRadian = (deg) => deg * (Math.PI / 180);
701
+ const dLat = toRadian(dst.latitude - src.latitude);
702
+ const dLon = toRadian(dst.longitude - src.longitude);
703
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadian(src.latitude)) * Math.cos(toRadian(dst.latitude)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
704
+ return RADIUS_OF_EARTH_IN_KM * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))) * 1e3;
705
+ };
706
+
707
+ //#endregion
708
+ //#region src/lib/predicateParser.ts
709
+ /**
710
+ * This module implements the commercetools query predicate filter expression.
711
+ * Support should be 100% complete.
712
+ *
713
+ * See https://docs.commercetools.com/api/predicates/query
714
+ */
715
+ var PredicateError = class {
716
+ message;
717
+ constructor(message) {
718
+ this.message = message;
719
+ }
720
+ };
721
+ const parseQueryExpression = (predicate) => {
722
+ if (Array.isArray(predicate)) {
723
+ const callbacks = predicate.map((item) => generateMatchFunc(item));
724
+ return (target, variables) => callbacks.every((callback) => callback(target, variables));
725
+ }
726
+ return generateMatchFunc(predicate);
727
+ };
728
+ const validateSymbol = (val) => {
729
+ if (!val.type) throw new PredicateError("Internal error");
730
+ if (val.type === "identifier") {
731
+ const char = val.value.charAt(0);
732
+ const line = val.pos?.start.line;
733
+ const column = val.pos?.start.column;
734
+ throw new PredicateError(`Invalid input '${char}', expected input parameter or primitive value (line ${line}, column ${column})`);
735
+ }
736
+ };
737
+ const resolveSymbol = (val, vars) => {
738
+ if (val.type === "var") {
739
+ if (!(val.value in (vars ?? {}))) throw new PredicateError(`Missing parameter value for ${val.value}`);
740
+ return vars[val.value];
741
+ }
742
+ return val.value;
743
+ };
744
+ const resolveValue = (obj, val) => {
745
+ if (val.type !== "identifier") throw new PredicateError("Internal error");
746
+ if (val.value === "variants" && obj.masterVariant && obj.variants !== void 0) return [obj.masterVariant, ...obj.variants ?? []];
747
+ if (!(val.value in obj)) {
748
+ if (Array.isArray(obj)) return Object.values(obj).filter((v) => val.value in v).map((v) => v[val.value]);
749
+ return;
750
+ }
751
+ return obj[val.value];
752
+ };
753
+ const getLexer = (value) => new Lexer(value).token("AND", /and(?![-_a-z0-9]+)/i).token("OR", /or(?![-_a-z0-9]+)/i).token("NOT", /not(?![-_a-z0-9]+)/i).token("WITHIN", /within(?![-_a-z0-9]+)/i).token("IN", /in(?![-_a-z0-9]+)/i).token("MATCHES_IGNORE_CASE", /matches\s+ignore\s+case(?![-_a-z0-9]+)/i).token("CONTAINS", /contains(?![-_a-z0-9]+)/i).token("ALL", /all(?![-_a-z0-9]+)/i).token("ANY", /any(?![-_a-z0-9]+)/i).token("EMPTY", /empty(?![-_a-z0-9]+)/i).token("IS", /is(?![-_a-z0-9]+)/i).token("DEFINED", /defined(?![-_a-z0-9]+)/i).token("IDENTIFIER", /[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("VARIABLE", /:([-_A-Za-z0-9]+)/).token("BOOLEAN", /(true|false)/).token("IDENTIFIER", /[-_A-Za-z0-9]+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("(", "(").token(")", ")").token(">=", ">=").token("<=", "<=").token(">", ">").token("<", "<").token("!=", "!=").token("=", "=").token("\"", "\"").token("WS", /\s+/, true);
754
+ /**
755
+ * This function converts a query expression in to a callable which returns a
756
+ * boolean to indicate if the given object matches or not.
757
+ *
758
+ * This currently parses the predicate each time it is called, but it should be
759
+ * straight-forward to add a query cache (lru-cache)
760
+ */
761
+ const generateMatchFunc = (predicate) => {
762
+ const lexer = getLexer(predicate);
763
+ const parser = new Parser(lexer).builder().nud("IDENTIFIER", 100, (t) => ({
764
+ type: "identifier",
765
+ value: t.token.match,
766
+ pos: t.token.strpos()
767
+ })).nud("BOOLEAN", 1, (t) => ({
768
+ type: "boolean",
769
+ value: t.token.match === "true",
770
+ pos: t.token.strpos()
771
+ })).nud("VARIABLE", 100, (t) => ({
772
+ type: "var",
773
+ value: t.token.groups[1],
774
+ pos: t.token.strpos()
775
+ })).nud("STRING", 100, (t) => ({
776
+ type: "string",
777
+ value: t.token.groups[1],
778
+ pos: t.token.strpos()
779
+ })).nud("INT", 1, (t) => ({
780
+ type: "int",
781
+ value: Number.parseInt(t.token.match, 10),
782
+ pos: t.token.strpos()
783
+ })).nud("FLOAT", 1, (t) => ({
784
+ type: "float",
785
+ value: Number.parseFloat(t.token.match),
786
+ pos: t.token.strpos()
787
+ })).nud("NOT", 100, ({ bp }) => {
788
+ const expr = parser.parse({ terminals: [bp - 1] });
789
+ return (obj) => !expr(obj);
790
+ }).nud("EMPTY", 10, ({ bp }) => "empty").nud("DEFINED", 10, ({ bp }) => "defined").led("AND", 5, ({ left, bp }) => {
791
+ const expr = parser.parse({ terminals: [bp - 1] });
792
+ return (obj, vars) => left(obj, vars) && expr(obj, vars);
793
+ }).led("OR", 5, ({ left, token, bp }) => {
794
+ const expr = parser.parse({ terminals: [bp - 1] });
795
+ return (obj, vars) => left(obj, vars) || expr(obj, vars);
796
+ }).led("COMMA", 1, ({ left, token, bp }) => {
797
+ const expr = parser.parse({ terminals: [bp - 1] });
798
+ if (Array.isArray(expr)) return [left, ...expr];
799
+ return [left, expr];
800
+ }).nud("(", 100, (t) => {
801
+ return parser.parse({ terminals: [")"] });
802
+ }).led("(", 100, ({ left, bp }) => {
803
+ const expr = parser.parse();
804
+ lexer.expect(")");
805
+ return (obj, vars) => {
806
+ if (Array.isArray(obj)) return obj.some((item) => {
807
+ const value = resolveValue(item, left);
808
+ if (value) return expr(value, vars);
809
+ return false;
810
+ });
811
+ const value = resolveValue(obj, left);
812
+ if (value) {
813
+ if (Array.isArray(value)) return value.some((item) => expr(item, vars));
814
+ return expr(value, vars);
815
+ }
816
+ return false;
817
+ };
818
+ }).bp(")", 0).led("=", 20, ({ left, bp }) => {
819
+ const expr = parser.parse({ terminals: [bp - 1] });
820
+ validateSymbol(expr);
821
+ return (obj, vars) => {
822
+ if (Array.isArray(obj)) return obj.some((item) => {
823
+ const value = resolveValue(item, left);
824
+ const other = resolveSymbol(expr, vars);
825
+ if (Array.isArray(value)) return !!value.some((elem) => elem === other);
826
+ return value === other;
827
+ });
828
+ const resolvedValue = resolveValue(obj, left);
829
+ const resolvedSymbol = resolveSymbol(expr, vars);
830
+ if (Array.isArray(resolvedValue)) return !!resolvedValue.some((elem) => elem === resolvedSymbol);
831
+ return resolvedValue === resolvedSymbol;
832
+ };
833
+ }).led("!=", 20, ({ left, bp }) => {
834
+ const expr = parser.parse({ terminals: [bp - 1] });
835
+ validateSymbol(expr);
836
+ return (obj, vars) => resolveValue(obj, left) !== resolveSymbol(expr, vars);
837
+ }).led(">", 20, ({ left, bp }) => {
838
+ const expr = parser.parse({ terminals: [bp - 1] });
839
+ validateSymbol(expr);
840
+ return (obj, vars) => resolveValue(obj, left) > resolveSymbol(expr, vars);
841
+ }).led(">=", 20, ({ left, bp }) => {
842
+ const expr = parser.parse({ terminals: [bp - 1] });
843
+ validateSymbol(expr);
844
+ return (obj, vars) => resolveValue(obj, left) >= resolveSymbol(expr, vars);
845
+ }).led("<", 20, ({ left, bp }) => {
846
+ const expr = parser.parse({ terminals: [bp - 1] });
847
+ validateSymbol(expr);
848
+ return (obj, vars) => resolveValue(obj, left) < resolveSymbol(expr, vars);
849
+ }).led("<=", 20, ({ left, bp }) => {
850
+ const expr = parser.parse({ terminals: [bp - 1] });
851
+ validateSymbol(expr);
852
+ return (obj, vars) => resolveValue(obj, left) <= resolveSymbol(expr, vars);
853
+ }).led("IS", 20, ({ left, bp }) => {
854
+ let invert = false;
855
+ if (lexer.peek().type === "NOT") {
856
+ invert = true;
857
+ lexer.next();
858
+ }
859
+ switch (parser.parse({ terminals: [bp - 1] })) {
860
+ case "empty":
861
+ if (!invert) return (obj, vars) => {
862
+ return resolveValue(obj, left).length === 0;
863
+ };
864
+ return (obj, vars) => {
865
+ return resolveValue(obj, left).length !== 0;
866
+ };
867
+ case "defined":
868
+ if (!invert) return (obj, vars) => {
869
+ return resolveValue(obj, left) !== void 0;
870
+ };
871
+ return (obj, vars) => {
872
+ return resolveValue(obj, left) === void 0;
873
+ };
874
+ default: throw new Error("Unexpected");
875
+ }
876
+ }).led("IN", 20, ({ left, bp }) => {
877
+ const firstToken = lexer.peek();
878
+ const expr = parser.parse({ terminals: [bp - 1] });
879
+ if (firstToken.match === "(") lexer.expect(")");
880
+ return (obj, vars) => {
881
+ let symbols = expr;
882
+ if (!Array.isArray(symbols)) symbols = [expr];
883
+ const inValues = symbols.flatMap((item) => resolveSymbol(item, vars));
884
+ const value = resolveValue(obj, left);
885
+ if (Array.isArray(value)) return inValues.some((inValue) => value.includes(inValue));
886
+ return inValues.includes(value);
887
+ };
888
+ }).led("MATCHES_IGNORE_CASE", 20, ({ left, bp }) => {
889
+ const expr = parser.parse({ terminals: [bp - 1] });
890
+ validateSymbol(expr);
891
+ return (obj, vars) => {
892
+ const value = resolveValue(obj, left);
893
+ const other = resolveSymbol(expr, vars);
894
+ if (typeof value !== "string") throw new PredicateError(`The field '${left.value}' does not support this expression.`);
895
+ return value.toLowerCase() === other.toLowerCase();
896
+ };
897
+ }).led("WITHIN", 20, ({ left, bp }) => {
898
+ const type = lexer.next();
899
+ if (type.match !== "circle") throw new PredicateError(`Invalid input '${type.match}', expected circle`);
900
+ lexer.expect("(");
901
+ const expr = parser.parse({ terminals: [")"] });
902
+ lexer.expect(")");
903
+ return (obj, vars) => {
904
+ const value = resolveValue(obj, left);
905
+ if (!value) return false;
906
+ const maxDistance = resolveSymbol(expr[2], vars);
907
+ return haversineDistance({
908
+ longitude: value[0],
909
+ latitude: value[1]
910
+ }, {
911
+ longitude: resolveSymbol(expr[0], vars),
912
+ latitude: resolveSymbol(expr[1], vars)
913
+ }) <= maxDistance;
914
+ };
915
+ }).led("CONTAINS", 20, ({ left, bp }) => {
916
+ const keyword = lexer.next();
917
+ let expr = parser.parse();
918
+ if (!Array.isArray(expr)) expr = [expr];
919
+ return (obj, vars) => {
920
+ const value = resolveValue(obj, left);
921
+ if (!Array.isArray(value)) throw new PredicateError(`The field '${left.value}' does not support this expression.`);
922
+ const array = expr.map((item) => resolveSymbol(item, vars));
923
+ if (keyword.type === "ALL") return array.every((item) => value.includes(item));
924
+ return array.some((item) => value.includes(item));
925
+ };
926
+ }).build();
927
+ const result = parser.parse();
928
+ if (typeof result !== "function") {
929
+ const lines = predicate.split("\n");
930
+ const column = lines[lines.length - 1].length;
931
+ throw new PredicateError(`Unexpected end of input, expected SphereIdentifierChar, comparison operator, not, in, contains, is, within or matches (line ${lines.length}, column ${column})`);
932
+ }
933
+ return result;
934
+ };
935
+
936
+ //#endregion
937
+ //#region src/storage/abstract.ts
938
+ var AbstractStorage = class {
939
+ /**
940
+ * Close the storage backend and release any resources.
941
+ * Override this in subclasses that hold external resources (e.g. database connections).
942
+ */
943
+ close() {}
944
+ async expand(projectKey, obj, clause) {
945
+ if (!clause) return obj;
946
+ if (Array.isArray(clause)) for (const c of clause) await this._resolveResource(projectKey, obj, c);
947
+ else await this._resolveResource(projectKey, obj, clause);
948
+ return obj;
949
+ }
950
+ async getByResourceIdentifier(projectKey, identifier) {
951
+ if (identifier.id) {
952
+ const resource = await this.get(projectKey, identifier.typeId, identifier.id);
953
+ if (resource) return resource;
954
+ throw new CommercetoolsError({
955
+ code: "ReferencedResourceNotFound",
956
+ message: `The referenced object of type '${identifier.typeId}' with id '${identifier.id}' was not found. It either doesn't exist, or it can't be accessed from this endpoint (e.g., if the endpoint filters by store or customer account).`,
957
+ typeId: identifier.typeId,
958
+ id: identifier.id
959
+ });
960
+ }
961
+ if (identifier.key) {
962
+ const resource = await this.getByKey(projectKey, identifier.typeId, identifier.key);
963
+ if (resource) return resource;
964
+ throw new CommercetoolsError({
965
+ code: "ReferencedResourceNotFound",
966
+ message: `The referenced object of type '${identifier.typeId}' with key '${identifier.key}' was not found. It either doesn't exist, or it can't be accessed from this endpoint (e.g., if the endpoint filters by store or customer account).`,
967
+ typeId: identifier.typeId,
968
+ key: identifier.key
969
+ });
970
+ }
971
+ throw new CommercetoolsError({
972
+ code: "InvalidJsonInput",
973
+ message: "Request body does not contain valid JSON.",
974
+ detailedErrorMessage: "ResourceIdentifier requires an 'id' xor a 'key'"
975
+ });
976
+ }
977
+ async search(projectKey, typeId, params) {
978
+ let resources = await this.all(projectKey, typeId);
979
+ if (params.where) try {
980
+ const filterFunc = parseQueryExpression(params.where);
981
+ resources = resources.filter((resource) => filterFunc(resource, {}));
982
+ } catch (err) {
983
+ throw new CommercetoolsError({
984
+ code: "InvalidInput",
985
+ message: err.message
986
+ }, 400);
987
+ }
988
+ const totalResources = resources.length;
989
+ const offset = params.offset || 0;
990
+ const limit = params.limit || 20;
991
+ resources = resources.slice(offset, offset + limit);
992
+ if (params.expand !== void 0) resources = await Promise.all(resources.map((resource) => this.expand(projectKey, resource, params.expand)));
993
+ return {
994
+ count: resources.length,
995
+ total: totalResources,
996
+ offset,
997
+ limit,
998
+ results: resources
999
+ };
1000
+ }
1001
+ async _resolveResource(projectKey, obj, expand) {
1002
+ const params = parseExpandClause(expand);
1003
+ if (params.index === "*") {
1004
+ const reference = obj[params.element];
1005
+ if (params.element === "lineItems" && params.rest?.startsWith("variant") && reference.every((item) => item.variant === void 0 && item.variantId !== void 0)) for (const item of reference) await this._resolveShoppingListLineItemVariant(projectKey, item);
1006
+ }
1007
+ if (!params.index) {
1008
+ const reference = obj[params.element];
1009
+ if (reference === void 0) return;
1010
+ await this._resolveReference(projectKey, reference, params.rest);
1011
+ } else if (params.index === "*") {
1012
+ const reference = obj[params.element];
1013
+ if (reference === void 0 || !Array.isArray(reference)) return;
1014
+ for (const itemRef of reference) await this._resolveReference(projectKey, itemRef, params.rest);
1015
+ } else {
1016
+ const reference = obj[params.element][params.index];
1017
+ if (reference === void 0) return;
1018
+ await this._resolveReference(projectKey, reference, params.rest);
1019
+ }
1020
+ }
1021
+ async _resolveReference(projectKey, reference, expand) {
1022
+ if (reference === void 0) return;
1023
+ if (reference.typeId !== void 0 && (reference.id !== void 0 || reference.key !== void 0)) {
1024
+ if (!reference.obj) reference.obj = await this.getByResourceIdentifier(projectKey, {
1025
+ typeId: reference.typeId,
1026
+ id: reference.id,
1027
+ key: reference.key
1028
+ });
1029
+ if (expand) await this._resolveResource(projectKey, reference.obj, expand);
1030
+ } else if (expand) await this._resolveResource(projectKey, reference, expand);
1031
+ }
1032
+ async _resolveShoppingListLineItemVariant(projectKey, lineItem) {
1033
+ const product = await this.getByResourceIdentifier(projectKey, {
1034
+ typeId: "product",
1035
+ id: lineItem.productId
1036
+ });
1037
+ if (!product) return;
1038
+ lineItem.variant = [product.masterData.current.masterVariant, ...product.masterData.current.variants].find((e) => e.id === lineItem.variantId);
1039
+ }
1040
+ };
1041
+
1042
+ //#endregion
1043
+ export { parseExpandClause as a, getBaseResourceProperties as c, queryParamsArray as d, queryParamsValue as f, Lexer as i, mapHeaderType as l, parseQueryExpression as n, cloneObject as o, CommercetoolsError as p, Parser as r, generateRandomString as s, AbstractStorage as t, nestedLookup as u };
1044
+ //# sourceMappingURL=abstract-BKFcva6S.mjs.map