Files

65 lines
2.6 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 removedParams = new Set(linkTemplate.removeParams || []);
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 (removedParams.has(key)) {
changes.push({ key, from:rawValue, to:'', removed:true });
return null;
}
if (!Object.prototype.hasOwnProperty.call(replacements, key)) return segment;
const replacement = String(replacements[key] ?? '');
if (rawValue !== replacement) changes.push({ key, from: rawValue, to: replacement, removed:false });
return `${rawKey}=${replacement}`;
}).filter((segment) => segment !== null);
return {
url: `${base}?${convertedSegments.join('&')}${hash}`,
type,
changes,
parameterCount,
preservedCount: parameterCount - changes.length
};
}
root.TrackingLinkConverter = { detectLinkType, convertTrackingLink };
})(typeof window === 'undefined' ? globalThis : window);