ng-postcode-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/api.d.ts +128 -0
- package/dist/api.js +198 -0
- package/dist/api.js.map +1 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +49 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/postcode.d.ts +71 -0
- package/dist/postcode.js +183 -0
- package/dist/postcode.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kayode Adeniyi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# ng-postcode-js
|
|
2
|
+
|
|
3
|
+
JavaScript and TypeScript library for Nigeria's National Digital Alphanumeric Postcode System (NDAPS), the building-level postcode NIPOST launched in October 2026. Parse, validate and format postcodes offline, and call the [postcode.gov.ng](https://docs.postcode.gov.ng) API for lookup, autocomplete and reverse geocoding.
|
|
4
|
+
|
|
5
|
+
Part of the [ng-postcode project](https://github.com/Adeniyikayodee/ng-postcode), which has the same behaviour in Rust and Python and an MCP server for AI assistants. All three run the same shared test cases.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install ng-postcode-js
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
No runtime dependencies. Needs Node 20 or later, or any runtime with `fetch`.
|
|
12
|
+
|
|
13
|
+
## Offline
|
|
14
|
+
|
|
15
|
+
Expected failures are returned as values, not thrown, so the type checker makes you handle them.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Postcode, parse } from "ng-postcode-js";
|
|
19
|
+
|
|
20
|
+
const code = parse("ek 01 a03 fk 01");
|
|
21
|
+
if (code instanceof Postcode) {
|
|
22
|
+
console.log(String(code)); // EK-01-A03-FK-01
|
|
23
|
+
console.log(code.compact); // EK01A03FK01, store this
|
|
24
|
+
console.log(code.spaced); // EK 01 A03 FK 01
|
|
25
|
+
console.log(code.prefix("area")); // EK-01-A03-FK
|
|
26
|
+
} else {
|
|
27
|
+
console.log(String(code)); // e.g. "invalid lga segment"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `parse` accepts hyphenated, spaced or compact input in either case.
|
|
32
|
+
- `parseLenient` first swaps look-alikes that cannot occur where they stand (`O`/`0`, `I`/`1`, `S`/`5`, `B`/`8`) and reports how many it changed.
|
|
33
|
+
- `fromSegments` assembles a code from its parts and zero-fills the LGA and unit.
|
|
34
|
+
- `isValid` answers yes or no.
|
|
35
|
+
|
|
36
|
+
A well-formed code is not necessarily assigned to a building. Only the API can confirm that a postcode exists.
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { Postcode, parse } from "ng-postcode-js";
|
|
42
|
+
import { ApiError, lookup } from "ng-postcode-js/api";
|
|
43
|
+
import { Client, TransportError } from "ng-postcode-js/client";
|
|
44
|
+
|
|
45
|
+
const code = parse("FC-03-B06-AG-12");
|
|
46
|
+
if (!(code instanceof Postcode)) throw new Error(String(code));
|
|
47
|
+
|
|
48
|
+
const client = new Client(process.env.NG_POSTCODE_API_KEY ?? "");
|
|
49
|
+
const found = await client.send(lookup(code, 1));
|
|
50
|
+
|
|
51
|
+
if (found instanceof ApiError || found instanceof TransportError) {
|
|
52
|
+
console.error(String(found)); // e.g. "invalid_api_key (401): ..."
|
|
53
|
+
} else {
|
|
54
|
+
console.log(found.valid, found.status); // true valid
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`ng-postcode-js/api` covers `lookup`, `autocomplete`, `reverse` and `nearby`. Each returns a plain `Request`, and `decode` turns a status and body into a typed result, so it works with any HTTP client. A request that cannot succeed, such as a level outside 1 to 5, an empty autocomplete or a coordinate that is not finite, throws `RangeError` before anything is sent.
|
|
59
|
+
|
|
60
|
+
The client refuses redirects, so the key is never sent to another host. Response fields keep the API's own names, such as `administrative_address`.
|
|
61
|
+
|
|
62
|
+
Get a key from the [NIPOST developer dashboard](https://dashboard.postcode.gov.ng). Level 1 lookups confirm a code is assigned; levels 2 and up return address details and consume credits.
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The NIPOST Postcode API as plain data: requests to send and responses to decode.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here performs I/O, so it works with any HTTP client. Assembly and
|
|
5
|
+
* disassembly are not modelled: `parse` and `fromSegments` do both offline.
|
|
6
|
+
* Response fields keep the API's own names.
|
|
7
|
+
*/
|
|
8
|
+
import { type Postcode, type Segment } from "./postcode.js";
|
|
9
|
+
export declare const BASE_URL = "https://api.postcode.gov.ng";
|
|
10
|
+
/** A GET request whose successful response decodes to `T`. */
|
|
11
|
+
export interface Request<T> {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly params: ReadonlyArray<readonly [string, string]>;
|
|
14
|
+
readonly read: (data: unknown) => T | undefined;
|
|
15
|
+
}
|
|
16
|
+
export interface Coordinate {
|
|
17
|
+
readonly lat: number;
|
|
18
|
+
readonly lng: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The API refused the request, with `code` taken from its error envelope
|
|
22
|
+
* (`auth_required`, `insufficient_credits`, ...), or its answer was not the
|
|
23
|
+
* documented envelope, with `code` set to `malformed_response`.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ApiError {
|
|
26
|
+
readonly status: number;
|
|
27
|
+
readonly code: string;
|
|
28
|
+
readonly message: string;
|
|
29
|
+
constructor(status: number, code: string, message: string);
|
|
30
|
+
toString(): string;
|
|
31
|
+
}
|
|
32
|
+
export interface AdministrativeAddress {
|
|
33
|
+
readonly state_name: string | null;
|
|
34
|
+
readonly lga_name: string | null;
|
|
35
|
+
readonly locality_name: string | null;
|
|
36
|
+
readonly zone: string | null;
|
|
37
|
+
}
|
|
38
|
+
/** Fields above the level granted to the key are `null`. */
|
|
39
|
+
export interface Lookup {
|
|
40
|
+
readonly postcode: string;
|
|
41
|
+
readonly valid: boolean;
|
|
42
|
+
/** `valid`, `not_found`, or `invalid` for a malformed code. Sent at every level. */
|
|
43
|
+
readonly status: string | null;
|
|
44
|
+
readonly verified: boolean | null;
|
|
45
|
+
/** Level 2. */
|
|
46
|
+
readonly administrative_address: AdministrativeAddress | null;
|
|
47
|
+
/** Level 2. */
|
|
48
|
+
readonly recent_house_address: string | null;
|
|
49
|
+
/** Level 3. */
|
|
50
|
+
readonly building_use_status: string | null;
|
|
51
|
+
/** Level 4. Undocumented, so left as raw JSON. */
|
|
52
|
+
readonly other_building_info: unknown;
|
|
53
|
+
/** Level 5. Undocumented, so left as raw JSON. */
|
|
54
|
+
readonly point_geometry: unknown;
|
|
55
|
+
}
|
|
56
|
+
export interface Suggestion {
|
|
57
|
+
/** The value of the segment being completed, such as `A03`, not a full prefix. */
|
|
58
|
+
readonly code: string;
|
|
59
|
+
/** Documented by NIPOST but not sent by the live API as of October 2026. */
|
|
60
|
+
readonly label: string | null;
|
|
61
|
+
}
|
|
62
|
+
export interface Autocomplete {
|
|
63
|
+
/** The segment the suggestions complete. */
|
|
64
|
+
readonly segment: Segment | null;
|
|
65
|
+
readonly suggestions: readonly Suggestion[];
|
|
66
|
+
}
|
|
67
|
+
export interface NearestUnit {
|
|
68
|
+
readonly postcode: string;
|
|
69
|
+
readonly display: string;
|
|
70
|
+
readonly distance_m: number | null;
|
|
71
|
+
/** `high`, `medium` or `low`, graded by distance. */
|
|
72
|
+
readonly confidence: string | null;
|
|
73
|
+
readonly state_name: string | null;
|
|
74
|
+
readonly lga_name: string | null;
|
|
75
|
+
readonly locality_name: string | null;
|
|
76
|
+
/** Recent house address. This and the names above need level 2. */
|
|
77
|
+
readonly address: string | null;
|
|
78
|
+
}
|
|
79
|
+
export interface Reverse {
|
|
80
|
+
readonly found: boolean;
|
|
81
|
+
/** The queried point, echoed back. */
|
|
82
|
+
readonly coordinate: Coordinate | null;
|
|
83
|
+
/** The nearest building, absent when nothing is in range. */
|
|
84
|
+
readonly unit: NearestUnit | null;
|
|
85
|
+
readonly area: string | null;
|
|
86
|
+
readonly district: string | null;
|
|
87
|
+
readonly state: string | null;
|
|
88
|
+
/** Set when nothing is in range. */
|
|
89
|
+
readonly message: string | null;
|
|
90
|
+
/** The radius the API actually applied. */
|
|
91
|
+
readonly radius_m: number | null;
|
|
92
|
+
/** How deep the match goes, such as `unit`. */
|
|
93
|
+
readonly depth: string | null;
|
|
94
|
+
}
|
|
95
|
+
export interface NearbyUnit {
|
|
96
|
+
readonly postcode: string;
|
|
97
|
+
readonly display: string;
|
|
98
|
+
readonly distance_m: number | null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolve a postcode. Levels are cumulative from 1 (validity only) to 5, and
|
|
102
|
+
* the API caps the answer at the level granted to the key.
|
|
103
|
+
*
|
|
104
|
+
* Throws `RangeError` for a level outside 1 to 5.
|
|
105
|
+
*/
|
|
106
|
+
export declare function lookup(code: Postcode, level?: number): Request<Lookup>;
|
|
107
|
+
/**
|
|
108
|
+
* Suggest completions for a partial postcode such as `EK 01 A`.
|
|
109
|
+
*
|
|
110
|
+
* Throws `RangeError` for an empty `partial`: the live API never answers one.
|
|
111
|
+
*/
|
|
112
|
+
export declare function autocomplete(partial: string): Request<Autocomplete>;
|
|
113
|
+
/**
|
|
114
|
+
* Find the postcode of the nearest building, within 25 m unless `maxDistanceM`
|
|
115
|
+
* says otherwise. The API clamps it to 250 m.
|
|
116
|
+
*
|
|
117
|
+
* Throws `RangeError` for a coordinate or distance that is not a finite number.
|
|
118
|
+
*/
|
|
119
|
+
export declare function reverse(at: Coordinate, maxDistanceM?: number): Request<Reverse>;
|
|
120
|
+
/**
|
|
121
|
+
* List buildings around a point, nearest first, within 300 m unless `radiusM`
|
|
122
|
+
* says otherwise. Empty when nothing is in range.
|
|
123
|
+
*
|
|
124
|
+
* Throws `RangeError` for a coordinate or radius that is not a finite number.
|
|
125
|
+
*/
|
|
126
|
+
export declare function nearby(at: Coordinate, radiusM?: number): Request<readonly NearbyUnit[]>;
|
|
127
|
+
/** Decode the response to `request` from its status and body. */
|
|
128
|
+
export declare function decode<T>(request: Request<T>, status: number, body: string): T | ApiError;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The NIPOST Postcode API as plain data: requests to send and responses to decode.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here performs I/O, so it works with any HTTP client. Assembly and
|
|
5
|
+
* disassembly are not modelled: `parse` and `fromSegments` do both offline.
|
|
6
|
+
* Response fields keep the API's own names.
|
|
7
|
+
*/
|
|
8
|
+
import { SEGMENTS } from "./postcode.js";
|
|
9
|
+
export const BASE_URL = "https://api.postcode.gov.ng";
|
|
10
|
+
/**
|
|
11
|
+
* The API refused the request, with `code` taken from its error envelope
|
|
12
|
+
* (`auth_required`, `insufficient_credits`, ...), or its answer was not the
|
|
13
|
+
* documented envelope, with `code` set to `malformed_response`.
|
|
14
|
+
*/
|
|
15
|
+
export class ApiError {
|
|
16
|
+
status;
|
|
17
|
+
code;
|
|
18
|
+
message;
|
|
19
|
+
constructor(status, code, message) {
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.message = message;
|
|
23
|
+
}
|
|
24
|
+
toString() {
|
|
25
|
+
return `${this.code} (${this.status}): ${this.message}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a postcode. Levels are cumulative from 1 (validity only) to 5, and
|
|
30
|
+
* the API caps the answer at the level granted to the key.
|
|
31
|
+
*
|
|
32
|
+
* Throws `RangeError` for a level outside 1 to 5.
|
|
33
|
+
*/
|
|
34
|
+
export function lookup(code, level = 1) {
|
|
35
|
+
if (!Number.isInteger(level) || level < 1 || level > 5) {
|
|
36
|
+
throw new RangeError(`level must be 1 to 5, got ${level}`);
|
|
37
|
+
}
|
|
38
|
+
const params = [
|
|
39
|
+
["code", code.toString()],
|
|
40
|
+
["level", String(level)],
|
|
41
|
+
];
|
|
42
|
+
return { path: "/v1/lookup", params, read: readLookup };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Suggest completions for a partial postcode such as `EK 01 A`.
|
|
46
|
+
*
|
|
47
|
+
* Throws `RangeError` for an empty `partial`: the live API never answers one.
|
|
48
|
+
*/
|
|
49
|
+
export function autocomplete(partial) {
|
|
50
|
+
if (!partial.trim())
|
|
51
|
+
throw new RangeError("partial must not be empty");
|
|
52
|
+
return { path: "/v1/search/autocomplete", params: [["q", partial]], read: readAutocomplete };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Find the postcode of the nearest building, within 25 m unless `maxDistanceM`
|
|
56
|
+
* says otherwise. The API clamps it to 250 m.
|
|
57
|
+
*
|
|
58
|
+
* Throws `RangeError` for a coordinate or distance that is not a finite number.
|
|
59
|
+
*/
|
|
60
|
+
export function reverse(at, maxDistanceM) {
|
|
61
|
+
const params = around(at, "max_distance_m", maxDistanceM);
|
|
62
|
+
return { path: "/v1/search/reverse", params, read: readReverse };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List buildings around a point, nearest first, within 300 m unless `radiusM`
|
|
66
|
+
* says otherwise. Empty when nothing is in range.
|
|
67
|
+
*
|
|
68
|
+
* Throws `RangeError` for a coordinate or radius that is not a finite number.
|
|
69
|
+
*/
|
|
70
|
+
export function nearby(at, radiusM) {
|
|
71
|
+
return { path: "/v1/search/nearby", params: around(at, "radius", radiusM), read: readNearby };
|
|
72
|
+
}
|
|
73
|
+
/** Decode the response to `request` from its status and body. */
|
|
74
|
+
export function decode(request, status, body) {
|
|
75
|
+
let envelope;
|
|
76
|
+
try {
|
|
77
|
+
envelope = JSON.parse(body);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return malformed(status, `not JSON: ${error instanceof Error ? error.message : error}`);
|
|
81
|
+
}
|
|
82
|
+
if (!isObject(envelope))
|
|
83
|
+
return malformed(status, "expected a JSON object");
|
|
84
|
+
const failure = envelope.error;
|
|
85
|
+
if (isObject(failure)) {
|
|
86
|
+
return new ApiError(status, text(failure, "code") ?? "unknown_error", text(failure, "message") ?? "");
|
|
87
|
+
}
|
|
88
|
+
if (typeof failure === "string")
|
|
89
|
+
return new ApiError(status, "unknown_error", failure);
|
|
90
|
+
if (status < 200 || status >= 300)
|
|
91
|
+
return malformed(status, "an error status without an error");
|
|
92
|
+
return request.read(envelope.data) ?? malformed(status, "unexpected data");
|
|
93
|
+
}
|
|
94
|
+
function around(at, key, metres) {
|
|
95
|
+
const point = [
|
|
96
|
+
["lat", numberText(at.lat)],
|
|
97
|
+
["lng", numberText(at.lng)],
|
|
98
|
+
];
|
|
99
|
+
return metres === undefined ? point : [...point, [key, numberText(metres)]];
|
|
100
|
+
}
|
|
101
|
+
function numberText(value) {
|
|
102
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
103
|
+
throw new RangeError(`expected a finite number, got ${value}`);
|
|
104
|
+
}
|
|
105
|
+
return String(value);
|
|
106
|
+
}
|
|
107
|
+
function malformed(status, message) {
|
|
108
|
+
return new ApiError(status, "malformed_response", message);
|
|
109
|
+
}
|
|
110
|
+
function isObject(value) {
|
|
111
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
112
|
+
}
|
|
113
|
+
function object(data, key) {
|
|
114
|
+
const value = data[key];
|
|
115
|
+
return isObject(value) ? value : null;
|
|
116
|
+
}
|
|
117
|
+
function text(data, key) {
|
|
118
|
+
const value = data[key];
|
|
119
|
+
return typeof value === "string" ? value : null;
|
|
120
|
+
}
|
|
121
|
+
function number(value) {
|
|
122
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
123
|
+
}
|
|
124
|
+
function readNearby(data) {
|
|
125
|
+
if (!Array.isArray(data))
|
|
126
|
+
return undefined;
|
|
127
|
+
return data.filter(isObject).map((item) => ({
|
|
128
|
+
postcode: text(item, "postcode") ?? "",
|
|
129
|
+
display: text(item, "display") ?? "",
|
|
130
|
+
distance_m: number(item.distance_m),
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
function readLookup(data) {
|
|
134
|
+
if (!isObject(data))
|
|
135
|
+
return undefined;
|
|
136
|
+
const admin = object(data, "administrative_address");
|
|
137
|
+
const recent = object(data, "recent_house_address");
|
|
138
|
+
return {
|
|
139
|
+
postcode: text(data, "postcode") ?? "",
|
|
140
|
+
valid: data.valid === true,
|
|
141
|
+
status: text(data, "status"),
|
|
142
|
+
verified: typeof data.verified === "boolean" ? data.verified : null,
|
|
143
|
+
administrative_address: admin && {
|
|
144
|
+
state_name: text(admin, "state_name"),
|
|
145
|
+
lga_name: text(admin, "lga_name"),
|
|
146
|
+
locality_name: text(admin, "locality_name"),
|
|
147
|
+
zone: text(admin, "zone"),
|
|
148
|
+
},
|
|
149
|
+
recent_house_address: recent && text(recent, "recent"),
|
|
150
|
+
building_use_status: text(data, "building_use_status"),
|
|
151
|
+
other_building_info: data.other_building_info ?? null,
|
|
152
|
+
point_geometry: data.point_geometry ?? null,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function readAutocomplete(data) {
|
|
156
|
+
if (!isObject(data))
|
|
157
|
+
return undefined;
|
|
158
|
+
const items = Array.isArray(data.suggestions) ? data.suggestions : [];
|
|
159
|
+
const suggestions = items.filter(isObject).map((item) => ({
|
|
160
|
+
code: text(item, "code") ?? "",
|
|
161
|
+
label: text(item, "label"),
|
|
162
|
+
}));
|
|
163
|
+
const segment = SEGMENTS.find((name) => name === data.segment) ?? null;
|
|
164
|
+
return { segment, suggestions };
|
|
165
|
+
}
|
|
166
|
+
function readReverse(data) {
|
|
167
|
+
if (!isObject(data))
|
|
168
|
+
return undefined;
|
|
169
|
+
const unit = object(data, "unit");
|
|
170
|
+
return {
|
|
171
|
+
found: data.found === true,
|
|
172
|
+
coordinate: readCoordinate(data.coordinate),
|
|
173
|
+
unit: unit && {
|
|
174
|
+
postcode: text(unit, "postcode") ?? "",
|
|
175
|
+
display: text(unit, "display") ?? "",
|
|
176
|
+
distance_m: number(unit.distance_m),
|
|
177
|
+
confidence: text(unit, "confidence"),
|
|
178
|
+
state_name: text(unit, "state_name"),
|
|
179
|
+
lga_name: text(unit, "lga_name"),
|
|
180
|
+
locality_name: text(unit, "locality_name"),
|
|
181
|
+
address: text(unit, "address"),
|
|
182
|
+
},
|
|
183
|
+
area: text(data, "area"),
|
|
184
|
+
district: text(data, "district"),
|
|
185
|
+
state: text(data, "state"),
|
|
186
|
+
message: text(data, "message"),
|
|
187
|
+
radius_m: number(data.radius_m),
|
|
188
|
+
depth: text(data, "depth"),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/** The API echoes points as `[lng, lat]`. */
|
|
192
|
+
function readCoordinate(value) {
|
|
193
|
+
if (!Array.isArray(value) || value.length !== 2)
|
|
194
|
+
return null;
|
|
195
|
+
const [lng, lat] = [number(value[0]), number(value[1])];
|
|
196
|
+
return lng === null || lat === null ? null : { lat, lng };
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** HTTP shell over `api`, built on `fetch`: the only module that performs I/O. */
|
|
2
|
+
import { type ApiError, type Request } from "./api.js";
|
|
3
|
+
export declare const TIMEOUT_MS = 10000;
|
|
4
|
+
/** The request never produced a response: DNS, TLS, timeout and the like. */
|
|
5
|
+
export declare class TransportError {
|
|
6
|
+
readonly reason: string;
|
|
7
|
+
constructor(reason: string);
|
|
8
|
+
toString(): string;
|
|
9
|
+
}
|
|
10
|
+
export interface ClientOptions {
|
|
11
|
+
/** Another host, such as a staging stack or a mock. */
|
|
12
|
+
readonly baseUrl?: string;
|
|
13
|
+
/** Your own `fetch`, for proxies or tests. */
|
|
14
|
+
readonly fetch?: typeof fetch;
|
|
15
|
+
readonly timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class Client {
|
|
18
|
+
#private;
|
|
19
|
+
constructor(apiKey: string, options?: ClientOptions);
|
|
20
|
+
send<T>(request: Request<T>): Promise<T | ApiError | TransportError>;
|
|
21
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** HTTP shell over `api`, built on `fetch`: the only module that performs I/O. */
|
|
2
|
+
import { BASE_URL, decode } from "./api.js";
|
|
3
|
+
export const TIMEOUT_MS = 10_000;
|
|
4
|
+
/** The request never produced a response: DNS, TLS, timeout and the like. */
|
|
5
|
+
export class TransportError {
|
|
6
|
+
reason;
|
|
7
|
+
constructor(reason) {
|
|
8
|
+
this.reason = reason;
|
|
9
|
+
}
|
|
10
|
+
toString() {
|
|
11
|
+
return this.reason;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class Client {
|
|
15
|
+
#apiKey;
|
|
16
|
+
#baseUrl;
|
|
17
|
+
#fetch;
|
|
18
|
+
#timeoutMs;
|
|
19
|
+
constructor(apiKey, options = {}) {
|
|
20
|
+
this.#apiKey = apiKey;
|
|
21
|
+
this.#baseUrl = options.baseUrl ?? BASE_URL;
|
|
22
|
+
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
23
|
+
this.#timeoutMs = options.timeoutMs ?? TIMEOUT_MS;
|
|
24
|
+
}
|
|
25
|
+
async send(request) {
|
|
26
|
+
const url = new URL(this.#baseUrl + request.path);
|
|
27
|
+
for (const [key, value] of request.params)
|
|
28
|
+
url.searchParams.append(key, value);
|
|
29
|
+
try {
|
|
30
|
+
const response = await this.#fetch(url, {
|
|
31
|
+
headers: { "X-API-Key": this.#apiKey },
|
|
32
|
+
// A redirect would carry the key to another host, so it is refused.
|
|
33
|
+
redirect: "error",
|
|
34
|
+
signal: AbortSignal.timeout(this.#timeoutMs),
|
|
35
|
+
});
|
|
36
|
+
return decode(request, response.status, await response.text());
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return new TransportError(reason(error));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function reason(error) {
|
|
44
|
+
if (!(error instanceof Error))
|
|
45
|
+
return String(error);
|
|
46
|
+
const cause = error.cause instanceof Error ? `: ${error.cause.message}` : "";
|
|
47
|
+
return `${error.message || error.name}${cause}`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAiB,QAAQ,EAAE,MAAM,EAAgB,MAAM,UAAU,CAAC;AAEzE,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAEjC,6EAA6E;AAC7E,MAAM,OAAO,cAAc;IACJ,MAAM;IAA3B,YAAqB,MAAc;sBAAd,MAAM;IAAW,CAAC;IAEvC,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAUD,MAAM,OAAO,MAAM;IACR,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,MAAM,CAAe;IACrB,UAAU,CAAS;IAE5B,YAAY,MAAc,EAAE,OAAO,GAAkB,EAAE;QACrD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAChD,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,OAAmB;QAC/B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM;YAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/E,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;gBACtC,OAAO,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE;gBACtC,oEAAoE;gBACpE,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;aAC7C,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;CACF;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;AAClD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nigeria's National Digital Alphanumeric Postcode (NDAPS), the building-level
|
|
3
|
+
* postcode issued by NIPOST.
|
|
4
|
+
*
|
|
5
|
+
* Expected failures come back as values, never exceptions:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { Postcode, parse } from "ng-postcode-js";
|
|
9
|
+
*
|
|
10
|
+
* const code = parse("ek 01 a03 fk 01");
|
|
11
|
+
* if (code instanceof Postcode) {
|
|
12
|
+
* console.log(String(code), code.compact); // EK-01-A03-FK-01 EK01A03FK01
|
|
13
|
+
* } else {
|
|
14
|
+
* console.log(String(code)); // e.g. "invalid lga segment"
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export { type Corrected, fromSegments, InvalidCharacter, InvalidSegment, isValid, LENGTH, type ParseError, Postcode, parse, parseLenient, SEGMENTS, type Segment, WrongLength, } from "./postcode.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nigeria's National Digital Alphanumeric Postcode (NDAPS), the building-level
|
|
3
|
+
* postcode issued by NIPOST.
|
|
4
|
+
*
|
|
5
|
+
* Expected failures come back as values, never exceptions:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { Postcode, parse } from "ng-postcode-js";
|
|
9
|
+
*
|
|
10
|
+
* const code = parse("ek 01 a03 fk 01");
|
|
11
|
+
* if (code instanceof Postcode) {
|
|
12
|
+
* console.log(String(code), code.compact); // EK-01-A03-FK-01 EK01A03FK01
|
|
13
|
+
* } else {
|
|
14
|
+
* console.log(String(code)); // e.g. "invalid lga segment"
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export { fromSegments, InvalidCharacter, InvalidSegment, isValid, LENGTH, Postcode, parse, parseLenient, SEGMENTS, WrongLength, } from "./postcode.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAEL,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,MAAM,EAEN,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,QAAQ,EAER,WAAW,GACZ,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Offline parsing, validation and formatting. Pure: no I/O, no mutation. */
|
|
2
|
+
export declare const LENGTH = 11;
|
|
3
|
+
/** The five segments of a postcode, `AA-99-H77-BB-55`, widest first. */
|
|
4
|
+
export declare const SEGMENTS: readonly ["state", "lga", "district", "area", "unit"];
|
|
5
|
+
export type Segment = (typeof SEGMENTS)[number];
|
|
6
|
+
/** The input did not hold exactly 11 letters and digits. */
|
|
7
|
+
export declare class WrongLength {
|
|
8
|
+
readonly found: number;
|
|
9
|
+
constructor(found: number);
|
|
10
|
+
toString(): string;
|
|
11
|
+
}
|
|
12
|
+
/** The input held something other than letters, digits, spaces and hyphens. */
|
|
13
|
+
export declare class InvalidCharacter {
|
|
14
|
+
readonly char: string;
|
|
15
|
+
readonly index: number;
|
|
16
|
+
constructor(char: string, index: number);
|
|
17
|
+
toString(): string;
|
|
18
|
+
}
|
|
19
|
+
/** A segment has the wrong shape, such as digits in the state or `00` as a unit. */
|
|
20
|
+
export declare class InvalidSegment {
|
|
21
|
+
readonly segment: Segment;
|
|
22
|
+
constructor(segment: Segment);
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
25
|
+
export type ParseError = WrongLength | InvalidCharacter | InvalidSegment;
|
|
26
|
+
/**
|
|
27
|
+
* A well-formed postcode, held in its compact upper-case form.
|
|
28
|
+
*
|
|
29
|
+
* Well formed is not the same as assigned: only the NIPOST API knows whether a
|
|
30
|
+
* code belongs to a real building. Build one with `parse`.
|
|
31
|
+
*/
|
|
32
|
+
export declare class Postcode {
|
|
33
|
+
readonly compact: string;
|
|
34
|
+
private constructor();
|
|
35
|
+
/** @internal Callers use `parse`; this takes a string already validated. */
|
|
36
|
+
static unchecked(compact: string): Postcode;
|
|
37
|
+
/** The canonical hyphenated form, `EK-01-A03-FK-01`. */
|
|
38
|
+
toString(): string;
|
|
39
|
+
toJSON(): string;
|
|
40
|
+
/** The form shown to people, `EK 01 A03 FK 01`. */
|
|
41
|
+
get spaced(): string;
|
|
42
|
+
get state(): string;
|
|
43
|
+
get lga(): string;
|
|
44
|
+
get district(): string;
|
|
45
|
+
get area(): string;
|
|
46
|
+
get unit(): string;
|
|
47
|
+
segment(segment: Segment): string;
|
|
48
|
+
/** The hyphenated code down to `through`: `prefix("area")` is `EK-01-A03-FK`. */
|
|
49
|
+
prefix(through: Segment): string;
|
|
50
|
+
}
|
|
51
|
+
/** The result of `parseLenient`. */
|
|
52
|
+
export interface Corrected {
|
|
53
|
+
readonly postcode: Postcode;
|
|
54
|
+
/** How many characters were swapped for their look-alike. */
|
|
55
|
+
readonly corrections: number;
|
|
56
|
+
}
|
|
57
|
+
/** Parse a hyphenated, spaced or compact code in either case. */
|
|
58
|
+
export declare function parse(text: string): Postcode | ParseError;
|
|
59
|
+
/**
|
|
60
|
+
* Parse after swapping look-alikes that cannot occur where they stand: `0 1 5 8`
|
|
61
|
+
* become `O I S B` where a letter is required, and `O I L S B` become `0 1 1 5 8`
|
|
62
|
+
* where a digit is. The district allows both, so it is never rewritten.
|
|
63
|
+
*
|
|
64
|
+
* The result is well formed but may not be the code the user meant, so confirm
|
|
65
|
+
* it with them when `corrections` is not zero.
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseLenient(text: string): Corrected | ParseError;
|
|
68
|
+
/** Build a code from its segments, zero-filling the LGA and unit. */
|
|
69
|
+
export declare function fromSegments(state: string, lga: string, district: string, area: string, unit: string): Postcode | ParseError;
|
|
70
|
+
/** Whether `text` is a well-formed postcode. */
|
|
71
|
+
export declare function isValid(text: string): boolean;
|
package/dist/postcode.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/** Offline parsing, validation and formatting. Pure: no I/O, no mutation. */
|
|
2
|
+
export const LENGTH = 11;
|
|
3
|
+
/** The five segments of a postcode, `AA-99-H77-BB-55`, widest first. */
|
|
4
|
+
export const SEGMENTS = ["state", "lga", "district", "area", "unit"];
|
|
5
|
+
const SPANS = {
|
|
6
|
+
state: [0, 2],
|
|
7
|
+
lga: [2, 4],
|
|
8
|
+
district: [4, 7],
|
|
9
|
+
area: [7, 9],
|
|
10
|
+
unit: [9, 11],
|
|
11
|
+
};
|
|
12
|
+
const ALPHA = new Set(["state", "area"]);
|
|
13
|
+
const NUMERIC = new Set(["lga", "unit"]);
|
|
14
|
+
const TO_LETTER = { "0": "O", "1": "I", "5": "S", "8": "B" };
|
|
15
|
+
const TO_DIGIT = { O: "0", I: "1", L: "1", S: "5", B: "8" };
|
|
16
|
+
/** The input did not hold exactly 11 letters and digits. */
|
|
17
|
+
export class WrongLength {
|
|
18
|
+
found;
|
|
19
|
+
constructor(found) {
|
|
20
|
+
this.found = found;
|
|
21
|
+
}
|
|
22
|
+
toString() {
|
|
23
|
+
return `expected ${LENGTH} letters and digits, found ${this.found}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** The input held something other than letters, digits, spaces and hyphens. */
|
|
27
|
+
export class InvalidCharacter {
|
|
28
|
+
char;
|
|
29
|
+
index;
|
|
30
|
+
constructor(char, index) {
|
|
31
|
+
this.char = char;
|
|
32
|
+
this.index = index;
|
|
33
|
+
}
|
|
34
|
+
toString() {
|
|
35
|
+
return `invalid character '${this.char}' at index ${this.index}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** A segment has the wrong shape, such as digits in the state or `00` as a unit. */
|
|
39
|
+
export class InvalidSegment {
|
|
40
|
+
segment;
|
|
41
|
+
constructor(segment) {
|
|
42
|
+
this.segment = segment;
|
|
43
|
+
}
|
|
44
|
+
toString() {
|
|
45
|
+
return `invalid ${this.segment} segment`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A well-formed postcode, held in its compact upper-case form.
|
|
50
|
+
*
|
|
51
|
+
* Well formed is not the same as assigned: only the NIPOST API knows whether a
|
|
52
|
+
* code belongs to a real building. Build one with `parse`.
|
|
53
|
+
*/
|
|
54
|
+
export class Postcode {
|
|
55
|
+
compact;
|
|
56
|
+
constructor(compact) {
|
|
57
|
+
this.compact = compact;
|
|
58
|
+
}
|
|
59
|
+
/** @internal Callers use `parse`; this takes a string already validated. */
|
|
60
|
+
static unchecked(compact) {
|
|
61
|
+
return new Postcode(compact);
|
|
62
|
+
}
|
|
63
|
+
/** The canonical hyphenated form, `EK-01-A03-FK-01`. */
|
|
64
|
+
toString() {
|
|
65
|
+
return this.prefix("unit");
|
|
66
|
+
}
|
|
67
|
+
toJSON() {
|
|
68
|
+
return this.toString();
|
|
69
|
+
}
|
|
70
|
+
/** The form shown to people, `EK 01 A03 FK 01`. */
|
|
71
|
+
get spaced() {
|
|
72
|
+
return SEGMENTS.map((segment) => this.segment(segment)).join(" ");
|
|
73
|
+
}
|
|
74
|
+
get state() {
|
|
75
|
+
return this.segment("state");
|
|
76
|
+
}
|
|
77
|
+
get lga() {
|
|
78
|
+
return this.segment("lga");
|
|
79
|
+
}
|
|
80
|
+
get district() {
|
|
81
|
+
return this.segment("district");
|
|
82
|
+
}
|
|
83
|
+
get area() {
|
|
84
|
+
return this.segment("area");
|
|
85
|
+
}
|
|
86
|
+
get unit() {
|
|
87
|
+
return this.segment("unit");
|
|
88
|
+
}
|
|
89
|
+
segment(segment) {
|
|
90
|
+
return part(this.compact, segment);
|
|
91
|
+
}
|
|
92
|
+
/** The hyphenated code down to `through`: `prefix("area")` is `EK-01-A03-FK`. */
|
|
93
|
+
prefix(through) {
|
|
94
|
+
return SEGMENTS.slice(0, SEGMENTS.indexOf(through) + 1)
|
|
95
|
+
.map((segment) => this.segment(segment))
|
|
96
|
+
.join("-");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Parse a hyphenated, spaced or compact code in either case. */
|
|
100
|
+
export function parse(text) {
|
|
101
|
+
const compact = collect(text);
|
|
102
|
+
if (typeof compact !== "string")
|
|
103
|
+
return compact;
|
|
104
|
+
return validate(compact) ?? Postcode.unchecked(compact);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse after swapping look-alikes that cannot occur where they stand: `0 1 5 8`
|
|
108
|
+
* become `O I S B` where a letter is required, and `O I L S B` become `0 1 1 5 8`
|
|
109
|
+
* where a digit is. The district allows both, so it is never rewritten.
|
|
110
|
+
*
|
|
111
|
+
* The result is well formed but may not be the code the user meant, so confirm
|
|
112
|
+
* it with them when `corrections` is not zero.
|
|
113
|
+
*/
|
|
114
|
+
export function parseLenient(text) {
|
|
115
|
+
const raw = collect(text);
|
|
116
|
+
if (typeof raw !== "string")
|
|
117
|
+
return raw;
|
|
118
|
+
const fixed = SEGMENTS.map((segment) => unconfuse(segment, part(raw, segment))).join("");
|
|
119
|
+
const error = validate(fixed);
|
|
120
|
+
if (error)
|
|
121
|
+
return error;
|
|
122
|
+
const corrections = [...raw].filter((char, index) => char !== fixed[index]).length;
|
|
123
|
+
return { postcode: Postcode.unchecked(fixed), corrections };
|
|
124
|
+
}
|
|
125
|
+
/** Build a code from its segments, zero-filling the LGA and unit. */
|
|
126
|
+
export function fromSegments(state, lga, district, area, unit) {
|
|
127
|
+
const values = [state, lga, district, area, unit];
|
|
128
|
+
const padded = SEGMENTS.map((segment, index) => pad(segment, values[index] ?? ""));
|
|
129
|
+
const error = padded.find((value) => value instanceof InvalidSegment);
|
|
130
|
+
if (error instanceof InvalidSegment)
|
|
131
|
+
return error;
|
|
132
|
+
return parse(padded.join(""));
|
|
133
|
+
}
|
|
134
|
+
/** Whether `text` is a well-formed postcode. */
|
|
135
|
+
export function isValid(text) {
|
|
136
|
+
return parse(text) instanceof Postcode;
|
|
137
|
+
}
|
|
138
|
+
function isAsciiAlphanumeric(char) {
|
|
139
|
+
return /^[A-Za-z0-9]$/.test(char);
|
|
140
|
+
}
|
|
141
|
+
function collect(text) {
|
|
142
|
+
const kept = [];
|
|
143
|
+
let index = 0;
|
|
144
|
+
for (const char of text) {
|
|
145
|
+
if (char !== " " && char !== "-") {
|
|
146
|
+
if (!isAsciiAlphanumeric(char))
|
|
147
|
+
return new InvalidCharacter(char, index);
|
|
148
|
+
kept.push(char);
|
|
149
|
+
}
|
|
150
|
+
index += 1;
|
|
151
|
+
}
|
|
152
|
+
if (kept.length !== LENGTH)
|
|
153
|
+
return new WrongLength(kept.length);
|
|
154
|
+
return kept.join("").toUpperCase();
|
|
155
|
+
}
|
|
156
|
+
function part(compact, segment) {
|
|
157
|
+
const [start, end] = SPANS[segment];
|
|
158
|
+
return compact.slice(start, end);
|
|
159
|
+
}
|
|
160
|
+
function validate(compact) {
|
|
161
|
+
const bad = SEGMENTS.find((segment) => !accepts(segment, part(compact, segment)));
|
|
162
|
+
return bad ? new InvalidSegment(bad) : undefined;
|
|
163
|
+
}
|
|
164
|
+
function accepts(segment, text) {
|
|
165
|
+
if (ALPHA.has(segment))
|
|
166
|
+
return /^[A-Z]*$/.test(text);
|
|
167
|
+
if (NUMERIC.has(segment))
|
|
168
|
+
return /^[0-9]*$/.test(text) && text !== "00";
|
|
169
|
+
return /^[A-Z0-9]*$/.test(text);
|
|
170
|
+
}
|
|
171
|
+
function unconfuse(segment, text) {
|
|
172
|
+
const table = ALPHA.has(segment) ? TO_LETTER : NUMERIC.has(segment) ? TO_DIGIT : {};
|
|
173
|
+
return [...text].map((char) => table[char] ?? char).join("");
|
|
174
|
+
}
|
|
175
|
+
function pad(segment, value) {
|
|
176
|
+
const text = value.trim();
|
|
177
|
+
const [start, end] = SPANS[segment];
|
|
178
|
+
const width = end - start;
|
|
179
|
+
const shortest = NUMERIC.has(segment) ? 1 : width;
|
|
180
|
+
const fits = text.length >= shortest && text.length <= width && /^[A-Za-z0-9]+$/.test(text);
|
|
181
|
+
return fits ? text.padStart(width, "0") : new InvalidSegment(segment);
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=postcode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postcode.js","sourceRoot":"","sources":["../src/postcode.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ng-postcode-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Parse, validate and format Nigeria's NIPOST digital postcode (NDAPS) offline, plus a client for the postcode.gov.ng API.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Kayode Adeniyi",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Adeniyikayodee/ng-postcode.git",
|
|
10
|
+
"directory": "js/packages/ng-postcode-js"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://adeniyikayodee.github.io/ng-postcode/",
|
|
13
|
+
"bugs": "https://github.com/Adeniyikayodee/ng-postcode/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"nigeria",
|
|
16
|
+
"postcode",
|
|
17
|
+
"nipost",
|
|
18
|
+
"ndaps",
|
|
19
|
+
"address",
|
|
20
|
+
"address-validation",
|
|
21
|
+
"geocoding",
|
|
22
|
+
"postal-code"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./api": {
|
|
32
|
+
"types": "./dist/api.d.ts",
|
|
33
|
+
"default": "./dist/api.js"
|
|
34
|
+
},
|
|
35
|
+
"./client": {
|
|
36
|
+
"types": "./dist/client.d.ts",
|
|
37
|
+
"default": "./dist/client.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"prepack": "npm run build"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
52
|
+
}
|
|
53
|
+
}
|