diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ea89a..1e25852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## v3.0.0 - unreleased +Most notably, v3 switches the letter case of generated IDs from uppercase (e.g., +"036Z951MHJIKZIK2GSL81GR7L") to lowercase (e.g., "036z951mhjikzik2gsl81gr7l"), +though it is technically not supposed to break existing code because SCRU128 is +a case-insensitive scheme. Other changes include the removal of deprecated APIs. + ### Removed - CommonJS entry point @@ -14,6 +19,10 @@ in Node v14 or older where Web Crypto API is not yet available - Non-ESM browser test runner +### Changed + +- Letter case of generated IDs from uppercase to lowercase + ## v2.5.0 - 2023-06-21 ### Added diff --git a/README.md b/README.md index 72ebe84..bd14a6d 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,15 @@ decentralized, globally unique time-ordered identifiers. SCRU128 is inspired by ```javascript import { scru128, scru128String } from "scru128"; // or on browsers: -// import { scru128, scru128String } from "https://unpkg.com/scru128@^2"; +// import { scru128, scru128String } from "https://unpkg.com/scru128@^3"; // generate a new identifier object const x = scru128(); -console.log(String(x)); // e.g. "036Z951MHJIKZIK2GSL81GR7L" +console.log(String(x)); // e.g., "036z951mhjikzik2gsl81gr7l" console.log(x.toBigInt()); // as a 128-bit unsigned integer // generate a textual representation directly -console.log(scru128String()); // e.g. "036Z951MHZX67T63MQ9XE6Q0J" +console.log(scru128String()); // e.g., "036z951mhzx67t63mq9xe6q0j" ``` See [SCRU128 Specification] for details. diff --git a/src/index.ts b/src/index.ts index 427ea9b..d2bf3d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,15 +5,15 @@ * ```javascript * import { scru128, scru128String } from "scru128"; * // or on browsers: - * // import { scru128, scru128String } from "https://unpkg.com/scru128@^2"; + * // import { scru128, scru128String } from "https://unpkg.com/scru128@^3"; * * // generate a new identifier object * const x = scru128(); - * console.log(String(x)); // e.g. "036Z951MHJIKZIK2GSL81GR7L" + * console.log(String(x)); // e.g., "036z951mhjikzik2gsl81gr7l" * console.log(x.toBigInt()); // as a 128-bit unsigned integer * * // generate a textual representation directly - * console.log(scru128String()); // e.g. "036Z951MHZX67T63MQ9XE6Q0J" + * console.log(scru128String()); // e.g., "036z951mhzx67t63mq9xe6q0j" * ``` * * @packageDocumentation @@ -29,7 +29,7 @@ const MAX_COUNTER_HI = 0xff_ffff; const MAX_COUNTER_LO = 0xff_ffff; /** Digit characters used in the Base36 notation. */ -const DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +const DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"; /** An O(1) map from ASCII code points to Base36 digit values. */ const DECODE_MAP = [ @@ -55,7 +55,7 @@ const DEFAULT_ROLLBACK_ALLOWANCE = 10_000; // 10 seconds * ```javascript * import { Scru128Id } from "scru128"; * - * const x = Scru128Id.fromString("036Z968FU2TUGY7SVKFZNEWKK"); + * const x = Scru128Id.fromString("036z968fu2tugy7svkfznewkk"); * console.log(String(x)); * * const y = Scru128Id.fromBigInt(0x017fa1de51a80fd992f9e8cc2d5eb88en); @@ -592,9 +592,9 @@ export class Scru128Generator { * import { Scru128Generator } from "scru128"; * * const [a, b, c] = new Scru128Generator(); - * console.log(String(a)); // e.g. "038MQR9E14CJC12DH9AMW7I5O" - * console.log(String(b)); // e.g. "038MQR9E14CJC12DH9DTPWFR3" - * console.log(String(c)); // e.g. "038MQR9E14CJC12DH9E6RJMQI" + * console.log(String(a)); // e.g., "038mqr9e14cjc12dh9amw7i5o" + * console.log(String(b)); // e.g., "038mqr9e14cjc12dh9dtpwfr3" + * console.log(String(c)); // e.g., "038mqr9e14cjc12dh9e6rjmqi" * ``` */ [Symbol.iterator](): Iterator { diff --git a/test/identifier.mjs b/test/identifier.mjs index 48a2007..e313e0c 100644 --- a/test/identifier.mjs +++ b/test/identifier.mjs @@ -40,8 +40,8 @@ describe("Scru128Id", function () { const fromString = Scru128Id.fromString(e[1]); assert(fromFields.equals(fromString)); - assert(fromFields.toString() === e[1].toUpperCase()); - assert(fromString.toString() === e[1].toUpperCase()); + assert(fromFields.toString() === e[1].toLowerCase()); + assert(fromString.toString() === e[1].toLowerCase()); for (let i = 0; i < fs.length; i++) { assert(fromFields[fs[i]] === e[0][i]); assert(fromString[fs[i]] === e[0][i]); @@ -52,25 +52,25 @@ describe("Scru128Id", function () { it("throws error if an invalid string representation is supplied", function () { const cases = [ "", - " 036Z8PUQ4TSXSIGK6O19Y164Q", - "036Z8PUQ54QNY1VQ3HCBRKWEB ", - " 036Z8PUQ54QNY1VQ3HELIVWAX ", - "+036Z8PUQ54QNY1VQ3HFCV3SS0", - "-036Z8PUQ54QNY1VQ3HHY8U1CH", - "+36Z8PUQ54QNY1VQ3HJQ48D9P", - "-36Z8PUQ5A7J0TI08OZ6ZDRDY", - "036Z8PUQ5A7J0T_08P2CDZ28V", - "036Z8PU-5A7J0TI08P3OL8OOL", - "036Z8PUQ5A7J0TI08P4J 6CYA", - "F5LXX1ZZ5PNORYNQGLHZMSP34", - "ZZZZZZZZZZZZZZZZZZZZZZZZZ", - "039O\tVVKLFMQLQE7FZLLZ7C7T", - "039ONVVKLFMQLQ漢字FGVD1", - "039ONVVKL🤣QE7FZR2HDOQU", - "頭ONVVKLFMQLQE7FZRHTGCFZ", - "039ONVVKLFMQLQE7FZTFT5尾", - "039漢字A52XP4BVF4SN94E09CJA", - "039OOA52XP4BV😘SN97642MWL", + " 036z8puq4tsxsigk6o19y164q", + "036z8puq54qny1vq3hcbrkweb ", + " 036z8puq54qny1vq3helivwax ", + "+036z8puq54qny1vq3hfcv3ss0", + "-036z8puq54qny1vq3hhy8u1ch", + "+36z8puq54qny1vq3hjq48d9p", + "-36z8puq5a7j0ti08oz6zdrdy", + "036z8puq5a7j0t_08p2cdz28v", + "036z8pu-5a7j0ti08p3ol8ool", + "036z8puq5a7j0ti08p4j 6cya", + "f5lxx1zz5pnorynqglhzmsp34", + "zzzzzzzzzzzzzzzzzzzzzzzzz", + "039o\tvvklfmqlqe7fzllz7c7t", + "039onvvklfmqlq漢字fgvd1", + "039onvvkl🤣qe7fzr2hdoqu", + "頭onvvklfmqlqe7fzrhtgcfz", + "039onvvklfmqlqe7fztft5尾", + "039漢字a52xp4bvf4sn94e09cja", + "039ooa52xp4bv😘sn97642mwl", ]; for (const e of cases) { diff --git a/test/index.mjs b/test/index.mjs index bc04683..e1713ae 100644 --- a/test/index.mjs +++ b/test/index.mjs @@ -27,7 +27,7 @@ describe("scru128String()", function () { } it("generates 25-digit canonical string", function () { - const re = /^[0-9A-Z]{25}$/; + const re = /^[0-9a-z]{25}$/; assert(samples.every((e) => typeof e === "string" && re.test(e))); });