All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m25s
136 lines
4.7 KiB
TypeScript
136 lines
4.7 KiB
TypeScript
const sizeOrder = ['2', '4', '6', '8', '10', '12', '14', '16', 'PP', 'P', 'M', 'G', 'GG', 'XG', 'G1', 'G2', 'G3', 'G4', 'G5'];
|
|
const sizeSet = new Set(sizeOrder);
|
|
const knownColors = [
|
|
'BRANCO + PRETO',
|
|
'CINZA/PRETO',
|
|
'VERDE BANDEIRA',
|
|
'VERDE MILITAR',
|
|
'AZUL MARINHO',
|
|
'CINZA GRAFITE',
|
|
'AMARELO',
|
|
'BRANCO',
|
|
'GRAFITE',
|
|
'MARINHO',
|
|
'VERMELHO',
|
|
'BORDO',
|
|
'CAFE',
|
|
'CAQUI',
|
|
'CHUMBO',
|
|
'CINZA',
|
|
'MARROM',
|
|
'PEROLA',
|
|
'PRETO',
|
|
'ROYAL',
|
|
'ROSA',
|
|
'ROXO',
|
|
'VERDE',
|
|
'AZUL',
|
|
'BEGE'
|
|
].sort((a, b) => b.length - a.length);
|
|
|
|
export const normalizeProductText = (value: string) => value.replace(/\s+/g, ' ').trim();
|
|
|
|
const normalizeForMatch = (value: string) => normalizeProductText(value)
|
|
.normalize('NFD')
|
|
.replace(/\p{Diacritic}/gu, '')
|
|
.toUpperCase();
|
|
|
|
const escapeRegex = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
|
const toFlexiblePattern = (value: string) => escapeRegex(value).replace(/\s+/g, '\\s+');
|
|
|
|
const findLeadingColor = (value: string) => {
|
|
const normalizedValue = normalizeForMatch(value);
|
|
return knownColors.find(color => normalizedValue === color || normalizedValue.startsWith(`${color} `)) || '';
|
|
};
|
|
|
|
const findTrailingColor = (value: string) => {
|
|
const normalizedValue = normalizeForMatch(value);
|
|
return knownColors.find(color => normalizedValue === color || normalizedValue.endsWith(` ${color}`) || normalizedValue.endsWith(`- ${color}`)) || '';
|
|
};
|
|
|
|
export const encodeProductGroupKey = (value: string) => {
|
|
const normalizedValue = normalizeProductText(value);
|
|
const bytes = new TextEncoder().encode(normalizedValue);
|
|
const binary = Array.from(bytes, byte => String.fromCharCode(byte)).join('');
|
|
|
|
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
};
|
|
|
|
export const decodeProductGroupKey = (value: string) => {
|
|
const base64 = value.replace(/-/g, '+').replace(/_/g, '/');
|
|
const paddedBase64 = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');
|
|
const binary = atob(paddedBase64);
|
|
const bytes = Uint8Array.from(binary, character => character.charCodeAt(0));
|
|
|
|
return normalizeProductText(new TextDecoder().decode(bytes));
|
|
};
|
|
|
|
export const sortProductSizes = (sizes: string[]) => [...sizes].sort((a, b) => {
|
|
const indexA = sizeOrder.indexOf(a);
|
|
const indexB = sizeOrder.indexOf(b);
|
|
if (indexA !== -1 || indexB !== -1) {
|
|
return (indexA === -1 ? Number.MAX_SAFE_INTEGER : indexA) - (indexB === -1 ? Number.MAX_SAFE_INTEGER : indexB);
|
|
}
|
|
return a.localeCompare(b, 'pt-BR');
|
|
});
|
|
|
|
export const parseProductName = (name: string) => {
|
|
const cleanName = normalizeProductText(name);
|
|
const explicitSizeMatch = cleanName.match(/\bTAMANHO\s*-?\s*([A-Z0-9]+)\b/i);
|
|
const trailingTokenMatch = cleanName.match(/(?:\s+-\s+|\s)([A-Z0-9]+)$/i);
|
|
const trailingToken = trailingTokenMatch?.[1]?.toUpperCase() || '';
|
|
let size = (explicitSizeMatch?.[1] || (sizeSet.has(trailingToken) ? trailingToken : '')).toUpperCase();
|
|
|
|
const colorMatch = cleanName.match(/\bCOR\s+(.+?)(?:\s+TAMANHO|\s+-\s+[A-Z0-9]+$|$)/i);
|
|
let color = normalizeProductText(findLeadingColor(colorMatch?.[1] || '') || colorMatch?.[1] || '');
|
|
|
|
if (!color && size) {
|
|
const nameBeforeSize = cleanName.replace(new RegExp(`(?:\\s+-\\s+|\\s)${escapeRegex(size)}$`, 'i'), '');
|
|
color = findTrailingColor(nameBeforeSize);
|
|
}
|
|
|
|
if (!color) {
|
|
const trailingColor = findTrailingColor(cleanName);
|
|
if (trailingColor) {
|
|
const normalizedName = normalizeForMatch(cleanName);
|
|
const normalizedPrefix = normalizeProductText(normalizedName.replace(new RegExp(`${escapeRegex(trailingColor)}$`), ''));
|
|
const tokenBeforeColor = normalizedPrefix.match(/([A-Z0-9]+)$/)?.[1] || '';
|
|
if (sizeSet.has(tokenBeforeColor)) {
|
|
color = trailingColor;
|
|
size = tokenBeforeColor;
|
|
}
|
|
}
|
|
}
|
|
|
|
let baseName = cleanName
|
|
.replace(/\bCOR\s+.+?(?:\s+TAMANHO\s*-?\s*[A-Z0-9]+|\s+-\s+[A-Z0-9]+$|$)/i, '')
|
|
.replace(/\bTAMANHO\s*-?\s*[A-Z0-9]+\b/i, '')
|
|
.replace(/\s+-\s*[A-Z0-9]+$/i, '');
|
|
|
|
if (color && size) {
|
|
const colorPattern = toFlexiblePattern(color);
|
|
const sizePattern = escapeRegex(size);
|
|
baseName = baseName
|
|
.replace(new RegExp(`\\s+-\\s*${colorPattern}\\s+${sizePattern}$`, 'i'), '')
|
|
.replace(new RegExp(`\\s+${colorPattern}\\s+-\\s*${sizePattern}$`, 'i'), '')
|
|
.replace(new RegExp(`\\s+${sizePattern}\\s+${colorPattern}$`, 'i'), '')
|
|
.replace(new RegExp(`\\s+${colorPattern}\\s+${sizePattern}$`, 'i'), '');
|
|
}
|
|
|
|
if (color) {
|
|
const colorPattern = toFlexiblePattern(color);
|
|
baseName = baseName
|
|
.replace(new RegExp(`\\s+-\\s*${colorPattern}$`, 'i'), '')
|
|
.replace(new RegExp(`\\s+${colorPattern}$`, 'i'), '');
|
|
}
|
|
|
|
baseName = normalizeProductText(baseName.replace(/\s+-\s*$/g, ''));
|
|
|
|
return {
|
|
baseName: baseName || cleanName,
|
|
color,
|
|
size
|
|
};
|
|
};
|