npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pure-geojson-validation

v0.3.0

Published

A geojson validator and coordinate checker with purify-ts support.

Downloads

852

Readme

pure-geojson-validation

pure-geojson-validation is a typescript library to check the internal consistency of geojson objects. In addition to checking the JSON structure of a possible geojson blob, the library can also check the internal consistency of the given coordinates.

Dependencies

The library will use the geojson type definitions as found in the package: @types/geojson. It uses algorithmic data structures from purify-ts and is intended to work with it. Especially the Maybe monad is used extensively when parsing and validating a possible geojson strings or objects. It is worth considering to look at purify, even if you don't intend to work with monads.

If you never heard of a monad or a maybe, it is a form of control structure found in pureley functional languages like haskell. What a monad is is hard to explain, an I can only point you to people that are far better at explaining it than me: Like the haskell wikibook, Computerphile or Bartosz Milewski.

Limitations

  • The library currently cannot parse GeometryCollection geometries correctly. For now validating a GeometryCollection geometry will yield Nothing.

  • The library does not and will not support deprecated geojson features like the crs property. Although any additional properties are valid (RFC7946, #6), only geojson object members will be returned by parser- or validation functions. That means, if you parse a GeoJSON object with an additional property like e.g. crs it will not be represented in the resulting object.

  • The Polygon and MultiPolygon geometries are checked for right handedness. If a left handed polygon-ring is found a warning is issued. The validator will not reverse the order of left handed rings.

Usage

Git

To check out the project, run:

git clone https://github.com/maze-le/pure-geojson-validation.git

Test

To test the repository, run:

npm run test

Install as lib

In your project:

npm i -D @types/geojson
npm i purify-ts pure-geojson-validation

Code Example

With Maybe

The library exposes several functions to parse strings as GeoJSON objects. Methods that start with maybe always return a Maybe (a value wrapped in a Just or Nothing). It is recommended to use the Maybe implementations of the library.

In the Maybe context
import { maybeFeatureCollection } from "pure-geojson-validation";

const storeFeatureCollection = (path: string) =>
  maybeFeatureCollection(content)
    .ifNothing(() => console.error("error parsing feature collection"))
    .caseOf({
      Just: (FeatureCollection) =>
        writeToFile(path, JSON.stringify(FeatureCollection)),
      Nothing: () => console.warn(`skipped writing file "${path}"`),
    });
From the Maybe context to a regular context
import { maybeFeatureCollection } from "pure-geojson-validation";

function getFeatureCollectionOrNull() {
  const content = readFileSync("path/to/file.geojson");
  const maybeFC = maybeFeatureCollection(content)
    .ifJust(() => console.info("successfully parsed feature collection"))
    .ifNothing(() => console.error("could not parse feature collection"));

  return maybeFC.isNothing() ? null : maybeFC.unsafeCoerce();
}

With try/catch

Alternatively you can also use the "unsafe" try methods that will raise an error if a string cannot be parsed or validated.

import { tryFeatureCollection } from "pure-geojson-validation";

function getFeatureCollectionOrNull() {
  try {
    const content = readFileSync("path/to/file.geojson");
    const unsafeFC = tryFeatureCollection(content);

    console.info("successfully parsed feature collection");

    return unsafeFC;
  } catch (err) {
    console.error("could not parse feature collection");
    return null;
  }
}

Methods

String validation methods

The following methods turns a string representation of a possible FeatureCollection eventually into a FeatureCollection as defined in @types/geojson.

Sanity checks are performed on coordinate values, if they fail the function returns with the associated geometry set to null and a warning is issued. Additional checks are performed on bounding boxes and features. If they fail the function returns Nothing. If the collection is valid, Just(GeoJSONobject) is returned.

The associated try methods will raise an error when the validations fail.

const maybeGeoJSON: (content: string) => Maybe<GeoJSONobject>;
const tryGeoJSON: (content: string) => GeoJSONobject;

Attempts to parse and validate the content string as Maybe of a GeoJSON object (Geometry, Feature or FeatureCollection).

const maybeFeatureCollection: (content: string) => Maybe<FeatureCollection>;
const tryFeatureCollection: (content: string) => FeatureCollection;

Attempts to parse and validate the content string as Maybe of a GeoJSON FeatureCollection.

const maybeFeature: (content: string) => Maybe<Feature>;
const tryFeature: (content: string) => Feature;

Attempts to parse and validate the content string as Maybe of a GeoJSON Geometry.

const maybeGeometry: (content: string) => Maybe<Geometry>;
const tryGeometry: (content: string) => Geometry;

Attempts to parse and validate the content string as Maybe of a GeoJSON FeatureCollection.

Object validation methods

validateBBox

const validateBBox: (bbox: unknown) => Maybe<BBox>;

Validates a possible bounding box and eventually returns with a GeoJSON BBox object. bbox is expected to be an array of length 4 or 6.

validateFeature

const validateFeature: (feat: unknown) => Maybe<Feature>;

Validates a possible GeoJSON feature and eventually returns with a Feature object as found in @types/geojson. feat is expected to be a GeoJSON feature object (RFC7946,3.1.2).

validateFeatureCollection

const validateFeatureCollection: (fc: unknown) => Maybe<FeatureCollection>;

Validates a possible GeoJSON feature collections and eventually returns with a FeatureCollection object as found in @types/geojson.

validateGeometry

const validateGeometry: (geometry: record | null) => Maybe<Geometry>;

Coordinate Predicates

The following methods check if coordinate values are valid and within the bounds of a WSG84 coordinate projection. The arguments (except for isLat and isLon) are of type unknown, but are assumed to be nested number arrays, depending on the chosen geometry type. If you want to work with these predicates and with Maybe create a Maybe from a predicate like this:

import { isPoint } from "pure-geojson-validation";
const maybePoint = (point: unknown) => Maybe.fromPredicate(isPoint, point);

isLat

const isLat: (lat: number) => boolean;

Returns true if lat is a number representing a latitude angle in WSG84.

isLon

const isLon: (lat: number) => boolean;

Returns true if lat is a number representing a longitude angle in WSG84.

isPoint

const isPoint: (p: unknown) => boolean;

Returns true if p is a point geometry as defined in RFC7946,3.1.2.

The time complexity of this function is O(1).

isMultiPoint

const isMultiPoint: (mp: unknown) => boolean;

Returns true if mp is a multipoint geometry as defined in RFC7946,3.1.3.

The time complexity of this function is O(1).

isLineString

const isLine: (pa: unknown) => boolean;

Returns true if pa is a line- or multipoint geometry as defined in RFC7946,3.1.4.

The time complexity of this function is O(n), with n=length(pa).

isMultiLineString

const isMultiLineString: (pa: unknown) => boolean;

Returns true if pa is a line- or multipoint geometry as defined in RFC7946,3.1.5.

The time complexity of this function is O(n*m), with n=length(pa); m=length(pa).

isPolygon

const isPolygon: (la: unknown) => boolean;

Returns true if la is a polygon- or multiline geometry as defined in RFC7946,3.1.6.

The time complexity of this function is O(n^2).

isMultiPolygon

const isMultiPolygon: (multipolygon: unknown) => boolean;

Returns true if multipolygon is a polygon array as defined in RFC7946,3.1.7.

The time complexity of this function is O(n^3).

isRightHand

  const isRightHand = (xs: Position[]): boolean;

Checks whether a ring (closed LineString) has right hand winding number. see RFC7946,3.1.6 The time complexity of this function is O(n) with n: length of xs.

isLinearRing

  const isLinearRing = (xs: unknown[][]): boolean;

Returns true if xs is an array of closed line segments

isLinearRingArray

  const isLinearRingArray = (xs: unknown[][][]): boolean;

Returns true if xs is an array of linear rings

Types and Objects

Constants

The Array of possible geometry types is exposed to give non-typescript users access to valid geometry types. The geometryTypes array contains all currently supported geometry types as string.

const geometryTypes: GeoJsonGeometryTypes[];

Types

The following types are exposed to ensure type consistency when using it as a library.

record

type record = Record<string, unknown>;

A shorthand type for objects with entries of unknown value.

BBoxTuple

type BBoxTuple<T> = [T, T, T, T] | [T, T, T, T, T, T];

An internal type that describes bounding boxes.

Position

export type Position = number[];

The internal representation of point geometries. Point geometries with more than 3 entries are valid, but any entry past index 3 in an array will be ignored.

Coordinates

export type Coordinates = Position | Position[] | Position[][] | Position[][][];

The internal representation of coordinates that describe more complex geometries than the point.

Geometry

type Geom =
  | LineString
  | MultiLineString
  | MultiPoint
  | MultiPolygon
  | Point
  | Polygon;

A geojson geomtry as defined in @types/geojson except the GeometryCollection type as it is not implemented yet.

Future Developments

The library should be able to read and validate any geojson object (not just FeatureCollections) in a furure iteration.

I plan to implement further sanity checks on geometries (avoiding self intersections, zero length line segments, etc.) in the future, as well as having an options-object that can be passed to the library methods to enforce strict or loose validation rules.