((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);