lt-public-transport-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/assets/architecture.png +0 -0
- package/dist/config.d.ts +221 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +200 -0
- package/dist/config.js.map +1 -0
- package/dist/enrichment/index.d.ts +6 -0
- package/dist/enrichment/index.d.ts.map +1 -0
- package/dist/enrichment/index.js +6 -0
- package/dist/enrichment/index.js.map +1 -0
- package/dist/enrichment/route-matcher.d.ts +64 -0
- package/dist/enrichment/route-matcher.d.ts.map +1 -0
- package/dist/enrichment/route-matcher.js +121 -0
- package/dist/enrichment/route-matcher.js.map +1 -0
- package/dist/errors.d.ts +70 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +104 -0
- package/dist/errors.js.map +1 -0
- package/dist/gtfs/index.d.ts +7 -0
- package/dist/gtfs/index.d.ts.map +1 -0
- package/dist/gtfs/index.js +7 -0
- package/dist/gtfs/index.js.map +1 -0
- package/dist/gtfs/parser.d.ts +39 -0
- package/dist/gtfs/parser.d.ts.map +1 -0
- package/dist/gtfs/parser.js +189 -0
- package/dist/gtfs/parser.js.map +1 -0
- package/dist/gtfs/sync.d.ts +72 -0
- package/dist/gtfs/sync.d.ts.map +1 -0
- package/dist/gtfs/sync.js +271 -0
- package/dist/gtfs/sync.js.map +1 -0
- package/dist/index.d.ts +203 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +342 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/gps-full.d.ts +39 -0
- package/dist/parsers/gps-full.d.ts.map +1 -0
- package/dist/parsers/gps-full.js +212 -0
- package/dist/parsers/gps-full.js.map +1 -0
- package/dist/parsers/gps-lite.d.ts +60 -0
- package/dist/parsers/gps-lite.d.ts.map +1 -0
- package/dist/parsers/gps-lite.js +141 -0
- package/dist/parsers/gps-lite.js.map +1 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +7 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/schemas.d.ts +129 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +200 -0
- package/dist/schemas.js.map +1 -0
- package/dist/scripts/test-city-specific.d.ts +2 -0
- package/dist/scripts/test-city-specific.d.ts.map +1 -0
- package/dist/scripts/test-city-specific.js +264 -0
- package/dist/scripts/test-city-specific.js.map +1 -0
- package/dist/scripts/test-config-options.d.ts +2 -0
- package/dist/scripts/test-config-options.d.ts.map +1 -0
- package/dist/scripts/test-config-options.js +166 -0
- package/dist/scripts/test-config-options.js.map +1 -0
- package/dist/scripts/test-data-quality.d.ts +2 -0
- package/dist/scripts/test-data-quality.d.ts.map +1 -0
- package/dist/scripts/test-data-quality.js +204 -0
- package/dist/scripts/test-data-quality.js.map +1 -0
- package/dist/scripts/test-error-handling.d.ts +2 -0
- package/dist/scripts/test-error-handling.d.ts.map +1 -0
- package/dist/scripts/test-error-handling.js +146 -0
- package/dist/scripts/test-error-handling.js.map +1 -0
- package/dist/scripts/test-live.d.ts +2 -0
- package/dist/scripts/test-live.d.ts.map +1 -0
- package/dist/scripts/test-live.js +121 -0
- package/dist/scripts/test-live.js.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/coordinates.d.ts +68 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/coordinates.js +98 -0
- package/dist/utils/coordinates.js.map +1 -0
- package/dist/utils/encoding.d.ts +47 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +153 -0
- package/dist/utils/encoding.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/time.d.ts +50 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +94 -0
- package/dist/utils/time.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { LtTransport } from '../index.js';
|
|
2
|
+
import { ALL_CITY_IDS, CITY_CONFIGS } from '../config.js';
|
|
3
|
+
function getErrorMessage(error) {
|
|
4
|
+
if (error instanceof Error) {
|
|
5
|
+
return error.message;
|
|
6
|
+
}
|
|
7
|
+
return String(error);
|
|
8
|
+
}
|
|
9
|
+
async function runLiveTest() {
|
|
10
|
+
console.log('🚀 Starting Live SDK Tests...\n');
|
|
11
|
+
const client = new LtTransport({
|
|
12
|
+
requestTimeout: 30000, // Longer timeout for live tests
|
|
13
|
+
filterStale: false, // We want to see stale data stats
|
|
14
|
+
autoEnrich: true,
|
|
15
|
+
});
|
|
16
|
+
const cityStats = {};
|
|
17
|
+
let totalErrors = 0;
|
|
18
|
+
for (const city of ALL_CITY_IDS) {
|
|
19
|
+
console.log(`\n---------------------------------------------------`);
|
|
20
|
+
console.log(`Testing City: ${city.toUpperCase()} (${CITY_CONFIGS[city].tier} tier)`);
|
|
21
|
+
console.log(`---------------------------------------------------`);
|
|
22
|
+
const stats = {
|
|
23
|
+
gps: { available: false, count: 0, stale: 0, invalidCoords: 0 },
|
|
24
|
+
gtfs: { routes: 0, stops: 0, synced: false },
|
|
25
|
+
enrichment: { matched: 0 }
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
// 1. Test GPS Stream
|
|
29
|
+
console.log(`📡 Fetching live vehicles...`);
|
|
30
|
+
if (CITY_CONFIGS[city].gps.enabled) {
|
|
31
|
+
try {
|
|
32
|
+
const vehicles = await client.getVehicles(city);
|
|
33
|
+
stats.gps.available = true;
|
|
34
|
+
stats.gps.count = vehicles.length;
|
|
35
|
+
stats.gps.stale = vehicles.filter(v => v.isStale).length;
|
|
36
|
+
stats.gps.invalidCoords = vehicles.filter(v => v.latitude === 0 || v.longitude === 0).length;
|
|
37
|
+
console.log(` ✅ Success: ${String(vehicles.length)} vehicles found`);
|
|
38
|
+
console.log(` - Stale: ${String(stats.gps.stale)}`);
|
|
39
|
+
console.log(` - enriching...`); // Will be checked after sync
|
|
40
|
+
// Check sample vehicle
|
|
41
|
+
if (vehicles.length > 0 && vehicles[0] !== undefined) {
|
|
42
|
+
const sample = vehicles[0];
|
|
43
|
+
console.log(` 🔍 Sample: [${sample.route}] ${sample.vehicleNumber} (${sample.type})`);
|
|
44
|
+
console.log(` Lat/Lon: ${sample.latitude.toFixed(4)}, ${sample.longitude.toFixed(4)}`);
|
|
45
|
+
console.log(` Measured: ${sample.measuredAt.toISOString()}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(` ❌ GPS Error: ${getErrorMessage(err)}`);
|
|
50
|
+
totalErrors++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log(` ⚠️ GPS not enabled for this city.`);
|
|
55
|
+
}
|
|
56
|
+
// 2. Test GTFS Sync
|
|
57
|
+
console.log(`⬇️ Syncing GTFS data...`);
|
|
58
|
+
try {
|
|
59
|
+
const syncResult = await client.sync(city);
|
|
60
|
+
stats.gtfs.synced = true;
|
|
61
|
+
stats.gtfs.routes = syncResult.routeCount;
|
|
62
|
+
stats.gtfs.stops = syncResult.stopCount;
|
|
63
|
+
console.log(` ✅ Synced: ${syncResult.status}`);
|
|
64
|
+
console.log(` - Routes: ${String(syncResult.routeCount)}`);
|
|
65
|
+
console.log(` - Stops: ${String(syncResult.stopCount)}`);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error(` ❌ GTFS Sync Error: ${getErrorMessage(err)}`);
|
|
69
|
+
totalErrors++;
|
|
70
|
+
}
|
|
71
|
+
// 3. Test GTFS Data Access
|
|
72
|
+
if (stats.gtfs.synced) {
|
|
73
|
+
try {
|
|
74
|
+
const routes = await client.getRoutes(city);
|
|
75
|
+
const stops = await client.getStops(city);
|
|
76
|
+
console.log(` ✅ Cache verified: ${String(routes.length)} routes, ${String(stops.length)} stops loaded.`);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.error(` ❌ GTFS Access Error: ${getErrorMessage(err)}`);
|
|
80
|
+
totalErrors++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// 4. Test Enrichment (Fetch vehicles again if GPS enabled)
|
|
84
|
+
if (CITY_CONFIGS[city].gps.enabled && stats.gtfs.synced) {
|
|
85
|
+
// Wait a bit to ensure async processing doesn't race? No, getVehicles should await enrichment.
|
|
86
|
+
const vehicles = await client.getVehicles(city);
|
|
87
|
+
const enriched = vehicles.filter(v => v.destination !== null);
|
|
88
|
+
stats.enrichment.matched = enriched.length;
|
|
89
|
+
console.log(` ✨ Enrichment: ${String(enriched.length)}/${String(vehicles.length)} vehicles have destinations`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
console.error(`❌ Critical City Error: ${getErrorMessage(err)}`);
|
|
94
|
+
totalErrors++;
|
|
95
|
+
}
|
|
96
|
+
cityStats[city] = stats;
|
|
97
|
+
}
|
|
98
|
+
console.log('\n===================================================');
|
|
99
|
+
console.log('TEST SUMMARY');
|
|
100
|
+
console.log('===================================================');
|
|
101
|
+
console.table(Object.entries(cityStats).map(([city, s]) => ({
|
|
102
|
+
City: city,
|
|
103
|
+
Vehicles: s.gps.count,
|
|
104
|
+
'Stale%': s.gps.count ? String(Math.round((s.gps.stale / s.gps.count) * 100)) + '%' : '-',
|
|
105
|
+
'Routes': s.gtfs.routes,
|
|
106
|
+
'Stops': s.gtfs.stops,
|
|
107
|
+
'Enriched': s.enrichment.matched
|
|
108
|
+
})));
|
|
109
|
+
if (totalErrors > 0) {
|
|
110
|
+
console.error(`\n❌ Completed with ${String(totalErrors)} errors.`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(`\n✅ All tests passed successfully!`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
runLiveTest().catch((err) => {
|
|
118
|
+
console.error(getErrorMessage(err));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=test-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-live.js","sourceRoot":"","sources":["../../src/scripts/test-live.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for Lithuanian Public Transport SDK
|
|
3
|
+
* @module types
|
|
4
|
+
*/
|
|
5
|
+
import type { CityId } from './config.js';
|
|
6
|
+
export type { CityId, CityTier } from './config.js';
|
|
7
|
+
/**
|
|
8
|
+
* Vehicle types from Lithuanian public transport.
|
|
9
|
+
* - bus: Standard city buses (GTFS route_type 3)
|
|
10
|
+
* - trolleybus: Electric trolleybuses (GTFS route_type 800)
|
|
11
|
+
* - ferry: Water transport / boats (GTFS route_type 4 or 1200) - seasonal in Vilnius
|
|
12
|
+
* - unknown: Unrecognized vehicle type
|
|
13
|
+
*/
|
|
14
|
+
export type VehicleType = 'bus' | 'trolleybus' | 'ferry' | 'unknown';
|
|
15
|
+
/**
|
|
16
|
+
* GTFS route_type to VehicleType mapping.
|
|
17
|
+
* Uses both standard and extended GTFS route types.
|
|
18
|
+
*/
|
|
19
|
+
export declare const GTFS_ROUTE_TYPE_MAP: Readonly<Record<number, VehicleType>>;
|
|
20
|
+
/**
|
|
21
|
+
* Lithuanian transport type names to VehicleType mapping.
|
|
22
|
+
* Used when parsing GPS data streams.
|
|
23
|
+
*/
|
|
24
|
+
export declare const LT_TRANSPORT_TYPE_MAP: Readonly<Record<string, VehicleType>>;
|
|
25
|
+
/**
|
|
26
|
+
* Normalized vehicle object representing a single public transport vehicle.
|
|
27
|
+
* This interface is consistent across all cities regardless of data source format.
|
|
28
|
+
*/
|
|
29
|
+
export interface Vehicle {
|
|
30
|
+
/** Unique identifier for this vehicle tracking record */
|
|
31
|
+
readonly id: string;
|
|
32
|
+
/** Vehicle number/code as displayed on the vehicle */
|
|
33
|
+
readonly vehicleNumber: string;
|
|
34
|
+
/** Route identifier (e.g., "4G", "N1", "S11") - always a string */
|
|
35
|
+
readonly route: string;
|
|
36
|
+
/** Type of vehicle */
|
|
37
|
+
readonly type: VehicleType;
|
|
38
|
+
/** Latitude in WGS84 decimal degrees */
|
|
39
|
+
readonly latitude: number;
|
|
40
|
+
/** Longitude in WGS84 decimal degrees */
|
|
41
|
+
readonly longitude: number;
|
|
42
|
+
/** Heading/bearing in degrees (0-359, 0 = North) */
|
|
43
|
+
readonly bearing: number;
|
|
44
|
+
/** Current speed in km/h */
|
|
45
|
+
readonly speed: number;
|
|
46
|
+
/** Destination/terminus name, if available */
|
|
47
|
+
readonly destination: string | null;
|
|
48
|
+
/** Delay in seconds (positive = late, negative = early), if available */
|
|
49
|
+
readonly delaySeconds: number | null;
|
|
50
|
+
/** Trip identifier from source system, if available */
|
|
51
|
+
readonly tripId: string | null;
|
|
52
|
+
/** GTFS trip reference, if available (Vilnius only) */
|
|
53
|
+
readonly gtfsTripId: string | null;
|
|
54
|
+
/** Next stop ID (Kaunas only) */
|
|
55
|
+
readonly nextStopId: string | null;
|
|
56
|
+
/** Predicted arrival time at next stop in seconds from midnight (Kaunas only) */
|
|
57
|
+
readonly arrivalTimeSeconds: number | null;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this data is considered stale.
|
|
60
|
+
* True if measurement time is older than configured threshold.
|
|
61
|
+
*/
|
|
62
|
+
readonly isStale: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Timestamp when the GPS position was measured.
|
|
65
|
+
* Falls back to server receive time if measurement time unavailable.
|
|
66
|
+
*/
|
|
67
|
+
readonly measuredAt: Date;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Static stop/station data from GTFS.
|
|
71
|
+
*/
|
|
72
|
+
export interface Stop {
|
|
73
|
+
/** Unique stop identifier from GTFS */
|
|
74
|
+
readonly id: string;
|
|
75
|
+
/** Short code for the stop, if available */
|
|
76
|
+
readonly code: string | null;
|
|
77
|
+
/** Human-readable stop name */
|
|
78
|
+
readonly name: string;
|
|
79
|
+
/** Additional description, if available */
|
|
80
|
+
readonly description: string | null;
|
|
81
|
+
/** Latitude in WGS84 decimal degrees */
|
|
82
|
+
readonly latitude: number;
|
|
83
|
+
/** Longitude in WGS84 decimal degrees */
|
|
84
|
+
readonly longitude: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Route information from GTFS.
|
|
88
|
+
*/
|
|
89
|
+
export interface Route {
|
|
90
|
+
/** Unique route identifier from GTFS */
|
|
91
|
+
readonly id: string;
|
|
92
|
+
/** Short route name (e.g., "4G", "N1") */
|
|
93
|
+
readonly shortName: string;
|
|
94
|
+
/** Full route name with endpoints */
|
|
95
|
+
readonly longName: string;
|
|
96
|
+
/** Type of vehicles on this route */
|
|
97
|
+
readonly type: VehicleType;
|
|
98
|
+
/** Route color for display (hex without #) */
|
|
99
|
+
readonly color: string;
|
|
100
|
+
/** Text color for display on route color background (hex without #) */
|
|
101
|
+
readonly textColor: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Result of a GTFS sync operation.
|
|
105
|
+
*/
|
|
106
|
+
export interface SyncResult {
|
|
107
|
+
/** City that was synced */
|
|
108
|
+
readonly city: CityId;
|
|
109
|
+
/** Whether data was updated or already current */
|
|
110
|
+
readonly status: 'updated' | 'up-to-date';
|
|
111
|
+
/** Number of routes in cache after sync */
|
|
112
|
+
readonly routeCount: number;
|
|
113
|
+
/** Number of stops in cache after sync */
|
|
114
|
+
readonly stopCount: number;
|
|
115
|
+
/** Last-Modified timestamp from server */
|
|
116
|
+
readonly lastModified: string | null;
|
|
117
|
+
/** When this sync was performed */
|
|
118
|
+
readonly syncedAt: Date;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for Lithuanian Public Transport SDK
|
|
3
|
+
* @module types
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* GTFS route_type to VehicleType mapping.
|
|
7
|
+
* Uses both standard and extended GTFS route types.
|
|
8
|
+
*/
|
|
9
|
+
export const GTFS_ROUTE_TYPE_MAP = {
|
|
10
|
+
3: 'bus', // Standard GTFS: Bus
|
|
11
|
+
800: 'trolleybus', // Extended GTFS: Trolleybus
|
|
12
|
+
4: 'ferry', // Standard GTFS: Ferry
|
|
13
|
+
1200: 'ferry', // Extended GTFS: Ferry Service
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Lithuanian transport type names to VehicleType mapping.
|
|
17
|
+
* Used when parsing GPS data streams.
|
|
18
|
+
*/
|
|
19
|
+
export const LT_TRANSPORT_TYPE_MAP = {
|
|
20
|
+
'Autobusai': 'bus',
|
|
21
|
+
'Troleibusai': 'trolleybus',
|
|
22
|
+
'Laivai': 'ferry',
|
|
23
|
+
'Keltai': 'ferry',
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA0C;IACxE,CAAC,EAAE,KAAK,EAAU,qBAAqB;IACvC,GAAG,EAAE,YAAY,EAAE,4BAA4B;IAC/C,CAAC,EAAE,OAAO,EAAQ,uBAAuB;IACzC,IAAI,EAAE,OAAO,EAAK,+BAA+B;CACzC,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA0C;IAC1E,WAAW,EAAE,KAAK;IAClB,aAAa,EAAE,YAAY;IAC3B,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,OAAO;CACT,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coordinate normalization and validation utilities
|
|
3
|
+
* @module utils/coordinates
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Lithuania's geographic bounding box in WGS84 decimal degrees.
|
|
7
|
+
* Used to validate coordinates are within expected range.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LITHUANIA_BOUNDS: {
|
|
10
|
+
/** Minimum latitude (southern border) */
|
|
11
|
+
readonly latMin: 53.89;
|
|
12
|
+
/** Maximum latitude (northern border) */
|
|
13
|
+
readonly latMax: 56.45;
|
|
14
|
+
/** Minimum longitude (western border) */
|
|
15
|
+
readonly lonMin: 20.93;
|
|
16
|
+
/** Maximum longitude (eastern border) */
|
|
17
|
+
readonly lonMax: 26.83;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a raw integer coordinate to WGS84 decimal degrees.
|
|
21
|
+
*
|
|
22
|
+
* @param raw - Raw coordinate as integer (e.g., 25255492 for ~25.255492°)
|
|
23
|
+
* @returns Normalized coordinate in decimal degrees
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* normalizeCoordinate(25255492) // => 25.255492
|
|
27
|
+
* normalizeCoordinate(54633886) // => 54.633886
|
|
28
|
+
*/
|
|
29
|
+
export declare function normalizeCoordinate(raw: number): number;
|
|
30
|
+
/**
|
|
31
|
+
* Check if coordinates fall within Lithuania's bounding box.
|
|
32
|
+
*
|
|
33
|
+
* @param lat - Latitude in WGS84 decimal degrees
|
|
34
|
+
* @param lon - Longitude in WGS84 decimal degrees
|
|
35
|
+
* @returns true if coordinates are within Lithuania
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* isValidLithuaniaCoord(54.687, 25.279) // => true (Vilnius)
|
|
39
|
+
* isValidLithuaniaCoord(48.856, 2.352) // => false (Paris)
|
|
40
|
+
*/
|
|
41
|
+
export declare function isValidLithuaniaCoord(lat: number, lon: number): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Validate and normalize raw integer coordinates.
|
|
44
|
+
* Returns null if coordinates are invalid or outside Lithuania.
|
|
45
|
+
*
|
|
46
|
+
* @param rawLat - Raw latitude as integer
|
|
47
|
+
* @param rawLon - Raw longitude as integer
|
|
48
|
+
* @returns Object with normalized lat/lon, or null if invalid
|
|
49
|
+
*/
|
|
50
|
+
export declare function normalizeAndValidateCoordinates(rawLat: number, rawLon: number): {
|
|
51
|
+
latitude: number;
|
|
52
|
+
longitude: number;
|
|
53
|
+
} | null;
|
|
54
|
+
/**
|
|
55
|
+
* Normalize bearing to 0-359 range.
|
|
56
|
+
*
|
|
57
|
+
* @param bearing - Raw bearing value
|
|
58
|
+
* @returns Normalized bearing in degrees
|
|
59
|
+
*/
|
|
60
|
+
export declare function normalizeBearing(bearing: number): number;
|
|
61
|
+
/**
|
|
62
|
+
* Normalize speed to non-negative value.
|
|
63
|
+
*
|
|
64
|
+
* @param speed - Raw speed value
|
|
65
|
+
* @returns Speed in km/h, minimum 0
|
|
66
|
+
*/
|
|
67
|
+
export declare function normalizeSpeed(speed: number): number;
|
|
68
|
+
//# sourceMappingURL=coordinates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinates.d.ts","sourceRoot":"","sources":["../../src/utils/coordinates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B,yCAAyC;;IAEzC,yCAAyC;;IAEzC,yCAAyC;;IAEzC,yCAAyC;;CAEjC,CAAC;AAQX;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAOvE;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAahD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coordinate normalization and validation utilities
|
|
3
|
+
* @module utils/coordinates
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Lithuania's geographic bounding box in WGS84 decimal degrees.
|
|
7
|
+
* Used to validate coordinates are within expected range.
|
|
8
|
+
*/
|
|
9
|
+
export const LITHUANIA_BOUNDS = {
|
|
10
|
+
/** Minimum latitude (southern border) */
|
|
11
|
+
latMin: 53.89,
|
|
12
|
+
/** Maximum latitude (northern border) */
|
|
13
|
+
latMax: 56.45,
|
|
14
|
+
/** Minimum longitude (western border) */
|
|
15
|
+
lonMin: 20.93,
|
|
16
|
+
/** Maximum longitude (eastern border) */
|
|
17
|
+
lonMax: 26.83,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Coordinate divisor for stops.lt integer format.
|
|
21
|
+
* Raw coordinates are multiplied by 1,000,000 to avoid floating point.
|
|
22
|
+
*/
|
|
23
|
+
const COORDINATE_DIVISOR = 1_000_000;
|
|
24
|
+
/**
|
|
25
|
+
* Normalize a raw integer coordinate to WGS84 decimal degrees.
|
|
26
|
+
*
|
|
27
|
+
* @param raw - Raw coordinate as integer (e.g., 25255492 for ~25.255492°)
|
|
28
|
+
* @returns Normalized coordinate in decimal degrees
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* normalizeCoordinate(25255492) // => 25.255492
|
|
32
|
+
* normalizeCoordinate(54633886) // => 54.633886
|
|
33
|
+
*/
|
|
34
|
+
export function normalizeCoordinate(raw) {
|
|
35
|
+
return raw / COORDINATE_DIVISOR;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if coordinates fall within Lithuania's bounding box.
|
|
39
|
+
*
|
|
40
|
+
* @param lat - Latitude in WGS84 decimal degrees
|
|
41
|
+
* @param lon - Longitude in WGS84 decimal degrees
|
|
42
|
+
* @returns true if coordinates are within Lithuania
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* isValidLithuaniaCoord(54.687, 25.279) // => true (Vilnius)
|
|
46
|
+
* isValidLithuaniaCoord(48.856, 2.352) // => false (Paris)
|
|
47
|
+
*/
|
|
48
|
+
export function isValidLithuaniaCoord(lat, lon) {
|
|
49
|
+
return (lat >= LITHUANIA_BOUNDS.latMin &&
|
|
50
|
+
lat <= LITHUANIA_BOUNDS.latMax &&
|
|
51
|
+
lon >= LITHUANIA_BOUNDS.lonMin &&
|
|
52
|
+
lon <= LITHUANIA_BOUNDS.lonMax);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate and normalize raw integer coordinates.
|
|
56
|
+
* Returns null if coordinates are invalid or outside Lithuania.
|
|
57
|
+
*
|
|
58
|
+
* @param rawLat - Raw latitude as integer
|
|
59
|
+
* @param rawLon - Raw longitude as integer
|
|
60
|
+
* @returns Object with normalized lat/lon, or null if invalid
|
|
61
|
+
*/
|
|
62
|
+
export function normalizeAndValidateCoordinates(rawLat, rawLon) {
|
|
63
|
+
if (!Number.isFinite(rawLat) || !Number.isFinite(rawLon)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const latitude = normalizeCoordinate(rawLat);
|
|
67
|
+
const longitude = normalizeCoordinate(rawLon);
|
|
68
|
+
if (!isValidLithuaniaCoord(latitude, longitude)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return { latitude, longitude };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Normalize bearing to 0-359 range.
|
|
75
|
+
*
|
|
76
|
+
* @param bearing - Raw bearing value
|
|
77
|
+
* @returns Normalized bearing in degrees
|
|
78
|
+
*/
|
|
79
|
+
export function normalizeBearing(bearing) {
|
|
80
|
+
if (!Number.isFinite(bearing)) {
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
// Handle negative values and wrap around
|
|
84
|
+
return ((bearing % 360) + 360) % 360;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Normalize speed to non-negative value.
|
|
88
|
+
*
|
|
89
|
+
* @param speed - Raw speed value
|
|
90
|
+
* @returns Speed in km/h, minimum 0
|
|
91
|
+
*/
|
|
92
|
+
export function normalizeSpeed(speed) {
|
|
93
|
+
if (!Number.isFinite(speed) || speed < 0) {
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
return speed;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=coordinates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinates.js","sourceRoot":"","sources":["../../src/utils/coordinates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,yCAAyC;IACzC,MAAM,EAAE,KAAK;IACb,yCAAyC;IACzC,MAAM,EAAE,KAAK;IACb,yCAAyC;IACzC,MAAM,EAAE,KAAK;IACb,yCAAyC;IACzC,MAAM,EAAE,KAAK;CACL,CAAC;AAEX;;;GAGG;AACH,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAErC;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG,GAAG,kBAAkB,CAAC;AAClC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW,EAAE,GAAW;IAC5D,OAAO,CACL,GAAG,IAAI,gBAAgB,CAAC,MAAM;QAC9B,GAAG,IAAI,gBAAgB,CAAC,MAAM;QAC9B,GAAG,IAAI,gBAAgB,CAAC,MAAM;QAC9B,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAC/B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAC7C,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE9C,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,yCAAyC;IACzC,OAAO,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text encoding utilities for handling Windows-1257 and mojibake repair
|
|
3
|
+
* @module utils/encoding
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Attempt to repair mojibake (garbled text) caused by encoding mismatches.
|
|
7
|
+
* Common when Windows-1257 encoded text is read as UTF-8.
|
|
8
|
+
*
|
|
9
|
+
* @param text - Potentially corrupted text
|
|
10
|
+
* @returns Repaired text with Lithuanian characters restored
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* repairMojibake('Autobusų parkas(EiÅ¡iÅ¡kių pl.)')
|
|
14
|
+
* // => 'Autobusų parkas(Eišiškių pl.)'
|
|
15
|
+
*/
|
|
16
|
+
export declare function repairMojibake(text: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Check if text contains likely mojibake patterns.
|
|
19
|
+
*
|
|
20
|
+
* @param text - Text to check
|
|
21
|
+
* @returns true if mojibake patterns detected
|
|
22
|
+
*/
|
|
23
|
+
export declare function hasMojibake(text: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Decode a byte array from Windows-1257 (Baltic) encoding to UTF-8 string.
|
|
26
|
+
*
|
|
27
|
+
* @param bytes - Raw bytes in Windows-1257 encoding
|
|
28
|
+
* @returns Decoded UTF-8 string
|
|
29
|
+
*/
|
|
30
|
+
export declare function decodeWindows1257(bytes: Uint8Array): string;
|
|
31
|
+
/**
|
|
32
|
+
* Decode text from an ArrayBuffer, trying UTF-8 first, then falling back
|
|
33
|
+
* to Windows-1257 if mojibake is detected.
|
|
34
|
+
*
|
|
35
|
+
* @param buffer - Raw data buffer
|
|
36
|
+
* @returns Properly decoded string
|
|
37
|
+
*/
|
|
38
|
+
export declare function decodeBalticText(buffer: ArrayBuffer): string;
|
|
39
|
+
/**
|
|
40
|
+
* Clean and normalize a text field from transport data.
|
|
41
|
+
* Handles encoding issues and trims whitespace.
|
|
42
|
+
*
|
|
43
|
+
* @param text - Raw text field
|
|
44
|
+
* @returns Cleaned text
|
|
45
|
+
*/
|
|
46
|
+
export declare function cleanTextField(text: string): string;
|
|
47
|
+
//# sourceMappingURL=encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/utils/encoding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoCH;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjD;AAyBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAe3D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAoB5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnD"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text encoding utilities for handling Windows-1257 and mojibake repair
|
|
3
|
+
* @module utils/encoding
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Common mojibake patterns when Windows-1257 text is incorrectly decoded as UTF-8.
|
|
7
|
+
* Maps corrupted sequences to correct Lithuanian characters.
|
|
8
|
+
*/
|
|
9
|
+
const MOJIBAKE_REPAIRS = new Map([
|
|
10
|
+
// Lowercase Lithuanian letters
|
|
11
|
+
['Ä…', 'ą'],
|
|
12
|
+
['ć', 'ć'], // Not Lithuanian but may appear
|
|
13
|
+
['Ä—', 'ė'],
|
|
14
|
+
['Ä™', 'ę'], // Not Lithuanian but may appear
|
|
15
|
+
['į', 'į'],
|
|
16
|
+
['Å¡', 'š'],
|
|
17
|
+
['ų', 'ų'],
|
|
18
|
+
['Å«', 'ū'],
|
|
19
|
+
['ž', 'ž'],
|
|
20
|
+
// Uppercase Lithuanian letters
|
|
21
|
+
['Ä„', 'Ą'],
|
|
22
|
+
['Ć', 'Ć'], // Not Lithuanian but may appear
|
|
23
|
+
['Ä–', 'Ė'],
|
|
24
|
+
['Ę', 'Ę'], // Not Lithuanian but may appear
|
|
25
|
+
['Ä®', 'Į'],
|
|
26
|
+
['Å ', 'Š'],
|
|
27
|
+
['Ų', 'Ų'],
|
|
28
|
+
['Ū', 'Ū'],
|
|
29
|
+
['Ž', 'Ž'],
|
|
30
|
+
// Additional patterns that may occur
|
|
31
|
+
['è', 'č'],
|
|
32
|
+
['Ã ', 'ę'],
|
|
33
|
+
['Å„', 'ń'],
|
|
34
|
+
['Ä', 'č'], // Sometimes Ä alone appears for č
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Attempt to repair mojibake (garbled text) caused by encoding mismatches.
|
|
38
|
+
* Common when Windows-1257 encoded text is read as UTF-8.
|
|
39
|
+
*
|
|
40
|
+
* @param text - Potentially corrupted text
|
|
41
|
+
* @returns Repaired text with Lithuanian characters restored
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* repairMojibake('Autobusų parkas(EiÅ¡iÅ¡kių pl.)')
|
|
45
|
+
* // => 'Autobusų parkas(Eišiškių pl.)'
|
|
46
|
+
*/
|
|
47
|
+
export function repairMojibake(text) {
|
|
48
|
+
let result = text;
|
|
49
|
+
for (const [corrupted, correct] of MOJIBAKE_REPAIRS) {
|
|
50
|
+
// Use global replace for all occurrences
|
|
51
|
+
result = result.split(corrupted).join(correct);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if text contains likely mojibake patterns.
|
|
57
|
+
*
|
|
58
|
+
* @param text - Text to check
|
|
59
|
+
* @returns true if mojibake patterns detected
|
|
60
|
+
*/
|
|
61
|
+
export function hasMojibake(text) {
|
|
62
|
+
for (const corrupted of MOJIBAKE_REPAIRS.keys()) {
|
|
63
|
+
if (text.includes(corrupted)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Windows-1257 (Baltic) code page byte-to-character mapping.
|
|
71
|
+
* Only maps bytes 128-255; 0-127 are identical to ASCII.
|
|
72
|
+
*/
|
|
73
|
+
const WINDOWS_1257_MAP = [
|
|
74
|
+
// 0x80-0x8F
|
|
75
|
+
'\u20AC', '', '\u201A', '', '\u201E', '\u2026', '\u2020', '\u2021', '', '\u2030', '', '\u2039', '', '\u00A8', '\u02C7', '\u00B8',
|
|
76
|
+
// 0x90-0x9F
|
|
77
|
+
'', '\u2018', '\u2019', '\u201C', '\u201D', '\u2022', '\u2013', '\u2014', '', '\u2122', '', '\u203A', '', '\u00AF', '\u02DB', '',
|
|
78
|
+
// 0xA0-0xAF
|
|
79
|
+
'\u00A0', '', '\u00A2', '\u00A3', '\u00A4', '', '\u00A6', '\u00A7', '\u00D8', '\u00A9', '\u0156', '\u00AB', '\u00AC', '\u00AD', '\u00AE', '\u00C6',
|
|
80
|
+
// 0xB0-0xBF
|
|
81
|
+
'\u00B0', '\u00B1', '\u00B2', '\u00B3', '\u00B4', '\u00B5', '\u00B6', '\u00B7', '\u00F8', '\u00B9', '\u0157', '\u00BB', '\u00BC', '\u00BD', '\u00BE', '\u00E6',
|
|
82
|
+
// 0xC0-0xCF
|
|
83
|
+
'\u0104', '\u012E', '\u0100', '\u0106', '\u00C4', '\u00C5', '\u0118', '\u0112', '\u010C', '\u00C9', '\u0179', '\u0116', '\u0122', '\u0136', '\u012A', '\u013B',
|
|
84
|
+
// 0xD0-0xDF
|
|
85
|
+
'\u0160', '\u0143', '\u0145', '\u00D3', '\u014C', '\u00D5', '\u00D6', '\u00D7', '\u0172', '\u0141', '\u015A', '\u016A', '\u00DC', '\u017B', '\u017D', '\u00DF',
|
|
86
|
+
// 0xE0-0xEF
|
|
87
|
+
'\u0105', '\u012F', '\u0101', '\u0107', '\u00E4', '\u00E5', '\u0119', '\u0113', '\u010D', '\u00E9', '\u017A', '\u0117', '\u0123', '\u0137', '\u012B', '\u013C',
|
|
88
|
+
// 0xF0-0xFF
|
|
89
|
+
'\u0161', '\u0144', '\u0146', '\u00F3', '\u014D', '\u00F5', '\u00F6', '\u00F7', '\u0173', '\u0142', '\u015B', '\u016B', '\u00FC', '\u017C', '\u017E', '\u02D9',
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Decode a byte array from Windows-1257 (Baltic) encoding to UTF-8 string.
|
|
93
|
+
*
|
|
94
|
+
* @param bytes - Raw bytes in Windows-1257 encoding
|
|
95
|
+
* @returns Decoded UTF-8 string
|
|
96
|
+
*/
|
|
97
|
+
export function decodeWindows1257(bytes) {
|
|
98
|
+
const chars = [];
|
|
99
|
+
for (const byte of bytes) {
|
|
100
|
+
if (byte < 128) {
|
|
101
|
+
// ASCII range - direct mapping
|
|
102
|
+
chars.push(String.fromCharCode(byte));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Extended range - use Windows-1257 mapping
|
|
106
|
+
const mapped = WINDOWS_1257_MAP[byte - 128];
|
|
107
|
+
chars.push(mapped !== undefined && mapped !== '' ? mapped : '?');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return chars.join('');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Decode text from an ArrayBuffer, trying UTF-8 first, then falling back
|
|
114
|
+
* to Windows-1257 if mojibake is detected.
|
|
115
|
+
*
|
|
116
|
+
* @param buffer - Raw data buffer
|
|
117
|
+
* @returns Properly decoded string
|
|
118
|
+
*/
|
|
119
|
+
export function decodeBalticText(buffer) {
|
|
120
|
+
const bytes = new Uint8Array(buffer);
|
|
121
|
+
// First, try UTF-8 decoding
|
|
122
|
+
const decoder = new TextDecoder('utf-8', { fatal: false });
|
|
123
|
+
let text = decoder.decode(bytes);
|
|
124
|
+
// Check for mojibake patterns
|
|
125
|
+
if (hasMojibake(text)) {
|
|
126
|
+
// Try to repair the mojibake
|
|
127
|
+
text = repairMojibake(text);
|
|
128
|
+
}
|
|
129
|
+
// If still looks corrupted, try Windows-1257 directly
|
|
130
|
+
// (Check for remaining replacement characters or known patterns)
|
|
131
|
+
if (text.includes('\uFFFD') || /[\x80-\x9F]/.test(text)) {
|
|
132
|
+
text = decodeWindows1257(bytes);
|
|
133
|
+
}
|
|
134
|
+
return text;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Clean and normalize a text field from transport data.
|
|
138
|
+
* Handles encoding issues and trims whitespace.
|
|
139
|
+
*
|
|
140
|
+
* @param text - Raw text field
|
|
141
|
+
* @returns Cleaned text
|
|
142
|
+
*/
|
|
143
|
+
export function cleanTextField(text) {
|
|
144
|
+
if (!text)
|
|
145
|
+
return '';
|
|
146
|
+
// Repair any mojibake
|
|
147
|
+
let cleaned = repairMojibake(text.trim());
|
|
148
|
+
// Remove any control characters (ASCII 0-31 and 127)
|
|
149
|
+
// eslint-disable-next-line no-control-regex
|
|
150
|
+
cleaned = cleaned.replace(/[\x00-\x1F\x7F]/g, '');
|
|
151
|
+
return cleaned;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=encoding.js.map
|