feed-common 1.77.1 → 1.77.3

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 (108) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/dist/constants/profile.constants.d.ts +12 -0
  4. package/dist/constants/profile.constants.d.ts.map +1 -1
  5. package/dist/constants/profile.constants.js +39 -1
  6. package/dist/constants/profile.constants.js.map +1 -1
  7. package/dist/index.d.ts +11 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +11 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/sources/country.source.d.ts +5 -0
  12. package/dist/sources/country.source.d.ts.map +1 -0
  13. package/dist/sources/country.source.js +78 -0
  14. package/dist/sources/country.source.js.map +1 -0
  15. package/dist/sources/currency.source.d.ts.map +1 -1
  16. package/dist/sources/currency.source.js +0 -1
  17. package/dist/sources/currency.source.js.map +1 -1
  18. package/dist/sources/ebay-gallery-type.source.d.ts +5 -0
  19. package/dist/sources/ebay-gallery-type.source.d.ts.map +1 -0
  20. package/dist/sources/ebay-gallery-type.source.js +5 -0
  21. package/dist/sources/ebay-gallery-type.source.js.map +1 -0
  22. package/dist/sources/ebay-inventory-tracking.source.d.ts +3 -0
  23. package/dist/sources/ebay-inventory-tracking.source.d.ts.map +1 -0
  24. package/dist/sources/ebay-inventory-tracking.source.js +11 -0
  25. package/dist/sources/ebay-inventory-tracking.source.js.map +1 -0
  26. package/dist/sources/ebay-listing-type.source.d.ts +5 -0
  27. package/dist/sources/ebay-listing-type.source.d.ts.map +1 -0
  28. package/dist/sources/ebay-listing-type.source.js +5 -0
  29. package/dist/sources/ebay-listing-type.source.js.map +1 -0
  30. package/dist/sources/ebay-yes-no.source.d.ts +5 -0
  31. package/dist/sources/ebay-yes-no.source.d.ts.map +1 -0
  32. package/dist/sources/ebay-yes-no.source.js +2 -0
  33. package/dist/sources/ebay-yes-no.source.js.map +1 -0
  34. package/dist/sources/google-availability.source.d.ts +5 -0
  35. package/dist/sources/google-availability.source.d.ts.map +1 -0
  36. package/dist/sources/google-availability.source.js +7 -0
  37. package/dist/sources/google-availability.source.js.map +1 -0
  38. package/dist/sources/language.source.d.ts +5 -0
  39. package/dist/sources/language.source.d.ts.map +1 -0
  40. package/dist/sources/language.source.js +31 -0
  41. package/dist/sources/language.source.js.map +1 -0
  42. package/dist/utils/feed-templates/{index.d.ts → common-schemas.d.ts} +24 -29
  43. package/dist/utils/feed-templates/common-schemas.d.ts.map +1 -0
  44. package/dist/utils/feed-templates/{index.js → common-schemas.js} +668 -176
  45. package/dist/utils/feed-templates/common-schemas.js.map +1 -0
  46. package/dist/utils/feed-templates/common.d.ts +20 -0
  47. package/dist/utils/feed-templates/common.d.ts.map +1 -0
  48. package/dist/utils/feed-templates/common.js +60 -0
  49. package/dist/utils/feed-templates/common.js.map +1 -0
  50. package/dist/utils/feed-templates/ebay.template.d.ts +1 -1
  51. package/dist/utils/feed-templates/ebay.template.d.ts.map +1 -1
  52. package/dist/utils/feed-templates/ebay.template.js +189 -2
  53. package/dist/utils/feed-templates/ebay.template.js.map +1 -1
  54. package/dist/utils/feed-templates/facebook.template.d.ts.map +1 -1
  55. package/dist/utils/feed-templates/facebook.template.js +2 -1
  56. package/dist/utils/feed-templates/facebook.template.js.map +1 -1
  57. package/dist/utils/feed-templates/google-api.template.d.ts.map +1 -1
  58. package/dist/utils/feed-templates/google-api.template.js +19 -7
  59. package/dist/utils/feed-templates/google-api.template.js.map +1 -1
  60. package/dist/utils/feed-templates/google.template.d.ts.map +1 -1
  61. package/dist/utils/feed-templates/google.template.js +7 -15
  62. package/dist/utils/feed-templates/google.template.js.map +1 -1
  63. package/dist/utils/feed-templates/microsoft.template.d.ts.map +1 -1
  64. package/dist/utils/feed-templates/microsoft.template.js +11 -7
  65. package/dist/utils/feed-templates/microsoft.template.js.map +1 -1
  66. package/dist/utils/feed-templates/template-utils.d.ts +4 -0
  67. package/dist/utils/feed-templates/template-utils.d.ts.map +1 -0
  68. package/dist/utils/feed-templates/template-utils.js +29 -0
  69. package/dist/utils/feed-templates/template-utils.js.map +1 -0
  70. package/dist/utils/feed-templates/tiktok.template.d.ts.map +1 -1
  71. package/dist/utils/feed-templates/tiktok.template.js +2 -1
  72. package/dist/utils/feed-templates/tiktok.template.js.map +1 -1
  73. package/dist/utils/profile.d.ts +2 -1
  74. package/dist/utils/profile.d.ts.map +1 -1
  75. package/dist/utils/profile.js +82 -1
  76. package/dist/utils/profile.js.map +1 -1
  77. package/dist/utils/utils.d.ts +2 -0
  78. package/dist/utils/utils.d.ts.map +1 -1
  79. package/dist/utils/utils.js +23 -3
  80. package/dist/utils/utils.js.map +1 -1
  81. package/package.json +5 -4
  82. package/src/constants/profile.constants.ts +39 -1
  83. package/src/index.ts +11 -1
  84. package/src/sources/country.source.ts +77 -0
  85. package/src/sources/currency.source.ts +0 -1
  86. package/src/sources/ebay-gallery-type.source.ts +4 -0
  87. package/src/sources/ebay-inventory-tracking.source.ts +12 -0
  88. package/src/sources/ebay-listing-type.source.ts +4 -0
  89. package/src/sources/ebay-yes-no.source.ts +1 -0
  90. package/src/sources/google-availability.source.ts +6 -0
  91. package/src/sources/language.source.ts +30 -0
  92. package/src/utils/feed-templates/common-schemas.ts +1014 -0
  93. package/src/utils/feed-templates/common.ts +82 -0
  94. package/src/utils/feed-templates/ebay.template.ts +215 -4
  95. package/src/utils/feed-templates/facebook.template.ts +2 -1
  96. package/src/utils/feed-templates/google-api.template.ts +54 -29
  97. package/src/utils/feed-templates/google.template.ts +46 -52
  98. package/src/utils/feed-templates/microsoft.template.ts +26 -21
  99. package/src/utils/feed-templates/template-utils.ts +30 -0
  100. package/src/utils/feed-templates/tiktok.template.ts +4 -2
  101. package/src/utils/profile.ts +116 -2
  102. package/src/utils/utils.ts +25 -5
  103. package/tests/company.spec.ts +39 -39
  104. package/tests/profile-utils.spec.ts +38 -0
  105. package/tests/validator.spec.ts +1 -5
  106. package/dist/utils/feed-templates/index.d.ts.map +0 -1
  107. package/dist/utils/feed-templates/index.js.map +0 -1
  108. package/src/utils/feed-templates/index.ts +0 -514
