How to List Specific File Types in GeoLibre: A Complete Developer Guide

Use filterSupportedFiles() from @geolibre/ui/file-names to whitelist extensions, then apply custom Set-based filters for granular control over vector, raster, or project-specific file lists.

GeoLibre is an open-source, multi-platform geospatial workbench built on a monorepo architecture with npm workspaces (apps/*, packages/*, workers/*) and a Python FastAPI side-car. Listing specific file types is a core requirement when building custom import dialogs, batch processors, or plugins that handle geospatial data. The platform provides centralized file-type utilities that ensure consistent behavior across desktop (Tauri), web, and embedded environments.

Core File-Type Filtering Architecture

GeoLibre's file-type handling lives in the desktop application's I/O layer, specifically in apps/geolibre-desktop/src/lib/file-names.ts. This module exports the foundational utilities that the entire codebase uses to validate and categorize files.

Primary Filtering Functions

The main entry point for file-type operations is filterSupportedFiles(files: File[]): File[], which returns only files whose extensions match GeoLibre's internal whitelist. This whitelist excludes non-geospatial formats, system files (like macOS __MACOSX entries), and metadata files by default.

For extension extraction, the codebase uses extOf(file), a lightweight utility that returns the lower-cased extension from a File object. This normalization ensures case-insensitive matching across operating systems.

Extension Categories in GeoLibre

GeoLibre internally groups supported extensions by data category:

  • Vector: .shp, .geojson, .parquet, .kml, .gml
  • Raster: .tif, .png, .jpg, .mbtiles
  • Project/Config: Varies by plugin (filtered by default in most contexts)

Listing Specific File Types: Implementation Patterns

Pattern 1: Filter by Raster Format Only

To display only raster imagery in a custom "Add Raster Layer" dialog:

import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

const rasterExts = new Set(['.tif', '.png', '.jpg', '.mbtiles']);

function listRasterFiles(files: File[]): File[] {
  const supported = filterSupportedFiles(files);
  return supported.filter(f => rasterExts.has(extOf(f).toLowerCase()));
}

Pattern 2: Isolate Shapefile Components

ESRI Shapefiles require multiple companion files. The filtering logic in tauri-io.ts demonstrates how to collect all parts of a Shapefile dataset:

import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

// `selected` comes from a file-picker dialog
const supported = filterSupportedFiles(selected);

// Keep only Shapefile parts using explicit extension list
const shpParts = supported.filter(f =>
  ['.shp', '.shx', '.dbf', '.prj', '.cpg'].includes(extOf(f).toLowerCase())
);

console.log('Shapefile parts to load:', shpParts.map(f => f.name));

The desktop-specific routine in apps/geolibre-desktop/src/lib/tauri-io.ts extends this pattern—it reads a chosen .shp file and automatically discovers its side-car files from the same directory, filtering unsupported entries before integration into the Zustand store.

Pattern 3: Custom Category Filter with Multiple Sets

For plugins that need dynamic category selection:

import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

type FileCategory = 'vector' | 'raster' | 'project';

const extensionMap: Record<FileCategory, Set<string>> = {
  vector: new Set(['.shp', '.geojson', '.parquet', '.kml', '.gml']),
  raster: new Set(['.tif', '.png', '.jpg', '.mbtiles', '.webp']),
  project: new Set(['.geolib', '.json'])
};

function listFilesByCategory(
  files: File[], 
  category: FileCategory
): File[] {
  const supported = filterSupportedFiles(files);
  const targetExts = extensionMap[category];
  return supported.filter(f => targetExts.has(extOf(f).toLowerCase()));
}

Key Source Files and Their Roles

File Path Responsibility
file-names.ts apps/geolibre-desktop/src/lib/file-names.ts Extension extraction (extOf), generic whitelist filtering (filterSupportedFiles), display name mapping
tauri-io.ts apps/geolibre-desktop/src/lib/tauri-io.ts Desktop file reading, Shapefile side-car discovery, platform-specific filtering
types.ts packages/plugins/src/types.ts VectorFile type definition documenting primary files and companions
maplibre-vector.ts packages/plugins/src/plugins/maplibre-vector.ts Vector plugin integrating filtered files into MapLibre rendering

Summary

  • Centralized filtering through filterSupportedFiles() in file-names.ts ensures consistent behavior across all GeoLibre hosts.
  • Extension-based granularity using extOf() and custom Set filters enables precise control over vector, raster, or specialized format lists.
  • Shapefile handling requires explicit multi-extension filtering to capture .shp, .shx, .dbf, .prj, and .cpg components.
  • Cross-platform parity is maintained because the same utilities power the desktop UI, web UI, and Jupyter embedded environments.

Frequently Asked Questions

How does GeoLibre handle case-insensitive file extensions?

GeoLibre normalizes all extensions to lowercase using extOf(), which is implemented in apps/geolibre-desktop/src/lib/file-names.ts. This ensures .TIF, .Tif, and .tif are treated identically regardless of the source operating system.

Can I add custom file types to the whitelist?

Yes. While filterSupportedFiles() uses an internal whitelist, you can bypass it and implement custom validation by using extOf() directly. For plugin-wide changes, extend the type definitions in packages/plugins/src/types.ts and register your extensions with the core store.

Why does GeoLibre filter out __MACOSX directories automatically?

The tauri-io.ts module explicitly excludes macOS resource fork directories and other meta-files during the file discovery phase. This prevents system-generated content from polluting the layer list when users import data from Apple-compressed archives.

Does the web version use the same file-type utilities?

Yes. The @geolibre/ui/file-names package is shared across environments. The web UI imports the same filterSupportedFiles and extOf functions, ensuring identical filtering logic whether running in Tauri desktop or a browser context.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →