"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * Returns a cloned copy of the passed GeoJSON Object, including possible 'Foreign Members'. * ~3-5x faster than the common JSON.parse + JSON.stringify combo method. * * @name clone * @param {GeoJSON} geojson GeoJSON Object * @returns {GeoJSON} cloned GeoJSON Object * @example * var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]], {color: 'red'}); * * var lineCloned = turf.clone(line); */ function clone(geojson) { if (!geojson) { throw new Error("geojson is required"); } switch (geojson.type) { case "Feature": return cloneFeature(geojson); case "FeatureCollection": return cloneFeatureCollection(geojson); case "Point": case "LineString": case "Polygon": case "MultiPoint": case "MultiLineString": case "MultiPolygon": case "GeometryCollection": return cloneGeometry(geojson); default: throw new Error("unknown GeoJSON type"); } } /** * Clone Feature * * @private * @param {Feature} geojson GeoJSON Feature * @returns {Feature} cloned Feature */ function cloneFeature(geojson) { var cloned = { type: "Feature" }; // Preserve Foreign Members Object.keys(geojson).forEach(function (key) { switch (key) { case "type": case "properties": case "geometry": return; default: cloned[key] = geojson[key]; } }); // Add properties & geometry last cloned.properties = cloneProperties(geojson.properties); cloned.geometry = cloneGeometry(geojson.geometry); return cloned; } /** * Clone Properties * * @private * @param {Object} properties GeoJSON Properties * @returns {Object} cloned Properties */ function cloneProperties(properties) { var cloned = {}; if (!properties) { return cloned; } Object.keys(properties).forEach(function (key) { var value = properties[key]; if (typeof value === "object") { if (value === null) { // handle null cloned[key] = null; } else if (Array.isArray(value)) { // handle Array cloned[key] = value.map(function (item) { return item; }); } else { // handle generic Object cloned[key] = cloneProperties(value); } } else { cloned[key] = value; } }); return cloned; } /** * Clone Feature Collection * * @private * @param {FeatureCollection} geojson GeoJSON Feature Collection * @returns {FeatureCollection} cloned Feature Collection */ function cloneFeatureCollection(geojson) { var cloned = { type: "FeatureCollection" }; // Preserve Foreign Members Object.keys(geojson).forEach(function (key) { switch (key) { case "type": case "features": return; default: cloned[key] = geojson[key]; } }); // Add features cloned.features = geojson.features.map(function (feature) { return cloneFeature(feature); }); return cloned; } /** * Clone Geometry * * @private * @param {Geometry} geometry GeoJSON Geometry * @returns {Geometry} cloned Geometry */ function cloneGeometry(geometry) { var geom = { type: geometry.type }; if (geometry.bbox) { geom.bbox = geometry.bbox; } if (geometry.type === "GeometryCollection") { geom.geometries = geometry.geometries.map(function (g) { return cloneGeometry(g); }); return geom; } geom.coordinates = deepSlice(geometry.coordinates); return geom; } /** * Deep Slice coordinates * * @private * @param {Coordinates} coords Coordinates * @returns {Coordinates} all coordinates sliced */ function deepSlice(coords) { var cloned = coords; if (typeof cloned[0] !== "object") { return cloned.slice(); } return cloned.map(function (coord) { return deepSlice(coord); }); } exports.default = clone;