parseCsv static method
Parse CSV content lines (header + rows) into canonical links.
Implementation
static List<Map<String, dynamic>> parseCsv(List<String> lines) {
final header = _splitCsvLine(lines[0]);
// Map each header column index -> canonical key (or null if unrecognized).
final colKey = header.map((h) {
final n = _normHeader(h);
for (final entry in _csvColumns.entries) {
if (entry.value.contains(n)) return entry.key;
}
return null;
}).toList();
if (!colKey.any((k) => k != null)) {
throw FdlParseError(
'CSV header has no recognized columns. Expected at least a "link" column '
'(the deep-link destination); got: ${header.join(', ')}',
);
}
final rows = lines.sublist(1);
if (rows.isEmpty) throw FdlParseError('CSV had a header but no data rows.');
final out = <Map<String, dynamic>>[];
for (var i = 0; i < rows.length; i++) {
final cells = _splitCsvLine(rows[i]);
String? val(String key) {
final idx = colKey.indexOf(key);
final v = idx == -1 ? null : (idx < cells.length ? cells[idx] : null);
return (v == null || v == '') ? null : v;
}
final linkVal = val('link');
final shortVal = val('shortlink');
try {
// Convenience: if there's no destination column but the short/url column
// holds a full FDL long link (with its own ?link=... params), parse that.
if (linkVal == null &&
shortVal != null &&
RegExp(r'[?&]link=').hasMatch(shortVal)) {
out.add(parseUrl(shortVal));
continue;
}
final info = <String, dynamic>{
'link': linkVal,
'shortLink': shortVal,
'androidInfo': {
'androidPackageName': val('apn'),
'androidFallbackLink': val('afl'),
'androidMinPackageVersionCode': val('amv'),
},
'iosInfo': {
'iosBundleId': val('ibi'),
'iosAppStoreId': val('isi'),
'iosFallbackLink': val('ifl'),
'iosCustomScheme': val('ius'),
'iosMinimumVersion': val('imv'),
'iosIpadBundleId': val('ipbi'),
'iosIpadFallbackLink': val('ipfl'),
},
'navigationInfo': <String, dynamic>{},
'analyticsInfo': {
'googlePlayAnalytics': {
'utmSource': val('utm_source'),
'utmMedium': val('utm_medium'),
'utmCampaign': val('utm_campaign'),
'utmTerm': val('utm_term'),
'utmContent': val('utm_content'),
'gclid': val('gclid'),
},
'itunesConnectAnalytics': {
'at': val('at'),
'ct': val('ct'),
'mt': val('mt'),
'pt': val('pt'),
},
},
'socialMetaTagInfo': {
'socialTitle': val('st'),
'socialDescription': val('sd'),
'socialImageLink': val('si'),
},
};
if (val('ofl') != null) info['otherFallbackLink'] = val('ofl');
out.add(_normalizeObject(info));
} on FdlParseError catch (e) {
throw FdlParseError('Row #${i + 1}: ${e.message}');
}
}
return out;
}