@@ -0,0 +1,82 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { resolveSourceValue } from '../profile.js';
3
+ import { dimensionRegex } from './common-schemas.js';
4
+
5
+ export function splitByCommaAndTrim(str: string): string[] {
6
+ return typeof str === 'string'
7
+ ? str
8
+ .split(',')
9
+ .map(s => s.trim())
10
+ .filter(Boolean)
11
+ : [];
12
+ }
13
+
14
+ export function parseDimensionString({
15
+ dimension,
16
+ min = 0,
17
+ max = 1000000,
18
+ }: {
19
+ dimension: string;
20
+ min?: number;
21
+ max?: number;
22
+ }): {
23
+ value: string;
24
+ unit: string;
25
+ } {
26
+ const match = dimensionRegex.exec(dimension);
27
+
28
+ if (!match) {
29
+ throw new Error('Invalid format');
30
+ } else if (
31
+ !Number.isFinite(Number(match.groups?.value)) ||
32
+ Number(match.groups?.value) < min ||
33
+ Number(match.groups?.value) > max
34
+ ) {
35
+ throw new Error(`Value should be between ${min} and ${max}`);
36
+ }
37
+
38
+ return { value: match.groups?.value as string, unit: match.groups?.unit as string };
39
+ }
40
+
41
+ export function convertToBoolean(value: string): boolean {
42
+ if (value === 'true') {
43
+ return true;
44
+ }
45
+
46
+ if (value === 'false') {
47
+ return false;
48
+ }
49
+
50
+ throw new Error('Invalid boolean value');
51
+ }
52
+
53
+ export function castToArray(value: string): string[] {
54
+ return Array.isArray(value) ? value : [value];
55
+ }
56
+
57
+ export function castToInt(value: string): number {
58
+ return typeof value === 'string' ? parseInt(value, 10) : value;
59
+ }
60
+
61
+ /**
62
+ * Create a macro string for use in feed templates
63
+ * @param source
64
+ * @param value
65
+ * @returns
66
+ */
67
+ export function makeMacroString(source: string, value?: string[]): string {
68
+ if (value) {
69
+ if (source.startsWith('source.')) {
70
+ const resolved = resolveSourceValue(source)?.filter(v => value.includes(v.value));
71
+
72
+ if (resolved?.length) {
73
+ return `{{${source}:${JSON.stringify(resolved)}}}`;
74
+ }
75
+ } else {
76
+ // action
77
+ return `{{${source}:${value.join(',')}}}`;
78
+ }
79
+ }
80
+
81
+ return source.startsWith('source.') ? `{{${source}:}}` : `{{${source}}}`;
82
+ }
@@ -1,7 +1,218 @@
1
- import { XmlFeedTemplateType } from "../../types/profile.types";
1
+ import { z } from 'zod';
2
+ import { makeMacroString } from './common.js';
3
+ import { validateIfNoMacro } from './common-schemas.js';
4
+ import {
5
+ ACTION_ARRAY_FIRST_ITEMS,
6
+ SOURCE_EBAY_GALLERY_TYPE,
7
+ SOURCE_EBAY_INVENTORY_TRACKING,
8
+ SOURCE_EBAY_LISTING_TYPE,
9
+ SOURCE_EBAY_YES_NO,
10
+ SOURCE_SHOPIFY_DESCRIPTION_HTML,
11
+ SOURCE_SHOPIFY_IMAGE,
12
+ SOURCE_SHOPIFY_IMAGES,
13
+ SOURCE_SHOPIFY_SHOP_COUNTRY,
14
+ SOURCE_SHOPIFY_SHOP_CURRENCY,
15
+ } from '../../constants/profile.constants.js';
16
+ import { SelectItem, XmlFeedTemplateType } from '../../types/profile.types.js';
17
+ import { resolveSourceValue } from '../profile.js';
18
+ import { countrySchema, currencySchema, oneOfOptionalSchema } from './common-schemas.js';
19
+
20
+ const yesNoSchema = z.coerce.string().refine(
21
+ v =>
22
+ resolveSourceValue(SOURCE_EBAY_YES_NO)
23
+ ?.map(r => r.value)
24
+ .includes(v),
25
+ { message: 'Value must be 0 or 1' }
26
+ );
2
27
 
