Skip to content

Commit

Permalink
feat: add DecimalUnsignedPrefixedHemisphereFormat for parsing unsigne…
Browse files Browse the repository at this point in the history
…d prefixed hemisphere coordinates and enhance tests
  • Loading branch information
reskume committed Dec 4, 2024
1 parent 3833e46 commit a54b511
Show file tree
Hide file tree
Showing 5 changed files with 400 additions and 249 deletions.
55 changes: 55 additions & 0 deletions src/formats/decimal-unsigned-prefixed-hemisphere-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { z } from 'zod';
import { isNumeric } from '../is-numeric.js';
import type { Coordinate } from '../types.js';
import { validateSchema } from '../validate-schema.js';
import { BaseFormat } from './base-format.js';

const REGEX = /^([NS])\s*(-?\d{1,2}(\.\d+)?)\s*[, ]?\s*([EW])\s*(-?\d{1,3}(\.\d+)?)\s*$/;

/**
* Parses coordinates strings in decimal format with hemisphere notations. Coordinate ordering is
* always latitude, longitude.
*
* Supported formats:
*
* N12,E56
* N 12.234 E 56.678
* N 12.234, E 56.678
* N12.234,E56.678
* N12.234E56.678
*/
export class DecimalUnsignedPrefixedHemisphereFormat extends BaseFormat {
parse(coordinateString: string): Coordinate {
validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' });

if (DecimalUnsignedPrefixedHemisphereFormat.canParse(coordinateString) === false) {
throw new Error('Invalid coordinate string');
}
// use the regex to parse the latitude and longitude
const match = coordinateString.match(REGEX);
if (match == null) {
throw new Error('Invalid coordinate string');
}
const latitude = match[2];
const longitude = match[5];
if (isNumeric(latitude) === false || isNumeric(longitude) === false) {
throw new Error('Invalid coordinate string');
}

this.enforceValidLatitude(latitude);
this.enforceValidLongitude(longitude);
const lat = parseFloat(latitude).toFixed(this.precision);
const lon = parseFloat(longitude).toFixed(this.precision);

return {
latitude: parseFloat(lat),
longitude: parseFloat(lon),
};
}

static canParse(coordinateString: string): boolean {
validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' });

return REGEX.test(coordinateString);
}
}
2 changes: 2 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DecimalSignedFormat } from './formats/decimal-signed-format.js';
import { DecimalSignedPrefixedHemisphereFormat } from './formats/decimal-signed-prefixed-hemisphere-format.js';
import { DecimalSignedSuffixedHemisphereFormat } from './formats/decimal-signed-suffixed-hemisphere-format.js';
import { DecimalUnsignedFormat } from './formats/decimal-unsigned-format.js';
import { DecimalUnsignedPrefixedHemisphereFormat } from './formats/decimal-unsigned-prefixed-hemisphere-format.js';
import { DecimalUnsignedSuffixedHemisphereFormat } from './formats/decimal-unsigned-suffixed-hemisphere-format.js';
import { DmUnsignedSuffixedHemisphereFormat } from './formats/dm-unsigned-suffixed-hemisphere-format.js';
import type { Coordinate } from './types.js';
Expand Down Expand Up @@ -46,6 +47,7 @@ export class Parser {
new DecimalSignedPrefixedHemisphereFormat({ precision: precision }),
new DecimalUnsignedSuffixedHemisphereFormat({ precision: precision }),
new DecimalSignedFormat({ precision: precision }),
new DecimalUnsignedPrefixedHemisphereFormat({ precision: precision }),
new DecimalSignedSuffixedHemisphereFormat({ precision: precision }),
new DmUnsignedSuffixedHemisphereFormat({ precision: precision }),
];
Expand Down
52 changes: 52 additions & 0 deletions tests/decimal-unsigned-prefixed-hemisphere-format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, expect, it } from 'vitest';
import { DecimalUnsignedPrefixedHemisphereFormat } from '../src/formats/decimal-unsigned-prefixed-hemisphere-format.js';

describe('canParse', () => {
it('returns true for known formats', () => {
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12 E56')).toBe(true);
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12,E56')).toBe(true);
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N 12.234 E 56.678')).toBe(true);
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12.234,E56.678')).toBe(true);
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12.234E56.678')).toBe(true);
});

it('returns false for unknown formats', () => {
expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('1.234 5.678')).toBe(false);
});
});
describe('parse', () => {
it("returns the correct latitude and longitude for 'N12 E56'", () => {
const formatParser = new DecimalUnsignedPrefixedHemisphereFormat();
const result = formatParser.parse('N12 E56');
expect(result.latitude).toBe(12);
expect(result.longitude).toBe(56);
});

it("returns the correct latitude and longitude for 'N12,E56'", () => {
const formatParser = new DecimalUnsignedPrefixedHemisphereFormat();
const result = formatParser.parse('N12,E56');
expect(result.latitude).toBe(12);
expect(result.longitude).toBe(56);
});

it("returns the correct latitude and longitude for 'N 12.234 E 56.678'", () => {
const formatParser = new DecimalUnsignedPrefixedHemisphereFormat();
const result = formatParser.parse('N 12.234 E 56.678');
expect(result.latitude).toBe(12.234);
expect(result.longitude).toBe(56.678);
});

it("returns the correct latitude and longitude for 'N12.234,E56.678'", () => {
const formatParser = new DecimalUnsignedPrefixedHemisphereFormat();
const result = formatParser.parse('N12.234,E56.678');
expect(result.latitude).toBe(12.234);
expect(result.longitude).toBe(56.678);
});

it("returns the correct latitude and longitude for 'N12.234E56.678'", () => {
const formatParser = new DecimalUnsignedPrefixedHemisphereFormat();
const result = formatParser.parse('N12.234E56.678');
expect(result.latitude).toBe(12.234);
expect(result.longitude).toBe(56.678);
});
});
7 changes: 5 additions & 2 deletions tests/decimal-unsigned-suffixed-hemisphere-format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { DecimalUnsignedSuffixedHemisphereFormat } from '../src/formats/decimal-

describe('canParse', () => {
it('returns true for known formats', () => {
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('1.234N 5.678E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('1.234 N, 5.678 E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12N,56E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234 N 56.678 E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234 N, 56.678 E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234N,56.678E')).toBe(true);
expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234N56.678E')).toBe(true);
});

it('returns false for unknown formats', () => {
Expand Down
Loading

0 comments on commit a54b511

Please sign in to comment.