From 214533c35756c3224b48a37f085d030a1fa3b693 Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 26 May 2020 02:44:42 +0300 Subject: [PATCH 01/12] test: parsing non RFC uuid values --- test/unit/v35.test.js | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/unit/v35.test.js b/test/unit/v35.test.js index 9addbd1d..e9172ce5 100644 --- a/test/unit/v35.test.js +++ b/test/unit/v35.test.js @@ -108,6 +108,29 @@ describe('v5', () => { assert.ok(v3('hello.example.com', '00000000-0000-0000-0000-000000000000')); }); + test('v3 parsing non RFC uuid values', () => { + assert.strictEqual( + v3( + 'hello.example.com', + // equal '00000000-0000-0000-0000-000000000000' + '00000000000000000000000000000000', + ), + '8ccfd135-fc23-3a10-a477-5a4f02f92cf9', + ); + + // During parsing only two hex chars in a row are taken into account + // The remaining characters are ignored. + + assert.strictEqual( + v3( + 'hello.example.com', + // equal '00000000-0000-0000-0000-000000000000' + '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', + ), + '8ccfd135-fc23-3a10-a477-5a4f02f92cf9', + ); + }); + test('v3 namespace buffer validation', () => { assert.throws(() => { v3('hello.example.com', new Array(15)); @@ -204,6 +227,29 @@ describe('v5', () => { assert.ok(v5('hello.example.com', '00000000-0000-0000-0000-000000000000')); }); + test('v5 parsing non RFC uuid values', () => { + assert.strictEqual( + v5( + 'hello.example.com', + // equal '00000000-0000-0000-0000-000000000000' + '00000000000000000000000000000000', + ), + '9aefd4c8-16b3-555b-9731-72b19be683e4', + ); + + // During parsing only two hex chars in a row are taken into account + // The remaining characters are ignored. + + assert.strictEqual( + v5( + 'hello.example.com', + // equal '00000000-0000-0000-0000-000000000000' + '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', + ), + '9aefd4c8-16b3-555b-9731-72b19be683e4', + ); + }); + test('v5 namespace buffer validation', () => { assert.throws(() => { v5('hello.example.com', new Array(15)); From fbc317efe1f1921d0d9598c1e8d8c1b162c0482c Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 27 May 2020 21:00:54 +0300 Subject: [PATCH 02/12] feat: create validate, version, uuidRegex (and import to public API) --- src/index.js | 3 +++ src/regex.js | 3 +++ src/v35.js | 37 ++++++++++++++++++++++++++++--------- src/validate.js | 7 +++++++ src/version.js | 11 +++++++++++ test/unit/v35.test.js | 28 ++++++++++++---------------- test/unit/version.test.js | 18 ++++++++++++++++++ 7 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 src/regex.js create mode 100644 src/validate.js create mode 100644 src/version.js create mode 100644 test/unit/version.test.js diff --git a/src/index.js b/src/index.js index 30870af0..7a975d27 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 version } from './version.js'; +export { default as validate } from './validate.js'; +export { default as uuidRegex } from './regex.js'; diff --git a/src/regex.js b/src/regex.js new file mode 100644 index 00000000..c059acc7 --- /dev/null +++ b/src/regex.js @@ -0,0 +1,3 @@ +const uuidRegex = /^([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 uuidRegex; diff --git a/src/v35.js b/src/v35.js index 6099e9e7..6566f26b 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,12 +1,29 @@ import bytesToUuid from './bytesToUuid.js'; +import validate from './validate.js'; + +// Int32 to 4 bytes +function numberToBytes(num, bytes) { + const offset = bytes.length; + bytes.push(0, 0, 0, 0); + + for (let i = 0; i < 4; ++i) { + const byte = num & 0xff; + 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 = []; - uuid.replace(/[a-fA-F0-9]{2}/g, function (hex) { - bytes.push(parseInt(hex, 16)); - }); + if (!validate(uuid)) { + return bytes; + } + + numberToBytes(parseInt(uuid.slice(0, 8), 16), bytes); + numberToBytes(parseInt(uuid.slice(9, 13) + uuid.slice(14, 18), 16), bytes); + numberToBytes(parseInt(uuid.slice(19, 23) + uuid.slice(24, 28), 16), bytes); + numberToBytes(parseInt(uuid.slice(28), 16), bytes); return bytes; } @@ -28,8 +45,6 @@ export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; export default function (name, version, hashfunc) { function generateUUID(value, namespace, buf, offset) { - const off = (buf && offset) || 0; - if (typeof value === 'string') value = stringToBytes(value); if (typeof namespace === 'string') namespace = uuidToBytes(namespace); @@ -47,12 +62,16 @@ export default function (name, version, hashfunc) { bytes[8] = (bytes[8] & 0x3f) | 0x80; if (buf) { - for (let idx = 0; idx < 16; ++idx) { - buf[off + idx] = bytes[idx]; + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; } + + return buf; } - return buf || bytesToUuid(bytes); + return bytesToUuid(bytes); } // Function#name is not settable on some platforms (#270) diff --git a/src/validate.js b/src/validate.js new file mode 100644 index 00000000..b4832831 --- /dev/null +++ b/src/validate.js @@ -0,0 +1,7 @@ +import uuidRegex from './regex.js'; + +function validate(uuid) { + return uuidRegex.test(uuid); +} + +export default validate; diff --git a/src/version.js b/src/version.js new file mode 100644 index 00000000..eec62b26 --- /dev/null +++ b/src/version.js @@ -0,0 +1,11 @@ +import validate from './validate.js'; + +function version(uuid) { + if (validate(uuid)) { + return parseInt(uuid.substr(14, 1), 16); + } + + return -1; +} + +export default version; diff --git a/test/unit/v35.test.js b/test/unit/v35.test.js index e9172ce5..45cc444e 100644 --- a/test/unit/v35.test.js +++ b/test/unit/v35.test.js @@ -109,26 +109,24 @@ describe('v5', () => { }); test('v3 parsing non RFC uuid values', () => { - assert.strictEqual( + assert.throws(() => { v3( 'hello.example.com', // equal '00000000-0000-0000-0000-000000000000' '00000000000000000000000000000000', - ), - '8ccfd135-fc23-3a10-a477-5a4f02f92cf9', - ); + ); + }); // During parsing only two hex chars in a row are taken into account // The remaining characters are ignored. - assert.strictEqual( + assert.throws(() => { v3( 'hello.example.com', // equal '00000000-0000-0000-0000-000000000000' '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', - ), - '8ccfd135-fc23-3a10-a477-5a4f02f92cf9', - ); + ); + }); }); test('v3 namespace buffer validation', () => { @@ -228,26 +226,24 @@ describe('v5', () => { }); test('v5 parsing non RFC uuid values', () => { - assert.strictEqual( + assert.throws(() => { v5( 'hello.example.com', // equal '00000000-0000-0000-0000-000000000000' '00000000000000000000000000000000', - ), - '9aefd4c8-16b3-555b-9731-72b19be683e4', - ); + ); + }); // During parsing only two hex chars in a row are taken into account // The remaining characters are ignored. - assert.strictEqual( + assert.throws(() => { v5( 'hello.example.com', // equal '00000000-0000-0000-0000-000000000000' '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', - ), - '9aefd4c8-16b3-555b-9731-72b19be683e4', - ); + ); + }); }); test('v5 namespace buffer validation', () => { diff --git a/test/unit/version.test.js b/test/unit/version.test.js new file mode 100644 index 00000000..dca40ab2 --- /dev/null +++ b/test/unit/version.test.js @@ -0,0 +1,18 @@ +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.strictEqual(version('invalid uuid string'), -1); + }); +}); From 57ab10ad58124ac276de50c5c5cad8d9924a4ccd Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 27 May 2020 23:40:56 +0300 Subject: [PATCH 03/12] style: always curly braces added comments to numberToBytes func preallocated array in uuidToBytes func --- .eslintrc.json | 3 ++- src/regex.js | 2 +- src/uuid-bin.js | 19 +++++++++++++++---- src/v35.js | 31 +++++++++++++++++-------------- src/v4.js | 4 ++-- test/unit/v35.test.js | 24 +++++------------------- 6 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index cd838aeb..b329c54a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,6 +13,7 @@ }, "parser": "babel-eslint", "rules": { - "no-var": ["error"] + "no-var": ["error"], + "curly": ["error", "all"] } } diff --git a/src/regex.js b/src/regex.js index c059acc7..8420d0df 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +1,3 @@ -const uuidRegex = /^([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; +const uuidRegex = /^([0-9a-f]{8}-[0-9a-f]{4}-[1345][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})|((00000000-0000-0000-0000-000000000000))$/i; export default uuidRegex; diff --git a/src/uuid-bin.js b/src/uuid-bin.js index d1deaa42..f7305adc 100644 --- a/src/uuid-bin.js +++ b/src/uuid-bin.js @@ -39,8 +39,13 @@ switch (version) { assert(name != null, 'v3 name not specified'); assert(namespace != null, 'v3 namespace not specified'); - if (namespace === 'URL') namespace = v3.URL; - if (namespace === 'DNS') namespace = v3.DNS; + if (namespace === 'URL') { + namespace = v3.URL; + } + + if (namespace === 'DNS') { + namespace = v3.DNS; + } console.log(v3(name, namespace)); break; @@ -53,11 +58,17 @@ switch (version) { case 'v5': { const name = args.shift(); let namespace = args.shift(); + assert(name != null, 'v5 name not specified'); assert(namespace != null, 'v5 namespace not specified'); - if (namespace === 'URL') namespace = v5.URL; - if (namespace === 'DNS') namespace = v5.DNS; + if (namespace === 'URL') { + namespace = v5.URL; + } + + if (namespace === 'DNS') { + namespace = v5.DNS; + } console.log(v5(name, namespace)); break; diff --git a/src/v35.js b/src/v35.js index 6566f26b..dc7775fe 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,29 +1,27 @@ import bytesToUuid from './bytesToUuid.js'; import validate from './validate.js'; -// Int32 to 4 bytes -function numberToBytes(num, bytes) { - const offset = bytes.length; - bytes.push(0, 0, 0, 0); - +// 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) { - const bytes = []; - if (!validate(uuid)) { - return bytes; + return []; } - numberToBytes(parseInt(uuid.slice(0, 8), 16), bytes); - numberToBytes(parseInt(uuid.slice(9, 13) + uuid.slice(14, 18), 16), bytes); - numberToBytes(parseInt(uuid.slice(19, 23) + uuid.slice(24, 28), 16), bytes); - numberToBytes(parseInt(uuid.slice(28), 16), bytes); + 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; } @@ -45,8 +43,13 @@ export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; export default function (name, version, hashfunc) { function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') value = stringToBytes(value); - if (typeof namespace === 'string') namespace = uuidToBytes(namespace); + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = uuidToBytes(namespace); + } if (!Array.isArray(value)) { throw TypeError('value must be an array of bytes'); diff --git a/src/v4.js b/src/v4.js index ec7352ec..16765828 100644 --- a/src/v4.js +++ b/src/v4.js @@ -12,10 +12,10 @@ function v4(options, buf, offset) { // Copy bytes to buffer, if provided if (buf) { - const start = offset || 0; + offset = offset || 0; for (let i = 0; i < 16; ++i) { - buf[start + i] = rnds[i]; + buf[offset + i] = rnds[i]; } return buf; diff --git a/test/unit/v35.test.js b/test/unit/v35.test.js index 45cc444e..b509d5d7 100644 --- a/test/unit/v35.test.js +++ b/test/unit/v35.test.js @@ -32,7 +32,9 @@ describe('v5', () => { ]; function hashToHex(hash) { - if (hash instanceof Buffer) hash = Array.from(hash); + if (hash instanceof Buffer) { + hash = Array.from(hash); + } return hash .map(function (b) { return b.toString(16).padStart(2, '0'); @@ -110,20 +112,12 @@ describe('v5', () => { test('v3 parsing non RFC uuid values', () => { assert.throws(() => { - v3( - 'hello.example.com', - // equal '00000000-0000-0000-0000-000000000000' - '00000000000000000000000000000000', - ); + v3('hello.example.com', '00000000000000000000000000000000'); }); - // During parsing only two hex chars in a row are taken into account - // The remaining characters are ignored. - assert.throws(() => { v3( 'hello.example.com', - // equal '00000000-0000-0000-0000-000000000000' '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', ); }); @@ -227,20 +221,12 @@ describe('v5', () => { test('v5 parsing non RFC uuid values', () => { assert.throws(() => { - v5( - 'hello.example.com', - // equal '00000000-0000-0000-0000-000000000000' - '00000000000000000000000000000000', - ); + v5('hello.example.com', '00000000000000000000000000000000'); }); - // During parsing only two hex chars in a row are taken into account - // The remaining characters are ignored. - assert.throws(() => { v5( 'hello.example.com', - // equal '00000000-0000-0000-0000-000000000000' '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', ); }); From fc6cc23e0abe677b67570ca3533fb307766ca87e Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Thu, 28 May 2020 02:42:31 +0300 Subject: [PATCH 04/12] Update src/regex.js Co-authored-by: Robert Kieffer --- src/regex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/regex.js b/src/regex.js index 8420d0df..1c54d168 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +1,3 @@ const uuidRegex = /^([0-9a-f]{8}-[0-9a-f]{4}-[1345][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})|((00000000-0000-0000-0000-000000000000))$/i; -export default uuidRegex; +export default REGEX; From 865e6e7c378d67913ed4466e2343c6c420ab8965 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Thu, 28 May 2020 02:42:46 +0300 Subject: [PATCH 05/12] Update src/validate.js Co-authored-by: Robert Kieffer --- src/validate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validate.js b/src/validate.js index b4832831..73be827e 100644 --- a/src/validate.js +++ b/src/validate.js @@ -1,7 +1,7 @@ import uuidRegex from './regex.js'; function validate(uuid) { - return uuidRegex.test(uuid); + return typeof(uuid) === 'string' && uuidRegex.test(uuid); } export default validate; From 3fd422bd10c542020d9db1de515ac2c853539bfd Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Thu, 28 May 2020 02:43:17 +0300 Subject: [PATCH 06/12] Update src/version.js Co-authored-by: Robert Kieffer --- src/version.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/version.js b/src/version.js index eec62b26..0705a77c 100644 --- a/src/version.js +++ b/src/version.js @@ -1,11 +1,8 @@ import validate from './validate.js'; function version(uuid) { - if (validate(uuid)) { - return parseInt(uuid.substr(14, 1), 16); - } - - return -1; + if (!validate(uuid)) throw TypeError('Invalid UUID'); + return parseInt(uuid.substr(14, 1), 16); } export default version; From d6851cbebe99fd75f6687613b7f6c3ef604b8151 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Thu, 28 May 2020 02:44:36 +0300 Subject: [PATCH 07/12] Update test/unit/version.test.js Co-authored-by: Robert Kieffer --- test/unit/version.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/version.test.js b/test/unit/version.test.js index dca40ab2..a2ecceea 100644 --- a/test/unit/version.test.js +++ b/test/unit/version.test.js @@ -13,6 +13,6 @@ describe('version', () => { assert.strictEqual(version('90123e1c-7512-523e-bb28-76fab9f2f73d'), 5); - assert.strictEqual(version('invalid uuid string'), -1); + assert.throws(() => version('invalid uuid string')); }); }); From 10e1bfaa22fa6461f557315c44b754559bcf1053 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 28 May 2020 03:20:34 +0300 Subject: [PATCH 08/12] feat: throw error when invalid uuid --- src/index.js | 2 +- src/regex.js | 2 +- src/validate.js | 4 ++-- src/version.js | 5 ++++- test/unit/v35.test.js | 26 -------------------------- test/unit/version.test.js | 10 ++++++++++ 6 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/index.js b/src/index.js index 7a975d27..7702f92a 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +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'; -export { default as uuidRegex } from './regex.js'; diff --git a/src/regex.js b/src/regex.js index 1c54d168..4ed878b6 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +1,3 @@ -const uuidRegex = /^([0-9a-f]{8}-[0-9a-f]{4}-[1345][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})|((00000000-0000-0000-0000-000000000000))$/i; +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/validate.js b/src/validate.js index 73be827e..22a1217e 100644 --- a/src/validate.js +++ b/src/validate.js @@ -1,7 +1,7 @@ -import uuidRegex from './regex.js'; +import REGEX from './regex.js'; function validate(uuid) { - return typeof(uuid) === 'string' && uuidRegex.test(uuid); + return typeof uuid === 'string' && REGEX.test(uuid); } export default validate; diff --git a/src/version.js b/src/version.js index 0705a77c..2b993703 100644 --- a/src/version.js +++ b/src/version.js @@ -1,7 +1,10 @@ import validate from './validate.js'; function version(uuid) { - if (!validate(uuid)) throw TypeError('Invalid UUID'); + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + return parseInt(uuid.substr(14, 1), 16); } diff --git a/test/unit/v35.test.js b/test/unit/v35.test.js index b509d5d7..938e94a9 100644 --- a/test/unit/v35.test.js +++ b/test/unit/v35.test.js @@ -110,19 +110,6 @@ describe('v5', () => { assert.ok(v3('hello.example.com', '00000000-0000-0000-0000-000000000000')); }); - test('v3 parsing non RFC uuid values', () => { - assert.throws(() => { - v3('hello.example.com', '00000000000000000000000000000000'); - }); - - assert.throws(() => { - v3( - 'hello.example.com', - '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', - ); - }); - }); - test('v3 namespace buffer validation', () => { assert.throws(() => { v3('hello.example.com', new Array(15)); @@ -219,19 +206,6 @@ describe('v5', () => { assert.ok(v5('hello.example.com', '00000000-0000-0000-0000-000000000000')); }); - test('v5 parsing non RFC uuid values', () => { - assert.throws(() => { - v5('hello.example.com', '00000000000000000000000000000000'); - }); - - assert.throws(() => { - v5( - 'hello.example.com', - '=Y00a-f*v00b*-00c-00d#-p00f\b-00g-00h-####00i^^^-00j*1*2*3&-L00k-\n00l-/00m-----00n-fg000-00p-00r+', - ); - }); - }); - test('v5 namespace buffer validation', () => { assert.throws(() => { v5('hello.example.com', new Array(15)); diff --git a/test/unit/version.test.js b/test/unit/version.test.js index a2ecceea..ae9385bf 100644 --- a/test/unit/version.test.js +++ b/test/unit/version.test.js @@ -14,5 +14,15 @@ describe('version', () => { assert.strictEqual(version('90123e1c-7512-523e-bb28-76fab9f2f73d'), 5); 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 b57dc6732efc855003faa2d018b0fddf4136a754 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 28 May 2020 03:43:03 +0300 Subject: [PATCH 09/12] test: validate function --- test/unit/validate.test.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/unit/validate.test.js diff --git a/test/unit/validate.test.js b/test/unit/validate.test.js new file mode 100644 index 00000000..ef2f85ac --- /dev/null +++ b/test/unit/validate.test.js @@ -0,0 +1,27 @@ +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('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, + ); + }); +}); From d096cc21b14e84f86e2fd7d6bf5068cb1124b157 Mon Sep 17 00:00:00 2001 From: awwit Date: Fri, 29 May 2020 19:05:54 +0300 Subject: [PATCH 10/12] feat: short version of parsing UUID --- .babelrc.js | 2 +- .eslintrc.json | 3 +-- README.md | 4 ++-- README_js.md | 4 ++-- src/index.js | 6 +++--- src/regex.js | 4 ++-- src/uuid-bin.js | 18 ++++-------------- src/v35.js | 22 ++++------------------ test/unit/v35.test.js | 3 ++- test/unit/validate.test.js | 4 ++++ test/unit/version.test.js | 4 ++++ 11 files changed, 29 insertions(+), 45 deletions(-) diff --git a/.babelrc.js b/.babelrc.js index f42a05a4..03943e8d 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -6,7 +6,7 @@ module.exports = { presets: [['@babel/preset-env', { targets: { node: '8' }, modules: 'commonjs' }]], }, esmBrowser: { - presets: [['@babel/preset-env', { modules: false }]], + presets: [['@babel/preset-env', { targets: { ie: '11' }, modules: false }]], }, esmNode: { presets: [['@babel/preset-env', { targets: { node: '8' }, modules: false }]], diff --git a/.eslintrc.json b/.eslintrc.json index b329c54a..cd838aeb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,7 +13,6 @@ }, "parser": "babel-eslint", "rules": { - "no-var": ["error"], - "curly": ["error", "all"] + "no-var": ["error"] } } diff --git a/README.md b/README.md index f683ca56..7390813b 100644 --- a/README.md +++ b/README.md @@ -292,7 +292,7 @@ ddeb27fb-d9a0-4624-be4d-4615062daed4 The default is to generate version 4 UUIDS, however the other versions are supported. Type `uuid --help` for details: -``` +```shell $ uuid --help Usage: @@ -323,7 +323,7 @@ uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' To run the examples you must first create a dist build of this library in the module root: -``` +```shell npm run build ``` diff --git a/README_js.md b/README_js.md index bdbb1b75..e16e45f4 100644 --- a/README_js.md +++ b/README_js.md @@ -281,7 +281,7 @@ ddeb27fb-d9a0-4624-be4d-4615062daed4 The default is to generate version 4 UUIDS, however the other versions are supported. Type `uuid --help` for details: -``` +```shell $ uuid --help Usage: @@ -312,7 +312,7 @@ uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' To run the examples you must first create a dist build of this library in the module root: -``` +```shell npm run build ``` diff --git a/src/index.js b/src/index.js index 7702f92a..051c8123 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +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'; +export { default as getVersionUUID } from './version.js'; +export { default as validateUUID } from './validate.js'; +export { default as UUID_REGEXP } from './regex.js'; diff --git a/src/regex.js b/src/regex.js index 4ed878b6..5c2709c9 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +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; +const UUID_REGEXP = /^(?:[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 UUID_REGEXP; diff --git a/src/uuid-bin.js b/src/uuid-bin.js index f7305adc..0a82fd27 100644 --- a/src/uuid-bin.js +++ b/src/uuid-bin.js @@ -39,13 +39,8 @@ switch (version) { assert(name != null, 'v3 name not specified'); assert(namespace != null, 'v3 namespace not specified'); - if (namespace === 'URL') { - namespace = v3.URL; - } - - if (namespace === 'DNS') { - namespace = v3.DNS; - } + if (namespace === 'URL') namespace = v3.URL; + if (namespace === 'DNS') namespace = v3.DNS; console.log(v3(name, namespace)); break; @@ -62,13 +57,8 @@ switch (version) { assert(name != null, 'v5 name not specified'); assert(namespace != null, 'v5 namespace not specified'); - if (namespace === 'URL') { - namespace = v5.URL; - } - - if (namespace === 'DNS') { - namespace = v5.DNS; - } + if (namespace === 'URL') namespace = v5.URL; + if (namespace === 'DNS') namespace = v5.DNS; console.log(v5(name, namespace)); break; diff --git a/src/v35.js b/src/v35.js index dc7775fe..a0f68ab6 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,29 +1,15 @@ 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; - } -} +// Char offset to hex pairs in uuid strings +const HEX_PAIRS = [0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34]; function uuidToBytes(uuid) { if (!validate(uuid)) { - return []; + throw TypeError('Invalid UUID'); } - 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; + return HEX_PAIRS.map((i) => parseInt(uuid.substr(i, 2), 16)); } function stringToBytes(str) { diff --git a/test/unit/v35.test.js b/test/unit/v35.test.js index 938e94a9..b6d9312f 100644 --- a/test/unit/v35.test.js +++ b/test/unit/v35.test.js @@ -6,7 +6,7 @@ import sha1Browser from '../../src/sha1-browser.js'; import v3 from '../../src/v3.js'; import v5 from '../../src/v5.js'; -describe('v5', () => { +describe('v35', () => { const HASH_SAMPLES = [ { input: '', @@ -35,6 +35,7 @@ describe('v5', () => { if (hash instanceof Buffer) { hash = Array.from(hash); } + return hash .map(function (b) { return b.toString(16).padStart(2, '0'); diff --git a/test/unit/validate.test.js b/test/unit/validate.test.js index ef2f85ac..12980ae5 100644 --- a/test/unit/validate.test.js +++ b/test/unit/validate.test.js @@ -13,6 +13,10 @@ describe('validate', () => { 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); diff --git a/test/unit/version.test.js b/test/unit/version.test.js index ae9385bf..32c18261 100644 --- a/test/unit/version.test.js +++ b/test/unit/version.test.js @@ -13,6 +13,10 @@ describe('version', () => { assert.strictEqual(version('90123e1c-7512-523e-bb28-76fab9f2f73d'), 5); + assert.throws(() => version()); + + assert.throws(() => version('')); + assert.throws(() => version('invalid uuid string')); assert.throws(() => { From 70f4179cef25a26642ba1d94d2484fafacba82e2 Mon Sep 17 00:00:00 2001 From: Christoph Tavan Date: Fri, 29 May 2020 21:05:05 +0200 Subject: [PATCH 11/12] fix: remove explicit ie babel target --- .babelrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.babelrc.js b/.babelrc.js index 03943e8d..f42a05a4 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -6,7 +6,7 @@ module.exports = { presets: [['@babel/preset-env', { targets: { node: '8' }, modules: 'commonjs' }]], }, esmBrowser: { - presets: [['@babel/preset-env', { targets: { ie: '11' }, modules: false }]], + presets: [['@babel/preset-env', { modules: false }]], }, esmNode: { presets: [['@babel/preset-env', { targets: { node: '8' }, modules: false }]], From 22182670721f7391b2b9a4a38476b224175fa3e4 Mon Sep 17 00:00:00 2001 From: Christoph Tavan Date: Fri, 29 May 2020 21:05:51 +0200 Subject: [PATCH 12/12] Revert "feat: short version of parsing UUID" This reverts commit d096cc21b14e84f86e2fd7d6bf5068cb1124b157. --- src/index.js | 6 +++--- src/regex.js | 4 ++-- src/uuid-bin.js | 18 ++++++++++++++---- src/v35.js | 22 ++++++++++++++++++---- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/index.js b/src/index.js index 051c8123..7702f92a 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +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 getVersionUUID } from './version.js'; -export { default as validateUUID } from './validate.js'; -export { default as UUID_REGEXP } from './regex.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 index 5c2709c9..4ed878b6 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,3 +1,3 @@ -const UUID_REGEXP = /^(?:[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; +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 UUID_REGEXP; +export default REGEX; diff --git a/src/uuid-bin.js b/src/uuid-bin.js index 0a82fd27..f7305adc 100644 --- a/src/uuid-bin.js +++ b/src/uuid-bin.js @@ -39,8 +39,13 @@ switch (version) { assert(name != null, 'v3 name not specified'); assert(namespace != null, 'v3 namespace not specified'); - if (namespace === 'URL') namespace = v3.URL; - if (namespace === 'DNS') namespace = v3.DNS; + if (namespace === 'URL') { + namespace = v3.URL; + } + + if (namespace === 'DNS') { + namespace = v3.DNS; + } console.log(v3(name, namespace)); break; @@ -57,8 +62,13 @@ switch (version) { assert(name != null, 'v5 name not specified'); assert(namespace != null, 'v5 namespace not specified'); - if (namespace === 'URL') namespace = v5.URL; - if (namespace === 'DNS') namespace = v5.DNS; + if (namespace === 'URL') { + namespace = v5.URL; + } + + if (namespace === 'DNS') { + namespace = v5.DNS; + } console.log(v5(name, namespace)); break; diff --git a/src/v35.js b/src/v35.js index a0f68ab6..dc7775fe 100644 --- a/src/v35.js +++ b/src/v35.js @@ -1,15 +1,29 @@ import bytesToUuid from './bytesToUuid.js'; import validate from './validate.js'; -// Char offset to hex pairs in uuid strings -const HEX_PAIRS = [0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34]; +// 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)) { - throw TypeError('Invalid UUID'); + return []; } - return HEX_PAIRS.map((i) => parseInt(uuid.substr(i, 2), 16)); + 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; } function stringToBytes(str) {