Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ This repo holds the source of the site at <https://gatepost-dev.github.io/docs/>
## What the site holds

- A [playground](https://gatepost-dev.github.io/docs/playground/) where you check a postcode in your browser.
- A page on the postcode format, with a regex, and a page that validates a postcode in TypeScript, PHP and an HTML form.
- Guides for the TypeScript core, the TypeScript client, the PHP package, the HTML field, the React field and the WooCommerce plugin.
- An API reference that the build writes from the TSDoc comments and the PHP doc comments.
- The spec pages: the grammar, the client contract, the field and the glossary.
- The spec pages: the grammar, the client contract, the field, the glossary and the state codes.
- A [readiness tracker](https://gatepost-dev.github.io/docs/readiness/) of common tools that reject the new postcode.

## Run it on your computer
Expand Down
2 changes: 1 addition & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export default defineConfig({
reactTypeDoc(typeDocOf('react')),
],
sidebar: [
{ label: 'Start', items: ['start', 'playground'] },
{ label: 'Start', items: ['start', 'postcode-format', 'validate-postcode', 'playground'] },
{ label: 'Guides', items: [{ autogenerate: { directory: 'guides' } }] },
{ label: 'Spec', items: [{ autogenerate: { directory: 'spec' } }] },
{
Expand Down
59 changes: 57 additions & 2 deletions scripts/spec-pages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-FileCopyrightText: 2026 The Gatepost authors
// SPDX-License-Identifier: Apache-2.0
// Writes the spec pages of the site from the spec submodule, so that the site shows the grammar,
// the client contract, the field and the glossary that the SDKs implement, word for word.
// the client contract, the field and the glossary that the SDKs implement, word for word. The page
// of state codes comes from the data file that the SDKs read, so it cannot drift from them.
import { execFileSync } from 'node:child_process';
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
Expand Down Expand Up @@ -94,6 +95,59 @@ export function specPages(specDir: string, commit: string): readonly SpecPage[]
});
}

interface StateData {
readonly source: string;
readonly states: readonly {
readonly code: string;
readonly name: string;
readonly iso: string;
}[];
}

/**
* Builds the page that lists the state codes, from `data/states.json` of a spec folder. People
* search for these codes, so the page has a title and a description of its own.
*
* @param specDir - The spec folder, such as the `spec` submodule.
* @param commit - The commit of the spec folder, for the link to the data file.
* @returns The page, with its front matter.
*/
export function stateCodesPage(specDir: string, commit: string): SpecPage {
const version = readFileSync(join(specDir, 'VERSION'), 'utf8').trim();
const file = 'data/states.json';
const { source, states } = JSON.parse(readFileSync(join(specDir, file), 'utf8')) as StateData;
const url = `https://github.com/gatepost-dev/spec/blob/${commit}/${file}`;
const description =
`The ${String(states.length)} two-letter state codes that start a Nigerian postcode, ` +
'with the name and the ISO 3166-2:NG code of each state.';
const lines = [
'---',
'title: Nigerian state codes for postcodes',
`description: "${description}"`,
'editUrl: false',
`sidebar: { label: State codes, order: ${String(SOURCES.length + 1)} }`,
'---',
'',
`:::note\nThis page shows [\`${file}\`](${url}) from spec ${version}.\n:::`,
'',
'The first segment of a postcode is the state. It is a code of two letters.',
'The table lists the code of each state and of the Federal Capital Territory.',
'`parse` gives `unknown_state` for any other two letters.',
'',
'## Codes and names',
'',
'| Code | State | ISO 3166-2 |',
'|---|---|---|',
...states.map(({ code, name, iso }) => `| \`${code}\` | ${name} | \`${iso}\` |`),
'',
'## Source',
'',
source,
'',
];
return { slug: 'state-codes', text: wrapTables(lines.join('\n')) };
}

/**
* Writes the spec pages into the docs collection. The build calls it before it reads the pages.
*
Expand All @@ -104,7 +158,8 @@ export function writeSpecPages(root: string): void {
const commit = execFileSync('git', ['-C', specDir, 'rev-parse', 'HEAD'], { encoding: 'utf8' });
const folder = join(root, 'src/content/docs/spec');
mkdirSync(folder, { recursive: true });
for (const { slug, text } of specPages(specDir, commit.trim())) {
const pages = [...specPages(specDir, commit.trim()), stateCodesPage(specDir, commit.trim())];
for (const { slug, text } of pages) {
writeFileSync(join(folder, `${slug}.md`), text);
}
}
4 changes: 2 additions & 2 deletions src/content/docs/guides/html.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Add a postcode field to a web form
description: Use the gatepost-postcode-field element in any HTML form, with or without a framework.
title: Add a Nigerian postcode field to an HTML form
description: Add a Nigerian postcode field to any HTML form with the gatepost-postcode-field element. It checks the format while the user types.
sidebar:
label: HTML field
order: 4
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/guides/php.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Check and look up postcodes in PHP
description: Read Nigeria's digital postcodes offline and query NIPOST's gateway with gatepost/postcode.
title: Validate and look up Nigerian postcodes in PHP
description: Validate Nigeria's digital postcodes offline, and call the NIPOST postcode API, in PHP with the gatepost/postcode Composer package.
sidebar:
label: PHP
order: 3
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/guides/react.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Add a postcode field to a React form
description: Use the PostcodeField component of @gatepost/react in React 18 or 19, and in Next.js.
title: Add a Nigerian postcode field to a React form
description: Add a Nigerian postcode field to a React 18 or 19 form, or to Next.js, with the PostcodeField component of @gatepost/react.
sidebar:
label: React
order: 5
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/guides/typescript-client.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Look up postcodes in TypeScript
description: Ask NIPOST's gateway about a postcode, a place or a typed code with @gatepost/client.
title: Use the NIPOST postcode API from TypeScript
description: Look up a Nigerian postcode with NIPOST's API and @gatepost/client. Find the postcode of a place, and complete a postcode as the user types.
sidebar:
label: TypeScript client
order: 2
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/guides/typescript.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Check postcodes in TypeScript
description: Read, clean and format Nigeria's digital postcodes with @gatepost/core, with no network call.
title: Check Nigerian postcodes in TypeScript
description: Parse and validate Nigeria's digital postcodes in TypeScript or JavaScript with @gatepost/core. It works offline and needs no API key.
sidebar:
label: TypeScript
order: 1
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/guides/woocommerce.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Add the postcode to a WooCommerce checkout
description: Install Gatepost Postcode for WooCommerce, and choose how it checks each postcode.
title: Add the Nigerian postcode to a WooCommerce checkout
description: Show the Nigerian postcode field in the WooCommerce checkout, and check each postcode. The plugin can ask NIPOST whether a postcode exists.
sidebar:
label: WooCommerce
order: 6
Expand Down
41 changes: 37 additions & 4 deletions src/content/docs/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
---
title: Tools for Nigeria's digital postcode
description: Unofficial, open-source developer tools for Nigeria's digital postcode.
title: Tools for Nigeria's NIPOST digital postcode
description: Unofficial open-source tools that check, format and look up Nigeria's NIPOST digital postcode in TypeScript, PHP, HTML forms and WooCommerce.
head:
- tag: meta
attrs:
property: og:type
content: website
# Search engines read this data to name the site and its software. It loads nothing.
- tag: script
attrs:
type: application/ld+json
content: |
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebSite",
"@id": "https://gatepost-dev.github.io/docs/#website",
"name": "Gatepost",
"url": "https://gatepost-dev.github.io/docs/",
"description": "Unofficial open-source developer tools for Nigeria's digital postcode.",
"inLanguage": "en-GB"
},
{
"@type": "SoftwareSourceCode",
"@id": "https://gatepost-dev.github.io/docs/#software",
"name": "Gatepost",
"description": "Open-source tools that check, format and look up Nigeria's NIPOST digital postcode. Unofficial. Not made or endorsed by NIPOST.",
"url": "https://gatepost-dev.github.io/docs/",
"codeRepository": "https://github.com/gatepost-dev",
"programmingLanguage": ["TypeScript", "PHP"],
"license": "https://www.apache.org/licenses/LICENSE-2.0"
}
]
}
template: splash
hero:
title: Gatepost
Expand All @@ -14,7 +47,7 @@ hero:
variant: minimal
---

On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode such as `EK-01-A03-FK-01` has five segments. From large to small, they are the state, the LGA, the district, the area and the unit. The unit is one building.
On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode such as `EK-01-A03-FK-01` has five segments. From large to small, they are the state, the LGA, the district, the area and the unit. The unit is one building. The [postcode format](postcode-format/) page explains each segment, and the [state codes](spec/state-codes/) page lists each state.

Gatepost helps apps, websites and online stores accept these postcodes.

Expand All @@ -24,7 +57,7 @@ Gatepost helps apps, websites and online stores accept these postcodes.
- Recognise an old 6-digit postcode.
- Ask NIPOST's gateway about a postcode with your own API key.

Only NIPOST's gateway can say whether a building has a given postcode. Gatepost checks the form first, so your app calls the gateway less often and with clean input.
Only NIPOST's gateway can say whether a building has a given postcode. Gatepost checks the form first, so your app calls the gateway less often and with clean input. [Validate a Nigerian postcode](validate-postcode/) shows the check in TypeScript, PHP and an HTML form.

Gatepost is independent. NIPOST did not make it and does not support it. For a problem with NIPOST's own app, data or API, contact NIPOST through its official website.

Expand Down
6 changes: 4 additions & 2 deletions src/content/docs/playground.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: Playground
description: Try the postcode parser of @gatepost/core in your browser, with no network call.
title: Nigerian postcode checker
description: Check the format of a Nigerian postcode in your browser, and see its segments, its state and its three forms. Nothing you type leaves the page.
sidebar:
label: Playground
---

import ClientSamples from '../../components/ClientSamples.astro';
Expand Down
99 changes: 99 additions & 0 deletions src/content/docs/postcode-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Nigeria's digital postcode format
description: "The format of Nigeria's NIPOST postcode: five segments, three written forms, the characters of each segment and a regex for the format check."
sidebar:
label: Postcode format
---

On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode has 11 letters and digits in five segments, such as `EK-01-A03-FK-01`. This page describes the format. The [postcode grammar](../spec/grammar/) holds the full rules that every Gatepost SDK follows.

## The five segments

From large to small, the segments are the state, the LGA, the district, the area and the unit. The unit names one building or delivery point.

<div class="table-scroll" role="region" tabindex="0" aria-label="Table: Segments of a postcode">

| Segment | Example | Length | Characters | Rule |
| -------- | ------- | ------ | ----------------- | ------------------------------------------------- |
| State | `EK` | 2 | letters | one of the 37 [state codes](../spec/state-codes/) |
| LGA | `01` | 2 | digits | `01` to `99` |
| District | `A03` | 3 | letters or digits | any combination of letters and digits |
| Area | `FK` | 2 | letters | any two letters |
| Unit | `01` | 2 | digits | `01` to `99` |

</div>

The letters are A to Z, and the digits are 0 to 9. The LGA is a local government area within the state. The district is within the LGA. The area is the smallest polygon in the system.

`00` is never a valid LGA or unit. Both segments run from `01` to `99`, so an area holds at most 99 units. `parse` rejects `EK-01-A03-FK-00` with the error `bad_segment`.

## Partial postcodes

A partial postcode stops after the state, the LGA, the district or the area. It has 2, 4, 7 or 9 letters and digits, such as `EK-01-A03` for a district. `parse` accepts a partial postcode only with the option `allowPartial`.

## Written forms

Gatepost writes a postcode in three forms. All three name the same postcode.

<div class="table-scroll" role="region" tabindex="0" aria-label="Table: Written forms">

| Form | Example | Use |
| --------- | ----------------- | ---------------------- |
| Canonical | `EK-01-A03-FK-01` | APIs and logs |
| Display | `EK 01 A03 FK 01` | screens and print |
| Compact | `EK01A03FK01` | storage and comparison |

</div>

People type postcodes in many ways. Before Gatepost checks a postcode, it normalises the text in three steps:

1. It applies Unicode NFKC. This changes full-width letters and digits to ASCII.
2. It removes each separator: white space, hyphens and dashes, the full stop and zero-width characters.
3. It changes the letters a to z to upper case.

So `ek 01 a03 fk 01`, `EK.01.A03.FK.01` and `EK01A03FK01` are the same postcode.

## Old 6-digit postcodes

Before the digital postcode, NIPOST used postcodes of 6 digits. Many records still hold such a legacy postcode.

<div class="table-scroll" role="region" tabindex="0" aria-label="Table: Legacy and digital postcodes">

| Detail | Legacy postcode | Digital postcode |
| ---------- | --------------- | ------------------------ |
| Example | `900108` | `EK-01-A03-FK-01` |
| Length | 6 | 11 |
| Characters | digits | letters and digits |
| Names | an area | one building or location |

</div>

`parse` gives the error `legacy_code` for exactly 6 digits, and `isLegacy` recognises a legacy postcode. Your form can then ask for the new postcode.

## A regex for the format check

`parse` is the full check. Use a regex where no Gatepost SDK runs, such as in a database rule. This regex accepts the three forms in upper case. It checks the state code and the range of the LGA and the unit.

```ts
const POSTCODE =
/^(?:AB|AD|AK|AN|BA|BE|BR|BY|CR|DE|EB|ED|EK|EN|FC|GM|IM|JI|KD|KE|KG|KN|KT|KW|LA|NA|NI|OG|ON|OS|OY|PL|RI|SK|TA|YB|ZA)[ -]?(?:0[1-9]|[1-9][0-9])[ -]?[A-Z0-9]{3}[ -]?[A-Z]{2}[ -]?(?:0[1-9]|[1-9][0-9])$/;

POSTCODE.test('EK-01-A03-FK-01'); // true
POSTCODE.test('EK 01 A03 FK 01'); // true
POSTCODE.test('EK01A03FK01'); // true
POSTCODE.test('EK-01-A03-FK-00'); // false
POSTCODE.test('XX-01-A03-FK-01'); // false
POSTCODE.test('900108'); // false
```

The regex does less than `parse`. It does not normalise the text. Remove the white space at the start and the end, and change the letters to upper case first. The regex gives no reason for a failure and no suggestion for a typo.

:::note
A postcode in the right format can still be one that NIPOST did not assign. Only NIPOST's gateway can say whether a postcode exists. [Look up a postcode](../guides/typescript-client/) to ask it.
:::

## Next steps

- [Validate a postcode](../validate-postcode/) in TypeScript, PHP or an HTML form.
- [Find the code of a state](../spec/state-codes/).
- [Check a postcode in the playground](../playground/).
6 changes: 4 additions & 2 deletions src/content/docs/privacy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: Privacy
description: What this site keeps, what it sends and what GitHub logs.
title: Privacy of the Gatepost docs
description: This site has no analytics, no tracking and no cookies. Read what your browser keeps, what the site sends and what GitHub logs.
sidebar:
label: Privacy
---

This site has no analytics, no tracking and no cookies. Every script, font, image and style comes from this site itself. No page loads anything from another website.
Expand Down
6 changes: 4 additions & 2 deletions src/content/docs/readiness.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: Readiness tracker
description: Common tools that reject or hide Nigeria's new postcode, and the state of the fix for each one.
title: Readiness tracker for Nigeria's new postcode
description: Common tools, such as Shopify worldwide and WooCommerce, that reject or hide Nigeria's new postcode, and the state of the fix for each one.
sidebar:
label: Readiness tracker
---

On 1 October 2026, NIPOST launched a postcode of 11 letters and digits, as [its docs](https://docs.postcode.gov.ng) describe. Some common tools still accept only the old 6-digit postcode, or hide the postcode field for Nigeria. Gatepost has sent a fix to three of the five tools below and has not sent a fix to the other two. This page shows the state on 3 October 2026.
Expand Down
6 changes: 4 additions & 2 deletions src/content/docs/start.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: Choose a tool
description: Find the Gatepost package that fits your app, and learn what each one needs.
title: Choose a tool for Nigerian postcodes
description: Find the Gatepost package that checks or looks up Nigerian postcodes in TypeScript, PHP, an HTML or React form, or a WooCommerce shop.
sidebar:
label: Choose a tool
---

Each Gatepost tool follows the same spec, so each one reads a postcode in the same way. Choose by the language of your app and by what it must know.
Expand Down
Loading