music-codes
Version:
Small library for music codes (ISRC, ISWC, UPC)
250 lines (249 loc) • 7.09 kB
JavaScript
class p extends Error {
}
class I extends Error {
}
class n extends Error {
}
class h extends Error {
}
class v extends Error {
}
function o(r) {
const t = String(r);
if (!/^\d+$/.test(t)) throw new I(`Invalid code: ${t}`);
const e = t.split("").reverse().reduce((i, c, a) => i + (a % 2 ? 1 : 3) * Number.parseInt(c), 0) % 10;
return e === 0 ? 0 : 10 - e;
}
function u(r) {
throw new p(r);
}
const y = ["GTIN-8", "GTIN-12", "GTIN-13", "GTIN-14", "GSIN", "SSCC"], S = Object.freeze({
"GTIN-8": 8,
"GTIN-12": 12,
"GTIN-13": 13,
"GTIN-14": 14,
GSIN: 17,
SSCC: 18
}), l = Object.fromEntries(
Object.entries(S).map(([r, t]) => [t, r])
);
class s {
constructor(t, e = void 0, i = !0) {
if (!/^\d+$/.test(t))
throw new n(`Invalid GTIN: ${t}`);
if (!l[t.length])
throw new n(`Unsupported GTIN length: ${t.length}`);
if (e && !t.startsWith(e))
throw new n(`Invalid prefix '${e}' for '${t}'`);
if (this.length = t.length, this.code = BigInt(t.slice(0, -1)), this.check = Number.parseInt(t.slice(-1), 10), this.prefix = e, i && this.check !== o(this.code))
throw new n(`Invalid check digit: ${t}`);
}
get gtinFormat() {
return l[this.length] ?? u(`Unsupported GTIN length: ${this.length}`);
}
get realGtinFormat() {
let t = `${this.code}${this.check}`.length;
for (; t < this.length; ) {
const e = l[t];
if (e) return e;
t++;
}
return l[this.length] ?? u(`Unsupported GTIN length: ${this.length}`);
}
first() {
const t = (this.prefix ?? "1").padEnd(this.length - 1, "0"), e = o(t);
return new s(`${t}${e}`, this.prefix, !1);
}
last() {
const t = (this.prefix ?? "9").padEnd(this.length - 1, "9"), e = o(t);
return new s(`${t}${e}`, this.prefix, !1);
}
previous() {
const t = o(this.code - 1n), e = `${this.code - 1n}${t}`.padStart(this.length, "0");
if (this.code === 1n || this.code === BigInt(10n ** BigInt(this.length - 2)))
throw new h(`GTIN boundary reached: ${e}`);
if (this.prefix && !e.startsWith(this.prefix))
throw new h(`GTIN prefix overflow: ${this.prefix}`);
return new s(e, this.prefix, !1);
}
next() {
const t = o(this.code + 1n), e = `${this.code + 1n}${t}`.padStart(this.length, "0");
if (e.length > this.length)
throw new h(`GTIN boundary reached: ${e}`);
if (this.prefix && !e.startsWith(this.prefix))
throw new h(`GTIN prefix overflow: ${this.prefix}`);
return new s(e, this.prefix, !1);
}
*iterate(t = !0) {
let e = this;
for (; ; ) {
yield e;
try {
e = t ? e.next() : e.previous();
} catch {
break;
}
}
}
toString() {
return `${this.code}${this.check}`.padStart(this.length, "0");
}
}
function x(r, t) {
if (!l[t])
throw new n(`Unsupported GTIN length: ${t}`);
if (r.length < 1)
throw new n(`Prefix is too short: ${r}`);
if (r.length > t - 1)
throw new n(`Prefix is too long: ${r}`);
const e = r.padEnd(t - 1, "0"), i = o(e);
return new s(`${e}${i}`, r, !1);
}
function N(r, t) {
if (!/^[\d]{13}$/.test(r))
throw new n(`Invalid EAN: ${r}`);
return new s(r, t, !0);
}
function k(r) {
if (r.length < 1)
throw new n(`Prefix is too short: ${r}`);
if (r.length > 12)
throw new n(`Prefix is too long: ${r}`);
const t = r.padEnd(12, "0"), e = o(t);
return new s(`${t}${e}`, r, !1);
}
class d {
constructor(t, e, i) {
if (!/^([a-zA-Z]{2}[a-zA-Z0-9]{3})$/.test(t))
throw new n(`Invalid prefix: ${t}`);
if (e < 0 || e > 99)
throw new n(`Invalid year: ${e}`);
if (i < 0 || i > 99999)
throw new n(`Invalid code: ${i}`);
this.prefix = t.toUpperCase(), this.year = e, this.code = i;
}
first() {
return new d(this.prefix, this.year, 0);
}
last() {
return new d(this.prefix, this.year, 99999);
}
previous() {
if (this.code === 0)
throw new h(`ISRC boundary reached: ${this.toString()}`);
return new d(this.prefix, this.year, this.code - 1);
}
next() {
if (this.code === 99999)
throw new h(`ISRC boundary reached: ${this.toString()}`);
return new d(this.prefix, this.year, this.code + 1);
}
*iterate(t = !0) {
let e = this;
for (; ; ) {
yield e;
try {
e = t ? e.next() : e.previous();
} catch {
break;
}
}
}
toString() {
return `${this.prefix}${this.year.toString().padStart(2, "0")}${this.code.toString().padStart(5, "0")}`;
}
}
function m(r, t = void 0) {
const e = r.match(/^([a-zA-Z]{2}[a-zA-Z0-9]{3})([\d]{2})([\d]{5})$/i);
if (!e)
throw new n(`Invalid ISRC: ${r}`);
if (t && e[1] !== t)
throw new n(`Invalid prefix '${t}' for '${r}'`);
const i = e[1] ?? "", c = Number.parseInt(e[2] ?? "", 10), a = Number.parseInt(e[3] ?? "", 10);
return new d(i, c, a);
}
class w {
constructor(t, e, i) {
if (t !== "T")
throw new n(`Invalid work type: ${t}`);
if (e < 1 || e >= 1e9)
throw new n(`Invalid code: ${e}`);
const a = (10 - e.toString().padStart(9, "0").split("").map(Number).reduce((f, $, g) => f + (g + 1) * $, 1) % 10) % 10;
if (typeof i < "u" && i !== a)
throw new n(`Invalid check digit: ${i}`);
this.workType = t, this.code = e, this.check = a;
}
first() {
return new w(this.workType, 1);
}
last() {
return new w(this.workType, 999999999);
}
previous() {
if (this.code === 0)
throw new h(`ISWC boundary reached: ${this.toString()}`);
return new w(this.workType, this.code - 1);
}
next() {
if (this.code === 1e10 - 1)
throw new h(`ISWC boundary reached: ${this.toString()}`);
return new w(this.workType, this.code + 1);
}
*iterate(t = !0) {
let e = this;
for (; ; ) {
yield e;
try {
e = t ? e.next() : e.previous();
} catch {
break;
}
}
}
toString(t = !0) {
let e = this.code.toString().padStart(9, "0");
return t && (e = e.replace(/(\d{3})(\d{3})(\d{3})/, "$1.$2.$3")), `${this.workType}-${e}-${this.check}`;
}
}
function T(r) {
const t = r.match(/^(T)-(\d{3}).?(\d{3}).?(\d{3})-(\d)$/);
if (!t)
throw new n(`Invalid ISWC: ${r}`);
const e = t[1] ?? "", i = Number.parseInt(`${t[2]}${t[3]}${t[4]}`, 10), c = Number.parseInt(t[5] ?? "", 10);
return new w(e, i, c);
}
function G(r, t) {
if (!/^[\d]{12}$/.test(r))
throw new n(`Invalid UPC: ${r}`);
return new s(r, t, !0);
}
function b(r) {
if (r.length < 1)
throw new n(`Prefix is too short: ${r}`);
if (r.length > 11)
throw new n(`Prefix is too long: ${r}`);
const t = r.padEnd(11, "0"), e = o(t);
return new s(`${t}${e}`, r, !1);
}
export {
h as BoundaryError,
I as CodeValidationError,
v as FormatError,
s as GTIN,
S as GtinFormatToLength,
y as GtinFormats,
l as GtinLengthToFormat,
d as ISRC,
w as ISWC,
p as InvalidStateError,
n as ParseError,
k as getEanFromPrefix,
x as getGtinFromPrefix,
o as getLuhnCheckDigit,
b as getUpcFromPrefix,
N as parseEAN,
m as parseISRC,
T as parseISWC,
G as parseUPC,
u as raise
};