3
28
  export const eBayFeedTemplate: XmlFeedTemplateType = {
4
29
  formats: [],
5
- documentation: '',
6
- mapping: []
7
- }
30
+ documentation: 'https://developer.ebay.com/devzone/xml/docs/reference/ebay/AddFixedPriceItem.html',
31
+ mapping: [
32
+ {
33
+ attribute: 'AutoPay',
34
+ label: 'AutoPay',
35
+ description: 'Indicates whether the seller requires immediate payment for the item',
36
+ required: false,
37
+ type: 'macro-input',
38
+ defaultValue: makeMacroString(SOURCE_EBAY_YES_NO, ['1']),
39
+ rules: { sections: [] },
40
+ baseMode: false,
41
+ validator: v => validateIfNoMacro(v, yesNoSchema),
42
+ fixedValue: true,
43
+ singleChoice: true,
44
+ },
45
+ {
46
+ attribute: 'BestOfferEnabled',
47
+ label: 'Best Offer Enabled',
48
+ description: 'Indicates whether the seller is accepting Best Offers for the item',
49
+ required: false,
50
+ type: 'macro-input',
51
+ defaultValue: makeMacroString(SOURCE_EBAY_YES_NO, ['0']),
52
+ rules: { sections: [] },
53
+ baseMode: false,
54
+ validator: v => validateIfNoMacro(v, yesNoSchema),
55
+ fixedValue: true,
56
+ singleChoice: true,
57
+ },
58
+ {
59
+ attribute: 'CategoryMappingAllowed',
60
+ label: 'Category Mapping Allowed',
61
+ description:
62
+ 'This boolean field controls whether or not eBay automatically maps outdated Category ID(s) specified in a PrimaryCategory and/or SecondaryCategory container(s) to the updated Category ID(s) no longer exists in the current category structure',
63
+ required: false,
64
+ type: 'macro-input',
65
+ defaultValue: makeMacroString(SOURCE_EBAY_YES_NO, ['1']),
66
+ rules: { sections: [] },
67
+ baseMode: false,
68
+ validator: v => validateIfNoMacro(v, yesNoSchema),
69
+ fixedValue: true,
70
+ singleChoice: true,
71
+ },
72
+ {
73
+ attribute: 'ConditionID',
74
+ label: 'Condition',
75
+ description: 'The condition of the item. For example, New, Used, or Refurbished',
76
+ required: false,
77
+ type: 'macro-input',
78
+ defaultValue: '',
79
+ rules: { sections: [] },
80
+ baseMode: false,
81
+ singleChoice: true,
82
+ },
83
+ {
84
+ attribute: 'Country',
85
+ label: 'Country',
86
+ description: 'The country where the item is located',
87
+ required: true,
88
+ type: 'macro-input',
89
+ defaultValue: makeMacroString(SOURCE_SHOPIFY_SHOP_COUNTRY),
90
+ rules: { sections: [] },
91
+ validator: v => validateIfNoMacro(v, countrySchema),
92
+ baseMode: true,
93
+ singleChoice: true,
94
+ },
95
+ {
96
+ attribute: 'Currency',
97
+ label: 'Currency',
98
+ description: 'The currency of the item price',
99
+ required: true,
100
+ type: 'macro-input',
101
+ defaultValue: makeMacroString(SOURCE_SHOPIFY_SHOP_CURRENCY),
102
+ rules: { sections: [] },
103
+ validator: v => validateIfNoMacro(v, currencySchema),
104
+ baseMode: true,
105
+ singleChoice: true,
106
+ },
107
+ {
108
+ attribute: 'Description',
109
+ label: 'Description',
110
+ description: 'The description of the item',
111
+ required: true,
112
+ type: 'macro-input',
113
+ defaultValue: makeMacroString(SOURCE_SHOPIFY_DESCRIPTION_HTML),
114
+ rules: { sections: [] },
115
+ baseMode: true,
116
+ validator: v => validateIfNoMacro(v, z.string().max(500000)),
117
+ singleChoice: true,
118
+ },
119
+ {
120
+ attribute: 'DiscountPrice',
121
+ label: 'Description',
122
+ description: 'The discount price of the item',
123
+ required: false,
124
+ type: 'macro-input',
125
+ defaultValue: makeMacroString(SOURCE_SHOPIFY_DESCRIPTION_HTML),
126
+ rules: { sections: [] },
127
+ baseMode: false,
128
+ validator: v => validateIfNoMacro(v, z.coerce.number().positive()),
129
+ singleChoice: true,
130
+ },
131
+ {
132
+ attribute: 'DispatchTimeMax',
133
+ label: 'Dispatch Time Max',
134
+ description:
135
+ 'The maximum number of business days the seller commits to for shipping an item to a buyer after receiving a cleared payment',
136
+ required: false,
137
+ type: 'macro-input',
138
+ defaultValue: '',
139
+ rules: { sections: [] },
140
+ baseMode: false,
141
+ validator: v => validateIfNoMacro(v, z.coerce.number().gte(0)),
142
+ singleChoice: true,
143
+ },
144
+ {
145
+ attribute: 'InventoryTrackingMethod',
146
+ label: 'Inventory Tracking Method',
147
+ description: 'The method used to track the inventory level of the item',
148
+ required: false,
149
+ type: 'macro-input',
150
+ defaultValue: makeMacroString(SOURCE_EBAY_INVENTORY_TRACKING),
151
+ rules: { sections: [] },
152
+ baseMode: false,
153
+ validator: v =>
154
+ validateIfNoMacro(
155
+ v,
156
+ oneOfOptionalSchema(resolveSourceValue(SOURCE_EBAY_INVENTORY_TRACKING) as SelectItem[])
157
+ ),
158
+ singleChoice: true,
159
+ fixedValue: true,
160
+ },
161
+ // TODO: add compatibility list items
162
+ // TODO: add item specifics
163
+ {
164
+ attribute: 'ListingDuration',
165
+ label: 'Listing Duration',
166
+ description: 'The length of time the listing will be active',
167
+ required: false,
168
+ type: 'macro-input',
169
+ defaultValue: '', // TODO: add source
170
+ rules: { sections: [] },
171
+ baseMode: false,
172
+ fixedValue: true,
173
+ singleChoice: true,
174
+ },
175
+ {
176
+ attribute: 'ListingType',
177
+ label: 'Listing Type',
178
+ description: 'The type of listing',
179
+ required: true,
180
+ type: 'macro-input',
181
+ defaultValue: makeMacroString(SOURCE_EBAY_LISTING_TYPE, ['FixedPriceItem']),
182
+ rules: { sections: [] },
183
+ baseMode: true,
184
+ fixedValue: true,
185
+ singleChoice: true,
186
+ },
187
+ {
188
+ attribute: 'GalleryType',
189
+ label: 'Gallery Type',
190
+ description: 'The type of gallery image to use for the listing. Waring: Plus type implies additional fee',
191
+ required: false,
192
+ type: 'macro-input',
193
+ defaultValue: makeMacroString(SOURCE_EBAY_GALLERY_TYPE, ['Gallery']),
194
+ rules: { sections: [] },
195
+ baseMode: false,
196
+ fixedValue: true,
197
+ singleChoice: true,
198
+ },
199
+ // TODO: set PictureSource to Vendor
200
+ {
201
+ attribute: 'PictureURL',
202
+ label: 'Picture URL',
203
+ description:
204
+ 'Contains the URL for a picture of the item. You can pass in up to 24 picture URLs for each listing. The Gallery image will be the first PictureURL in the list',
205
+ required: false,
206
+ type: 'macro-input',
207
+ defaultValue:
208
+ makeMacroString(SOURCE_SHOPIFY_IMAGE) +
209
+ ',' +
210
+ makeMacroString(SOURCE_SHOPIFY_IMAGES) +
211
+ makeMacroString(ACTION_ARRAY_FIRST_ITEMS, ['24']),
212
+ rules: { sections: [] },
213
+ baseMode: false,
214
+ fixedValue: true,
215
+ singleChoice: true,
216
+ },
217
+ ],
218
+ };
@@ -2,7 +2,8 @@
2
2
  /* eslint-disable quotes */
