{
  "version": 3,
  "sources": ["../../src/location-conflation.ts"],
  "sourcesContent": [
    "import * as CountryCoder from '@rapideditor/country-coder';\nimport * as Polyclip from 'polyclip-ts';\nimport calcArea from '@mapbox/geojson-area';\nimport circleToPolygon from 'circle-to-polygon';\nimport precision from 'geojson-precision';\nimport prettyStringify from 'json-stringify-pretty-compact';\nimport whichPolygon from 'which-polygon';\nimport type { Geom } from 'polyclip-ts';\n\nimport type {\n  HasLocationSet,\n  HasLocationSetID,\n  LocoFeature,\n  LocoProperties,\n  Location,\n  LocationID,\n  LocationSet,\n  LocationSetID,\n  ResolvedLocation,\n  ResolvedLocationSet,\n  StringifyOptions,\n  ValidatedLocation,\n  ValidatedLocationSet,\n  Vec2,\n} from './types.ts';\n\n\n// Re-export everything from types.ts so consumers can `import { … } from '@rapideditor/location-conflation'`\nexport type * from './types.ts';\n\n\n\n/**\n * LocationConflation lets you define complex geographic regions by including and\n * excluding country codes, points, and custom `.geojson` shapes.\n *\n * It resolves these definitions into GeoJSON `Feature`s with polygon geometries,\n * caching expensive polygon-clipping operations for performance.\n *\n * @example\n * ```ts\n * import { LocationConflation } from '@rapideditor/location-conflation';\n *\n * const loco = new LocationConflation(myFeatureCollection);\n *\n * const result = loco.resolveLocationSet({ include: ['de'], exclude: ['de-berlin.geojson'] });\n * console.log(result.feature);  // GeoJSON Feature of Germany minus Berlin\n * ```\n */\nexport class LocationConflation {\n  /**\n   * Internal cache of all resolved features, keyed by stable identifiers.\n   * Identifiers look like:\n   * - `'[8.67039,49.41882]'` — point locations\n   * - `'de-hamburg.geojson'` — geojson file locations\n   * - `'Q2'` — country-coder locations (Wikidata QIDs)\n   * - `'+[Q2]-[Q18,Q27611]'` — aggregated location sets\n   */\n  private _resolved: Map<LocationID | LocationSetID, LocoFeature>;\n\n  // Internal cache of registered LocationSetID → approximate area in km²\n  private _registered: Map<LocationSetID, number>;\n\n  // Spatial index state, built by `registerLocationSets()` and rebuilt by `rebuildIndex()`.\n  // Inverted index: locationID → Set of locationSetIDs that include/exclude that component location.\n  // Reads as English: \"the sets including this location\" / \"the sets excluding this location\".\n  private _setsIncluding: Map<LocationID, Set<LocationSetID>>;\n  private _setsExcluding: Map<LocationID, Set<LocationSetID>>;\n\n  // A `WhichPolygon` spatial index for custom .geojson and point-radius features only.\n  // CountryCoder regions are looked up via CountryCoder's own spatial index.\n  private _spatialIndex: ReturnType<typeof whichPolygon<{ id: string }>> | null;\n\n\n  /**\n   * @constructor\n   * Creates a new LocationConflation instance.\n   * @param fc - Optional GeoJSON FeatureCollection of known features with filename-like IDs\n   *   (e.g. `\"something.geojson\"`).  Accepts a standard `GeoJSON.FeatureCollection` from\n   *   `@types/geojson` — no casts needed.  Features without a `.geojson` id are silently skipped.\n   */\n  constructor(fc?: GeoJSON.FeatureCollection) {\n    this._resolved = new Map();\n    this._registered = new Map();\n    this._setsIncluding = new Map();\n    this._setsExcluding = new Map();\n    this._spatialIndex = null;\n\n    // Load any .geojson features from the input FeatureCollection.\n    if (fc) {\n      this.addFeatures(fc);\n    }\n\n    this._setupWorld();  // will also call rebuildIndex()\n  }\n\n\n  /**\n   * Setup the world objects.\n   * This ensures that we both have our world location and world locationSet available.\n   *\n   * Calling `registerLocationSets` is important here because allows `locationSetsAt`\n   * to return the world locationSet, even if no locationSets have been otherwise registered.\n   */\n  private _setupWorld(): void {\n    // Note that CountryCoder's \"world\" is an aggregate of its administrative boundaries.\n    // (It excludes regions like the north pole or ocean.)\n    // What we want for our purposes is a polygon that covers the entire world.\n    const WORLD_GEOMETRY: GeoJSON.Polygon = {\n      type: 'Polygon',\n      coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]],\n    };\n\n    // 'Q2' - A Location representing the entire world.\n    const WORLD_LOCATION: LocoFeature = {\n      type: 'Feature',\n      id: 'Q2',\n      properties: { id: 'Q2', area: _getArea(WORLD_GEOMETRY) },\n      geometry: WORLD_GEOMETRY\n    };\n\n    // '+[Q2]' - A LocationSet that just includes the entire world.\n    const WORLD_LOCATIONSET: HasLocationSet = {\n      locationSet: { include: ['Q2'] }\n    };\n\n    this._resolved.set('Q2', WORLD_LOCATION);\n    this.registerLocationSets([WORLD_LOCATIONSET]);  // will also call rebuildIndex()\n  }\n\n\n  /**\n   * Returns whether a coordinate pair is within valid WGS84 bounds.\n   */\n  private _isValidPoint(loc: Vec2): boolean {\n    const [lon, lat] = loc;\n    return (\n      Number.isFinite(lon) && lon >= -180 && lon <= 180 &&\n      Number.isFinite(lat) && lat >= -90  && lat <= 90\n    );\n  }\n\n\n  /**\n   * Adds `.geojson` features to the cache of known locations.\n   *\n   * Each feature must have a filename-like `id` ending in `.geojson` (either on\n   * the feature itself or in its `properties`).  Features without a qualifying\n   * `id` are silently skipped.\n   *\n   * The method normalizes each feature into the {@link LocoFeature} shape\n   * (lowercased id, guaranteed `area` property, polygon geometry).  If a\n   * feature with the same id already exists in the cache, it is replaced.\n   *\n   * @param fc - A GeoJSON FeatureCollection containing custom locations.\n   *   Accepts a standard `GeoJSON.FeatureCollection` — no casts needed.\n   *\n   * @example\n   * ```ts\n   * // Load additional features after construction\n   * const loco = new LocationConflation();\n   * loco.addFeatures(additionalFeatureCollection);\n   *\n   * // Now these features are available for resolving\n   * const result = loco.resolveLocation('philly_metro.geojson');\n   * ```\n   */\n  addFeatures(fc: GeoJSON.FeatureCollection): void {\n    if (fc?.type !== 'FeatureCollection' || !Array.isArray(fc.features)) return;\n\n    for (const feature of fc.features) {\n      const props = feature.properties ?? {};\n\n      // Get `id` from either `id` or `properties.id`.\n      // Features without a valid id are silently skipped.\n      let id = feature.id ?? props['id'];\n      if (!id || !/^\\S+\\.geojson$/i.test(String(id))) continue;\n\n      // Ensure `id` exists and is lowercase\n      id = String(id).toLowerCase();\n\n      const geometry = feature.geometry as GeoJSON.Polygon | GeoJSON.MultiPolygon;\n\n      // Ensure `area` property exists.\n      // The purpose of the `area` property is to enable rough size comparisons.\n      const existingArea = props['area'] as number | undefined;\n      const area = existingArea || _getArea(geometry);\n\n      const lcFeature: LocoFeature = {\n        type: 'Feature',\n        id,\n        properties: { ...props, id, area } as LocoProperties,\n        geometry,\n      };\n\n      this._resolved.set(id, lcFeature);\n    }\n\n    this.rebuildIndex();   // Need to rebuild the index after adding new locations.\n  }\n\n\n  /**\n   * Removes `.geojson` features from the cache by id.\n   * Each id should be a filename-like string ending in `.geojson`.\n   * Ids are matched case-insensitively (lowercased before lookup).\n   * Non-`.geojson` ids and ids not present in the cache are silently ignored.\n   *\n   * @param ids - One or more feature ids to remove.\n   *\n   * @example\n   * ```ts\n   * loco.removeFeatures('philly_metro.geojson', 'dc_metro.geojson');\n   * ```\n   */\n  removeFeatures(...ids: string[]): void {\n    for (const id of ids) {\n      if (!/^\\S+\\.geojson$/i.test(id)) continue;\n      this._resolved.delete(id.toLowerCase());\n    }\n\n    this.rebuildIndex();   // Need to rebuild the index after removing locations.\n  }\n\n\n  /**\n   * Removes all cached resolved features.\n   * This clears everything from the resolved cache — `.geojson` features, resolved\n   * country-coder features, point circles, and aggregated location sets.\n   * The world feature ('Q2') is re-added automatically.\n   *\n   * @example\n   * ```ts\n   * loco.clearFeatures();\n   * // Cache now contains only the world feature (Q2)\n   * ```\n   */\n  clearFeatures(): void {\n    this._resolved.clear();\n    this._setupWorld();  // will also call rebuildIndex()\n  }\n\n\n  /**\n   * Backward-compatibility alias to direct access the internal resolved-feature cache.\n   * If you use this to change the features, make sure to call `rebuildIndex()` after.\n   * @deprecated Use the LocationConflation cache management APIs instead (`addFeatures`, `removeFeatures`, `clearFeatures`).\n   */\n  public get _cache(): Map<string, LocoFeature> {\n    return this._resolved;\n  }\n\n\n  /**\n   * Validates a location and returns its type and stable identifier.\n   * @param location - Location to validate (point, geojson filename, or country code)\n   * @returns Validated location result object\n   * @throws  Throws Error if the given location is invalid.\n   *\n   * @example\n   * ```typescript\n   * // Point location with default 25km radius\n   * loco.validateLocation([8.67039, 49.41882]);\n   * // => { type: 'point', location: [8.67039, 49.41882], id: '[8.67039,49.41882]' }\n   *\n   * // Point location with custom radius\n   * loco.validateLocation([-77.0369, 38.9072, 10]);\n   * // => { type: 'point', location: [-77.0369, 38.9072, 10], id: '[-77.0369,38.9072,10]' }\n   *\n   * // Country code\n   * loco.validateLocation('de');\n   * // => { type: 'countrycoder', location: 'de', id: 'Q183' }\n  * loco.validateLocation('001');\n  * // => { type: 'countrycoder', location: '001', id: 'Q2' }\n   *\n   * // GeoJSON file\n   * loco.validateLocation('philly_metro.geojson');\n   * // => { type: 'geojson', location: 'philly_metro.geojson', id: 'philly_metro.geojson' }\n   * ```\n   */\n  validateLocation(location: Location): ValidatedLocation {\n    // A [lon, lat] or [lon, lat, radius] point?\n    if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {\n      const lon = location[0];\n      const lat = location[1];\n      const radius = location[2];\n      if (\n        this._isValidPoint([lon, lat]) &&\n        (location.length === 2 || (radius !== undefined && Number.isFinite(radius) && radius > 0))\n      ) {\n        const id = '[' + location.toString() + ']';\n        return { type: 'point', location, id };\n      }\n\n    // A custom .geojson filename?\n    } else if (typeof location === 'string' && /^\\S+\\.geojson$/i.test(location)) {\n      const id = location.toLowerCase();\n      if (this._resolved.has(id)) {\n        return { type: 'geojson', location, id };\n      }\n\n    // A country-coder identifier?\n    } else if (typeof location === 'string' || typeof location === 'number') {\n      // a country-coder value?\n      const feature = CountryCoder.feature(location);\n      if (feature) {\n        // Normalize CountryCoder location id by using the returned Wikidata QID.\n        // It's the one property that everything in CountryCoder is guaranteed to have,\n        // and it allows us to match 'Q2' World and resolve it to our own world polygon.\n        const id = feature.properties.wikidata;\n        return { type: 'countrycoder', location, id };\n      }\n    }\n\n    throw new Error(`validateLocation:  Invalid location: \"${location}\".`);\n  }\n\n\n  /**\n   * Resolves a location to a GeoJSON Feature.\n   * @param location - Location to resolve\n   * @returns Resolved location result object, including the GeoJSON Feature\n   * @throws  Throws Error if the given location is invalid or cannot be resolved.\n   *\n   * @example\n   * ```typescript\n   * // Resolve a point location to a circular polygon\n   * const result = loco.resolveLocation([8.67039, 49.41882]);\n   * // result.feature is a GeoJSON Feature with a circular Polygon geometry\n   *\n   * // Resolve a country code\n   * const germany = loco.resolveLocation('de');\n   * // germany.feature is a GeoJSON Feature with Germany's boundary\n   *\n   * // Resolve a custom GeoJSON file\n   * const metro = loco.resolveLocation('philly_metro.geojson');\n   * // metro.feature is the pre-loaded GeoJSON Feature\n   * ```\n   */\n  resolveLocation(location: Location): ResolvedLocation {\n    const valid = this.validateLocation(location);\n    const id = valid.id;\n\n    // Return an already-resolved result from cache if we can.\n    // This will hit cache for:\n    // - all custom .geojson\n    // - previously generated point-radius\n    // - previously seen country coder locations\n    // - our custom 'Q2' World location\n    if (this._resolved.has(id)) {\n      return { ...valid, feature: this._resolved.get(id)! };\n    }\n\n    // A newly seen [lon, lat] or [lon, lat, radius] point?\n    if (valid.type === 'point' && Array.isArray(location)) {\n      const lon = location[0];\n      const lat = location[1];\n      const radius = location[2] || 25;  // km\n      const EDGES = 10;\n      const PRECISION = 3;\n      const area = Math.PI * radius * radius;   // km²\n      const feature: LocoFeature = precision(\n        {\n          type: 'Feature',\n          id,\n          properties: { id, area: Number(area.toFixed(2)) },\n          geometry: circleToPolygon([lon, lat], radius * 1000, EDGES),  // km to m\n        },\n        PRECISION\n      );\n      this._resolved.set(id, feature);\n      return { ...valid, feature };\n    }\n\n    // A newly seen country-coder identifier?\n    if (valid.type === 'countrycoder') {\n      // id is a wikidata QID that validateLocation already confirmed exists in CountryCoder\n      const ccFeature = CountryCoder.feature(id)!;\n      const ccProps = ccFeature.properties;\n      let geometry: GeoJSON.Polygon | GeoJSON.MultiPolygon | undefined;\n\n      // -> This block of code is weird and requires some explanation. <-\n      // CountryCoder includes higher level features which are made up of members.\n      // These features don't have their own geometry, but CountryCoder provides an\n      //   `aggregateFeature` method to combine these members into a MultiPolygon.\n      // In the past, Turf/JSTS/martinez could not handle the aggregated features,\n      //   so we'd iteratively union them all together.  (this was slow)\n      // But now mfogel/polygon-clipping handles these MultiPolygons like a boss.\n      // This approach also has the benefit of removing all the internal borders and\n      //   simplifying the regional polygons a lot.\n      if (Array.isArray(ccProps.members)) {\n        const aggregate = CountryCoder.aggregateFeature(id);\n        if (aggregate) {\n          const clipped = _clip([{\n            type: 'Feature',\n            id: '',\n            properties: {} as LocoProperties,\n            geometry: aggregate.geometry as GeoJSON.Polygon | GeoJSON.MultiPolygon,\n          }], 'UNION');\n          if (clipped) {\n            geometry = clipped.geometry;\n          }\n        }\n      }\n\n      // Clone geometry so we never hold a reference to CountryCoder's internal data.\n      // Skip the clone for aggregate features — clip() already produced a fresh geometry.\n      if (!geometry) {\n        geometry = structuredClone(ccFeature.geometry) as GeoJSON.Polygon | GeoJSON.MultiPolygon;\n      }\n\n      // Ensure `area` property exists\n      const area = _getArea(geometry);\n\n      const feature: LocoFeature = {\n        type: 'Feature',\n        id,\n        properties: { id, area } as LocoProperties,\n        geometry,\n      };\n\n      this._resolved.set(id, feature);\n      return { ...valid, feature };\n    }\n\n    throw new Error(`resolveLocation:  Couldn't resolve location \"${location}\".`);\n  }\n\n\n  /**\n   * Validates a locationSet and returns its stable identifier.\n   * @param locationSet - LocationSet with include/exclude arrays\n   * @returns Validated locationSet result object\n   * @throws  Throws Error if any referenced location is invalid, or locationSet has no include.\n   *\n   * @example\n   * ```typescript\n   * // Include multiple countries\n   * loco.validateLocationSet({ include: ['de', 'fr', 'it'] });\n   * // => { type: 'locationset', locationSet: {...}, id: '+[Q183,Q142,Q38]' }\n   *\n   * // Include with exclusions\n   * loco.validateLocationSet({\n   *   include: ['de'],\n   *   exclude: ['de-berlin.geojson']\n   * });\n   * // => { type: 'locationset', locationSet: {...}, id: '+[Q183]-[de-berlin.geojson]' }\n   *\n   * // Mix different location types\n   * loco.validateLocationSet({\n   *   include: ['us', [8.67039, 49.41882], 'philly_metro.geojson']\n   * });\n   * ```\n   */\n  validateLocationSet(locationSet?: LocationSet): ValidatedLocationSet {\n    locationSet = locationSet || {};\n    const validator = this.validateLocation.bind(this);\n    const include = (locationSet.include || []).map(validator) as ValidatedLocation[];\n    const exclude = (locationSet.exclude || []).map(validator) as ValidatedLocation[];\n\n    if (!include.length) {\n      throw new Error('validateLocationSet:  LocationSet includes nothing.');\n    }\n\n    // Generate stable identifier\n    include.sort(_sortLocations);\n    let id = '+[' + include.map((d) => d.id).join(',') + ']';\n    if (exclude.length) {\n      exclude.sort(_sortLocations);\n      id += '-[' + exclude.map((d) => d.id).join(',') + ']';\n    }\n\n    return { type: 'locationset', locationSet, id };\n  }\n\n\n  /**\n   * Resolves a locationSet to a GeoJSON Feature by combining included/excluded regions.\n   * @param locationSet - LocationSet with include/exclude arrays\n   * @returns Resolved locationSet result object, including the GeoJSON Feature\n   * @throws  Throws Error if any referenced location is invalid, or locationSet has no include.\n   *\n   * @example\n   * ```typescript\n   * // Combine multiple countries into one feature\n   * const benelux = loco.resolveLocationSet({\n   *   include: ['be', 'nl', 'lu']\n   * });\n   * // benelux.feature is a GeoJSON Feature with combined boundaries\n   *\n   * // Germany excluding Berlin\n   * const germanyNoCapital = loco.resolveLocationSet({\n   *   include: ['de'],\n   *   exclude: ['de-berlin.geojson']\n   * });\n   * // Result is Germany with Berlin cut out\n   *\n   * // Complex region definition\n   * const customRegion = loco.resolveLocationSet({\n   *   include: ['us-ca', 'us-or', 'us-wa'],\n   *   exclude: [[8.67039, 49.41882, 50]]\n   * });\n   * // West coast states minus a 50km circle\n   * ```\n   */\n  resolveLocationSet(locationSet?: LocationSet): ResolvedLocationSet {\n    locationSet = locationSet || {};\n    const valid = this.validateLocationSet(locationSet);\n    const id = valid.id;\n\n    // Return a result from cache if we can\n    if (this._resolved.has(id)) {\n      return { ...valid, feature: this._resolved.get(id)! };\n    }\n\n    const resolver = this.resolveLocation.bind(this);\n    const includes = (locationSet.include || []).map(resolver) as ResolvedLocation[];\n    const excludes = (locationSet.exclude || []).map(resolver) as ResolvedLocation[];\n\n    // Return quickly if it's just a single included location.\n    if (includes.length === 1 && excludes.length === 0) {\n      return { ...valid, feature: includes[0]!.feature };\n    }\n\n    // Calculate unions\n    const includeGeoJSON = _clip(includes.map((d) => d.feature), 'UNION')!;\n    const excludeGeoJSON = _clip(excludes.map((d) => d.feature), 'UNION');\n\n    // Calculate difference, update `area` and return result\n    const resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], 'DIFFERENCE')! : includeGeoJSON;\n    resultGeoJSON.id = id;\n    resultGeoJSON.properties = { id, area: _getArea(resultGeoJSON.geometry) };\n\n    this._resolved.set(id, resultGeoJSON);\n    return { ...valid, feature: resultGeoJSON };\n  }\n\n\n  /**\n   * Registers `locationSet`-bearing objects so that {@link locationSetsAt} can tell you\n   * which of them cover a given point.\n   *\n   * For each object, this method:\n   * 1. Validates the `locationSet` and assigns its stable `locationSetID` (e.g. `'+[Q183]'`).\n   * 2. Walks the `include` / `exclude` components and records them in an inverted index\n   *    (component `locationID` → set of `locationSetID`s that reference it).\n   * 3. Sums the approximate areas of the `include` components so results can be ranked\n   *    smallest-first.\n   *\n   * Unlike the single-item `validate*` / `resolve*` methods, this method is **tolerant** of\n   * bad input so that a batch of thousands of presets won't be rejected over a single typo:\n   * - Objects with a missing, empty, or invalid `locationSet` fall back to world (`+[Q2]`).\n   * - Individual invalid `include` / `exclude` components are silently ignored.\n   *\n   * This method **accumulates** — calling it multiple times (e.g. for different data sources)\n   * inserts all locationSets into the same index.  The spatial index is rebuilt automatically.\n   * To reset the index entirely, create a new `LocationConflation` instance.\n   *\n   * Note: this does **not** resolve each locationSet to a combined polygon — that expensive\n   * clipping step is deferred to {@link resolveLocationSet}, called only when the caller\n   * actually needs the GeoJSON geometry.\n   *\n   * @param objects - Objects with a `locationSet` property to index.\n   * @returns The same array of objects, narrowed to guarantee `locationSetID` is set.\n   *\n   * @example\n   * ```ts\n   * const presets = [\n   *   { id: 'amenity/cafe', locationSet: { include: ['de'] } },\n   *   { id: 'amenity/atm',  locationSet: { include: ['001'] } },\n   * ];\n   * loco.registerLocationSets(presets);\n   * // presets[0].locationSetID === '+[Q183]'\n   * // presets[1].locationSetID === '+[Q2]'\n   * ```\n   */\n  registerLocationSets<T extends HasLocationSet>(objects: T[]): (T & HasLocationSetID)[] {\n    if (!Array.isArray(objects)) return [];\n\n    for (const obj of objects) {\n      // Resolve the locationSet to a stable id; fall back to world on any problem\n      // (missing, empty include, or all-invalid components).\n      let locationSet: LocationSet = obj.locationSet ?? {};\n      let locationSetID: LocationSetID;\n      try {\n        locationSetID = this.validateLocationSet(locationSet).id;\n      } catch {\n        locationSet = { include: ['Q2'] };\n        locationSetID = '+[Q2]';\n      }\n      obj.locationSet = locationSet;\n      obj.locationSetID = locationSetID;\n\n      // If we've already registered this exact locationSetID, skip the inner work.\n      // The object has already gotten its locationSetID assigned above.\n      if (this._registered.has(locationSetID)) continue;\n\n      let area = 0;\n\n      for (const location of (locationSet.include ?? [])) {\n        // Silently skip invalid/unresolvable locations in batch mode.\n        let resolved: ResolvedLocation;\n        try {\n          resolved = this.resolveLocation(location);\n        } catch {\n          continue;\n        }\n        const locationID: LocationID = resolved.id;\n        area += resolved.feature.properties.area;\n\n        let s = this._setsIncluding.get(locationID);\n        if (!s) { s = new Set(); this._setsIncluding.set(locationID, s); }\n        s.add(locationSetID);\n      }\n\n      for (const location of (locationSet.exclude ?? [])) {\n        // Silently skip invalid/unresolvable locations in batch mode.\n        let resolved: ResolvedLocation;\n        try {\n          resolved = this.resolveLocation(location);\n        } catch {\n          continue;\n        }\n        const locationID: LocationID = resolved.id;\n\n        let s = this._setsExcluding.get(locationID);\n        if (!s) { s = new Set(); this._setsExcluding.set(locationID, s); }\n        s.add(locationSetID);\n      }\n\n      this._registered.set(locationSetID, area);\n    }\n\n    this.rebuildIndex();\n\n    return objects as unknown as (T & HasLocationSetID)[];\n  }\n\n\n  /**\n   * Rebuilds the internal spatial index from the current cache and inverted index.\n   *\n   * Normally you don't need to call this yourself — {@link registerLocationSets},\n   * {@link addFeatures}, {@link removeFeatures}, and {@link clearFeatures} all rebuild\n   * the index automatically when appropriate.  Call it manually only if you've mutated\n   * the cache through the (deprecated) `_cache` getter.\n   */\n  rebuildIndex(): void {\n    // Collect all unique component locationIDs referenced by the inverted index.\n    const allLocationIDs = new Set([\n      ...this._setsIncluding.keys(),\n      ...this._setsExcluding.keys(),\n    ]);\n\n    // Only custom .geojson features (ids ending in `.geojson`) and point-radius features\n    // (ids starting with `[`) go into our which-polygon index.  CountryCoder regions are\n    // deliberately skipped here because CountryCoder already provides its own optimized\n    // spatial index via `featuresContaining()`, which we use directly in `locationSetsAt`.\n    const features: Array<{ type: 'Feature'; geometry: GeoJSON.Polygon | GeoJSON.MultiPolygon; properties: { id: LocationID } }> = [];\n    for (const locationID of allLocationIDs) {\n      if (!locationID.startsWith('[') && !/\\.geojson$/i.test(locationID)) continue;\n\n      const feature = this._resolved.get(locationID);\n      if (feature) {\n        features.push({\n          type: 'Feature',\n          geometry: feature.geometry,\n          properties: { id: locationID },\n        });\n      }\n    }\n\n    this._spatialIndex = whichPolygon({ type: 'FeatureCollection', features });\n  }\n\n\n  /**\n   * Returns the registered locationSets that cover the given point,\n   * mapped to their approximate area in km².\n   *\n   * Uses the inverted spatial index built by {@link registerLocationSets} — no polygon clipping is\n   * performed.  For country-coder regions, CountryCoder's built-in spatial index is used.\n   * For custom `.geojson` and point-radius features, our local which-polygon index is used.\n   *\n   * The returned `Map` gives callers O(1) `has(locationSetID)` membership tests (the common\n   * \"is this locationSet valid here?\" check).\n   * Results are not sorted — if you need them ordered, sort `[...result.entries()]` by value.\n   *\n   * Call {@link resolveLocationSet} on any returned ID if you need the actual GeoJSON feature.\n   *\n   * @param loc - `[longitude, latitude]` coordinate to query.\n   * @returns Map of locationSetID → approximate area (km²), for all sets valid at the point.\n   *\n   * @example\n   * ```ts\n   * loco.registerLocationSets(presets);\n   * const hits = loco.locationSetsAt([-75.16, 39.95]);\n   * if (hits.has('+[Q30]')) { ... }\n   * // Iterate smallest-first:\n   * const sorted = [...hits.entries()].sort((a, b) => a[1] - b[1]);\n   * ```\n   */\n  locationSetsAt(loc: Vec2): Map<LocationSetID, number> {\n    const results = new Map<LocationSetID, number>();\n    const isValidPoint = this._isValidPoint(loc);\n\n    // Two-pass design:\n    //   1. For each component location covering the point, walk the inverted index to\n    //      collect the locationSetIDs that include or exclude it.\n    //   2. Apply exclusions (a locationSet that excludes any covering location is removed).\n    //\n    // Location lookup is split across two spatial indexes because CountryCoder regions\n    // use CountryCoder's own index, while custom .geojson and point-radius features use ours.\n    // Unlike some earlier designs, we do NOT put resolved locationSet polygons into\n    // which-polygon — membership is always derived from location hits via the inverted\n    // index.  This keeps the spatial index small and avoids needing to resolve every\n    // locationSet to a GeoJSON polygon, which is expensive.\n    const toExclude = new Set<LocationSetID>();\n\n    // Search the inverted index for occurrances of the given locationID.\n    const gather = (locationID: LocationID): void => {\n      for (const id of (this._setsIncluding.get(locationID) ?? [])) {\n        results.set(id, this._registered.get(id) ?? Infinity);\n      }\n      for (const id of (this._setsExcluding.get(locationID) ?? [])) {\n        toExclude.add(id);\n      }\n    };\n\n    // Country-coder components: delegate to CountryCoder's own spatial index.\n    // CountryCoder models \"world\" as an aggregation of known administrative features,\n    // which can be empty in places like open ocean/poles. We still guarantee `+[Q2]`\n    // for any valid coordinate via special handling below.\n    if (isValidPoint) {\n      try {\n        for (const ccFeature of CountryCoder.featuresContaining(loc)) {\n          gather(ccFeature.properties.wikidata);\n        }\n      } catch {\n        // Defensive: treat lookup failures as \"no CountryCoder matches\".\n      }\n    }\n\n    // Custom .geojson and point-radius components: use our which-polygon index\n    // which-polygon returns null (not []) when multi=true and no matches\n    if (isValidPoint && this._spatialIndex) {\n      for (const props of (this._spatialIndex(loc, true) ?? [])) {\n        gather(props.id);\n      }\n    }\n\n    // Apply exclusions\n    for (const id of toExclude) {\n      results.delete(id);\n    }\n\n    // Our world means \"any valid lon/lat in [-180..180] x [-90..90]\", not just\n    // CountryCoder's aggregated administrative coverage. Ensure `+[Q2]` is present\n    // for valid coordinates unless that locationSet was explicitly excluded.\n    if (isValidPoint && !toExclude.has('+[Q2]')) {\n      const worldArea = this._registered.get('+[Q2]');\n      if (worldArea !== undefined) {\n        results.set('+[Q2]', worldArea);\n      }\n    }\n\n    return results;\n  }\n\n  /**\n   * Returns the approximate area (in km²) of a registered locationSet.\n   * The area is the sum of `include` location areas computed during\n   * {@link registerLocationSets} — it does not subtract `exclude` areas.\n   * Returns `undefined` if the locationSet has not been registered.\n   *\n   * @param locationSetID - Stable locationSet identifier, e.g. `'+[Q183]'`.\n   * @returns Approximate area in km², or `undefined` if not registered.\n   *\n   * @example\n   * ```ts\n   * loco.registerLocationSets([{ locationSet: { include: ['de'] } }]);\n   * loco.getLocationSetArea('+[Q183]');  // ~357000\n   * ```\n   */\n  getLocationSetArea(locationSetID: LocationSetID): number | undefined {\n    return this._registered.get(locationSetID);\n  }\n\n  /**\n   * Convenience method to pretty-stringify an object.\n   * @param obj - Object to stringify\n   * @param options - Stringify options\n   * @returns Pretty-formatted JSON string\n   *\n   * @example\n   * ```typescript\n   * const result = loco.resolveLocation('de');\n   * console.log(LocationConflation.stringify(result.feature));\n   * // Outputs a compact, readable JSON representation of the feature\n   *\n   * // Custom formatting options\n   * console.log(LocationConflation.stringify(result.feature, { indent: 2, maxLength: 80 }));\n   * ```\n   */\n  static stringify(obj: unknown, options?: StringifyOptions): string {\n    return prettyStringify(obj, options);\n  }\n}\n\n\n/** The two polygon clipping operations used internally. */\ntype ClipOperation = 'UNION' | 'DIFFERENCE';\n\n/**\n * Wraps the polyclip-ts library and returns a GeoJSON feature.\n * @param features - Array of features to clip\n * @param which - Operation type (UNION or DIFFERENCE)\n * @returns Clipped GeoJSON feature or null if features array is empty\n */\nfunction _clip(features: LocoFeature[], which: ClipOperation): LocoFeature | null {\n  if (!Array.isArray(features) || !features.length) return null;\n\n  const fn = which === 'UNION' ? Polyclip.union : Polyclip.difference;\n  const first = features[0]!.geometry.coordinates as Geom;\n  const rest: Geom[] = [];\n  for (let i = 1; i < features.length; i++) {\n    rest.push(features[i]!.geometry.coordinates as Geom);\n  }\n  const coords = fn(first, ...rest);\n\n  return {\n    type: 'Feature',\n    properties: {} as LocoProperties,\n    geometry: {\n      type: whichType(coords),\n      coordinates: coords,\n    } as GeoJSON.Polygon | GeoJSON.MultiPolygon,\n    id: '',\n  };\n\n  // is this a Polygon or a MultiPolygon?\n  function whichType(coords: unknown): 'Polygon' | 'MultiPolygon' {\n    const a = Array.isArray(coords);\n    const b = a && Array.isArray(coords[0]);\n    const c = b && Array.isArray(coords[0][0]);\n    const d = c && Array.isArray(coords[0][0][0]);\n    return d ? 'MultiPolygon' : 'Polygon';\n  }\n}\n\n\n/**\n * Sorting function for locations to generate deterministic IDs.\n * Note that sorting the include/exclude lists is ok because their contents end up unioned together.\n * @param a - First location\n * @param b - Second location\n * @returns Sort order\n */\nfunction _sortLocations(a: ValidatedLocation, b: ValidatedLocation): number {\n  const rank = { countrycoder: 1, geojson: 2, point: 3 };\n  const aRank = rank[a.type];\n  const bRank = rank[b.type];\n\n  return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);\n}\n\n\n/**\n * Compute the rough area of a GeoJSON geometry, in km².\n * We ensure that all resolved GeoJSON features have an `area` property.\n * The purpose of the `area` property is to enable rough size comparisons.\n * @param geom - The geometry to compute the area for\n * @returns  Area, in km², and truncated to 2 decimal places\n */\nfunction _getArea(geom: GeoJSON.Geometry): number {\n  return Number((calcArea.geometry(geom) / 1e6).toFixed(2));  // m² to km²\n}\n\n\nexport default LocationConflation;\n"
  ],
  "mappings": "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",
  "debugId": "7912B099A0052E7564756E2164756E21",
  "names": []
}