Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Validate & parse UK postcodes
Utility methods for UK Postcodes, including validating the shape of a postcode, extracting postcode elements (like incodes, outcodes, areas and more).
Tested against ~1.7 million postcodes on ONSPD.
npm install postcode
import { isValid } from "postcode";
isValid("AA1 1AB"); // => true
Pass a string to parse
. This will return a valid or invalid postcode instance which can be easily destructured.
ValidPostcode
type definition
import { parse } from "postcode";
const {
postcode, // => "SW1A 2AA"
outcode, // => "SW1A"
incode, // => "2AA"
area, // => "SW"
district, // => "SW1"
unit, // => "AA"
sector, // => "SW1A 2"
subDistrict, // => "SW1A"
valid, // => true
} = parse("Sw1A 2aa");
InvalidPostcode
type definition
const {
postcode, // => null
outcode, // => null
incode, // => null
area, // => null
district, // => null
unit, // => null
sector, // => null
subDistrict, // => null
valid, // => false
} = parse(" Oh no, ): ");
The TypeScript compiler can infer if you have a valid postcode type from parse
by checking the valid
attribute
import { parse } from "postcode";
const postcode = parse("SW1A 2AA");
if (postcode.valid) {
// `postcode` adheres to the `ValidPostcode` interface
processString(postcode.outcode.toLowerCase()); // TypeScript compiler knows `outcode` to be a string
processString(postcode.subDistrict.toLowerCase()); // And it will throw errors on common gotchas (e.g. subdistrict can be `null` on a valid postcode)
} else {
// `postcode` adheres to the `InvalidPostcode` interface
processInvalidPostcode(postcode);
}
Postcode | .outcode | .incode | .area | .district | .subDistrict | .sector | .unit |
---|---|---|---|---|---|---|---|
AA9A 9AA | AA9A | 9AA | AA | AA9 | AA9A | AA9A 9 | AA |
A9A 9AA | A9A | 9AA | A | A9 | A9A | A9A 9 | AA |
A9 9AA | A9 | 9AA | A | A9 | null | A9 9 | AA |
A99 9AA | A99 | 9AA | A | A99 | null | A99 9 | AA |
AA9 9AA | AA9 | 9AA | AA | AA9 | null | AA9 9 | AA |
AA99 9AA | AA99 | 9AA | AA | AA99 | null | AA99 9 | AA |
If you're just after a single value, you can import a single method.
isValid("Sw1A 2aa"); // => true
import {
toNormalised,
toOutcode,
toIncode,
toArea,
toDistrict,
toSubDistrict,
toSector,
toUnit,
} from "postcode";
toNormalised("Sw1A 2aa"); // => "SW1A 2AA"
toOutcode("Sw1A 2aa"); // => "SW1A"
toIncode("Sw1A 2aa"); // => "2AA"
toArea("Sw1A 2aa"); // => "AA"
toDistrict("Sw1A 2aa"); // => "SW1"
toSubDistrict("Sw1A 2aa"); // => "SW1A"
toSector("Sw1A 2aa"); // => "SW1A 2"
toUnit("Sw1A 2aa"); // => "AA"
fix
Attempts to correct and clean up a postcode without validating by replacing commonly misplaced characters (e.g. mixing up 0
and "O"
, 1
and "I"
). This method will also uppercase and fix spacing. The original input is returned if it cannot be reliably fixed.
fix("SWIA 2AA") => "SW1A 2AA" // Corrects I to 1
fix("SW1A 21A") => "SW1A 2IA" // Corrects 1 to I
fix("SW1A OAA") => "SW1A 0AA" // Corrects O to 0
fix("SW1A 20A") => "SW1A 2OA" // Corrects 0 to O
// Other effects
fix(" SW1A 2AO") => "SW1A 2AO" // Properly spaces
fix("SW1A 2A0") => "SW1A 2AO" // 0 is coerced into "0"
Aims to be used in conjunction with parse to make postcode entry more forgiving:
const { inward } = parse(fix("SW1A 2A0")); // inward = "2AO"
If the input is not deemed fixable, the original string will be returned
fix("12a") => "12a"
match
. Retrieve valid postcodes in a body of text
const matches = match("The PM and her no.2 live at SW1A2aa and SW1A 2AB"); // => ["SW1A2aa", "SW1A 2AB"]
// Perform transformations like normalisation using `.map` and `toNormalised`
matches.map(toNormalised); // => ["SW1A 2AA", "SW1A 2AB"]
matches.map(toOutcode); // => ["SW1A", "SW1A"]
// No matches yields empty array
match("Some London outward codes are SW1A, NW1 and E1"); // => []
replace
. Replace postcodes in a body of text, returning the updated corpus and any matching postcodes
const { match, result } = replace("The PM and her no.2 live at SW1A2AA and SW1A 2AB");
// => match: ["SW1A2AA", "SW1A 2AB"]
// => result: "The PM and her no.2 live at and "
// Add custom replacement
replace("The PM lives at SW1A 2AA", "Downing Street");
// => { match: ["SW1A 2AA"], result: "The PM lives at Downing Street" };
// No match
replace("Some London outward codes are SW1A, NW1 and E1");
// => { match: [], result: "Some London outward codes are SW1A, NW1 and E1" }
5.0.0 brings changes which allows for better treeshaking and interopability with ES Modules. It also deprecates legacy class based APIs in favour of single purpose methods.
postcode
no longer exports a class. Legacy new Postcode()
functionality has been removed. Methods attached to Postcode
are all available as named exports.postcode
no longer uses default exports. All exports are named. E.g.// In <= 4.0.0
import Postcode from "postcode";
Postcode.parse("SW1A 2AA");
// In >= 5.0.0
import { parse } from "postcode";
parse("SW1A 2AA");
In many cases, migration can be achieved by changing import Postcode from "postcode"
to import * as Postcode from "postcode"
, however this gives up treeshaking advantages.
postcode
now exports a ES Module buildmatch
accepts a string and returns all valid postcodesreplace
accepts a string and replaces valid postcodes with an optional second argument. Default replacement text is empty string ""
See the postcode format guide for a glossary of postcode component terms.
Postcodes cannot be validated just with a regular expression (however complex). True postcode validation requires having a full list of postcodes to check against. Relying on a regex will produce false postives/negatives.
See the postcode validation guide for an overview of the approaches and tradeoffs associated with postcode validation.
npm test
MIT
Contains Ordnance Survey Data © Crown Copyright & Database Right
FAQs
UK Postcode helper methods
We found that postcode demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.