Skip to content

Commit

Permalink
#build-minor: new format parsers added
Browse files Browse the repository at this point in the history
  • Loading branch information
reskume committed Dec 5, 2024
1 parent ccb762d commit fab787a
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 2 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ Currently the out-of-the-box format parsers supports the following various forma
- `N40:07 W74:07`
- `N40:07.38W74:07.38`
- `N 40:07.38 W 74:07.38`
- `40:07N 74:07W`
- `40:07.38N74:07.38W`
- `40:07.38 N 74:07.38 W`
- `40:07.38N 74:07.38W`
- `N40:07.38 W74:07.38`
- `4007 N 7407 W`
- `4007.38 N 7407.38 W`
Expand Down
72 changes: 72 additions & 0 deletions src/formats/dm-unsigned-delimited-suffixed-hemisphere-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { z } from 'zod';
import type { Coordinate, DmsCoordinate } from '../types.js';
import { validateSchema } from '../validate-schema.js';
import { BaseFormat } from './base-format.js';

const REGEX = /^(\d+:\d+(\.\d+)?\s*[NS])\s*(\d+:\d+(\.\d+)?\s*[EW])$/;

/**
* Supported formats:
*
* 40:07N 74:07W
* 40:07.38N74:07.38W
* 40:07.38 N 74:07.38 W
* 40:07.38N 74:07.38W
*/
export class DmUnsignedDelimitedSuffixedHemisphereFormat extends BaseFormat {
parse(coordinateString: string): Coordinate {
validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' });

if (DmUnsignedDelimitedSuffixedHemisphereFormat.canParse(coordinateString) === false) {
throw new Error('Invalid coordinate string');
}
this.enforceNoHyphen(coordinateString);
// 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[1];
const longitude = match[3];
// to DMS
const dmsLat = this.toDms(latitude.replace(/\s/g, ''));
const dmsLon = this.toDms(longitude.replace(/\s/g, ''));
// DMS to decimal
const decimalLat = this.dmsToDecimal(dmsLat);
const decimalLon = this.dmsToDecimal(dmsLon);
this.enforceValidLatitude(decimalLat);
this.enforceValidLongitude(decimalLon);
const lat = decimalLat.toFixed(this.precision);
const lon = decimalLon.toFixed(this.precision);

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

/**
* Converts a DM notation coordinate like "4007.38N" to DMS parts.
*/
toDms(value: string): DmsCoordinate {
validateSchema(value, z.string(), { assert: true, name: 'value' });

const match = value.match(/^(\d{2,3}):(\d{2})(\.\d+)?\s*([NSWE])$/);
if (match) {
return {
degrees: parseInt(match[1], 10),
minutes: parseInt(match[2], 10),
seconds: Math.round(60 * parseFloat(`0${match[3]}`)),
direction: match[4],
};
} else {
throw new Error('Invalid coordinate string');
}
}

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

return REGEX.test(coordinateString);
}
}
2 changes: 1 addition & 1 deletion src/formats/dm-unsigned-prefixed-hemisphere-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class DmUnsignedPrefixedHemisphereFormat extends BaseFormat {
}

