1import { files } from '@sublimated/sdk'2
3const AIRPORTS = {4 ARN: [17.9186, 59.6519],5 ATH: [23.9445, 37.9364],6 BCN: [2.0785, 41.2971],7 BEG: [20.3091, 44.8184],8 BER: [13.5033, 52.3667],9 BOG: [-74.1469, 4.7016],10 BUD: [19.2556, 47.4298],11 CAG: [9.0543, 39.2515],12 CDG: [2.5479, 49.0097],13 CGH: [-46.6564, -23.6261],14 CPH: [12.6561, 55.6181],15 CUN: [-86.8770, 21.0365],16 CWL: [-3.3433, 51.3967],17 DEN: [-104.6732, 39.8561],18 DPS: [115.1671, -8.7482],19 DSS: [-17.4902, 14.7397],20 DUB: [-6.2701, 53.4264],21 EDI: [-3.3725, 55.9500],22 EPA: [-58.6126, -34.6099],23 EWR: [-74.1687, 40.6895],24 EZE: [-58.5356, -34.8222],25 FCO: [12.2389, 41.8003],26 FMM: [10.2395, 47.9888],27 FRA: [8.5622, 50.0333],28 GIG: [-43.2436, -22.8099],29 GRU: [-46.4730, -23.4356],30 GUA: [-90.5275, 14.5833],31 GYE: [-79.8836, -2.1574],32 HEL: [24.9633, 60.3172],33 HKG: [113.9145, 22.3089],34 HNL: [-157.9224, 21.3187],35 HRK: [36.2860, 49.9248],36 IAH: [-95.3414, 29.9844],37 IGR: [-54.4734, -25.7373],38 IST: [28.8141, 40.9769],39 JFK: [-73.7781, 40.6413],40 KBP: [30.8947, 50.3450],41 KEF: [-22.6056, 63.9850],42 KRK: [19.7836, 50.0777],43 LAS: [-115.1523, 36.0840],44 LAX: [-118.4085, 33.9425],45 LHR: [-0.4614, 51.4700],46 LIS: [-9.1354, 38.7742],47 MAD: [-3.5673, 40.4936],48 MEX: [-99.0721, 19.4363],49 MIA: [-80.2906, 25.7959],50 MID: [-89.6577, 20.9370],51 MUC: [11.7861, 48.3538],52 MUN: [11.7861, 48.3538],53 NYO: [16.9122, 58.7886],54 OAK: [-122.2208, 37.7213],55 OGG: [-156.4305, 20.8986],56 ORY: [2.3594, 48.7233],57 OZH: [35.3157, 47.8671],58 PDX: [-122.5975, 45.5898],59 PHX: [-112.0116, 33.4373],60 PRG: [14.2632, 50.1008],61 PTY: [-79.3835, 9.0714],62 PVR: [-105.2551, 20.6801],63 PXM: [-97.0898, 15.8769],64 SAN: [-117.1896, 32.7336],65 SAW: [29.3092, 40.8986],66 SCL: [-70.7858, -33.3930],67 SDU: [-43.1631, -22.9105],68 SFO: [-122.3790, 37.6213],69 SIN: [103.9894, 1.3502],70 SJU: [-66.0018, 18.4394],71 SKP: [21.6214, 41.9617],72 SLC: [-111.9791, 40.7884],73 STL: [-90.3700, 38.7487],74 TGD: [19.2519, 42.3593],75 TIJ: [-116.9700, 32.5411],76 TIV: [18.7233, 42.4047],77 TLL: [24.8328, 59.4133],78 TXL: [13.2877, 52.5597],79 UIO: [-78.3575, -0.1292],80 VIE: [16.5697, 48.1103],81 WAW: [20.9671, 52.1657],82}83
84const CITIES = {85 'Agoura Hills, US': [-118.7609, 34.1531],86 'Athens, GR': [23.7275, 37.9838],87 'Bacalar, MX': [-88.3918, 18.6813],88 'Badajoz, ES': [-6.9706, 38.8794],89 'Banos, EC': [-78.4247, -1.3928],90 'Barcelona, ES': [2.1734, 41.3851],91 'Becici, ME': [18.8567, 42.2886],92 'Belgrade, RS': [20.4568, 44.7866],93 'Berlin, DE': [13.4050, 52.5200],94 'Bologna, IT': [11.3426, 44.4949],95 'Brookfield, CT, US': [-73.4068, 41.4645],96 'Buenos Aires, AR': [-58.3816, -34.6037],97 'Cadiz, ES': [-6.2926, 36.5271],98 'Cancun, MX': [-86.8515, 21.1619],99 'Cardiff, GB': [-3.1791, 51.4816],100 'Carmel-by-the-Sea, US': [-121.9233, 36.5552],101 'Castelldefels, ES': [1.9767, 41.2800],102 'Ciudad de Mexico, MX': [-99.1332, 19.4326],103 'Denpasar, ID': [115.2126, -8.6500],104 'Denver, US': [-104.9903, 39.7392],105 'Dresden, DE': [13.7373, 51.0504],106 'Drogobych, UA': [23.5064, 49.3497],107 'Dubrovnik, HR': [18.0944, 42.6507],108 'Edinburgh, GB': [-3.1883, 55.9533],109 'El Palomar, AR': [-58.6126, -34.6099],110 'Ellenville, NY, US': [-74.3968, 41.7170],111 'Encinitas, US': [-117.2928, 33.0370],112 'Florence, IT': [11.2558, 43.7696],113 'Fremont, CA, US': [-121.9886, 37.5485],114 'Gili Trawangan, ID': [116.0345, -8.3520],115 'Glasgow, GB': [-4.2518, 55.8642],116 'Guadalajara, MX': [-103.3496, 20.6597],117 'Guatemala City, GT': [-90.5069, 14.6349],118 'Hani i Hotit, AL': [19.5603, 42.5336],119 'Helsinki, FI': [24.9384, 60.1699],120 'Ivano-Frankivsk, UA': [24.7111, 48.9226],121 'Kahului, HI, US': [-156.4729, 20.8893],122 'Karlovy Vary, CZ': [12.8714, 50.2306],123 'Kharkiv, UA': [36.2304, 49.9935],124 'Kihei, HI, US': [-156.4659, 20.7644],125 'Kornati, HR': [15.3000, 43.8000],126 'Krakow, PL': [19.9450, 50.0647],127 'Kramatorsk, UA': [37.5558, 48.7362],128 'Kyiv, UA': [30.5234, 50.4501],129 'Larkspur, CA, US': [-122.5352, 37.9341],130 'Leon, NI': [-86.8780, 12.4346],131 'Lisbon, PT': [-9.1393, 38.7223],132 'Los Angeles, US': [-118.2437, 34.0522],133 'Lviv, UA': [24.0297, 49.8397],134 'Madrid, ES': [-3.7038, 40.4168],135 'Mahahual, MX': [-87.7112, 18.7142],136 'Mammoth, CA, US': [-118.9721, 37.6485],137 'Managua, NI': [-86.2504, 12.1150],138 'Manchester, GB': [-2.2426, 53.4808],139 'Memmingen, DE': [10.1811, 47.9837],140 'Merida, MX': [-89.5926, 20.9674],141 'Milan, IT': [9.1900, 45.4642],142 'Morelia, MX': [-101.1950, 19.7060],143 'Munich, DE': [11.5820, 48.1351],144 'Napa, US': [-122.2869, 38.2975],145 'New York, US': [-74.0060, 40.7128],146 'Newark, NJ, US': [-74.1724, 40.7357],147 'Ohrid, MK': [20.8019, 41.1231],148 'Panama City, PA': [-79.5197, 8.9824],149 'Paris, FR': [2.3522, 48.8566],150 'Playa del Carmen, MX': [-87.0739, 20.6296],151 'Podgorica, ME': [19.2636, 42.4304],152 'Prague, CZ': [14.4378, 50.0755],153 'Provo, US': [-111.6585, 40.2338],154 'Puerto Vallarta, MX': [-105.2253, 20.6534],155 'Pylypets, UA': [23.3311, 48.6614],156 'Quito, EC': [-78.4678, -0.1807],157 'Rio de Janeiro, BR': [-43.1729, -22.9068],158 'Rome, IT': [12.4964, 41.9028],159 'Sacramento, US': [-121.4944, 38.5816],160 'Salt Lake City, US': [-111.8910, 40.7608],161 'San Clemente, US': [-117.6120, 33.4270],162 'San Diego, US': [-117.1611, 32.7157],163 'San Francisco, US': [-122.4194, 37.7749],164 'San Jose, CR': [-84.0907, 9.9281],165 'San Luis Obispo, US': [-120.6596, 35.2828],166 'San Salvador, SV': [-89.1872, 13.6929],167 'Santa Rosa, US': [-122.7141, 38.4405],168 'Sao Paulo, BR': [-46.6333, -23.5505],169 'Sarajevo, BA': [18.4131, 43.8563],170 'Sayulita, MX': [-105.4413, 20.8692],171 'Sevilla, ES': [-5.9845, 37.3891],172 'Shkoder, AL': [19.5126, 42.0693],173 'Skopje, MK': [21.4254, 41.9973],174 'Split, HR': [16.4402, 43.5081],175 'Stockton, US': [-121.2908, 37.9577],176 'Tallinn, EE': [24.7536, 59.4370],177 'Tegucigalpa, HN': [-87.2068, 14.0723],178 'Temecula, US': [-117.1484, 33.4936],179 'Thira, GR': [25.4615, 36.3932],180 'Tijuana, MX': [-117.0382, 32.5149],181 'Tirana, AL': [19.8187, 41.3275],182 'Tivat, ME': [18.7233, 42.4047],183 'Tulum, MX': [-87.4654, 20.2115],184 'Vail, CO, US': [-106.3742, 39.6403],185 'Vallejo, CA, US': [-122.2566, 38.1041],186 'Venice, IT': [12.3155, 45.4408],187 'Vorokhta, UA': [24.5417, 48.2747],188 'Warsaw, PL': [21.0122, 52.2297],189 'Washington, US': [-77.0369, 38.9072],190 'Wroclaw, PL': [17.0385, 51.1079],191 'Yosemite Village, CA, US': [-119.5936, 37.7490],192 'Zadar, HR': [15.2314, 44.1194],193 'Zagreb, HR': [15.9819, 45.8150],194 'Zaporizhzhia, UA': [35.1396, 47.8388],195 'Zurich, CH': [8.5417, 47.3769],196}197
198function resolveLocation(loc) {199 var trimmed = loc.trim()200 if (AIRPORTS[trimmed]) return AIRPORTS[trimmed]201 if (CITIES[trimmed]) return CITIES[trimmed]202 return null203}204
205function parseTrip(filename, content) {206 var segments = []207 var lines = content.split('\n')208 var inTable = false209
210 for (var i = 0; i < lines.length; i++) {211 var line = lines[i]212 if (line.match(/^\|\s*from\s*\|/i)) {213 inTable = true214 continue215 }216 if (inTable && line.match(/^\|\s*-/)) continue217 if (inTable && line.startsWith('|')) {218 var parts = line.split('|').map(function(p) { return p.trim() }).filter(Boolean)219 if (parts.length >= 4) {220 var fromCoord = resolveLocation(parts[0])221 var toCoord = resolveLocation(parts[1])222 if (fromCoord && toCoord) {223 segments.push({224 from: parts[0], to: parts[1], date: parts[2], mode: parts[3],225 trip: filename, fromCoord: fromCoord, toCoord: toCoord,226 })227 }228 }229 } else if (inTable && !line.startsWith('|')) {230 inTable = false231 }232 }233 return segments234}235
236function isFlightMode(mode) {237 return mode.toLowerCase().startsWith('flight')238}239
240export default async function () {241 var allFiles = await files.list('.')242 var mdFiles = allFiles.filter(function(f) { return f.endsWith('.md') })243
244 var allSegments = []245
246 for (var i = 0; i < mdFiles.length; i++) {247 var content = await files.read(mdFiles[i])248 if (!content) continue249 var segments = parseTrip(mdFiles[i], content)250 allSegments.push.apply(allSegments, segments)251 }252
253 // per-trip geojson files254 var segmentsByTrip = {}255 for (var i = 0; i < allSegments.length; i++) {256 var seg = allSegments[i]257 if (!segmentsByTrip[seg.trip]) segmentsByTrip[seg.trip] = []258 segmentsByTrip[seg.trip].push(seg)259 }260
261 var tripNames = Object.keys(segmentsByTrip)262 for (var t = 0; t < tripNames.length; t++) {263 var trip = tripNames[t]264 var segs = segmentsByTrip[trip]265 var features = []266 var stops = {}267 for (var j = 0; j < segs.length; j++) {268 var s = segs[j]269 features.push({270 type: 'Feature',271 properties: {272 layer: isFlightMode(s.mode) ? 'flight' : 'route',273 from: s.from, to: s.to, date: s.date, mode: s.mode,274 },275 geometry: { type: 'LineString', coordinates: [s.fromCoord, s.toCoord] },276 })277 stops[s.from] = s.fromCoord278 stops[s.to] = s.toCoord279 }280 var stopNames = Object.keys(stops)281 for (var k = 0; k < stopNames.length; k++) {282 features.push({283 type: 'Feature',284 properties: { layer: 'stop', name: stopNames[k] },285 geometry: { type: 'Point', coordinates: stops[stopNames[k]] },286 })287 }288 await files.write(trip + '.geojson', JSON.stringify({ type: 'FeatureCollection', features: features }, null, 2))289 }290
291 // global flights.geojson292 var globalFeatures = []293 var globalStops = {}294 for (var i = 0; i < allSegments.length; i++) {295 var seg = allSegments[i]296 globalFeatures.push({297 type: 'Feature',298 properties: {299 layer: isFlightMode(seg.mode) ? 'flight' : 'route',300 from: seg.from, to: seg.to, date: seg.date, mode: seg.mode, trip: seg.trip,301 },302 geometry: { type: 'LineString', coordinates: [seg.fromCoord, seg.toCoord] },303 })304 globalStops[seg.from] = seg.fromCoord305 globalStops[seg.to] = seg.toCoord306 }307 var globalStopNames = Object.keys(globalStops)308 for (var i = 0; i < globalStopNames.length; i++) {309 globalFeatures.push({310 type: 'Feature',311 properties: { layer: 'stop', name: globalStopNames[i] },312 geometry: { type: 'Point', coordinates: globalStops[globalStopNames[i]] },313 })314 }315 await files.write('flights.geojson', JSON.stringify({ type: 'FeatureCollection', features: globalFeatures }, null, 2))316
317 return new Response(JSON.stringify({318 ok: true,319 trips: tripNames.length,320 segments: allSegments.length,321 stops: globalStopNames.length,322 flights: allSegments.filter(isFlightMode).length,323 }))324} v1 of v17
commit 8cdae43
message create generate-map.js via macOS
author anton
date Apr 18, 2026
size 10.4 KB