60 lines
2.3 KiB
JavaScript
60 lines
2.3 KiB
JavaScript
((root) => {
|
|
function decodeKey(value) {
|
|
try { return decodeURIComponent(value.replace(/\+/g, ' ')); }
|
|
catch (_) { return value; }
|
|
}
|
|
|
|
function detectLinkType(link) {
|
|
const pathname = new URL(link).pathname.toLowerCase();
|
|
return /(?:^|\/)imp(?:\/|$)/.test(pathname) ? 'imp' : 'click';
|
|
}
|
|
|
|
function convertTrackingLink(originalLink, template) {
|
|
const original = originalLink.trim();
|
|
const parsed = new URL(original);
|
|
if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('仅支持 HTTP 或 HTTPS 链接');
|
|
if (!parsed.search) throw new Error('链接中没有可转换的查询参数');
|
|
|
|
const type = detectLinkType(original);
|
|
const linkTemplate = template.links[type];
|
|
if (!linkTemplate) {
|
|
const typeLabel = type === 'imp' ? 'Impression' : 'Click';
|
|
throw new Error(`${template.name} 暂未配置 ${typeLabel} 宏模板`);
|
|
}
|
|
|
|
const hashIndex = original.indexOf('#');
|
|
const hash = hashIndex >= 0 ? original.slice(hashIndex) : '';
|
|
const withoutHash = hashIndex >= 0 ? original.slice(0, hashIndex) : original;
|
|
const queryIndex = withoutHash.indexOf('?');
|
|
const base = withoutHash.slice(0, queryIndex);
|
|
const query = withoutHash.slice(queryIndex + 1);
|
|
const replacements = { platform: template.platformCode, ...linkTemplate.mappings };
|
|
const changes = [];
|
|
let parameterCount = 0;
|
|
|
|
const convertedSegments = query.split('&').map((segment) => {
|
|
if (!segment) return segment;
|
|
parameterCount += 1;
|
|
const equalIndex = segment.indexOf('=');
|
|
const rawKey = equalIndex >= 0 ? segment.slice(0, equalIndex) : segment;
|
|
const rawValue = equalIndex >= 0 ? segment.slice(equalIndex + 1) : '';
|
|
const key = decodeKey(rawKey);
|
|
if (!Object.prototype.hasOwnProperty.call(replacements, key)) return segment;
|
|
|
|
const replacement = String(replacements[key] ?? '');
|
|
if (rawValue !== replacement) changes.push({ key, from: rawValue, to: replacement });
|
|
return `${rawKey}=${replacement}`;
|
|
});
|
|
|
|
return {
|
|
url: `${base}?${convertedSegments.join('&')}${hash}`,
|
|
type,
|
|
changes,
|
|
parameterCount,
|
|
preservedCount: parameterCount - changes.length
|
|
};
|
|
}
|
|
|
|
root.TrackingLinkConverter = { detectLinkType, convertTrackingLink };
|
|
})(typeof window === 'undefined' ? globalThis : window);
|