3
3
  import * as z from 'zod';
4
4
  import { ulid } from 'ulid';
5
- import { dateRangeSchema, gtinSchema, measureUnitsSchema, priceSchema, salePriceSchema, validate, validateIfNoMacro } from './index.js';
5
+ import { validate, validateIfNoMacro } from './common-schemas.js';
6
+ import { dateRangeSchema, gtinSchema, measureUnitsSchema, priceSchema, salePriceSchema } from './common-schemas.js';
6
7
  import { XmlFeedTemplateType } from '../../types/profile.types.js';
7
8
  import { XmlFeedFormat } from '../../constants/profile.constants.js';
8
9
 
@@ -1,11 +1,20 @@
1
1
  /* eslint-disable quotes */
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
3
  /* eslint-disable max-len */
4
- import { countrySchema, dateRangeSchema, getSourceValueSeparator, gtinSchema, languageSchema, measureUnitsSchema, priceSchema, validateIfNoMacro } from './index.js';
4
+ import { validateIfNoMacro } from './common-schemas.js';
5
+ import {
6
+ countrySchema,
7
+ dateRangeSchema,
8
+ gtinSchema,
9
+ languageSchema,
10
+ measureUnitsSchema,
11
+ priceSchema,
12
+ } from './common-schemas.js';
5
13
  import { SOURCE_GOOGLE_PRODUCT_HIGHLIGHT } from '../../constants/profile.constants.js';
