pure-geojson-validation
TypeScript icon, indicating that this package has built-in type declarations

0.3.0 • Public • Published

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.

Package Sidebar

Install

npm i pure-geojson-validation

Weekly Downloads

1,200

Version

0.3.0

License

MIT

Unpacked Size

72.1 kB

Total Files

26

Last publish

Collaborators

  • maze-le