From ddb7ee961dcbb35bbdeb97d44301ad4b725fbe65 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 2 Jun 2020 18:37:41 +0300 Subject: [PATCH 01/18] test: parsing non RFC uuid values (#455) * test: parsing non RFC uuid values * feat: create validate, version, uuidRegex (and import to public API) * style: always curly braces added comments to numberToBytes func preallocated array in uuidToBytes func * Update src/regex.js Co-authored-by: Robert Kieffer * Update src/validate.js Co-authored-by: Robert Kieffer * Update src/version.js Co-authored-by: Robert Kieffer * Update test/unit/version.test.js Co-authored-by: Robert Kieffer * feat: throw error when invalid uuid * test: validate function * feat: short version of parsing UUID * fix: remove explicit ie babel target * Revert "feat: short version of parsing UUID" This reverts commit d096cc21b14e84f86e2fd7d6bf5068cb1124b157. Co-authored-by: Robert Kieffer Co-authored-by: Christoph Tavan --- src/index.js | 3 +++ src/regex.js | 3 +++ src/v35.js | 25 ++++++++++++++++++++----- src/validate.js | 7 +++++++ src/version.js | 11 +++++++++++ test/unit/validate.test.js | 31 +++++++++++++++++++++++++++++++ test/unit/version.test.js | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/regex.js create mode 100644 src/validate.js create mode 100644 src/version.js create mode 100644 test/unit/validate.test.js create mode 100644 test/unit/version.test.js diff --git a/src/index.js b/src/index.js index 30870af0..7702f92a 100644 --- a/src/index.js +++ b/src/index.js @@ -2,3 +2,6 @@ export { default as v1 } from './v1.js'; export { default as v3 } from './v3.js'; export { default as v4 } from './v4.js'; export { default as v5 } from './v5.js'; +export { default as REGEX } from './regex.js'; +export { default as version } from './version.js'; +export { default as validate } from './validate.js'; diff --git a/src/regex.js b/src/regex.js new file mode 100644 index 00000000..4ed878b6 --- /dev/null +++ b/src/regex.js @@ -0,0 +1,3 @@ +const REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + +export default REGEX; diff --git a/src/v35.js b/src/v35.js index 67fa8d8c..dc7775fe 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,12 +1,27 @@ import bytesToUuid from './bytesToUuid.js'; +import validate from './validate.js'; + +// Int32 to 4 bytes https://stackoverflow.com/a/12965194/3684944 +function numberToBytes(num, bytes, offset) { + for (let i = 0; i < 4; ++i) { + const byte = num & 0xff; + // Fill the 4 bytes right-to-left. + bytes[offset + 3 - i] = byte; + num = (num - byte) / 256; + } +} function uuidToBytes(uuid) { - // Note: We assume we're being passed a valid uuid string - const bytes = []; + if (!validate(uuid)) { + return []; + } + + const bytes = new Array(16); - uuid.replace(/[a-fA-F0-9]{2}/g, function (hex) { - bytes.push(parseInt(hex, 16)); - }); + numberToBytes(parseInt(uuid.slice(0, 8), 16), bytes, 0); + numberToBytes(parseInt(uuid.slice(9, 13) + uuid.slice(14, 18), 16), bytes, 4); + numberToBytes(parseInt(uuid.slice(19, 23) + uuid.slice(24, 28), 16), bytes, 8); + numberToBytes(parseInt(uuid.slice(28), 16), bytes, 12); return bytes; } diff --git a/src/validate.js b/src/validate.js new file mode 100644 index 00000000..22a1217e --- /dev/null +++ b/src/validate.js @@ -0,0 +1,7 @@ +import REGEX from './regex.js'; + +function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); +} + +export default validate; diff --git a/src/version.js b/src/version.js new file mode 100644 index 00000000..2b993703 --- /dev/null +++ b/src/version.js @@ -0,0 +1,11 @@ +import validate from './validate.js'; + +function version(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + return parseInt(uuid.substr(14, 1), 16); +} + +export default version; diff --git a/test/unit/validate.test.js b/test/unit/validate.test.js new file mode 100644 index 00000000..12980ae5 --- /dev/null +++ b/test/unit/validate.test.js @@ -0,0 +1,31 @@ +import assert from 'assert'; +import validate from '../../src/validate.js'; + +describe('validate', () => { + test('validate uuid', () => { + assert.strictEqual(validate('00000000-0000-0000-0000-000000000000'), true); + + assert.strictEqual(validate('d9428888-122b-11e1-b85c-61cd3cbb3210'), true); + + assert.strictEqual(validate('109156be-c4fb-41ea-b1b4-efe1671c5836'), true); + + assert.strictEqual(validate('a981a0c2-68b1-35dc-bcfc-296e52ab01ec'), true); + + assert.strictEqual(validate('90123e1c-7512-523e-bb28-76fab9f2f73d'), true); + + assert.strictEqual(validate(), false); + + assert.strictEqual(validate(''), false); + + assert.strictEqual(validate('invalid uuid string'), false); + + assert.strictEqual(validate('00000000000000000000000000000000'), false); + + assert.strictEqual( + validate( + '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', + ), + false, + ); + }); +}); diff --git a/test/unit/version.test.js b/test/unit/version.test.js new file mode 100644 index 00000000..32c18261 --- /dev/null +++ b/test/unit/version.test.js @@ -0,0 +1,32 @@ +import assert from 'assert'; +import version from '../../src/version.js'; + +describe('version', () => { + test('check uuid version', () => { + assert.strictEqual(version('00000000-0000-0000-0000-000000000000'), 0); + + assert.strictEqual(version('d9428888-122b-11e1-b85c-61cd3cbb3210'), 1); + + assert.strictEqual(version('109156be-c4fb-41ea-b1b4-efe1671c5836'), 4); + + assert.strictEqual(version('a981a0c2-68b1-35dc-bcfc-296e52ab01ec'), 3); + + assert.strictEqual(version('90123e1c-7512-523e-bb28-76fab9f2f73d'), 5); + + assert.throws(() => version()); + + assert.throws(() => version('')); + + assert.throws(() => version('invalid uuid string')); + + assert.throws(() => { + version('00000000000000000000000000000000'); + }); + + assert.throws(() => { + version( + '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', + ); + }); + }); +}); From 3d24e58e4e8ce9c928138f45eb9118b8e483d18b Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Wed, 24 Jun 2020 07:40:32 -0700 Subject: [PATCH 02/18] Version 9 improvements (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: improved uuidToBytes * chore: comment tweak * chore: bump bundlewatch sizes * fix: uuidToBytes test * feat: export uuidToBytes, uuidToBytes benchmark * chore: review comments * feat: export validate, parse, stringify methods * chore: stringify unit test and benchmark * fix: stringify test in browser * feat: add uuidVersion to rollup exports * chore: bump bundlewatch limits * chore: tweak function name * test: enable browserstack.console setting * fix: revert padStart * fix: pr review comments * fix: no Array.from in IE11 * improvement: hardcode namespace length Co-authored-by: Linus Unnebäck Co-authored-by: Christoph Tavan Co-authored-by: Linus Unnebäck --- bundlewatch.config.json | 14 ++-- examples/benchmark/benchmark.html | 2 + examples/benchmark/benchmark.js | 130 +++++++++++++++++++++--------- package-lock.json | 9 +++ package.json | 1 + rollup.config.js | 5 ++ src/bytesToUuid.js | 40 --------- src/index.js | 2 + src/parse.js | 41 ++++++++++ src/sha1-browser.js | 3 + src/stringify.js | 52 ++++++++++++ src/v1.js | 4 +- src/v35.js | 49 +++-------- src/v4.js | 4 +- test/unit/parse.test.js | 68 ++++++++++++++++ test/unit/stringify.test.js | 55 +++++++++++++ wdio.conf.js | 1 + 17 files changed, 353 insertions(+), 127 deletions(-) delete mode 100644 src/bytesToUuid.js create mode 100644 src/parse.js create mode 100644 src/stringify.js create mode 100644 test/unit/parse.test.js create mode 100644 test/unit/stringify.test.js diff --git a/bundlewatch.config.json b/bundlewatch.config.json index 4a3fb794..f3d7de16 100644 --- a/bundlewatch.config.json +++ b/bundlewatch.config.json @@ -1,13 +1,13 @@ { "files": [ - { "path": "./examples/browser-rollup/dist/v1-size.js", "maxSize": "0.8 kB" }, - { "path": "./examples/browser-rollup/dist/v3-size.js", "maxSize": "1.8 kB" }, - { "path": "./examples/browser-rollup/dist/v4-size.js", "maxSize": "0.5 kB" }, - { "path": "./examples/browser-rollup/dist/v5-size.js", "maxSize": "1.2 kB" }, + { "path": "./examples/browser-rollup/dist/v1-size.js", "maxSize": "0.9 kB" }, + { "path": "./examples/browser-rollup/dist/v3-size.js", "maxSize": "2.1 kB" }, + { "path": "./examples/browser-rollup/dist/v4-size.js", "maxSize": "0.6 kB" }, + { "path": "./examples/browser-rollup/dist/v5-size.js", "maxSize": "1.5 kB" }, { "path": "./examples/browser-webpack/dist/v1-size.js", "maxSize": "1.3 kB" }, - { "path": "./examples/browser-webpack/dist/v3-size.js", "maxSize": "2.2 kB" }, - { "path": "./examples/browser-webpack/dist/v4-size.js", "maxSize": "0.9 kB" }, - { "path": "./examples/browser-webpack/dist/v5-size.js", "maxSize": "1.6 kB" } + { "path": "./examples/browser-webpack/dist/v3-size.js", "maxSize": "2.5 kB" }, + { "path": "./examples/browser-webpack/dist/v4-size.js", "maxSize": "1.0 kB" }, + { "path": "./examples/browser-webpack/dist/v5-size.js", "maxSize": "1.9 kB" } ] } diff --git a/examples/benchmark/benchmark.html b/examples/benchmark/benchmark.html index 54be63f8..2f3bf78f 100644 --- a/examples/benchmark/benchmark.html +++ b/examples/benchmark/benchmark.html @@ -5,6 +5,8 @@ + + diff --git a/examples/benchmark/benchmark.js b/examples/benchmark/benchmark.js index dc3ff19f..cc36adcb 100644 --- a/examples/benchmark/benchmark.js +++ b/examples/benchmark/benchmark.js @@ -5,46 +5,96 @@ const uuidv1 = (typeof window !== 'undefined' && window.uuidv1) || require('uuid const uuidv4 = (typeof window !== 'undefined' && window.uuidv4) || require('uuid').v4; const uuidv3 = (typeof window !== 'undefined' && window.uuidv3) || require('uuid').v3; const uuidv5 = (typeof window !== 'undefined' && window.uuidv5) || require('uuid').v5; +const uuidParse = (typeof window !== 'undefined' && window.uuidParse) || require('uuid').parse; +const uuidStringify = + (typeof window !== 'undefined' && window.uuidStringify) || require('uuid').stringify; console.log('Starting. Tests take ~1 minute to run ...'); -const array = new Array(16); - -const suite = new Benchmark.Suite({ - onError(event) { - console.error(event.target.error); - }, -}); - -suite - .add('uuidv1()', function () { - uuidv1(); - }) - .add('uuidv1() fill existing array', function () { - try { - uuidv1(null, array, 0); - } catch (err) { - // The spec (https://tools.ietf.org/html/rfc4122#section-4.2.1.2) defines that only 10M/s v1 - // UUIDs can be generated on a single node. This library throws an error if we hit that limit - // (which can happen on modern hardware and modern Node.js versions). - } - }) - .add('uuidv4()', function () { - uuidv4(); - }) - .add('uuidv4() fill existing array', function () { - uuidv4(null, array, 0); - }) - .add('uuidv3()', function () { - uuidv3('hello.example.com', uuidv3.DNS); - }) - .add('uuidv5()', function () { - uuidv5('hello.example.com', uuidv5.DNS); - }) - .on('cycle', function (event) { - console.log(event.target.toString()); - }) - .on('complete', function () { - console.log('Fastest is ' + this.filter('fastest').map('name')); - }) - .run(); +function testParseAndStringify() { + const suite = new Benchmark.Suite({ + onError(event) { + console.error(event.target.error); + }, + }); + + const BYTES = [ + 0x0f, + 0x5a, + 0xbc, + 0xd1, + 0xc1, + 0x94, + 0x47, + 0xf3, + 0x90, + 0x5b, + 0x2d, + 0xf7, + 0x26, + 0x3a, + 0x08, + 0x4b, + ]; + + suite + .add('uuidStringify()', function () { + uuidStringify(BYTES); + }) + .add('uuidParse()', function () { + uuidParse('0f5abcd1-c194-47f3-905b-2df7263a084b'); + }) + .on('cycle', function (event) { + console.log(event.target.toString()); + }) + .on('complete', function () { + console.log('---\n'); + }) + .run(); +} + +function testGeneration() { + const array = new Array(16); + + const suite = new Benchmark.Suite({ + onError(event) { + console.error(event.target.error); + }, + }); + + suite + .add('uuidv1()', function () { + uuidv1(); + }) + .add('uuidv1() fill existing array', function () { + try { + uuidv1(null, array, 0); + } catch (err) { + // The spec (https://tools.ietf.org/html/rfc4122#section-4.2.1.2) defines that only 10M/s v1 + // UUIDs can be generated on a single node. This library throws an error if we hit that limit + // (which can happen on modern hardware and modern Node.js versions). + } + }) + .add('uuidv4()', function () { + uuidv4(); + }) + .add('uuidv4() fill existing array', function () { + uuidv4(null, array, 0); + }) + .add('uuidv3()', function () { + uuidv3('hello.example.com', uuidv3.DNS); + }) + .add('uuidv5()', function () { + uuidv5('hello.example.com', uuidv5.DNS); + }) + .on('cycle', function (event) { + console.log(event.target.toString()); + }) + .on('complete', function () { + console.log('Fastest is ' + this.filter('fastest').map('name')); + }) + .run(); +} + +testParseAndStringify(); +testGeneration(); diff --git a/package-lock.json b/package-lock.json index 0debcb87..0896f995 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12437,6 +12437,15 @@ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", "dev": true }, + "random-seed": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/random-seed/-/random-seed-0.3.0.tgz", + "integrity": "sha1-2UXy4fOPSejViRNDG4v2u5N1Vs0=", + "dev": true, + "requires": { + "json-stringify-safe": "^5.0.1" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", diff --git a/package.json b/package.json index 6dcccba7..cb150307 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "lint-staged": "10.1.3", "npm-run-all": "4.1.5", "prettier": "2.0.4", + "random-seed": "0.3.0", "rollup": "2.6.1", "rollup-plugin-terser": "5.3.0", "runmd": "1.3.2", diff --git a/rollup.config.js b/rollup.config.js index 34544dfd..920d599f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -20,4 +20,9 @@ export default [ chunk('v3', 'uuidv3'), chunk('v4', 'uuidv4'), chunk('v5', 'uuidv5'), + + chunk('version', 'uuidVersion'), + chunk('validate', 'uuidValidate'), + chunk('parse', 'uuidParse'), + chunk('stringify', 'uuidStringify'), ]; diff --git a/src/bytesToUuid.js b/src/bytesToUuid.js deleted file mode 100644 index 0f57c69f..00000000 --- a/src/bytesToUuid.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - */ -const byteToHex = []; - -for (let i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); -} - -function bytesToUuid(buf, offset_) { - const offset = offset_ || 0; - - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - return ( - byteToHex[buf[offset + 0]] + - byteToHex[buf[offset + 1]] + - byteToHex[buf[offset + 2]] + - byteToHex[buf[offset + 3]] + - '-' + - byteToHex[buf[offset + 4]] + - byteToHex[buf[offset + 5]] + - '-' + - byteToHex[buf[offset + 6]] + - byteToHex[buf[offset + 7]] + - '-' + - byteToHex[buf[offset + 8]] + - byteToHex[buf[offset + 9]] + - '-' + - byteToHex[buf[offset + 10]] + - byteToHex[buf[offset + 11]] + - byteToHex[buf[offset + 12]] + - byteToHex[buf[offset + 13]] + - byteToHex[buf[offset + 14]] + - byteToHex[buf[offset + 15]] - ).toLowerCase(); -} - -export default bytesToUuid; diff --git a/src/index.js b/src/index.js index 7702f92a..9586a544 100644 --- a/src/index.js +++ b/src/index.js @@ -5,3 +5,5 @@ export { default as v5 } from './v5.js'; export { default as REGEX } from './regex.js'; export { default as version } from './version.js'; export { default as validate } from './validate.js'; +export { default as stringify } from './stringify.js'; +export { default as parse } from './parse.js'; diff --git a/src/parse.js b/src/parse.js new file mode 100644 index 00000000..85edd846 --- /dev/null +++ b/src/parse.js @@ -0,0 +1,41 @@ +import validate from './validate.js'; + +function parse(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + let v; + const arr = new Uint8Array(16); + + // Parse ########-....-....-....-............ + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = (v >>> 16) & 0xff; + arr[2] = (v >>> 8) & 0xff; + arr[3] = v & 0xff; + + // Parse ........-####-....-....-............ + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; + + // Parse ........-....-####-....-............ + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; + + // Parse ........-....-....-####-............ + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; + + // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + arr[10] = ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff; + arr[11] = (v / 0x100000000) & 0xff; + arr[12] = (v >>> 24) & 0xff; + arr[13] = (v >>> 16) & 0xff; + arr[14] = (v >>> 8) & 0xff; + arr[15] = v & 0xff; + + return arr; +} + +export default parse; diff --git a/src/sha1-browser.js b/src/sha1-browser.js index 2bfa2cb0..377dc24c 100644 --- a/src/sha1-browser.js +++ b/src/sha1-browser.js @@ -29,6 +29,9 @@ function sha1(bytes) { for (let i = 0; i < msg.length; ++i) { bytes.push(msg.charCodeAt(i)); } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); } bytes.push(0x80); diff --git a/src/stringify.js b/src/stringify.js new file mode 100644 index 00000000..17e2b0df --- /dev/null +++ b/src/stringify.js @@ -0,0 +1,52 @@ +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ +const byteToHex = []; + +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).substr(1)); +} + +function stringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + const uuid = ( + byteToHex[arr[offset + 0]] + + byteToHex[arr[offset + 1]] + + byteToHex[arr[offset + 2]] + + byteToHex[arr[offset + 3]] + + '-' + + byteToHex[arr[offset + 4]] + + byteToHex[arr[offset + 5]] + + '-' + + byteToHex[arr[offset + 6]] + + byteToHex[arr[offset + 7]] + + '-' + + byteToHex[arr[offset + 8]] + + byteToHex[arr[offset + 9]] + + '-' + + byteToHex[arr[offset + 10]] + + byteToHex[arr[offset + 11]] + + byteToHex[arr[offset + 12]] + + byteToHex[arr[offset + 13]] + + byteToHex[arr[offset + 14]] + + byteToHex[arr[offset + 15]] + ).toLowerCase(); + + // Sanity check for valid UUID. This works because if any of + // the input array values don't map to a defined hex octet, the string length + // will get blown out (e.g. "74af23d8-85undefined2c44-...") + // + // This is a somewhat crude check, but avoids having to check each value + // individually. + if (uuid.length !== 36) { + throw new TypeError( + 'Invalid result UUID. Please ensure input is array-like, and contains 16 integer values 0-255', + ); + } + + return uuid; +} + +export default stringify; diff --git a/src/v1.js b/src/v1.js index dbf4f5ca..0643675e 100644 --- a/src/v1.js +++ b/src/v1.js @@ -1,5 +1,5 @@ import rng from './rng.js'; -import bytesToUuid from './bytesToUuid.js'; +import stringify from './stringify.js'; // **`v1()` - Generate time-based UUID** // @@ -109,7 +109,7 @@ function v1(options, buf, offset) { b[i + n] = node[n]; } - return buf || bytesToUuid(b); + return buf || stringify(b); } export default v1; diff --git a/src/v35.js b/src/v35.js index dc7775fe..e8706ff0 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,30 +1,5 @@ -import bytesToUuid from './bytesToUuid.js'; -import validate from './validate.js'; - -// Int32 to 4 bytes https://stackoverflow.com/a/12965194/3684944 -function numberToBytes(num, bytes, offset) { - for (let i = 0; i < 4; ++i) { - const byte = num & 0xff; - // Fill the 4 bytes right-to-left. - bytes[offset + 3 - i] = byte; - num = (num - byte) / 256; - } -} - -function uuidToBytes(uuid) { - if (!validate(uuid)) { - return []; - } - - const bytes = new Array(16); - - numberToBytes(parseInt(uuid.slice(0, 8), 16), bytes, 0); - numberToBytes(parseInt(uuid.slice(9, 13) + uuid.slice(14, 18), 16), bytes, 4); - numberToBytes(parseInt(uuid.slice(19, 23) + uuid.slice(24, 28), 16), bytes, 8); - numberToBytes(parseInt(uuid.slice(28), 16), bytes, 12); - - return bytes; -} +import stringify from './stringify.js'; +import parse from './parse.js'; function stringToBytes(str) { str = unescape(encodeURIComponent(str)); // UTF8 escape @@ -48,19 +23,21 @@ export default function (name, version, hashfunc) { } if (typeof namespace === 'string') { - namespace = uuidToBytes(namespace); + namespace = parse(namespace); } - if (!Array.isArray(value)) { - throw TypeError('value must be an array of bytes'); + if (namespace.length !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); } - if (!Array.isArray(namespace) || namespace.length !== 16) { - throw TypeError('namespace must be uuid string or an Array of 16 byte values'); - } + // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + let bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); - // Per 4.3 - const bytes = hashfunc(namespace.concat(value)); bytes[6] = (bytes[6] & 0x0f) | version; bytes[8] = (bytes[8] & 0x3f) | 0x80; @@ -74,7 +51,7 @@ export default function (name, version, hashfunc) { return buf; } - return bytesToUuid(bytes); + return stringify(bytes); } // Function#name is not settable on some platforms (#270) diff --git a/src/v4.js b/src/v4.js index 16765828..520613a4 100644 --- a/src/v4.js +++ b/src/v4.js @@ -1,5 +1,5 @@ import rng from './rng.js'; -import bytesToUuid from './bytesToUuid.js'; +import stringify from './stringify.js'; function v4(options, buf, offset) { options = options || {}; @@ -21,7 +21,7 @@ function v4(options, buf, offset) { return buf; } - return bytesToUuid(rnds); + return stringify(rnds); } export default v4; diff --git a/test/unit/parse.test.js b/test/unit/parse.test.js new file mode 100644 index 00000000..7137d953 --- /dev/null +++ b/test/unit/parse.test.js @@ -0,0 +1,68 @@ +import assert from 'assert'; +import uuidv4 from '../../src/v4.js'; +import parse from '../../src/parse.js'; +import stringify from '../../src/stringify.js'; +import gen from 'random-seed'; + +// Use deterministic PRNG for reproducable tests +const rand = gen.create('He who wonders discovers that this in itself is wonder.'); +function rng(bytes = []) { + for (let i = 0; i < 16; i++) { + bytes[i] = rand(256); + } + return bytes; +} + +describe('parse', () => { + test('String -> bytes parsing', () => { + assert.deepStrictEqual( + parse('0f5abcd1-c194-47f3-905b-2df7263a084b'), + Uint8Array.from([ + 0x0f, + 0x5a, + 0xbc, + 0xd1, + 0xc1, + 0x94, + 0x47, + 0xf3, + 0x90, + 0x5b, + 0x2d, + 0xf7, + 0x26, + 0x3a, + 0x08, + 0x4b, + ]), + ); + }); + + test('String -> bytes -> string symmetry for assorted uuids', () => { + for (let i = 0; i < 1000; i++) { + const uuid = uuidv4({ rng }); + assert.equal(stringify(parse(uuid)), uuid); + } + }); + + test('Case neutrality', () => { + // Verify upper/lower case neutrality + assert.deepStrictEqual( + parse('0f5abcd1-c194-47f3-905b-2df7263a084b'), + parse('0f5abcd1-c194-47f3-905b-2df7263a084b'.toUpperCase()), + ); + }); + + test('Null UUID case', () => { + assert.deepStrictEqual( + parse('00000000-0000-0000-0000-000000000000'), + Uint8Array.from(new Array(16).fill(0)), + ); + }); + + test('UUID validation', () => { + assert.throws(() => parse()); + assert.throws(() => parse('invalid uuid')); + assert.throws(() => parse('zyxwvuts-rqpo-nmlk-jihg-fedcba000000')); + }); +}); diff --git a/test/unit/stringify.test.js b/test/unit/stringify.test.js new file mode 100644 index 00000000..94de77d1 --- /dev/null +++ b/test/unit/stringify.test.js @@ -0,0 +1,55 @@ +import assert from 'assert'; +import stringify from '../../src/stringify.js'; + +const BYTES = [ + 0x0f, + 0x5a, + 0xbc, + 0xd1, + 0xc1, + 0x94, + 0x47, + 0xf3, + 0x90, + 0x5b, + 0x2d, + 0xf7, + 0x26, + 0x3a, + 0x08, + 0x4b, +]; + +describe('stringify', () => { + test('Stringify Array', () => { + assert.equal(stringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b'); + }); + + test('Stringify TypedArray', () => { + assert.equal(stringify(Uint8Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b'); + assert.equal(stringify(Int32Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b'); + }); + + test('Stringify w/ offset', () => { + assert.equal(stringify([0, 0, 0, ...BYTES], 3), '0f5abcd1-c194-47f3-905b-2df7263a084b'); + }); + + test('Throws on not enough values', () => { + const bytes = [...BYTES]; + bytes.length = 15; + assert.throws(() => stringify(bytes)); + }); + + test('Throws on undefined value', () => { + const bytes = [...BYTES]; + delete bytes[3]; + bytes.length = 15; + assert.throws(() => stringify(bytes)); + }); + + test('Throws on invalid value', () => { + const bytes = [...BYTES]; + bytes[3] = 256; + assert.throws(() => stringify(bytes)); + }); +}); diff --git a/wdio.conf.js b/wdio.conf.js index 4be214bf..a7cea646 100644 --- a/wdio.conf.js +++ b/wdio.conf.js @@ -12,6 +12,7 @@ const commonCapabilities = { name: 'browser test', 'browserstack.local': true, 'browserstack.debug': false, + 'browserstack.console': 'errors', resolution: '1024x768', }; From 7e2a3847dd081cf15bd2aaa7224ac99aac800bb8 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 11:00:55 -0700 Subject: [PATCH 03/18] feat: add NIL_UUID export, fixes #475 --- examples/browser-webpack/example-all.js | 1 + src/index.js | 1 + src/nil_uuid.js | 1 + test/unit/validate.test.js | 3 ++- test/unit/version.test.js | 3 ++- 5 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/nil_uuid.js diff --git a/examples/browser-webpack/example-all.js b/examples/browser-webpack/example-all.js index f67de6c2..59ed8a7e 100644 --- a/examples/browser-webpack/example-all.js +++ b/examples/browser-webpack/example-all.js @@ -36,6 +36,7 @@ testpage(function (addTest, done) { addTest('Same with default export'); + addTest('uuid.NIL_UUID', uuid.NIL_UUID); addTest('uuid.v1()', uuid.v1()); addTest('uuid.v4()', uuid.v4()); addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS)); diff --git a/src/index.js b/src/index.js index 9586a544..4e2c6694 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ export { default as v1 } from './v1.js'; export { default as v3 } from './v3.js'; export { default as v4 } from './v4.js'; export { default as v5 } from './v5.js'; +export { default as NIL_UUID } from './nil_uuid.js'; export { default as REGEX } from './regex.js'; export { default as version } from './version.js'; export { default as validate } from './validate.js'; diff --git a/src/nil_uuid.js b/src/nil_uuid.js new file mode 100644 index 00000000..de6f830e --- /dev/null +++ b/src/nil_uuid.js @@ -0,0 +1 @@ +export default '00000000-0000-0000-0000-000000000000'; diff --git a/test/unit/validate.test.js b/test/unit/validate.test.js index 12980ae5..19099b03 100644 --- a/test/unit/validate.test.js +++ b/test/unit/validate.test.js @@ -1,9 +1,10 @@ import assert from 'assert'; import validate from '../../src/validate.js'; +import NIL_UUID from '../../src/nil_uuid.js'; describe('validate', () => { test('validate uuid', () => { - assert.strictEqual(validate('00000000-0000-0000-0000-000000000000'), true); + assert.strictEqual(validate(NIL_UUID), true); assert.strictEqual(validate('d9428888-122b-11e1-b85c-61cd3cbb3210'), true); diff --git a/test/unit/version.test.js b/test/unit/version.test.js index 32c18261..3293a763 100644 --- a/test/unit/version.test.js +++ b/test/unit/version.test.js @@ -1,9 +1,10 @@ import assert from 'assert'; import version from '../../src/version.js'; +import NIL_UUID from '../../src/nil_uuid.js'; describe('version', () => { test('check uuid version', () => { - assert.strictEqual(version('00000000-0000-0000-0000-000000000000'), 0); + assert.strictEqual(version(NIL_UUID), 0); assert.strictEqual(version('d9428888-122b-11e1-b85c-61cd3cbb3210'), 1); From 25857284d783995555a20d0422ea092ca2ba23cb Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 11:18:51 -0700 Subject: [PATCH 04/18] chore: cleanup REGEX export --- src/regex.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/regex.js b/src/regex.js index 4ed878b6..92f79a1e 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +1 @@ -const REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; - -export default REGEX; +export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; From b3e9ec9d8d04cd4f7dd4095041aeabc771c5a268 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:06:25 -0700 Subject: [PATCH 05/18] chore: rename NIL_UUID -> NIL --- src/index.js | 3 +-- src/{nil_uuid.js => nil.js} | 0 test/unit/validate.test.js | 4 ++-- test/unit/version.test.js | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) rename src/{nil_uuid.js => nil.js} (100%) diff --git a/src/index.js b/src/index.js index 4e2c6694..142ce9e4 100644 --- a/src/index.js +++ b/src/index.js @@ -2,8 +2,7 @@ export { default as v1 } from './v1.js'; export { default as v3 } from './v3.js'; export { default as v4 } from './v4.js'; export { default as v5 } from './v5.js'; -export { default as NIL_UUID } from './nil_uuid.js'; -export { default as REGEX } from './regex.js'; +export { default as NIL } from './nil.js'; export { default as version } from './version.js'; export { default as validate } from './validate.js'; export { default as stringify } from './stringify.js'; diff --git a/src/nil_uuid.js b/src/nil.js similarity index 100% rename from src/nil_uuid.js rename to src/nil.js diff --git a/test/unit/validate.test.js b/test/unit/validate.test.js index 19099b03..29dbfe98 100644 --- a/test/unit/validate.test.js +++ b/test/unit/validate.test.js @@ -1,10 +1,10 @@ import assert from 'assert'; import validate from '../../src/validate.js'; -import NIL_UUID from '../../src/nil_uuid.js'; +import NIL from '../../src/nil.js'; describe('validate', () => { test('validate uuid', () => { - assert.strictEqual(validate(NIL_UUID), true); + assert.strictEqual(validate(NIL), true); assert.strictEqual(validate('d9428888-122b-11e1-b85c-61cd3cbb3210'), true); diff --git a/test/unit/version.test.js b/test/unit/version.test.js index 3293a763..9e0b8925 100644 --- a/test/unit/version.test.js +++ b/test/unit/version.test.js @@ -1,10 +1,10 @@ import assert from 'assert'; import version from '../../src/version.js'; -import NIL_UUID from '../../src/nil_uuid.js'; +import NIL from '../../src/nil.js'; describe('version', () => { test('check uuid version', () => { - assert.strictEqual(version(NIL_UUID), 0); + assert.strictEqual(version(NIL), 0); assert.strictEqual(version('d9428888-122b-11e1-b85c-61cd3cbb3210'), 1); From 3116a9ec528e6502a9af9c6d399b1bd3e6572241 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:07:23 -0700 Subject: [PATCH 06/18] chore: throw if stringify UUID is not valid --- src/stringify.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/stringify.js b/src/stringify.js index 17e2b0df..71b65370 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -1,3 +1,5 @@ +import validate from './validate.js'; + /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -42,7 +44,13 @@ function stringify(arr, offset = 0) { // individually. if (uuid.length !== 36) { throw new TypeError( - 'Invalid result UUID. Please ensure input is array-like, and contains 16 integer values 0-255', + 'Stringified UUID is invalid (All input values must be integers between 0 and 255)', + ); + } + + if (!validate(uuid)) { + throw TypeError( + 'Stringified UUID is invalid (Confirm the RFC `version` and `variant` fields are valid in the input values)', ); } From 13db698448d0d28c671c34be5602cbe049ad3733 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:08:27 -0700 Subject: [PATCH 07/18] chore: rename UUID_NIL -> NIL --- examples/browser-webpack/example-all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/browser-webpack/example-all.js b/examples/browser-webpack/example-all.js index 59ed8a7e..594db663 100644 --- a/examples/browser-webpack/example-all.js +++ b/examples/browser-webpack/example-all.js @@ -36,7 +36,7 @@ testpage(function (addTest, done) { addTest('Same with default export'); - addTest('uuid.NIL_UUID', uuid.NIL_UUID); + addTest('uuid.NIL', uuid.NIL); addTest('uuid.v1()', uuid.v1()); addTest('uuid.v4()', uuid.v4()); addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS)); From 5d5f23bbc091ff5fa1d24e121f5d8863476f506a Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:08:50 -0700 Subject: [PATCH 08/18] docs: v9 docs --- README.md | 320 ++++++++++++++++++++++++++++----------------------- README_js.md | 311 ++++++++++++++++++++++++++++--------------------- 2 files changed, 350 insertions(+), 281 deletions(-) diff --git a/README.md b/README.md index d5e26ab8..395ab5c8 100644 --- a/README.md +++ b/README.md @@ -21,93 +21,181 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs ## Quickstart +Looking to create some random UUIDs? Here's how ... + +Step 1: Install + ```shell npm install uuid ``` -Once installed, decide which type of UUID you need. RFC4122 provides for four versions, all of which are supported here. In order of popularity, they are: - -- Version 4 (random) - Created from cryptographically-strong random values -- Version 1 (timestamp) - Created from the system clock (plus random values) -- Version 5 (namespace, SHA-1) - Created from user-supplied name and namespace strings -- Version 3 (namespace, MD5) - Like version 5, above, but with a poorer hash algorithm - -**Unsure which one to use?** Use version 4 (random) unless you have a specific need for one of the other versions. See also [this FAQ](https://github.com/tc39/proposal-uuid#faq). - -### Create Version 4 (Random) UUIDs - -ECMAScript Module syntax: +Step 2: Create (ES6 module syntax) ```javascript import { v4 as uuidv4 } from 'uuid'; uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d' ``` -CommonJS syntax: +... or using CommonJS syntax: ```javascript const { v4: uuidv4 } = require('uuid'); uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' ``` -### Create Version 1 (Timestamp) UUIDs +For timestamp UUIDs, namespace UUIDs, and other options read on ... + +## API Summary + +| | | | +| ------------------ | -------------------------------------------- | ----------------- | +| `uuid.NIL` | The nil UUID string (all zeroes) | New in `uuid@8.2` | +| `uuid.parse()` | Convert UUID string to array of bytes | New in `uuid@8.2` | +| `uuid.stringify()` | Convert array of bytes to UUID string | New in `uuid@8.2` | +| `uuid.v1()` | Create a version 1 (timestamp) UUID | | +| `uuid.v3()` | Create a version 3 (namespace w/ MD5) UUID | | +| `uuid.v4()` | Create a version 4 (random) UUID | | +| `uuid.v5()` | Create a version 5 (namespace w/ SHA-1) UUID | | +| `uuid.validate()` | Test a string to see if it is a valid UUID | New in `uuid@8.2` | +| `uuid.version()` | Detect RFC version of a UUID | New in `uuid@8.2` | + +## API + +### uuid.NIL + +The nil UUID string (all zeroes) + +Example: ```javascript -import { v1 as uuidv1 } from 'uuid'; -uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d' +import { NIL as NIL_UUID } from 'uuid'; + +NIL_UUID; // ⇨ '00000000-0000-0000-0000-000000000000' ``` -### Create Version 3 or Version 5 (Namespace) UUIDs +### uuid.parse(str) -⚠️ Version 3 and Version 5 UUIDs are basically the same, differing only in the underlying hash algorithm. Note that per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." +Convert UUID string to array of bytes -⚠️ If using a custom namespace **be sure to generate your own namespace UUID**. You can grab one [here](https://www.uuidgenerator.net/). +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Uint8Array[16]` | +| _throws_ | `TypeError` if `str` is not a valid UUID | + +Example: ```javascript -import { v5 as uuidv5 } from 'uuid'; // For version 5 -import { v3 as uuidv3 } from 'uuid'; // For version 3 +import { parse as uuidParse } from 'uuid'; + +uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ + // Uint8Array [ + // 110, 192, 189, 127, 17, + // 192, 67, 218, 151, 94, + // 42, 138, 217, 235, 174, + // 11 + // ] +``` -// Using predefined DNS namespace (for domain names) -uuidv5('hello.example.com', uuidv5.DNS); // ⇨ 'fdda765f-fc57-5604-a269-52a7df8164ec' -uuidv3('hello.example.com', uuidv3.DNS); // ⇨ '9125a8dc-52ee-365b-a5aa-81b0b3681cf6' +### uuid.stringify(arr[, offset]) -// Using predefined URL namespace (for URLs) -uuidv5('http://example.com/hello', uuidv5.URL); // ⇨ '3bbcee75-cecc-5b56-8031-b6641c1ed1f1' -uuidv3('http://example.com/hello', uuidv3.URL); // ⇨ 'c6235813-3ba4-3801-ae84-e0a6ebb7d138' +Convert array of bytes to UUID string -// Using a custom namespace (See note, above, about generating your own -// namespace UUID) -const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; -uuidv5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681' -uuidv3('Hello, World!', MY_NAMESPACE); // ⇨ 'e8b5a51d-11c8-3310-a6ab-367563f20686' +| | | +| -------------- | ------------------------------------------------------ | +| `arr` | `Array`-like collection of 16 values between 0-255 | +| [`offset` = 0] | `Number` Starting index in the Array | +| _returns_ | `String` | +| _throws_ | `TypeError` If a valid UUID string cannot be generated | + +Example: + +```javascript +import { stringify as uuidStringify } from 'uuid'; + +const uuidBytes = [110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]; + +uuidStringify(uuidBytes); // ⇨ '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b' ``` -## API +### uuid.v1([options[, buffer[, offset]]]) -### Version 4 (Random) +Create an RFC version 1 (timestamp) UUID + +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.node` ] | RFC "node" field as an `Array[6]` of byte values (per 4.1.6) | +| [`options.clockseq`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff | +| [`options.msecs`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) | +| [`options.nsecs`] | RFC "timestamp" field (`Number` of nanseconds to add to `msecs`, should be 0-10,000) | +| [`options.random`] | `Array]` of 16 random bytes (0-255). | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | +| _throws_ | `Error` if more than 10M UUIDs/sec are requested | + +Note: The default [node id](https://tools.ietf.org/html/rfc4122#section-4.1.6) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process. + +Note: `options.random` and `options.rng` are only meaningful on the very first call to `v1()`, where they may be passed to initialize the internal `node` and `clockseq` fields. + +Example: ```javascript -import { v4 as uuidv4 } from 'uuid'; +import { v1 as uuidv1 } from 'uuid'; -// Incantations -uuidv4(); -uuidv4(options); -uuidv4(options, buffer, offset); +uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d' +``` + +Example using `options`: + +```javascript +import { v1 as uuidv1 } from 'uuid'; + +const v1options = { + node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], + clockseq: 0x1234, + msecs: new Date('2011-11-01').getTime(), + nsecs: 5678, +}; +uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab' ``` -Generate and return a RFC4122 version 4 UUID. +### uuid.v3(name, namespace[, buffer[, offset]]) + +Create an RFC version 3 (namespace w/ MD5) UUID + +API is identical to `v5()`, but uses "v3" instead. + +⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." + +### uuid.v4([options[, buffer[, offset]]]) -- `options` - (Object) Optional uuid state to apply. Properties may include: - - `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values. Takes precedence over `options.rng`. - - `rng` - (Function) Random # generator function that returns an Array[16] of byte values (0-255). Alternative to `options.random`. -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. +Create an RFC version 4 (random) UUID + +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.random`] | `Array` of 16 random bytes (0-255) | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | + +Example: + +```javascript +import { v4 as uuidv4 } from 'uuid'; -Returns `buffer`, if specified, otherwise the string form of the UUID +uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' +``` -Example: Generate string UUID with predefined `random` values +Example using predefined `random` values: ```javascript +import { v4 as uuidv4 } from 'uuid'; + const v4options = { random: [ 0x10, @@ -131,137 +219,75 @@ const v4options = { uuidv4(v4options); // ⇨ '109156be-c4fb-41ea-b1b4-efe1671c5836' ``` -Example: Generate two IDs in a single buffer +### uuid.v5(name, namespace[, buffer[, offset]]) -```javascript -const buffer = new Array(); -uuidv4(null, buffer, 0); // ⇨ - // [ - // 27, 157, 107, 205, 187, - // 253, 75, 45, 155, 93, - // 171, 141, 251, 189, 75, - // 237 - // ] -uuidv4(null, buffer, 16); // ⇨ - // [ - // 27, 157, 107, 205, 187, 253, 75, 45, - // 155, 93, 171, 141, 251, 189, 75, 237, - // 155, 29, 235, 77, 59, 125, 75, 173, - // 155, 221, 43, 13, 123, 61, 203, 109 - // ] -``` - -### Version 1 (Timestamp) - -```javascript -import { v1 as uuidv1 } from 'uuid'; +Createa an RFC version 5 (namespace w/ SHA-1) UUID -// Incantations -uuidv1(); -uuidv1(options); -uuidv1(options, buffer, offset); -``` +| | | +| --- | --- | +| `name` | `String \| Array` | +| `namespace` | `String \| Array[16]` Namespace UUID | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | -Generate and return a RFC4122 version 1 (timestamp) UUID. +Note: The RFC `DNS` and `URL` namespaces are available as `v5.DNS` and `v5.URL`. -- `options` - (Object) Optional uuid state to apply. Properties may include: - - `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID. See note 1. - - `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used. - - `msecs` - (Number) Time in milliseconds since unix Epoch. Default: The current time is used. - - `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2. - - `random` - (Number[16]) Array of 16 numbers (0-255) to use for initialization of `node` and `clockseq` as described above. Takes precedence over `options.rng`. - - `rng` - (Function) Random # generator function that returns an Array[16] of byte values (0-255). Alternative to `options.random`. -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. - -Returns `buffer`, if specified, otherwise the string form of the UUID - -Note: The default [node id](https://tools.ietf.org/html/rfc4122#section-4.1.6) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process. - -Example: Generate string UUID with fully-specified options +Example with custom namespace: ```javascript -const v1options = { - node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], - clockseq: 0x1234, - msecs: new Date('2011-11-01').getTime(), - nsecs: 5678, -}; -uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab' -``` +import { v5 as uuidv5 } from 'uuid'; -Example: In-place generation of two binary IDs +// Define a custom namespace. Readers, create your own using something like +// https://www.uuidgenerator.net/ +const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; -```javascript -// Generate two ids in an array -const arr = new Array(); -uuidv1(null, arr, 0); // ⇨ - // [ - // 44, 94, 164, 192, 64, 103, - // 17, 233, 146, 52, 155, 29, - // 235, 77, 59, 125 - // ] -uuidv1(null, arr, 16); // ⇨ - // [ - // 44, 94, 164, 192, 64, 103, 17, 233, - // 146, 52, 155, 29, 235, 77, 59, 125, - // 44, 94, 164, 193, 64, 103, 17, 233, - // 146, 52, 155, 29, 235, 77, 59, 125 - // ] +uuidv5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681' ``` -### Version 5 (Namespace) +Example with RFC `URL` namespace: ```javascript import { v5 as uuidv5 } from 'uuid'; -// Incantations -uuidv5(name, namespace); -uuidv5(name, namespace, buffer); -uuidv5(name, namespace, buffer, offset); +uuidv5('https://www.w3.org/', uuidv5.URL); // ⇨ 'c106a26a-21bb-5538-8bf2-57095d1976c1' ``` -Generate and return a RFC4122 version 5 UUID. +### uuid.validate(str) -- `name` - (String | Array[]) "name" to create UUID with -- `namespace` - (String | Array[]) "namespace" UUID either as a String or Array[16] of byte values -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. Default = 0 +Test a string to see if it is a valid UUID -Returns `buffer`, if specified, otherwise the string form of the UUID +| | | +| --------- | --------------------------------------------------- | +| `str` | `String` to validate | +| _returns_ | `true` if string is a valid UUID, `false` otherwise | Example: ```javascript -uuidv5('hello world', MY_NAMESPACE); // ⇨ '9f282611-e0fd-5650-8953-89c8e342da0b' -``` - -### Version 3 (Namespace) - -⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." - -```javascript -import { v3 as uuidv3 } from 'uuid'; +import { validate as uuidValidate } from 'uuid'; -// Incantations -uuidv3(name, namespace); -uuidv3(name, namespace, buffer); -uuidv3(name, namespace, buffer, offset); +uuidValidate('not a UUID'); // ⇨ false +uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ true ``` -Generate and return a RFC4122 version 3 UUID. +### uuid.version(str) -- `name` - (String | Array[]) "name" to create UUID with -- `namespace` - (String | Array[]) "namespace" UUID either as a String or Array[16] of byte values -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. Default = 0 +Detect RFC version of a UUID -Returns `buffer`, if specified, otherwise the string form of the UUID +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Number` The RFC version of the UUID | +| _throws_ | `TypeError` if `str` is not a valid UUID | Example: ```javascript -uuidv3('hello world', MY_NAMESPACE); // ⇨ '042ffd34-d989-321c-ad06-f60826172424' +import { version as uuidVersion } from 'uuid'; + +uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // ⇨ 1 +uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ 4 ``` ## Command Line diff --git a/README_js.md b/README_js.md index 9241fd8c..6722edb4 100644 --- a/README_js.md +++ b/README_js.md @@ -33,93 +33,175 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs ## Quickstart +Looking to create some random UUIDs? Here's how ... + +Step 1: Install + ```shell npm install uuid ``` -Once installed, decide which type of UUID you need. RFC4122 provides for four versions, all of which are supported here. In order of popularity, they are: - -- Version 4 (random) - Created from cryptographically-strong random values -- Version 1 (timestamp) - Created from the system clock (plus random values) -- Version 5 (namespace, SHA-1) - Created from user-supplied name and namespace strings -- Version 3 (namespace, MD5) - Like version 5, above, but with a poorer hash algorithm - -**Unsure which one to use?** Use version 4 (random) unless you have a specific need for one of the other versions. See also [this FAQ](https://github.com/tc39/proposal-uuid#faq). - -### Create Version 4 (Random) UUIDs - -ECMAScript Module syntax: +Step 2: Create (ES6 module syntax) -```javascript --run v4 +```javascript --run import { v4 as uuidv4 } from 'uuid'; uuidv4(); // RESULT ``` -CommonJS syntax: +... or using CommonJS syntax: -```javascript --run v4cjs +```javascript --run const { v4: uuidv4 } = require('uuid'); uuidv4(); // RESULT ``` -### Create Version 1 (Timestamp) UUIDs +For timestamp UUIDs, namespace UUIDs, and other options read on ... -```javascript --run v1 -import { v1 as uuidv1 } from 'uuid'; -uuidv1(); // RESULT +## API Summary + +| | | | +| ------------------ | -------------------------------------------- | ----------------- | +| `uuid.NIL` | The nil UUID string (all zeroes) | New in `uuid@8.2` | +| `uuid.parse()` | Convert UUID string to array of bytes | New in `uuid@8.2` | +| `uuid.stringify()` | Convert array of bytes to UUID string | New in `uuid@8.2` | +| `uuid.v1()` | Create a version 1 (timestamp) UUID | | +| `uuid.v3()` | Create a version 3 (namespace w/ MD5) UUID | | +| `uuid.v4()` | Create a version 4 (random) UUID | | +| `uuid.v5()` | Create a version 5 (namespace w/ SHA-1) UUID | | +| `uuid.validate()` | Test a string to see if it is a valid UUID | New in `uuid@8.2` | +| `uuid.version()` | Detect RFC version of a UUID | New in `uuid@8.2` | + +## API + +### uuid.NIL + +The nil UUID string (all zeroes) + +Example: + +```javascript --run +import { NIL as NIL_UUID } from 'uuid'; + +NIL_UUID; // RESULT ``` -### Create Version 3 or Version 5 (Namespace) UUIDs +### uuid.parse(str) + +Convert UUID string to array of bytes -⚠️ Version 3 and Version 5 UUIDs are basically the same, differing only in the underlying hash algorithm. Note that per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Uint8Array[16]` | +| _throws_ | `TypeError` if `str` is not a valid UUID | -⚠️ If using a custom namespace **be sure to generate your own namespace UUID**. You can grab one [here](https://www.uuidgenerator.net/). +Example: -```javascript --run v35 -import { v5 as uuidv5 } from 'uuid'; // For version 5 -import { v3 as uuidv3 } from 'uuid'; // For version 3 +```javascript --run +import { parse as uuidParse } from 'uuid'; -// Using predefined DNS namespace (for domain names) -uuidv5('hello.example.com', uuidv5.DNS); // RESULT -uuidv3('hello.example.com', uuidv3.DNS); // RESULT +uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT +``` -// Using predefined URL namespace (for URLs) -uuidv5('http://example.com/hello', uuidv5.URL); // RESULT -uuidv3('http://example.com/hello', uuidv3.URL); // RESULT +### uuid.stringify(arr[, offset]) -// Using a custom namespace (See note, above, about generating your own -// namespace UUID) -const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; -uuidv5('Hello, World!', MY_NAMESPACE); // RESULT -uuidv3('Hello, World!', MY_NAMESPACE); // RESULT +Convert array of bytes to UUID string + +| | | +| -------------- | ------------------------------------------------------ | +| `arr` | `Array`-like collection of 16 values between 0-255 | +| [`offset` = 0] | `Number` Starting index in the Array | +| _returns_ | `String` | +| _throws_ | `TypeError` If a valid UUID string cannot be generated | + +Example: + +```javascript --run +import { stringify as uuidStringify } from 'uuid'; + +const uuidBytes = [110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]; + +uuidStringify(uuidBytes); // RESULT ``` -## API +### uuid.v1([options[, buffer[, offset]]]) -### Version 4 (Random) +Create an RFC version 1 (timestamp) UUID -```javascript -import { v4 as uuidv4 } from 'uuid'; +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.node` ] | RFC "node" field as an `Array[6]` of byte values (per 4.1.6) | +| [`options.clockseq`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff | +| [`options.msecs`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) | +| [`options.nsecs`] | RFC "timestamp" field (`Number` of nanseconds to add to `msecs`, should be 0-10,000) | +| [`options.random`] | `Array]` of 16 random bytes (0-255). | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | +| _throws_ | `Error` if more than 10M UUIDs/sec are requested | -// Incantations -uuidv4(); -uuidv4(options); -uuidv4(options, buffer, offset); +Note: The default [node id](https://tools.ietf.org/html/rfc4122#section-4.1.6) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process. + +Note: `options.random` and `options.rng` are only meaningful on the very first call to `v1()`, where they may be passed to initialize the internal `node` and `clockseq` fields. + +Example: + +```javascript --run +import { v1 as uuidv1 } from 'uuid'; + +uuidv1(); // RESULT ``` -Generate and return a RFC4122 version 4 UUID. +Example using `options`: -- `options` - (Object) Optional uuid state to apply. Properties may include: - - `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values. Takes precedence over `options.rng`. - - `rng` - (Function) Random # generator function that returns an Array[16] of byte values (0-255). Alternative to `options.random`. -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. +```javascript --run +import { v1 as uuidv1 } from 'uuid'; -Returns `buffer`, if specified, otherwise the string form of the UUID +const v1options = { + node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], + clockseq: 0x1234, + msecs: new Date('2011-11-01').getTime(), + nsecs: 5678, +}; +uuidv1(v1options); // RESULT +``` + +### uuid.v3(name, namespace[, buffer[, offset]]) + +Create an RFC version 3 (namespace w/ MD5) UUID + +API is identical to `v5()`, but uses "v3" instead. + +⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." + +### uuid.v4([options[, buffer[, offset]]]) + +Create an RFC version 4 (random) UUID + +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.random`] | `Array` of 16 random bytes (0-255) | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | + +Example: + +```javascript --run +import { v4 as uuidv4 } from 'uuid'; + +uuidv4(); // RESULT +``` + +Example using predefined `random` values: -Example: Generate string UUID with predefined `random` values +```javascript --run +import { v4 as uuidv4 } from 'uuid'; -```javascript --run v4 const v4options = { random: [ 0x10, @@ -143,114 +225,75 @@ const v4options = { uuidv4(v4options); // RESULT ``` -Example: Generate two IDs in a single buffer +### uuid.v5(name, namespace[, buffer[, offset]]) -```javascript --run v4 -const buffer = new Array(); -uuidv4(null, buffer, 0); // RESULT -uuidv4(null, buffer, 16); // RESULT -``` - -### Version 1 (Timestamp) - -```javascript -import { v1 as uuidv1 } from 'uuid'; +Createa an RFC version 5 (namespace w/ SHA-1) UUID -// Incantations -uuidv1(); -uuidv1(options); -uuidv1(options, buffer, offset); -``` +| | | +| --- | --- | +| `name` | `String \| Array` | +| `namespace` | `String \| Array[16]` Namespace UUID | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | -Generate and return a RFC4122 version 1 (timestamp) UUID. +Note: The RFC `DNS` and `URL` namespaces are available as `v5.DNS` and `v5.URL`. -- `options` - (Object) Optional uuid state to apply. Properties may include: - - `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID. See note 1. - - `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used. - - `msecs` - (Number) Time in milliseconds since unix Epoch. Default: The current time is used. - - `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2. - - `random` - (Number[16]) Array of 16 numbers (0-255) to use for initialization of `node` and `clockseq` as described above. Takes precedence over `options.rng`. - - `rng` - (Function) Random # generator function that returns an Array[16] of byte values (0-255). Alternative to `options.random`. -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. +Example with custom namespace: -Returns `buffer`, if specified, otherwise the string form of the UUID - -Note: The default [node id](https://tools.ietf.org/html/rfc4122#section-4.1.6) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process. - -Example: Generate string UUID with fully-specified options - -```javascript --run v1 -const v1options = { - node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], - clockseq: 0x1234, - msecs: new Date('2011-11-01').getTime(), - nsecs: 5678, -}; -uuidv1(v1options); // RESULT -``` +```javascript --run +import { v5 as uuidv5 } from 'uuid'; -Example: In-place generation of two binary IDs +// Define a custom namespace. Readers, create your own using something like +// https://www.uuidgenerator.net/ +const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; -```javascript --run v1 -// Generate two ids in an array -const arr = new Array(); -uuidv1(null, arr, 0); // RESULT -uuidv1(null, arr, 16); // RESULT +uuidv5('Hello, World!', MY_NAMESPACE); // RESULT ``` -### Version 5 (Namespace) +Example with RFC `URL` namespace: -```javascript +```javascript --run import { v5 as uuidv5 } from 'uuid'; -// Incantations -uuidv5(name, namespace); -uuidv5(name, namespace, buffer); -uuidv5(name, namespace, buffer, offset); +uuidv5('https://www.w3.org/', uuidv5.URL); // RESULT ``` -Generate and return a RFC4122 version 5 UUID. +### uuid.validate(str) -- `name` - (String | Array[]) "name" to create UUID with -- `namespace` - (String | Array[]) "namespace" UUID either as a String or Array[16] of byte values -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. Default = 0 +Test a string to see if it is a valid UUID -Returns `buffer`, if specified, otherwise the string form of the UUID +| | | +| --------- | --------------------------------------------------- | +| `str` | `String` to validate | +| _returns_ | `true` if string is a valid UUID, `false` otherwise | Example: -```javascript --run v35 -uuidv5('hello world', MY_NAMESPACE); // RESULT -``` - -### Version 3 (Namespace) +```javascript --run +import { validate as uuidValidate } from 'uuid'; -⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." - -```javascript -import { v3 as uuidv3 } from 'uuid'; - -// Incantations -uuidv3(name, namespace); -uuidv3(name, namespace, buffer); -uuidv3(name, namespace, buffer, offset); +uuidValidate('not a UUID'); // RESULT +uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT ``` -Generate and return a RFC4122 version 3 UUID. +### uuid.version(str) -- `name` - (String | Array[]) "name" to create UUID with -- `namespace` - (String | Array[]) "namespace" UUID either as a String or Array[16] of byte values -- `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. -- `offset` - (Number) Starting index in `buffer` at which to begin writing. Default = 0 +Detect RFC version of a UUID -Returns `buffer`, if specified, otherwise the string form of the UUID +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Number` The RFC version of the UUID | +| _throws_ | `TypeError` if `str` is not a valid UUID | Example: -```javascript --run v35 -uuidv3('hello world', MY_NAMESPACE); // RESULT +```javascript --run +import { version as uuidVersion } from 'uuid'; + +uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // RESULT +uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT ``` ## Command Line From b84bfbe72722b446a21af16eb7bb9db4a0b71be9 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:19:49 -0700 Subject: [PATCH 09/18] fix: browser spec for nil UUID --- test/browser/browser.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/browser/browser.spec.js b/test/browser/browser.spec.js index 3ee235f4..aaf09ba1 100644 --- a/test/browser/browser.spec.js +++ b/test/browser/browser.spec.js @@ -7,6 +7,7 @@ const v4Regex = new RegExp( /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, ); +const v0 = (result) => expect(result).toBe('00000000-0000-0000-0000-000000000000'); const v1 = (result) => expect(result).toMatch(v1Regex); const v4 = (result) => expect(result).toMatch(v4Regex); const v3dns = (result) => expect(result).toBe('9125a8dc-52ee-365b-a5aa-81b0b3681cf6'); @@ -27,6 +28,7 @@ const expectations = { 'uuidv5() URL': v5url, 'uuidv5() MY_NAMESPACE': v5custom, 'Same with default export': ignore, + 'uuid.NIL': v0, 'uuid.v1()': v1, 'uuid.v4()': v4, 'uuid.v3() DNS': v3dns, From 44cc707a944acfcb8309201f9e9a3ec3831dc841 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:33:01 -0700 Subject: [PATCH 10/18] fix: remove nil uuid browser tests --- examples/browser-webpack/example-all.js | 1 - test/browser/browser.spec.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/examples/browser-webpack/example-all.js b/examples/browser-webpack/example-all.js index 594db663..f67de6c2 100644 --- a/examples/browser-webpack/example-all.js +++ b/examples/browser-webpack/example-all.js @@ -36,7 +36,6 @@ testpage(function (addTest, done) { addTest('Same with default export'); - addTest('uuid.NIL', uuid.NIL); addTest('uuid.v1()', uuid.v1()); addTest('uuid.v4()', uuid.v4()); addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS)); diff --git a/test/browser/browser.spec.js b/test/browser/browser.spec.js index aaf09ba1..3ee235f4 100644 --- a/test/browser/browser.spec.js +++ b/test/browser/browser.spec.js @@ -7,7 +7,6 @@ const v4Regex = new RegExp( /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, ); -const v0 = (result) => expect(result).toBe('00000000-0000-0000-0000-000000000000'); const v1 = (result) => expect(result).toMatch(v1Regex); const v4 = (result) => expect(result).toMatch(v4Regex); const v3dns = (result) => expect(result).toBe('9125a8dc-52ee-365b-a5aa-81b0b3681cf6'); @@ -28,7 +27,6 @@ const expectations = { 'uuidv5() URL': v5url, 'uuidv5() MY_NAMESPACE': v5custom, 'Same with default export': ignore, - 'uuid.NIL': v0, 'uuid.v1()': v1, 'uuid.v4()': v4, 'uuid.v3() DNS': v3dns, From 2ee80682541bd0e6a2e62eed775c815ae8258dd7 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Fri, 17 Jul 2020 15:36:40 -0700 Subject: [PATCH 11/18] chore: tweak README --- README.md | 8 ++++---- README_js.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 34adbb54..400e8213 100644 --- a/README.md +++ b/README.md @@ -21,15 +21,15 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs ## Quickstart -Looking to create some random UUIDs? Here's how ... +To create a random UUID... -Step 1: Install +**1. Install** ```shell npm install uuid ``` -Step 2: Create (ES6 module syntax) +**2: Create a UUID** (ES6 module syntax) ```javascript import { v4 as uuidv4 } from 'uuid'; @@ -63,7 +63,7 @@ For timestamp UUIDs, namespace UUIDs, and other options read on ... ### uuid.NIL -The nil UUID string (all zeroes) +The nil UUID string (all zeroes). Example: diff --git a/README_js.md b/README_js.md index 1dfd22d2..dd34f6a9 100644 --- a/README_js.md +++ b/README_js.md @@ -33,15 +33,15 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs ## Quickstart -Looking to create some random UUIDs? Here's how ... +To create a random UUID... -Step 1: Install +**1. Install** ```shell npm install uuid ``` -Step 2: Create (ES6 module syntax) +**2: Create a UUID** (ES6 module syntax) ```javascript --run import { v4 as uuidv4 } from 'uuid'; @@ -75,7 +75,7 @@ For timestamp UUIDs, namespace UUIDs, and other options read on ... ### uuid.NIL -The nil UUID string (all zeroes) +The nil UUID string (all zeroes). Example: From a9791a610b09ad95766a742d11ed474a83ae47e4 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Sun, 19 Jul 2020 11:15:20 -0700 Subject: [PATCH 12/18] fix: readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 400e8213..c1a494b7 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Example: import { parse as uuidParse } from 'uuid'; uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ - // Uint8Array [ + // Uint8Array(16) [ // 110, 192, 189, 127, 17, // 192, 67, 218, 151, 94, // 42, 138, 217, 235, 174, From af334d32463c371641f72de71504d2b18cc2a423 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Sun, 19 Jul 2020 11:19:43 -0700 Subject: [PATCH 13/18] fix: bundlewatch --- bundlewatch.config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundlewatch.config.json b/bundlewatch.config.json index f3d7de16..91b8b756 100644 --- a/bundlewatch.config.json +++ b/bundlewatch.config.json @@ -1,8 +1,8 @@ { "files": [ - { "path": "./examples/browser-rollup/dist/v1-size.js", "maxSize": "0.9 kB" }, + { "path": "./examples/browser-rollup/dist/v1-size.js", "maxSize": "1.0 kB" }, { "path": "./examples/browser-rollup/dist/v3-size.js", "maxSize": "2.1 kB" }, - { "path": "./examples/browser-rollup/dist/v4-size.js", "maxSize": "0.6 kB" }, + { "path": "./examples/browser-rollup/dist/v4-size.js", "maxSize": "0.7 kB" }, { "path": "./examples/browser-rollup/dist/v5-size.js", "maxSize": "1.5 kB" }, { "path": "./examples/browser-webpack/dist/v1-size.js", "maxSize": "1.3 kB" }, From 39a07c95f4b454b446906ee570da30bc5eecab4d Mon Sep 17 00:00:00 2001 From: Christoph Tavan Date: Mon, 20 Jul 2020 10:02:13 +0200 Subject: [PATCH 14/18] fix: readme --- README.md | 66 ++++++++++++++++++++++++++-------------------------- README_js.md | 66 ++++++++++++++++++++++++++-------------------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index c1a494b7..43cee5f9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs - **Small** - Zero-dependency, small footprint, plays nice with "tree shaking" packagers - **CLI** - Includes the [`uuid` command line](#command-line) utility -**Upgrading from uuid\@3?** Your code is probably okay, but check out [Upgrading From uuid\@3](#upgrading-from-uuid3) for details. +**Upgrading from `uuid@3.x`?** Your code is probably okay, but check out [Upgrading From `uuid@3.x`](#upgrading-from-uuid3x) for details. ## Quickstart @@ -29,7 +29,7 @@ To create a random UUID... npm install uuid ``` -**2: Create a UUID** (ES6 module syntax) +**2. Create a UUID** (ES6 module syntax) ```javascript import { v4 as uuidv4 } from 'uuid'; @@ -47,23 +47,23 @@ For timestamp UUIDs, namespace UUIDs, and other options read on ... ## API Summary -| | | | -| ------------------ | -------------------------------------------- | ----------------- | -| `uuid.NIL` | The nil UUID string (all zeroes) | New in `uuid@8.2` | -| `uuid.parse()` | Convert UUID string to array of bytes | New in `uuid@8.2` | -| `uuid.stringify()` | Convert array of bytes to UUID string | New in `uuid@8.2` | -| `uuid.v1()` | Create a version 1 (timestamp) UUID | | -| `uuid.v3()` | Create a version 3 (namespace w/ MD5) UUID | | -| `uuid.v4()` | Create a version 4 (random) UUID | | -| `uuid.v5()` | Create a version 5 (namespace w/ SHA-1) UUID | | -| `uuid.validate()` | Test a string to see if it is a valid UUID | New in `uuid@8.2` | -| `uuid.version()` | Detect RFC version of a UUID | New in `uuid@8.2` | +| | | | +| --- | --- | --- | +| [`uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | New in `uuid@8.2` | +| [`uuid.parse()`](#uuidparsestr) | Convert UUID string to array of bytes | New in `uuid@8.2` | +| [`uuid.stringify()`](#uuidstringifyarr-offset) | Convert array of bytes to UUID string | New in `uuid@8.2` | +| [`uuid.v1()`](#uuidv1options-buffer-offset) | Create a version 1 (timestamp) UUID | | +| [`uuid.v3()`](#uuidv3name-namespace-buffer-offset) | Create a version 3 (namespace w/ MD5) UUID | | +| [`uuid.v4()`](#uuidv4options-buffer-offset) | Create a version 4 (random) UUID | | +| [`uuid.v5()`](#uuidv5name-namespace-buffer-offset) | Create a version 5 (namespace w/ SHA-1) UUID | | +| [`uuid.validate()`](#uuidvalidatestr) | Test a string to see if it is a valid UUID | New in `uuid@8.2` | +| [`uuid.version()`](#uuidversionstr) | Detect RFC version of a UUID | New in `uuid@8.2` | ## API ### uuid.NIL -The nil UUID string (all zeroes). +The nil UUID string (all zeros). Example: @@ -101,12 +101,12 @@ uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ Convert array of bytes to UUID string -| | | -| -------------- | ------------------------------------------------------ | -| `arr` | `Array`-like collection of 16 values between 0-255 | -| [`offset` = 0] | `Number` Starting index in the Array | -| _returns_ | `String` | -| _throws_ | `TypeError` If a valid UUID string cannot be generated | +| | | +| -------------- | --------------------------------------------------------------------------- | +| `arr` | `Array`-like collection of 16 values (starting from `offset`) between 0-255 | +| [`offset` = 0] | `Number` Starting index in the Array | +| _returns_ | `String` | +| _throws_ | `TypeError` if a valid UUID string cannot be generated | Example: @@ -129,7 +129,7 @@ Create an RFC version 1 (timestamp) UUID | [`options.clockseq`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff | | [`options.msecs`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) | | [`options.nsecs`] | RFC "timestamp" field (`Number` of nanseconds to add to `msecs`, should be 0-10,000) | -| [`options.random`] | `Array]` of 16 random bytes (0-255). | +| [`options.random`] | `Array` of 16 random bytes (0-255) | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | | [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | @@ -366,7 +366,7 @@ To load this module directly into older browsers you can use the [UMD (Universal ``` -These CDNs all provide the same [`uuidv4()`](#version-4-random) method: +These CDNs all provide the same [`uuidv4()`](#uuidv4options-buffer-offset) method: ```html ``` -Methods for the other algorithms ([`uuidv1()`](#version-1-timestamp), [`uuidv3()`](#version-3-namespace) and [`uuidv5()`](#version-5-namespace)) are available from the files `uuidv1.min.js`, `uuidv3.min.js` and `uuidv5.min.js` respectively. +Methods for the other algorithms ([`uuidv1()`](#uuidv1options-buffer-offset), [`uuidv3()`](#uuidv3name-namespace-buffer-offset) and [`uuidv5()`](#uuidv5name-namespace-buffer-offset)) are available from the files `uuidv1.min.js`, `uuidv3.min.js` and `uuidv5.min.js` respectively. ## "getRandomValues() not supported" @@ -394,11 +394,11 @@ import { v4 as uuidv4 } from 'uuid'; [In Edge <= 18, Web Crypto is not supported in Web Workers or Service Workers](https://caniuse.com/#feat=cryptography) and we are not aware of a polyfill (let us know if you find one, please). -## Upgrading From uuid\@7 +## Upgrading From `uuid@7.x` ### Only Named Exports Supported When Using with Node.js ESM -uuid\@7 did not come with native ECMAScript Module (ESM) support for Node.js. Importing it in Node.js ESM consequently imported the CommonJS source with a default export. This library now comes with true Node.js ESM support and only provides named exports. +`uuid@7.x` did not come with native ECMAScript Module (ESM) support for Node.js. Importing it in Node.js ESM consequently imported the CommonJS source with a default export. This library now comes with true Node.js ESM support and only provides named exports. Instead of doing: @@ -416,24 +416,24 @@ uuidv4(); ### Deep Requires No Longer Supported -Deep requires like `require('uuid/v4')` [which have been deprecated in uuid\@7](#deep-requires-now-deprecated) are no longer supported. +Deep requires like `require('uuid/v4')` [which have been deprecated in `uuid@7.x`](#deep-requires-now-deprecated) are no longer supported. -## Upgrading From uuid\@3 +## Upgrading From `uuid@3.x` -"_Wait... what happened to uuid\@4 - uuid\@6?!?_" +"_Wait... what happened to `uuid@4.x` - `uuid@6.x`?!?_" -In order to avoid confusion with RFC [version 4](#version-4-random) and [version 5](#version-5-namespace) UUIDs, and a possible [version 6](http://gh.peabody.io/uuidv6/), releases 4 thru 6 of this module have been skipped. Hence, how we're now at uuid\@7. +In order to avoid confusion with RFC [version 4](#uuidv4options-buffer-offset) and [version 5](#uuidv5name-namespace-buffer-offset) UUIDs, and a possible [version 6](http://gh.peabody.io/uuidv6/), releases 4 thru 6 of this module have been skipped. ### Deep Requires Now Deprecated -uuid\@3 encouraged the use of deep requires to minimize the bundle size of browser builds: +`uuid@3.x` encouraged the use of deep requires to minimize the bundle size of browser builds: ```javascript const uuidv4 = require('uuid/v4'); // <== NOW DEPRECATED! uuidv4(); ``` -As of uuid\@7 this library now provides ECMAScript modules builds, which allow packagers like Webpack and Rollup to do "tree-shaking" to remove dead code. Instead, use the `import` syntax: +As of `uuid@7.x` this library now provides ECMAScript modules builds, which allow packagers like Webpack and Rollup to do "tree-shaking" to remove dead code. Instead, use the `import` syntax: ```javascript import { v4 as uuidv4 } from 'uuid'; @@ -449,13 +449,13 @@ uuidv4(); ### Default Export Removed -uuid\@3 was exporting the Version 4 UUID method as a default export: +`uuid@3.x` was exporting the Version 4 UUID method as a default export: ```javascript const uuid = require('uuid'); // <== REMOVED! ``` -This usage pattern was already discouraged in uuid\@3 and has been removed in uuid\@7. +This usage pattern was already discouraged in `uuid@3.x` and has been removed in `uuid@7.x`. ---- Markdown generated from [README_js.md](README_js.md) by [![RunMD Logo](http://i.imgur.com/h0FVyzU.png)](https://github.com/broofa/runmd) \ No newline at end of file diff --git a/README_js.md b/README_js.md index dd34f6a9..0327e1fc 100644 --- a/README_js.md +++ b/README_js.md @@ -29,7 +29,7 @@ For the creation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDs - **Small** - Zero-dependency, small footprint, plays nice with "tree shaking" packagers - **CLI** - Includes the [`uuid` command line](#command-line) utility -**Upgrading from uuid\@3?** Your code is probably okay, but check out [Upgrading From uuid\@3](#upgrading-from-uuid3) for details. +**Upgrading from `uuid@3.x`?** Your code is probably okay, but check out [Upgrading From `uuid@3.x`](#upgrading-from-uuid3x) for details. ## Quickstart @@ -41,7 +41,7 @@ To create a random UUID... npm install uuid ``` -**2: Create a UUID** (ES6 module syntax) +**2. Create a UUID** (ES6 module syntax) ```javascript --run import { v4 as uuidv4 } from 'uuid'; @@ -59,23 +59,23 @@ For timestamp UUIDs, namespace UUIDs, and other options read on ... ## API Summary -| | | | -| ------------------ | -------------------------------------------- | ----------------- | -| `uuid.NIL` | The nil UUID string (all zeroes) | New in `uuid@8.2` | -| `uuid.parse()` | Convert UUID string to array of bytes | New in `uuid@8.2` | -| `uuid.stringify()` | Convert array of bytes to UUID string | New in `uuid@8.2` | -| `uuid.v1()` | Create a version 1 (timestamp) UUID | | -| `uuid.v3()` | Create a version 3 (namespace w/ MD5) UUID | | -| `uuid.v4()` | Create a version 4 (random) UUID | | -| `uuid.v5()` | Create a version 5 (namespace w/ SHA-1) UUID | | -| `uuid.validate()` | Test a string to see if it is a valid UUID | New in `uuid@8.2` | -| `uuid.version()` | Detect RFC version of a UUID | New in `uuid@8.2` | +| | | | +| --- | --- | --- | +| [`uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | New in `uuid@8.2` | +| [`uuid.parse()`](#uuidparsestr) | Convert UUID string to array of bytes | New in `uuid@8.2` | +| [`uuid.stringify()`](#uuidstringifyarr-offset) | Convert array of bytes to UUID string | New in `uuid@8.2` | +| [`uuid.v1()`](#uuidv1options-buffer-offset) | Create a version 1 (timestamp) UUID | | +| [`uuid.v3()`](#uuidv3name-namespace-buffer-offset) | Create a version 3 (namespace w/ MD5) UUID | | +| [`uuid.v4()`](#uuidv4options-buffer-offset) | Create a version 4 (random) UUID | | +| [`uuid.v5()`](#uuidv5name-namespace-buffer-offset) | Create a version 5 (namespace w/ SHA-1) UUID | | +| [`uuid.validate()`](#uuidvalidatestr) | Test a string to see if it is a valid UUID | New in `uuid@8.2` | +| [`uuid.version()`](#uuidversionstr) | Detect RFC version of a UUID | New in `uuid@8.2` | ## API ### uuid.NIL -The nil UUID string (all zeroes). +The nil UUID string (all zeros). Example: @@ -107,12 +107,12 @@ uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT Convert array of bytes to UUID string -| | | -| -------------- | ------------------------------------------------------ | -| `arr` | `Array`-like collection of 16 values between 0-255 | -| [`offset` = 0] | `Number` Starting index in the Array | -| _returns_ | `String` | -| _throws_ | `TypeError` If a valid UUID string cannot be generated | +| | | +| -------------- | --------------------------------------------------------------------------- | +| `arr` | `Array`-like collection of 16 values (starting from `offset`) between 0-255 | +| [`offset` = 0] | `Number` Starting index in the Array | +| _returns_ | `String` | +| _throws_ | `TypeError` if a valid UUID string cannot be generated | Example: @@ -135,7 +135,7 @@ Create an RFC version 1 (timestamp) UUID | [`options.clockseq`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff | | [`options.msecs`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) | | [`options.nsecs`] | RFC "timestamp" field (`Number` of nanseconds to add to `msecs`, should be 0-10,000) | -| [`options.random`] | `Array]` of 16 random bytes (0-255). | +| [`options.random`] | `Array` of 16 random bytes (0-255) | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | | [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | @@ -372,7 +372,7 @@ To load this module directly into older browsers you can use the [UMD (Universal ``` -These CDNs all provide the same [`uuidv4()`](#version-4-random) method: +These CDNs all provide the same [`uuidv4()`](#uuidv4options-buffer-offset) method: ```html ``` -Methods for the other algorithms ([`uuidv1()`](#version-1-timestamp), [`uuidv3()`](#version-3-namespace) and [`uuidv5()`](#version-5-namespace)) are available from the files `uuidv1.min.js`, `uuidv3.min.js` and `uuidv5.min.js` respectively. +Methods for the other algorithms ([`uuidv1()`](#uuidv1options-buffer-offset), [`uuidv3()`](#uuidv3name-namespace-buffer-offset) and [`uuidv5()`](#uuidv5name-namespace-buffer-offset)) are available from the files `uuidv1.min.js`, `uuidv3.min.js` and `uuidv5.min.js` respectively. ## "getRandomValues() not supported" @@ -400,11 +400,11 @@ import { v4 as uuidv4 } from 'uuid'; [In Edge <= 18, Web Crypto is not supported in Web Workers or Service Workers](https://caniuse.com/#feat=cryptography) and we are not aware of a polyfill (let us know if you find one, please). -## Upgrading From uuid\@7 +## Upgrading From `uuid@7.x` ### Only Named Exports Supported When Using with Node.js ESM -uuid\@7 did not come with native ECMAScript Module (ESM) support for Node.js. Importing it in Node.js ESM consequently imported the CommonJS source with a default export. This library now comes with true Node.js ESM support and only provides named exports. +`uuid@7.x` did not come with native ECMAScript Module (ESM) support for Node.js. Importing it in Node.js ESM consequently imported the CommonJS source with a default export. This library now comes with true Node.js ESM support and only provides named exports. Instead of doing: @@ -422,24 +422,24 @@ uuidv4(); ### Deep Requires No Longer Supported -Deep requires like `require('uuid/v4')` [which have been deprecated in uuid\@7](#deep-requires-now-deprecated) are no longer supported. +Deep requires like `require('uuid/v4')` [which have been deprecated in `uuid@7.x`](#deep-requires-now-deprecated) are no longer supported. -## Upgrading From uuid\@3 +## Upgrading From `uuid@3.x` -"_Wait... what happened to uuid\@4 - uuid\@6?!?_" +"_Wait... what happened to `uuid@4.x` - `uuid@6.x`?!?_" -In order to avoid confusion with RFC [version 4](#version-4-random) and [version 5](#version-5-namespace) UUIDs, and a possible [version 6](http://gh.peabody.io/uuidv6/), releases 4 thru 6 of this module have been skipped. Hence, how we're now at uuid\@7. +In order to avoid confusion with RFC [version 4](#uuidv4options-buffer-offset) and [version 5](#uuidv5name-namespace-buffer-offset) UUIDs, and a possible [version 6](http://gh.peabody.io/uuidv6/), releases 4 thru 6 of this module have been skipped. ### Deep Requires Now Deprecated -uuid\@3 encouraged the use of deep requires to minimize the bundle size of browser builds: +`uuid@3.x` encouraged the use of deep requires to minimize the bundle size of browser builds: ```javascript const uuidv4 = require('uuid/v4'); // <== NOW DEPRECATED! uuidv4(); ``` -As of uuid\@7 this library now provides ECMAScript modules builds, which allow packagers like Webpack and Rollup to do "tree-shaking" to remove dead code. Instead, use the `import` syntax: +As of `uuid@7.x` this library now provides ECMAScript modules builds, which allow packagers like Webpack and Rollup to do "tree-shaking" to remove dead code. Instead, use the `import` syntax: ```javascript import { v4 as uuidv4 } from 'uuid'; @@ -455,10 +455,10 @@ uuidv4(); ### Default Export Removed -uuid\@3 was exporting the Version 4 UUID method as a default export: +`uuid@3.x` was exporting the Version 4 UUID method as a default export: ```javascript const uuid = require('uuid'); // <== REMOVED! ``` -This usage pattern was already discouraged in uuid\@3 and has been removed in uuid\@7. +This usage pattern was already discouraged in `uuid@3.x` and has been removed in `uuid@7.x`. From f15caed45b875178ffd045e6f2ac692d57915314 Mon Sep 17 00:00:00 2001 From: Christoph Tavan Date: Mon, 20 Jul 2020 10:27:53 +0200 Subject: [PATCH 15/18] fix: language --- src/stringify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stringify.js b/src/stringify.js index 71b65370..3226a43c 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -36,7 +36,7 @@ function stringify(arr, offset = 0) { byteToHex[arr[offset + 15]] ).toLowerCase(); - // Sanity check for valid UUID. This works because if any of + // Consistency check for valid UUID. This works because if any of // the input array values don't map to a defined hex octet, the string length // will get blown out (e.g. "74af23d8-85undefined2c44-...") // From 40cf16adbf3cdd28f7d06f9d3ac14584fe87a423 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Mon, 20 Jul 2020 14:03:56 -0700 Subject: [PATCH 16/18] fix: add uuidNIL --- rollup.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rollup.config.js b/rollup.config.js index 920d599f..a6153250 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -21,6 +21,8 @@ export default [ chunk('v4', 'uuidv4'), chunk('v5', 'uuidv5'), + chunk('NIL', 'uuidNIL'), + chunk('version', 'uuidVersion'), chunk('validate', 'uuidValidate'), chunk('parse', 'uuidParse'), From 91c1599453ea23aeed0d89013fad06fc99307df4 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Mon, 20 Jul 2020 14:18:00 -0700 Subject: [PATCH 17/18] fix: simplify stringify validation --- src/stringify.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/stringify.js b/src/stringify.js index 3226a43c..42fd4ecd 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -36,22 +36,13 @@ function stringify(arr, offset = 0) { byteToHex[arr[offset + 15]] ).toLowerCase(); - // Consistency check for valid UUID. This works because if any of - // the input array values don't map to a defined hex octet, the string length - // will get blown out (e.g. "74af23d8-85undefined2c44-...") - // - // This is a somewhat crude check, but avoids having to check each value - // individually. - if (uuid.length !== 36) { - throw new TypeError( - 'Stringified UUID is invalid (All input values must be integers between 0 and 255)', - ); - } - + // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields if (!validate(uuid)) { - throw TypeError( - 'Stringified UUID is invalid (Confirm the RFC `version` and `variant` fields are valid in the input values)', - ); + throw TypeError('Stringified UUID is invalid'); } return uuid; From c16ebbd4fed62e464f6d4afabd9a52e46c037a96 Mon Sep 17 00:00:00 2001 From: Robert Kieffer Date: Mon, 20 Jul 2020 21:11:19 -0700 Subject: [PATCH 18/18] fix: rename NIL -> nil --- rollup.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup.config.js b/rollup.config.js index a6153250..37de4056 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -21,7 +21,7 @@ export default [ chunk('v4', 'uuidv4'), chunk('v5', 'uuidv5'), - chunk('NIL', 'uuidNIL'), + chunk('nil', 'uuidNIL'), chunk('version', 'uuidVersion'), chunk('validate', 'uuidValidate'),