/**
* Converts a DMS notation coordinate like "4007.38N" to DMS parts.
* Converts a DM notation coordinate like "4007.38N" to DMS parts.
*/
toDms(value: string): DmsCoordinate {
validateSchema(value, z.string(), { assert: true, name: 'value' });
Expand Down
2 changes: 1 addition & 1 deletion src/formats/dm-unsigned-suffixed-hemisphere-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class DmUnsignedSuffixedHemisphereFormat extends BaseFormat {
}

/**
* Converts a DMS notation coordinate like "4007.38N" to DMS parts.
* notation coordinate like "4007.38N" to DMS parts.
*/
toDms(value: string): DmsCoordinate {
validateSchema(value, z.string(), { assert: true, name: 'value' });
Expand Down
2 changes: 2 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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 { DmUnsignedDelimitedPrefixedHemisphereFormat } from './formats/dm-unsigned-delimited-prefixed-hemisphere-format.js';
import { DmUnsignedDelimitedSuffixedHemisphereFormat } from './formats/dm-unsigned-delimited-suffixed-hemisphere-format.js';
import { DmUnsignedPrefixedHemisphereFormat } from './formats/dm-unsigned-prefixed-hemisphere-format.js';
import { DmUnsignedSuffixedHemisphereFormat } from './formats/dm-unsigned-suffixed-hemisphere-format.js';
import { DmsBlockPrefixedHemisphereFormat } from './formats/dms-block-prefixed-hemisphere-format.js';
Expand Down Expand Up @@ -61,6 +62,7 @@ export class Parser {
new DecimalUnsignedPrefixedHemisphereFormat({ precision: precision }),
new DecimalSignedSuffixedHemisphereFormat({ precision: precision }),
new DmUnsignedDelimitedPrefixedHemisphereFormat({ precision: precision }),
new DmUnsignedDelimitedSuffixedHemisphereFormat({ precision: precision }),
new DmUnsignedPrefixedHemisphereFormat({ precision: precision }),
new DmUnsignedSuffixedHemisphereFormat({ precision: precision }),
new DmsBlockPrefixedHemisphereFormat({ precision: precision }),
Expand Down
40 changes: 40 additions & 0 deletions tests/dm-unsigned-delimited-suffixed-hemisphere-format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it } from 'vitest';
import { DmUnsignedDelimitedSuffixedHemisphereFormat } from '../src/formats/dm-unsigned-delimited-suffixed-hemisphere-format';

describe('canParse', () => {
it('returns true for known formats', () => {
expect(DmUnsignedDelimitedSuffixedHemisphereFormat.canParse('40:07N 74:07W')).toBe(true);
expect(DmUnsignedDelimitedSuffixedHemisphereFormat.canParse('40:07.38N74:07.38W')).toBe(true);
expect(DmUnsignedDelimitedSuffixedHemisphereFormat.canParse('40:07.38 N 74:07.38 W')).toBe(true);
expect(DmUnsignedDelimitedSuffixedHemisphereFormat.canParse('40:07.38N 74:07.38W')).toBe(true);
});
});
describe('parse', () => {
it("returns the correct latitude and longitude for '40:07N 74:07W'", () => {
const formatParser = new DmUnsignedDelimitedSuffixedHemisphereFormat();
const result = formatParser.parse('40:07N 74:07W');
expect(result.latitude).toBe(40.11667);
expect(result.longitude).toBe(-74.11667);
});

it("returns the correct latitude and longitude for '40:07.38N74:07.38W'", () => {
const formatParser = new DmUnsignedDelimitedSuffixedHemisphereFormat();
const result = formatParser.parse('40:07.38N74:07.38W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for '40:07.38 N 74:07.38 W'", () => {
const formatParser = new DmUnsignedDelimitedSuffixedHemisphereFormat();
const result = formatParser.parse('40:07.38 N 74:07.38 W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for '40:07.38N 74:07.38W'", () => {
const formatParser = new DmUnsignedDelimitedSuffixedHemisphereFormat();
const result = formatParser.parse('40:07.38N 74:07.38W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});
});
58 changes: 58 additions & 0 deletions tests/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,64 @@ describe('Test that all configured format parsers do not interfere', () => {
expect(result.longitude).toBe(-74.12306);
});
});
describe('test dm unsigned delimited prefixed hemisphere format', () => {
it("returns the correct latitude and longitude for 'N40:07 W74:07'", () => {
const parser = new Parser();
const result = parser.parse('N40:07 W74:07');
expect(result.latitude).toBe(40.11667);
expect(result.longitude).toBe(-74.11667);
});

it("returns the correct latitude and longitude for 'N40:07.38W74:07.38'", () => {
const parser = new Parser();
const result = parser.parse('N40:07.38W74:07.38');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for 'N 40:07.38 W 74:07.38'", () => {
const parser = new Parser();
const result = parser.parse('N 40:07.38 W 74:07.38');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for 'N40:07.38 W74:07.38'", () => {
const parser = new Parser();
const result = parser.parse('N40:07.38 W74:07.38');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});
});
describe('test dm unsigned delimited suffixed hemisphere format', () => {
it("returns the correct latitude and longitude for '40:07N 74:07W'", () => {
const parser = new Parser();
const result = parser.parse('40:07N 74:07W');
expect(result.latitude).toBe(40.11667);
expect(result.longitude).toBe(-74.11667);
});

it("returns the correct latitude and longitude for '40:07.38N74:07.38W'", () => {
const parser = new Parser();
const result = parser.parse('40:07.38N74:07.38W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for '40:07.38 N 74:07.38 W'", () => {
const parser = new Parser();
const result = parser.parse('40:07.38 N 74:07.38 W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});

it("returns the correct latitude and longitude for '40:07.38N 74:07.38W'", () => {
const parser = new Parser();
const result = parser.parse('40:07.38N 74:07.38W');
expect(result.latitude).toBe(40.12306);
expect(result.longitude).toBe(-74.12306);
});
});
describe('test dms block prefixed hemisphere format', () => {
it(`returns the correct latitude and longitude for N400723 W0740723`, () => {
const parser = new Parser();
Expand Down

0 comments on commit fab787a

Please sign in to comment.