@softwear/latestcollectioncore 1.0.203 → 1.0.204
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.
- package/dist/imageBinder.d.ts +1 -1
- package/dist/imageBinder.js +253 -77
- package/package.json +1 -1
- package/src/imageBinder.ts +245 -79
- package/test/imageBinder.spec.js +52 -3
- package/test/imageBinderTestData/brandDataMatched/exxcellent.json +59633 -0
- package/test/imageBinderTestData/brandDataMatched/lingadore.json +16752 -0
- package/test/imageBinderTestData/brandDataMatched/pennAndInk.json +71524 -0
- package/test/imageBinderTestData/brandImages/exxcellent.json +491 -0
- package/test/imageBinderTestData/brandImages/lingadore.json +47 -0
- package/test/imageBinderTestData/brandImages/pennAndInk.json +511 -0
- package/test/imageBinderTestData/brandSkus/exxcellent.json +24453 -0
- package/test/imageBinderTestData/brandSkus/lingadore.json +5102 -0
- package/test/imageBinderTestData/brandSkus/pennAndInk.json +280186 -0
package/dist/imageBinder.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare function imageBinder(fileNames: Array<string>, filteredSkus: SkuI[], bra
|
|
|
6
6
|
fallbackCount: number;
|
|
7
7
|
patternCounter: {};
|
|
8
8
|
};
|
|
9
|
-
declare function testBatch(brand: string): Promise<{
|
|
9
|
+
declare function testBatch(brand: string, specifiedPattern?: Array<string>): Promise<{
|
|
10
10
|
Brand: string;
|
|
11
11
|
Files: any;
|
|
12
12
|
Skus: any;
|
package/dist/imageBinder.js
CHANGED
|
@@ -60,10 +60,82 @@ const GLOBAL_PATTERNS = [
|
|
|
60
60
|
['articleDescription', 'articleCode|articleCodeSupplier', 'colorCodeSupplier|colorSupplier'],
|
|
61
61
|
['colorCodeSupplier|colorSupplier', 'articleCode|articleCodeSupplier'],
|
|
62
62
|
['brand', 'collectionSupplier', 'colorCodeSupplier', 'articleCode|articleCodeSupplier'],
|
|
63
|
-
['brand', 'collectionSupplier', 'colorCodeSupplier', 'articleCode|articleCodeSupplier', 'buyPrice|valuePrice'],
|
|
64
63
|
['brand', 'articleDescription', 'colorSupplier'],
|
|
65
64
|
];
|
|
66
|
-
|
|
65
|
+
const FIELDS_TO_SKIP = ['__created', '__modified', 'images', 'brandhash', 'active', 'PRODUCT', 'colorFamily', 'price', 'sizeIndex', '_customsize', 'SELECTED'];
|
|
66
|
+
const MERGE_GROUPS = {
|
|
67
|
+
'id|barcode': 'id',
|
|
68
|
+
'articleCode|articleCodeSupplier': 'articleCode',
|
|
69
|
+
'colorCode|colorCodeSupplier|colorSupplier': 'color',
|
|
70
|
+
'size|sizeSupplier|mainSize|subSize|subSizeSupplier|_customsize': 'size',
|
|
71
|
+
'articleGroup|articleGroupSupplier': 'articleGroup',
|
|
72
|
+
'collection|collectionSupplier': 'collection',
|
|
73
|
+
'brand|brandSupplier': 'brand',
|
|
74
|
+
'_gender|genderSupplier': 'gender',
|
|
75
|
+
};
|
|
76
|
+
// Letters, digits, and apostrophe stay; everything else is a delimiter.
|
|
77
|
+
const DELIMITERS = /[^\p{L}\p{N}']+/gu;
|
|
78
|
+
/** Shared stem: decode URI, then strip from the first known image extension onward. */
|
|
79
|
+
function filenameStem(fileName) {
|
|
80
|
+
let s;
|
|
81
|
+
try {
|
|
82
|
+
s = decodeURIComponent(fileName);
|
|
83
|
+
}
|
|
84
|
+
catch (_a) {
|
|
85
|
+
s = fileName;
|
|
86
|
+
}
|
|
87
|
+
s = s.toLowerCase();
|
|
88
|
+
const extIdx = s.search(/\.(?:jpe?g|png|gif)/i);
|
|
89
|
+
if (extIdx !== -1)
|
|
90
|
+
s = s.slice(0, extIdx);
|
|
91
|
+
return s;
|
|
92
|
+
}
|
|
93
|
+
function checkPattern(fieldVals, fileName) {
|
|
94
|
+
const fieldIndexes2 = {};
|
|
95
|
+
const sortedFields = fieldVals.sort((a, b) => {
|
|
96
|
+
return b.length - a.length;
|
|
97
|
+
});
|
|
98
|
+
// Return quickly if one of the fields in the pattern is not in the fileName
|
|
99
|
+
for (const fieldVal of sortedFields) {
|
|
100
|
+
const idx = fileName.indexOf(fieldVal);
|
|
101
|
+
if (idx == -1) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
fieldIndexes2[fieldVal] = [idx, idx + fieldVal.length];
|
|
105
|
+
}
|
|
106
|
+
// Check if all fields have a specific place in file name, with no overlap
|
|
107
|
+
for (let i = 1; i < sortedFields.length; i++) {
|
|
108
|
+
const startIndex = fieldIndexes2[sortedFields[i]][0];
|
|
109
|
+
const endIndex = fieldIndexes2[sortedFields[i]][1];
|
|
110
|
+
for (let j = 0; j < i; j++) {
|
|
111
|
+
const startIndex2 = fieldIndexes2[sortedFields[j]][0];
|
|
112
|
+
const endIndex2 = fieldIndexes2[sortedFields[j]][1];
|
|
113
|
+
if (startIndex < endIndex2 && endIndex > startIndex2) {
|
|
114
|
+
const nextIndex = fileName.indexOf(sortedFields[i], endIndex2);
|
|
115
|
+
if (nextIndex == -1) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
fieldIndexes2[sortedFields[i]] = [nextIndex, nextIndex + sortedFields[i].length];
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
function normalizeSkuField(sku, fieldName) {
|
|
128
|
+
let fieldVal = sku[fieldName];
|
|
129
|
+
if (fieldVal == null || fieldVal == '')
|
|
130
|
+
return '';
|
|
131
|
+
if (typeof fieldVal == 'string') {
|
|
132
|
+
return fieldVal.replace(DELIMITERS, '').toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return fieldVal.toString();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function prepFilterSkusImagesAuto(filteredSkus, fileNames) {
|
|
67
139
|
const skusCopy = (0, deepCopy_1.default)(filteredSkus);
|
|
68
140
|
const preppedSkus = [];
|
|
69
141
|
const fileNames2skip = [];
|
|
@@ -82,44 +154,100 @@ function prepFilterSkusImages(filteredSkus, merge = true, fileNames) {
|
|
|
82
154
|
}
|
|
83
155
|
const fieldsToBeMerged = {};
|
|
84
156
|
for (const fieldName in sku) {
|
|
85
|
-
if (fieldName
|
|
157
|
+
if (FIELDS_TO_SKIP.indexOf(fieldName) != -1 || fieldName.includes('Price'))
|
|
158
|
+
continue;
|
|
159
|
+
if (!(fieldName in sku) || sku[fieldName] == null || sku[fieldName] == undefined)
|
|
86
160
|
continue;
|
|
87
|
-
|
|
88
|
-
|
|
161
|
+
sku[fieldName] = normalizeSkuField(sku, fieldName);
|
|
162
|
+
const fieldVal = sku[fieldName];
|
|
163
|
+
if (!fieldVal)
|
|
89
164
|
continue;
|
|
90
|
-
if (
|
|
91
|
-
|
|
165
|
+
if (fieldVal in fieldsToBeMerged) {
|
|
166
|
+
fieldsToBeMerged[fieldVal].push(fieldName);
|
|
92
167
|
}
|
|
93
168
|
else {
|
|
94
|
-
|
|
169
|
+
fieldsToBeMerged[fieldVal] = [fieldName];
|
|
95
170
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
171
|
+
}
|
|
172
|
+
const newSku = {};
|
|
173
|
+
newSku['originalSku'] = filteredSkus[idx];
|
|
174
|
+
for (const fieldVal in fieldsToBeMerged) {
|
|
175
|
+
const fieldNameArray = fieldsToBeMerged[fieldVal].sort();
|
|
176
|
+
if (fieldNameArray.length > 1) {
|
|
177
|
+
const groups = {};
|
|
178
|
+
for (const fieldName of fieldNameArray) {
|
|
179
|
+
let included = false;
|
|
180
|
+
Object.keys(MERGE_GROUPS).forEach((group) => {
|
|
181
|
+
if (group.includes(fieldName)) {
|
|
182
|
+
included = true;
|
|
183
|
+
if (!groups[MERGE_GROUPS[group]])
|
|
184
|
+
groups[MERGE_GROUPS[group]] = fieldName;
|
|
185
|
+
else
|
|
186
|
+
groups[MERGE_GROUPS[group]] = groups[MERGE_GROUPS[group]] + '|' + fieldName;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
if (!included) {
|
|
190
|
+
groups[fieldName] = fieldName;
|
|
191
|
+
}
|
|
103
192
|
}
|
|
193
|
+
Object.keys(groups).forEach((group) => {
|
|
194
|
+
newSku[groups[group]] = fieldVal;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
newSku[fieldNameArray[0]] = fieldVal;
|
|
104
199
|
}
|
|
105
200
|
}
|
|
106
|
-
|
|
201
|
+
preppedSkus.push(newSku);
|
|
202
|
+
});
|
|
203
|
+
const fileNames2Match = fileNames.filter((fileName) => {
|
|
204
|
+
return fileNames2skip.indexOf(fileName) == -1;
|
|
205
|
+
});
|
|
206
|
+
return { preppedSkus: preppedSkus, fileNames2Match: fileNames2Match };
|
|
207
|
+
}
|
|
208
|
+
function prepFilterSkusImagesManual(filteredSkus, fileNames, pattern) {
|
|
209
|
+
const skusCopy = (0, deepCopy_1.default)(filteredSkus);
|
|
210
|
+
const preppedSkus = [];
|
|
211
|
+
const fileNames2skip = [];
|
|
212
|
+
skusCopy.forEach((sku, idx) => {
|
|
213
|
+
if (sku.images && sku.images.length > 0) {
|
|
214
|
+
// If a fileName is already matched, we skip it
|
|
215
|
+
fileNames.forEach((fileName) => {
|
|
216
|
+
var _a;
|
|
217
|
+
if (((_a = sku.images) === null || _a === void 0 ? void 0 : _a.includes(fileName)) && fileNames2skip.indexOf(fileName) == -1)
|
|
218
|
+
fileNames2skip.push(fileName);
|
|
219
|
+
});
|
|
220
|
+
// If a sku has images, we skip it
|
|
221
|
+
sku['skip'] = true;
|
|
107
222
|
preppedSkus.push(sku);
|
|
223
|
+
return;
|
|
108
224
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
225
|
+
const foundValues = [];
|
|
226
|
+
for (const fieldName of pattern) {
|
|
227
|
+
if (!(fieldName in sku) || sku[fieldName] == null || sku[fieldName] == undefined) {
|
|
228
|
+
sku['skip'] = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
sku[fieldName] = normalizeSkuField(sku, fieldName);
|
|
232
|
+
if (!sku[fieldName]) {
|
|
233
|
+
sku['skip'] = true;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
for (const value of foundValues) {
|
|
237
|
+
if (value.includes(sku[fieldName]) || sku[fieldName] == value) {
|
|
238
|
+
if (!sku['subStrings'])
|
|
239
|
+
sku['subStrings'] = [];
|
|
240
|
+
sku['subStrings'].push([value, sku[fieldName]]);
|
|
116
241
|
}
|
|
117
|
-
else {
|
|
118
|
-
|
|
242
|
+
else if (sku[fieldName].includes(value)) {
|
|
243
|
+
if (!sku['subStrings'])
|
|
244
|
+
sku['subStrings'] = [];
|
|
245
|
+
sku['subStrings'].push([sku[fieldName], value]);
|
|
119
246
|
}
|
|
120
247
|
}
|
|
121
|
-
|
|
248
|
+
foundValues.push(sku[fieldName]);
|
|
122
249
|
}
|
|
250
|
+
preppedSkus.push(sku);
|
|
123
251
|
});
|
|
124
252
|
const fileNames2Match = fileNames.filter((fileName) => {
|
|
125
253
|
return fileNames2skip.indexOf(fileName) == -1;
|
|
@@ -127,16 +255,9 @@ function prepFilterSkusImages(filteredSkus, merge = true, fileNames) {
|
|
|
127
255
|
return { preppedSkus: preppedSkus, fileNames2Match: fileNames2Match };
|
|
128
256
|
}
|
|
129
257
|
function cleanFilename(fileName) {
|
|
130
|
-
return (fileName
|
|
131
|
-
// ── 1. strip any query string (everything from the first “?” to the end)
|
|
132
|
-
.replace(/\?.*$/, '')
|
|
133
|
-
// ── 2. strip a terminal image extension (case‑insensitive) .jpeg, .jpg, .png or .gif
|
|
134
|
-
.replace(/\.(?:jpe?g|png|gif)$/i, '')
|
|
135
|
-
// ── 3. drop every character that is NOT a letter (Unicode!) or a digit
|
|
136
|
-
.replace(/[^\p{L}\p{N}]+/gu, '')
|
|
137
|
-
.toLowerCase());
|
|
258
|
+
return filenameStem(fileName).replace(DELIMITERS, '');
|
|
138
259
|
}
|
|
139
|
-
function
|
|
260
|
+
function removeLastToken(fileName) {
|
|
140
261
|
// If last token equals any of the following patterns, we will check the fileName without the last token
|
|
141
262
|
// 1) includes front, back, side or sole
|
|
142
263
|
// 2) is 1 alphanumerical character
|
|
@@ -146,11 +267,9 @@ function checkWithoutLast(fileName) {
|
|
|
146
267
|
// 5) ends with a number
|
|
147
268
|
// 6) ends with two numbers
|
|
148
269
|
// If any of those checks are true, we return the fileName without the last token
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
.split(/[_\-.\s()]+|%[0-9A-Fa-f]{2}/)
|
|
153
|
-
.slice(0, -1);
|
|
270
|
+
// Tokens come from the shared stem (decode + extension strip), split on anything that is
|
|
271
|
+
// not a letter, digit, or apostrophe — same rule as cleanFilename.
|
|
272
|
+
const tokens = filenameStem(fileName).split(DELIMITERS).filter(Boolean);
|
|
154
273
|
const lastToken = tokens[tokens.length - 1];
|
|
155
274
|
let returnWithoutLast = false;
|
|
156
275
|
if (lastToken) {
|
|
@@ -165,42 +284,27 @@ function checkWithoutLast(fileName) {
|
|
|
165
284
|
const tokenLength = tokens.length;
|
|
166
285
|
if (returnWithoutLast) {
|
|
167
286
|
let sliceIndex = -1;
|
|
168
|
-
if (tokenLength > 3 && tokens[tokenLength - 3] == 'press' && (
|
|
287
|
+
if (tokenLength > 3 && tokens[tokenLength - 3] == 'press' && (tokens[tokenLength - 2] == 'pack' || tokens[tokenLength - 2] == 'model'))
|
|
169
288
|
sliceIndex = -3;
|
|
170
289
|
else if (tokenLength > 2 && tokens[tokenLength - 2] == 'packshot')
|
|
171
290
|
sliceIndex = -2;
|
|
172
|
-
return tokens
|
|
173
|
-
.slice(0, sliceIndex)
|
|
174
|
-
.join('')
|
|
175
|
-
.replace(/[^\p{L}\p{N}]+/gu, '');
|
|
291
|
+
return tokens.slice(0, sliceIndex).join('');
|
|
176
292
|
}
|
|
177
|
-
if (tokenLength > 2 && tokens[tokenLength - 2] == 'press' && (
|
|
178
|
-
return tokens
|
|
179
|
-
.slice(0, -2)
|
|
180
|
-
.join('')
|
|
181
|
-
.replace(/[^\p{L}\p{N}]+/gu, '');
|
|
293
|
+
if (tokenLength > 2 && tokens[tokenLength - 2] == 'press' && (tokens[tokenLength - 1] == 'pack' || tokens[tokenLength - 1] == 'model')) {
|
|
294
|
+
return tokens.slice(0, -2).join('');
|
|
182
295
|
}
|
|
183
296
|
else if (tokenLength > 1 && tokens[tokenLength - 1] == 'packshot') {
|
|
184
|
-
return tokens
|
|
185
|
-
.slice(0, -1)
|
|
186
|
-
.join('')
|
|
187
|
-
.replace(/[^\p{L}\p{N}]+/gu, '');
|
|
297
|
+
return tokens.slice(0, -1).join('');
|
|
188
298
|
}
|
|
189
299
|
if (lastToken.includes('product')) {
|
|
190
|
-
const joinedCleanFileName = tokens.join('')
|
|
300
|
+
const joinedCleanFileName = tokens.join('');
|
|
191
301
|
return joinedCleanFileName.slice(0, joinedCleanFileName.indexOf('product'));
|
|
192
302
|
}
|
|
193
303
|
else if (Number(lastToken.slice(-1))) {
|
|
194
|
-
return tokens
|
|
195
|
-
.join('')
|
|
196
|
-
.replace(/[^\p{L}\p{N}]+/gu, '')
|
|
197
|
-
.slice(0, -1);
|
|
304
|
+
return tokens.join('').slice(0, -1);
|
|
198
305
|
}
|
|
199
306
|
else if (Number(lastToken.slice(-2))) {
|
|
200
|
-
return tokens
|
|
201
|
-
.join('')
|
|
202
|
-
.replace(/[^\p{L}\p{N}]+/gu, '')
|
|
203
|
-
.substring(0, -2);
|
|
307
|
+
return tokens.join('').substring(0, -2);
|
|
204
308
|
}
|
|
205
309
|
}
|
|
206
310
|
return '';
|
|
@@ -413,7 +517,6 @@ function fallbackSearch(cleanedFileName, fileNameWithoutLast, preppedSkus) {
|
|
|
413
517
|
}
|
|
414
518
|
}
|
|
415
519
|
function imageBinder(fileNames, filteredSkus, brand, specifiedPattern, test = false) {
|
|
416
|
-
const totalLength = fileNames.length;
|
|
417
520
|
let count = 1;
|
|
418
521
|
const fileNameIndexMatch = {};
|
|
419
522
|
let quickCount = 0;
|
|
@@ -422,36 +525,109 @@ function imageBinder(fileNames, filteredSkus, brand, specifiedPattern, test = fa
|
|
|
422
525
|
let newPatterns = {};
|
|
423
526
|
if (specifiedPattern[0] != 'auto') {
|
|
424
527
|
// If the user/administrator provides a pattern, we use that by default
|
|
425
|
-
const prepObject =
|
|
528
|
+
const prepObject = prepFilterSkusImagesManual(filteredSkus, fileNames, specifiedPattern);
|
|
426
529
|
const preppedSkus = prepObject.preppedSkus;
|
|
427
530
|
const fileNames2Match = prepObject.fileNames2Match;
|
|
428
531
|
fileNames2Match.forEach((fileName) => {
|
|
429
532
|
const cleanedFileName = cleanFilename(fileName);
|
|
430
|
-
const fileNameWithoutLast = checkWithoutLast(fileName);
|
|
431
533
|
fileNameIndexMatch[fileName] = [];
|
|
534
|
+
const matchingCombinations = {};
|
|
535
|
+
// Check which skus match the specified pattern and store matching fields (combinations)
|
|
432
536
|
preppedSkus.forEach((sku, idx) => {
|
|
433
537
|
if (sku['skip'])
|
|
434
538
|
return;
|
|
435
539
|
let skuStillMatches = true;
|
|
540
|
+
let combinationArray = [];
|
|
436
541
|
specifiedPattern.every((fieldName) => {
|
|
437
|
-
|
|
542
|
+
const fieldVal = sku[fieldName];
|
|
543
|
+
if (!cleanedFileName.includes(fieldVal))
|
|
438
544
|
skuStillMatches = false;
|
|
439
|
-
else
|
|
440
|
-
|
|
441
|
-
if (!cleanedFileName.includes(fieldVal) && !fileNameWithoutLast.includes(fieldVal))
|
|
442
|
-
skuStillMatches = false;
|
|
443
|
-
}
|
|
545
|
+
else
|
|
546
|
+
combinationArray.push(fieldVal);
|
|
444
547
|
return skuStillMatches;
|
|
445
548
|
});
|
|
446
549
|
if (skuStillMatches) {
|
|
447
|
-
|
|
550
|
+
let combination = combinationArray.join('|');
|
|
551
|
+
if (combination in matchingCombinations) {
|
|
552
|
+
matchingCombinations[combination].push(idx);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
matchingCombinations[combination] = [idx];
|
|
556
|
+
}
|
|
448
557
|
}
|
|
449
558
|
});
|
|
559
|
+
let matchingIndices = [];
|
|
560
|
+
// If only one combination of specified pattern matches, we use it
|
|
561
|
+
if (Object.keys(matchingCombinations).length == 1) {
|
|
562
|
+
matchingIndices = matchingCombinations[Object.keys(matchingCombinations)[0]];
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
// In case of multiple combinations, do substring check
|
|
566
|
+
// -> Checks if all fields have a specific place in file name, with no overlap
|
|
567
|
+
const matchesAfterSubstringCheck = {};
|
|
568
|
+
Object.keys(matchingCombinations).forEach((combination) => {
|
|
569
|
+
const combinationArray = combination.split('|');
|
|
570
|
+
const isMatch = checkPattern(combinationArray, cleanedFileName);
|
|
571
|
+
if (isMatch) {
|
|
572
|
+
matchesAfterSubstringCheck[combination] = matchingCombinations[combination];
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
// If only one combination is left after substring check, we use it
|
|
576
|
+
if (Object.keys(matchesAfterSubstringCheck).length == 1) {
|
|
577
|
+
matchingIndices = matchesAfterSubstringCheck[Object.keys(matchesAfterSubstringCheck)[0]];
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
// In case there are still multiple combinations, we check longest combinations
|
|
581
|
+
// -> Longest combinations are more specific and therefore preferred
|
|
582
|
+
let lengthLongest = 0;
|
|
583
|
+
let longestCombinations = [];
|
|
584
|
+
Object.keys(matchesAfterSubstringCheck).forEach((combination) => {
|
|
585
|
+
if (combination.length > lengthLongest) {
|
|
586
|
+
lengthLongest = combination.length;
|
|
587
|
+
longestCombinations = [combination];
|
|
588
|
+
}
|
|
589
|
+
else if (combination.length == lengthLongest) {
|
|
590
|
+
longestCombinations.push(combination);
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
// If only one combination is left after longest combination check, we use it
|
|
594
|
+
if (longestCombinations.length == 1) {
|
|
595
|
+
matchingIndices = matchesAfterSubstringCheck[longestCombinations[0]];
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
// In case there are still multiple combinations, we check fileNameWithoutLast
|
|
599
|
+
// -> If any combination matches fileNameWithoutLast, we prefer it, as last tokens can be junk
|
|
600
|
+
const fileNameWithoutLast = removeLastToken(fileName);
|
|
601
|
+
const matchesWithoutLast = {};
|
|
602
|
+
if (fileNameWithoutLast) {
|
|
603
|
+
longestCombinations.forEach((combination) => {
|
|
604
|
+
const combinationArray = combination.split('|');
|
|
605
|
+
if (checkPattern(combinationArray, fileNameWithoutLast)) {
|
|
606
|
+
matchesWithoutLast[combination] = matchesAfterSubstringCheck[combination];
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
// If only one combination is left after fileNameWithoutLast check, we use it
|
|
611
|
+
if (Object.keys(matchesWithoutLast).length == 1) {
|
|
612
|
+
matchingIndices = matchesWithoutLast[Object.keys(matchesWithoutLast)[0]];
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
Object.keys(matchesAfterSubstringCheck).forEach((combination) => {
|
|
616
|
+
matchingIndices.push(...matchesAfterSubstringCheck[combination]);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (matchingIndices.length > 0)
|
|
623
|
+
fileNameIndexMatch[fileName] = matchingIndices;
|
|
624
|
+
if (!fileNameIndexMatch[fileName])
|
|
625
|
+
fileNameIndexMatch[fileName] = [];
|
|
450
626
|
});
|
|
451
627
|
}
|
|
452
628
|
else {
|
|
453
629
|
// Else, we look for patterns ourselves using a couple of methods, prioritized on efficiency
|
|
454
|
-
const prepObject =
|
|
630
|
+
const prepObject = prepFilterSkusImagesAuto(filteredSkus, fileNames);
|
|
455
631
|
const preppedSkus = prepObject.preppedSkus;
|
|
456
632
|
const fileNames2Match = prepObject.fileNames2Match;
|
|
457
633
|
let quickSearch = prepQuickSearch(preppedSkus);
|
|
@@ -459,7 +635,7 @@ function imageBinder(fileNames, filteredSkus, brand, specifiedPattern, test = fa
|
|
|
459
635
|
fileNames2Match.forEach((fileName) => {
|
|
460
636
|
let matchFound = false;
|
|
461
637
|
const cleanedFileName = cleanFilename(fileName);
|
|
462
|
-
const fileNameWithoutLast =
|
|
638
|
+
const fileNameWithoutLast = removeLastToken(fileName);
|
|
463
639
|
let indicesForFileName = [];
|
|
464
640
|
// Method #1: try quicksearch, an object with patterns as keys and arrays of [proposedFilename, sku] as values
|
|
465
641
|
// based on existing patterns in GLOBAL_PATTERNS
|
|
@@ -524,7 +700,7 @@ function onlySaveIDFromSkus(matchDict) {
|
|
|
524
700
|
}
|
|
525
701
|
return out;
|
|
526
702
|
}
|
|
527
|
-
function testBatch(brand) {
|
|
703
|
+
function testBatch(brand, specifiedPattern = ['auto']) {
|
|
528
704
|
return __awaiter(this, void 0, void 0, function* () {
|
|
529
705
|
var _a, _b, _c;
|
|
530
706
|
const [skusModule, imagesModule, matchedModule] = yield Promise.all([
|
|
@@ -537,7 +713,7 @@ function testBatch(brand) {
|
|
|
537
713
|
const expectedRaw = matchedModule.default;
|
|
538
714
|
// 1) Call imageBinder
|
|
539
715
|
const t0 = Date.now();
|
|
540
|
-
const imageBinderResult = imageBinder(fileNames, filteredSkus, brand,
|
|
716
|
+
const imageBinderResult = imageBinder(fileNames, filteredSkus, brand, specifiedPattern, true);
|
|
541
717
|
const t1 = Date.now();
|
|
542
718
|
const matchIndices = imageBinderResult.match || {};
|
|
543
719
|
// 2) Convert indices → actual SKU arrays → ID arrays
|