Functional Weave
Code in TypeScript

logistics.hs-code-validate@1.0.0

impl/typescript.ts

1,575 bytes · the TypeScript implementation · view raw

import { type HsCodeCheck } from "./logistics_hs_code_validate_types.ts";

const KINDS: { readonly [length: number]: string } = { 6: "hs", 8: "cn", 10: "taric" };

function invalid(reason: string): HsCodeCheck {
  return { valid: false, normalised: null, kind: null, chapter: null, heading: null, subheading: null, reason };
}

/**
 * Check the format of a 6-digit HS, 8-digit CN or 10-digit TARIC/UK commodity
 * code. Validators answer rather than throw: a malformed code is the answer "no".
 */
export function validateHsCode(value: string): HsCodeCheck {
  if (typeof value !== "string") return invalid("empty");
  let digits = "";
  for (const ch of value) {
    if (ch === " " || ch === ".") continue;
    if (ch < "0" || ch > "9") return invalid("bad-character");
    digits += ch;
  }
  if (digits.length === 0) return invalid("empty");
  const kind = KINDS[digits.length];
  if (kind === undefined) return invalid("bad-length");

  // Text, not a number: chapter "01" must keep its zero.
  const chapter = digits.slice(0, 2);
  if (chapter === "00") return invalid("bad-chapter");
  if (chapter === "77") return invalid("reserved-chapter");
  // 98 and 99 are left to national tariffs, so only a national-length code may use them.
  if ((chapter === "98" || chapter === "99") && kind === "hs") return invalid("national-chapter");
  if (digits.slice(2, 4) === "00") return invalid("bad-heading");

  return {
    valid: true,
    normalised: digits,
    kind,
    chapter,
    heading: digits.slice(0, 4),
    subheading: digits.slice(0, 6),
    reason: null,
  };
}