(function (root, factory) { var api = factory(); if (typeof module === 'object' && module.exports) { module.exports = api; } if (root) { root.TaberebaLegacyMigration = api; } }(typeof window !== 'undefined' ? window : globalThis, function () { 'use strict'; var settingsKey = 'tabereba_settings_v1'; var backupKey = 'tabereba_settings_v1_before_legacy_migration'; function clean(value, limit) { return String(value === null || typeof value === 'undefined' ? '' : value) .replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, limit); } function decodeInput(value) { value = clean(value, 65536); if (value.indexOf('%') === -1) { return value; } try { return decodeURIComponent(value.replace(/\+/g, ' ')); } catch (error) { return value; } } function decodeLegacyText(value) { return clean(value, 4096).replace(/"/gi, '"') .replace(/�*39;|�*27;|'/gi, "'") .replace(/</gi, '<').replace(/>/gi, '>').replace(/&/gi, '&'); } function findCookie(cookieString, cookieName) { cookieString = String(cookieString || ''); cookieName = clean(cookieName, 100); if (!/^[A-Za-z0-9_-]{1,100}$/.test(cookieName) || cookieString.length > 65536) { return ''; } var found = ''; cookieString.split(';').some(function (part) { var separator = part.indexOf('='); if (separator === -1 || part.slice(0, separator).trim() !== cookieName) { return false; } found = part.slice(separator + 1).trim().slice(0, 65536); return true; }); return found; } function parseRowsDetailed(value) { var rows = {}; var duplicateKeys = []; var unsupportedKeys = []; decodeInput(value).split('::').forEach(function (line) { var columns = line.split(','); var key = clean(columns.shift(), 20); if (!/^[a-z][a-z0-9_]{0,19}$/i.test(key)) { return; } if (Object.prototype.hasOwnProperty.call(rows, key)) { duplicateKeys.push(key); return; } if (['sn', 'hts', 'htp'].indexOf(key) === -1) { unsupportedKeys.push(key); return; } rows[key] = columns.map(decodeLegacyText); }); return {rows: rows, duplicate_keys: duplicateKeys, unsupported_keys: unsupportedKeys}; } function createHotpepperMylink(sid, pid) { if (!/^[0-9]{1,20}$/.test(sid) || !/^[0-9]{1,20}$/.test(pid)) { return ''; } var destination = encodeURIComponent('https://www.hotpepper.jp/'); return '' + 'ホットペッパー グルメ'; } function emptySite(name) { return { site_name: clean(name, 100), hotpepper_valuecommerce_html: '', tabelog_valuecommerce_html: '', gnavi_linkshare_html: '', image_size: 'medium', shop_label_suffix: '', template_key: 'amazlet-2', shop_icon_type: 'none', custom_css_preset: 'simple', show_catch: true, show_address: true, background_opacity: 100, migration_info: {} }; } function validSettingsJson(value) { try { var parsed = typeof value === 'string' ? JSON.parse(value) : value; return parsed && parsed.service === 'tabereba' && parsed.schema_version === 1 && parsed.version === 1 && Array.isArray(parsed.sites) && parsed.sites.length >= 1 && parsed.sites.length <= 20; } catch (error) { return false; } } function writeAndVerify(storage, key, value) { storage.setItem(key, value); return storage.getItem(key) === value; } function applyToStorage(storage, nextSettings) { if (!validSettingsJson(nextSettings)) { return {success: false, error: 'next_invalid'}; } var current; var next = JSON.stringify(nextSettings); try { current = storage.getItem(settingsKey) || ''; if (!validSettingsJson(current)) { return {success: false, error: 'current_invalid'}; } if (!writeAndVerify(storage, backupKey, current)) { return {success: false, error: 'backup_failed'}; } if (!writeAndVerify(storage, settingsKey, next)) { return {success: false, error: 'settings_failed'}; } return {success: true, error: ''}; } catch (error) { return {success: false, error: 'storage_failed'}; } } function restoreFromStorage(storage) { try { var backup = storage.getItem(backupKey) || ''; if (!validSettingsJson(backup)) { return {success: false, error: 'backup_invalid'}; } if (!writeAndVerify(storage, settingsKey, backup)) { return {success: false, error: 'settings_failed'}; } storage.removeItem(backupKey); return {success: storage.getItem(backupKey) === null, error: storage.getItem(backupKey) === null ? '' : 'backup_remove_failed'}; } catch (error) { return {success: false, error: 'storage_failed'}; } } function convert(value, options) { options = options || {}; var parsed = parseRowsDetailed(value); var rows = parsed.rows; var names = rows.sn || []; if (parsed.duplicate_keys.length > 0) { return {success: false, error: 'duplicate_key', settings: null, summary: null}; } if (parsed.unsupported_keys.length > 0) { return {success: false, error: 'unsupported_key', settings: null, summary: null}; } if (names.length < 1 || names.length > 5) { return {success: false, error: 'site_count', settings: null, summary: null}; } var migratedAt = clean(options.migratedAt || new Date().toISOString(), 40); var sidValues = rows.hts || []; var pidValues = rows.htp || []; var hasAffiliateRows = Object.prototype.hasOwnProperty.call(rows, 'hts') || Object.prototype.hasOwnProperty.call(rows, 'htp'); var countMismatch = hasAffiliateRows && (sidValues.length !== names.length || pidValues.length !== names.length); var migratedCount = 0; var incompleteCount = 0; var sites = names.map(function (name, index) { var site = emptySite(name); var sid = clean(sidValues[index], 20); var pid = clean(pidValues[index], 20); var hasPairValue = sid !== '' || pid !== ''; var mylink = countMismatch ? '' : createHotpepperMylink(sid, pid); var incomplete = countMismatch ? hasAffiliateRows : (hasPairValue && mylink === ''); if (mylink) { site.hotpepper_valuecommerce_html = mylink; migratedCount += 1; } if (incomplete) { incompleteCount += 1; } if (mylink || incomplete) { site.migration_info = { source: 'legacy_cookie', needs_affiliate_review: true, incomplete_valuecommerce_pairs: incomplete ? ['hotpepper'] : [], migrated_at: migratedAt, reviewed_at: '' }; } return site; }); return { success: true, error: '', settings: {service: 'tabereba', schema_version: 1, version: 1, default_site_index: 0, active_site_index: 0, sites: sites}, summary: {site_count: sites.length, hotpepper_count: migratedCount, incomplete_hotpepper_count: incompleteCount, count_mismatch: countMismatch} }; } return {settingsKey: settingsKey, backupKey: backupKey, findCookie: findCookie, createHotpepperMylink: createHotpepperMylink, validSettingsJson: validSettingsJson, applyToStorage: applyToStorage, restoreFromStorage: restoreFromStorage, convert: convert}; }));