-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate.js
More file actions
117 lines (98 loc) · 3.6 KB
/
validate.js
File metadata and controls
117 lines (98 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { normalizeFeature } from './normalize.js';
/**
* Validates a GeoJSON file.
*
* @param {object} geojson - Parsed GeoJSON object.
* @returns {boolean} - True if valid, throws an error otherwise.
*/
export function validateGeoJSON(geojson) {
if (!geojson) {
throw new Error("No data provided. Please provide a valid GeoJSON object.");
}
if (geojson.type !== 'FeatureCollection') {
throw new Error("Invalid GeoJSON format. Must be a 'FeatureCollection'.");
}
if (!Array.isArray(geojson.features) || geojson.features.length === 0) {
throw new Error("GeoJSON must contain at least one feature.");
}
geojson.features.forEach(feature => {
const normalizedFeature = normalizeFeature(feature);
validateFeature(normalizedFeature);
});
return true;
}
/**
* Single GeoJSON feature validation.
*
* @param {object} feature - GeoJSON feature to validate.
* @throws Error if the feature is invalid.
*/
export function validateFeature(feature) {
if (!feature || feature.type !== 'Feature') {
throw new Error("Invalid feature format. Each feature must have type 'Feature'.");
}
if (!feature.geometry || !validateGeometry(feature.geometry)) {
throw new Error(`Feature ${feature.id || 'without ID'} has an invalid or missing geometry.`);
}
if (!feature.properties || typeof feature.properties !== 'object') {
throw new Error(`Feature ${feature.id || 'without ID'} has invalid or missing properties.`);
}
if (!feature.id || typeof feature.id !== 'string') {
throw new Error(`Feature ${feature.id} has an invalid ID.`);
}
}
/**
* Geometry validation.
*
* @param {object} geometry - GeoJSON geometry object.
* @returns {boolean} - True if geometry is valid.
*/
export function validateGeometry(geometry) {
if (!geometry.type) {
throw new Error("Geometry is missing the 'type' field.");
}
const validTypes = ['Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon'];
if (!validTypes.includes(geometry.type)) {
throw new Error(`Invalid geometry type: ${geometry.type}.`);
}
if (!Array.isArray(geometry.coordinates)) {
throw new Error("Geometry is missing valid 'coordinates'.");
}
return validateCoordinates(geometry.coordinates, geometry.type);
}
/**
* Coordinates validation (based on geometry type).
*
* @param {Array} coordinates - Coordinates array.
* @param {string} type - Geometry type.
* @returns {boolean} - True if coordinates are valid.
*/
export function validateCoordinates(coordinates, type) {
switch (type) {
case 'Point':
if (coordinates.length !== 2) {
throw new Error("Point geometry must have exactly 2 coordinates.");
}
return validLatitude(coordinates[1]) && validLongitude(coordinates[0]);
case 'LineString':
case 'Polygon':
if (!coordinates.every(coord => Array.isArray(coord) && coord.length === 2)) {
throw new Error(`${type} must have valid 2D coordinate arrays.`);
}
return coordinates.every(coord => validLatitude(coord[1]) && validLongitude(coord[0]));
default:
throw new Error(`Unsupported geometry type: ${type}.`);
}
}
function validLatitude(lat) {
return lat >= -90 && lat <= 90;
}
function validLongitude(lon) {
return lon >= -180 && lon <= 180;
}