Deterministic UK postcode normalisation and correction for JavaScript/TypeScript, ported from jamiethompson/cikmov-php.
cikmov-js is a parity-led port of cikmov-php built around strict postcode grammar rules, not fuzzy matching.
Design principles:
- deterministic outcomes for the same input/options
- pure functions and immutable results
- no network lookups or allocation datasets
- rule-backed correction only
This package validates/corrects postcode format grammar only.
npm install cikmov-jsimport { normalise } from "cikmov-js";
const result = normalise("ec1a ial");
console.log(result);
// {
// input: 'ec1a ial',
// normalised: 'EC1A 1AL',
// isValid: true,
// isCorrected: true,
// errors: []
// }export interface NormaliseOptions {
correctionMode?: "none" | "strict" | "lenient";
}
export interface NormaliseResult {
readonly input: string;
readonly normalised: string | null;
readonly isValid: boolean;
readonly isCorrected: boolean;
readonly errors: readonly string[];
}
export function normalise(input: string, options?: NormaliseOptions): NormaliseResult;correctionMode controls when corrections are applied:
undefined(default): parity mode, equivalent to PHP default threshold (85)strict: applies only high-confidence corrections (>=95)lenient: applies broader corrections (>=80)none: never applies corrections to invalid input, but still validates already-valid input
input: original raw inputnormalised: canonical postcode when valid/corrected, otherwisenullisValid:truewhen canonical output is availableisCorrected:trueonly when input was invalid and correctederrors: deterministic error codes when invalid
Error codes:
INPUT_EMPTYMISSING_REQUIRED_CHARACTER_CLASSESNO_VALID_CANDIDATECONFIDENCE_BELOW_THRESHOLDCORRECTION_DISABLED
import { normalise } from "cikmov-js";
normalise("S01 1AA");
// default/parity => { normalised: 'SO1 1AA', isValid: true, isCorrected: true, errors: [] }
normalise("S01 1AA", { correctionMode: "strict" });
// => { normalised: null, isValid: false, isCorrected: false, errors: ['CONFIDENCE_BELOW_THRESHOLD'] }
normalise("EC1A IAL", { correctionMode: "none" });
// => { normalised: null, isValid: false, isCorrected: false, errors: ['CORRECTION_DISABLED'] }normalise("!!!!");
// => { normalised: null, isValid: false, isCorrected: false, errors: ['INPUT_EMPTY'] }
normalise("ABCDE");
// => { normalised: null, isValid: false, isCorrected: false, errors: ['MISSING_REQUIRED_CHARACTER_CLASSES'] }
normalise("GIR 0AA");
// => { normalised: 'GIR 0AA', isValid: true, isCorrected: false, errors: [] }import { normalise } from "cikmov-js";
const postcode = process.argv[2] ?? "EC1A IAL";
console.log(normalise(postcode));import { computed, ref } from "vue";
import { normalise } from "cikmov-js";
const postcode = ref("ec1a ial");
const normalised = computed(() => normalise(postcode.value));import { normalise } from "cikmov-js";
export function PostcodeLabel({ input }: { input: string }) {
const result = normalise(input);
return <span>{result.normalised ?? "Invalid"}</span>;
}import { Injectable } from "@angular/core";
import { normalise } from "cikmov-js";
@Injectable({ providedIn: "root" })
export class PostcodeService {
public normaliseInput(input: string) {
return normalise(input);
}
}API migration:
- PHP:
Cikmov::analyse(string $input, int $minConfidenceToApply = 85) - JS:
normalise(input, { correctionMode? })
Result shape migration:
- PHP fields like
confidence,bestCandidate,alternatives, andappliedPostcodeare internalized. - JS exposes a focused public contract:
normalised,isValid,isCorrected,errors.
Threshold migration:
- default JS behavior maps to PHP default threshold (
85) for parity strictandlenientare convenience threshold profiles
For design rationale and any divergence notes, see ADR.md.
- SemVer is used for releases.
0.xis parity-hardening phase.1.0.0is targeted after parity and API stability are fully proven.- Supported runtime baseline: Node.js
20+and modern ES2020+ browser bundles.
npm install
npm run verifyverify runs lint, typecheck, tests, and build.