Source: border.js

import { check } from "./helpers/check.js";
import { topology } from "topojson-server";
import { neighbors, mesh } from "topojson-client";
const topojson = Object.assign({}, { topology, neighbors, mesh });
import * as d3array from "d3-array";
const d3 = Object.assign({}, d3array);

/**
 * @function border
 * @summary Extract boundaries from a GeoJSON FeatureCollection
 * @description Based on `topojson.mesh()` and `topojson.neighbors()`
 * @param {object|array} data - A GeoJSON FeatureCollection, an array of features, an array of geometries, a single feature or a single geometry.
 * @param {object} options - Optional parameters.
 * @param {boolean} [options.id = false] - If you don't provide an id field (default), then the function returns a geoJSON with a single geometry. If you choose an id field, the function returns a geoJSON with multiple geometries and associated codes (two ids for each geometry).
 * @returns {object|array} - A GeoJSON FeatureCollection, an array of features, an array of geometries, a single feature or a single geometry (it depends on what you've set as `data`).
 * @example
 * geotoolbox.border(*a geojson*, {id: "ISO3"})
 */
export function border(data, { id } = {}) {
  const handle = check(data);
  let x = handle.import(data);
  const topo = topojson.topology({ d: x });

  // With ids
  if (typeof id === "string" && id !== "") {
    const ids = [...new Set(x.features.map((d) => d?.properties[id]))].filter(
      (d) => ![null, undefined, ""].includes(d)
    );
    const neighbors = topojson.neighbors(topo.objects["d"].geometries);
    let result = [];
    ids.forEach((e) => {
      let r = neighbors[ids.indexOf(e)].map((i) => ({
        type: "Feature",
        properties: {
          id: e.toString() + "|" + ids[i].toString(),
          i: e,
          j: ids[i],
        },
        geometry: topojson.mesh(
          topo,
          topo.objects["d"],
          (a, b) => (a.properties[id] == e) & (b.properties[id] == ids[i])
        ),
      }));
      result.push(r);
    });

    x.features = result.flat();
  } else {
    x.features = [
      {
        type: "Feature",
        properties: {},
        geometry: topojson.mesh(
          topo,
          Object.entries(topo.objects)[0][1],
          (a, b) => a !== b
        ),
      },
    ];
  }
  x.name = "border";
  return handle.export(x);
}