6
14
  import { ProductUploadMapSource, XmlFeedTemplateType } from '../../types/profile.types.js';
7
15
  import { z } from 'zod';
8
16
  import { ulid } from 'ulid';
17
+ import { getSourceValueSeparator } from '../utils.js';
9
18
 
10
19
  const availabilityMapping: ProductUploadMapSource = {
11
20
  attribute: 'availability',
@@ -54,13 +63,18 @@ export const googleApiTemplate: XmlFeedTemplateType = {
54
63
  {
55
64
  attribute: 'contentLanguage',
56
65
  label: 'Content language',
57
- description: 'The two-letter ISO 639-1 language code for the item. Use source Languages macro to set the language',
66
+ description:
67
+ 'The two-letter ISO 639-1 language code for the item. Use source Languages macro to set the language',
58
68
  required: true,
59
69
  type: 'macro-input',
60
70
  defaultValue: '{{source.language:}}',
61
71
  rules: { sections: [] },
62
72
  baseMode: true,
63
- validator: (v: string | number) => validateIfNoMacro(v, [languageSchema, z.string().min(2, { message: 'Language should be 2 characters long' })]),
73
+ validator: (v: string | number) =>
74
+ validateIfNoMacro(v, [
75
+ languageSchema,
76
+ z.string().min(2, { message: 'Language should be 2 characters long' }),
77
+ ]),
64
78
  singleChoice: true,
65
79
  fixedValue: true,
66
80
  },
@@ -72,7 +86,11 @@ export const googleApiTemplate: XmlFeedTemplateType = {
72
86
  type: 'macro-input',
73
87
  defaultValue: '{{source.country:}}',
74
88
  rules: { sections: [] },
75
- validator: (v: string | number) => validateIfNoMacro(v, [countrySchema, z.string().min(2, { message: 'Country code should be 2 characters long' })]),
89
+ validator: (v: string | number) =>
90
+ validateIfNoMacro(v, [
91
+ countrySchema,
92
+ z.string().min(2, { message: 'Country code should be 2 characters long' }),
93
+ ]),
76
94
  baseMode: true,
77
95
  singleChoice: true,
78
96
  fixedValue: true,
@@ -238,8 +256,10 @@ export const googleApiTemplate: XmlFeedTemplateType = {
238
256
  v,
239
257
  z
240
258
  .string()
241
- .refine(v => !v || z.string().datetime({ offset: true }).safeParse(v).success, { message: 'invalid date' })
242
- .refine(v => !v || new Date(v).getTime() < (1000 * 60 * 60 * 24 * 365 + new Date().getTime()), {
259
+ .refine(v => !v || z.string().datetime({ offset: true }).safeParse(v).success, {
260
+ message: 'invalid date',
261
+ })
262
+ .refine(v => !v || new Date(v).getTime() < 1000 * 60 * 60 * 24 * 365 + new Date().getTime(), {
243
263
  message: 'The date should be up to one year in the future',
244
264
  })
245
265
  ),
@@ -270,8 +290,10 @@ export const googleApiTemplate: XmlFeedTemplateType = {
270
290
  v,
271
291
  z
272
292
  .string()
273
- .refine(v => !v || z.string().datetime({ offset: true }).safeParse(v).success, { message: 'invalid date' })
274
- .refine(v => !v || new Date(v).getTime() < (1000 * 60 * 60 * 24 * 30 + new Date().getTime()), {
293
+ .refine(v => !v || z.string().datetime({ offset: true }).safeParse(v).success, {
294
+ message: 'invalid date',
295
+ })
296
+ .refine(v => !v || new Date(v).getTime() < 1000 * 60 * 60 * 24 * 30 + new Date().getTime(), {
275
297
  message: 'The date should be less than 30 days in the future',
276
298
  })
277
299
  ),
@@ -798,30 +820,33 @@ export const googleApiTemplate: XmlFeedTemplateType = {
798
820
  'The most relevant highlights of your products. Max 150 characters. Example: Supports thousands of apps, including Netflix, YouTube, and HBO Max',
799
821
  required: false,
800
822
  type: 'macro-input',
801
- validator: (v: string | number) => validateIfNoMacro(v, z.string().superRefine((v, ctx) => {
802
- if (!v) {
803
- return true;
804
- }
805
-
806
- const values = v.split(getSourceValueSeparator(SOURCE_GOOGLE_PRODUCT_HIGHLIGHT));
823
+ validator: (v: string | number) =>
824
+ validateIfNoMacro(
825
+ v,
826
+ z.string().superRefine((v, ctx) => {
827
+ if (!v) {
828
+ return true;
829
+ }
807
830
 
808
- if (values.length < 2) {
809
- ctx.addIssue({
810
- code: z.ZodIssueCode.custom,
811
- message: 'Minimum 2 values required',
812
- });
813
- return false;
814
- }
831
+ const values = v.split(getSourceValueSeparator(SOURCE_GOOGLE_PRODUCT_HIGHLIGHT));
815
832
 
816
- if (values.some(val => val.length > 150)) {
817
- ctx.addIssue({
818
- code: z.ZodIssueCode.custom,
819
- message: 'Max 150 characters per value',
820
- });
821
- return false;
822
- }
833
+ if (values.length < 2) {
834
+ ctx.addIssue({
835
+ code: z.ZodIssueCode.custom,
836
+ message: 'Minimum 2 values required',
837
+ });
838
+ return false;
839
+ }
823
840
 
824
- })),
841
+ if (values.some(val => val.length > 150)) {
842
+ ctx.addIssue({
843
+ code: z.ZodIssueCode.custom,
844
+ message: 'Max 150 characters per value',
845
+ });
846
+ return false;
847
+ }
848
+ })
849
+ ),
825
850
  defaultValue: '{{source.google_product_highlight:}}',
826
851
  rules: { sections: [] },
827
852
  fixedValue: true,
@@ -1,22 +1,22 @@
1
1
  /* eslint-disable quotes */
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
3
  /* eslint-disable max-len */
4
+ import { resolveSourceMacro } from '../utils.js';
5
+ import { validateIfNoMacro } from './common-schemas.js';
4
6
  import {
5
7
  countrySchema,
6
8
  dateRangeSchema,
7
9
  energyEfficiencyClassSchema,
8
- getSourceValueSeparator,
9
10
  gtinSchema,
10
11
  maxEnergyEfficiencyClassSchema,
11
12
  measureUnitsSchema,
12
13
  minEnergyEfficiencyClassSchema,
13
14
  priceSchema,
14
15
  requiredIfOtherPresentSchema,
15
- resolveSourceMacro,
16
16
  salePriceSchema,
17
17
  sameUnitScheme,
18
- validateIfNoMacro,
19
- } from './index.js';
18
+ } from './common-schemas.js';
19
+ import { getSourceValueSeparator } from '../utils.js';
20
20
  import { SOURCE_GOOGLE_PRODUCT_HIGHLIGHT, XmlFeedFormat } from '../../constants/profile.constants.js';
21
21
  import { ProductUploadMapSource, XmlFeedTemplateType } from '../../types/profile.types.js';
22
22
  import { z } from 'zod';
@@ -39,18 +39,6 @@ const availabilityMapping: ProductUploadMapSource = {
39
39
  fixedValue: true,
40
40
  };
41
41
 
42
- const customLabelMapping: ProductUploadMapSource = {
43
- attribute: '',
44
- label: '',
45
- description:
46
- 'Label that you assign to a product to help organize bidding and reporting in Shopping campaigns. Max 100 characters. Example: Seasonal',
47
- required: false,
48
- type: 'macro-input' as any,
49
- validator: (v: string | number) => validateIfNoMacro(v, z.string().max(100)),
50
- rules: { sections: [] },
51
- defaultValue: '',
52
- };
53
-
54
42
  export const googleFeedTemplate: XmlFeedTemplateType = {
55
43
  formats: [XmlFeedFormat.XML],
56
44
  documentation: 'https://support.google.com/merchants/answer/7052112',
@@ -124,21 +112,20 @@ export const googleFeedTemplate: XmlFeedTemplateType = {
124
112
  validator: (v: string | number) =>
125
113
  validateIfNoMacro(
126
114
  v,
127
- z
128
- .string().superRefine((v, ctx) => {
129
- if (!v) {
130
- return;
131
- }
115
+ z.string().superRefine((v, ctx) => {
116
+ if (!v) {
117
+ return;
118
+ }
132
119
 
133
- const urls = v.split(getSourceValueSeparator());
120
+ const urls = v.split(getSourceValueSeparator());
134
121
 
135
- if (urls.some(url => !z.string().url().safeParse(url).success)) {
136
- ctx.addIssue({
137
- code: z.ZodIssueCode.custom,
138
- message: 'invalid URL',
139
- });
140
- }
141
- })
122
+ if (urls.some(url => !z.string().url().safeParse(url).success)) {
123
+ ctx.addIssue({
124
+ code: z.ZodIssueCode.custom,
125
+ message: 'invalid URL',
126
+ });
127
+ }
128
+ })
142
129
  ),
143
130
  defaultValue: '',
144
131
  rules: { sections: [] },
@@ -898,30 +885,33 @@ export const googleFeedTemplate: XmlFeedTemplateType = {
898
885
  'The most relevant highlights of your products. Max 150 characters. Example: Supports thousands of apps, including Netflix, YouTube, and HBO Max',
899
886
  required: false,
900
887
  type: 'macro-input',
901
- validator: (v: string | number) => validateIfNoMacro(v, z.string().superRefine((v, ctx) => {
902
- if (!v) {
903
- return true;
904
- }
905
-
906
- const values = v.split(getSourceValueSeparator(SOURCE_GOOGLE_PRODUCT_HIGHLIGHT));
888
+ validator: (v: string | number) =>
889
+ validateIfNoMacro(
890
+ v,
891
+ z.string().superRefine((v, ctx) => {
892
+ if (!v) {
893
+ return true;
894
+ }
907
895
 
908
- if (values.length < 2) {
909
- ctx.addIssue({
910
- code: z.ZodIssueCode.custom,
911
- message: 'Minimum 2 values required',
912
- });
913
- return false;
914
- }
896
+ const values = v.split(getSourceValueSeparator(SOURCE_GOOGLE_PRODUCT_HIGHLIGHT));
915
897
 
916
- if (values.some(val => val.length > 150)) {
917
- ctx.addIssue({
918
- code: z.ZodIssueCode.custom,
919
- message: 'Max 150 characters per value',
920
- });
921
- return false;
922
- }
898
+ if (values.length < 2) {
899
+ ctx.addIssue({
900
+ code: z.ZodIssueCode.custom,
901
+ message: 'Minimum 2 values required',
902
+ });
903
+ return false;
904
+ }
923
905
 
924
- })),
906
+ if (values.some(val => val.length > 150)) {
907
+ ctx.addIssue({
908
+ code: z.ZodIssueCode.custom,
909
+ message: 'Max 150 characters per value',
910
+ });
911
+ return false;
912
+ }
913
+ })
914
+ ),
925
915
  defaultValue: '{{source.google_product_highlight:}}',
926
916
  rules: { sections: [] },
927
917
  fixedValue: true,
@@ -1149,8 +1139,12 @@ export const googleFeedTemplate: XmlFeedTemplateType = {
1149
1139
  if (!v) {
1150
1140
  return true;
1151
1141
  }
1152
- const installment = getSourceTagValueAndStripTags(values.find(v => v.attribute === 'installment')?.value as string ?? "")?.value;
1153
- const subscription = getSourceTagValueAndStripTags(values.find(v => v.attribute === 'subscription_cost')?.value as string ?? "")?.value;
1142
+ const installment = getSourceTagValueAndStripTags(
1143
+ (values.find(v => v.attribute === 'installment')?.value as string) ?? ''
1144
+ )?.value;
1145
+ const subscription = getSourceTagValueAndStripTags(
1146
+ (values.find(v => v.attribute === 'subscription_cost')?.value as string) ?? ''
1147
+ )?.value;
1154
1148
  const shippingValue = v.split(',').map(val => val.trim());
1155
1149
  const shipToSameCountry = new Set(shippingValue.map(v => v.split(':')[0])).size === 1;
1156
1150