diff --git a/README.md b/README.md
index c47313b0..43cee5f9 100644
--- a/README.md
+++ b/README.md
@@ -17,97 +17,185 @@ 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
+To create a random UUID...
+
+**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:
+**2. Create a UUID** (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`](#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 zeros).
+
+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(16) [
+ // 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 (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:
+
+```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
@@ -340,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"
@@ -368,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:
@@ -390,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';
@@ -423,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 581cc51f..0327e1fc 100644
--- a/README_js.md
+++ b/README_js.md
@@ -29,97 +29,179 @@ 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
+To create a random UUID...
+
+**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:
+**2. Create a UUID** (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`](#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 zeros).
+
+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 (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:
+
+```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
@@ -329,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"
@@ -357,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:
@@ -379,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';
@@ -412,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`.
diff --git a/bundlewatch.config.json b/bundlewatch.config.json
index e8f62881..91b8b756 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": "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.7 kB" },
+ { "path": "./examples/browser-rollup/dist/v5-size.js", "maxSize": "1.5 kB" },
- { "path": "./examples/browser-webpack/dist/v1-size.js", "maxSize": "1.0 kB" },
- { "path": "./examples/browser-webpack/dist/v3-size.js", "maxSize": "2.0 kB" },
- { "path": "./examples/browser-webpack/dist/v4-size.js", "maxSize": "0.7 kB" },
- { "path": "./examples/browser-webpack/dist/v5-size.js", "maxSize": "1.4 kB" }
+ { "path": "./examples/browser-webpack/dist/v1-size.js", "maxSize": "1.3 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 37b3a034..7958fc1b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14136,6 +14136,15 @@
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
"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"
+ }
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
diff --git a/package.json b/package.json
index 5e15606c..8a09f079 100644
--- a/package.json
+++ b/package.json
@@ -73,6 +73,7 @@
"lint-staged": "10.2.11",
"npm-run-all": "4.1.5",
"prettier": "2.0.5",
+ "random-seed": "0.3.0",
"rollup": "2.18.0",
"rollup-plugin-terser": "6.1.0",
"runmd": "1.3.2",
diff --git a/rollup.config.js b/rollup.config.js
index 34544dfd..37de4056 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -20,4 +20,11 @@ export default [
chunk('v3', 'uuidv3'),
chunk('v4', 'uuidv4'),
chunk('v5', 'uuidv5'),
+
+ chunk('nil', 'uuidNIL'),
+
+ 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 30870af0..142ce9e4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,3 +2,8 @@ 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 } from './nil.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/nil.js b/src/nil.js
new file mode 100644
index 00000000..de6f830e
--- /dev/null
+++ b/src/nil.js
@@ -0,0 +1 @@
+export default '00000000-0000-0000-0000-000000000000';
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/regex.js b/src/regex.js
new file mode 100644
index 00000000..92f79a1e
--- /dev/null
+++ b/src/regex.js
@@ -0,0 +1 @@
+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;
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..42fd4ecd
--- /dev/null
+++ b/src/stringify.js
@@ -0,0 +1,51 @@
+import validate from './validate.js';
+
+/**
+ * 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();
+
+ // 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');
+ }
+
+ 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 67fa8d8c..e8706ff0 100644
--- a/src/v35.js
+++ b/src/v35.js
@@ -1,15 +1,5 @@
-import bytesToUuid from './bytesToUuid.js';
-
-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));
- });
-
- return bytes;
-}
+import stringify from './stringify.js';
+import parse from './parse.js';
function stringToBytes(str) {
str = unescape(encodeURIComponent(str)); // UTF8 escape
@@ -33,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;
@@ -59,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/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/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/test/unit/validate.test.js b/test/unit/validate.test.js
new file mode 100644
index 00000000..29dbfe98
--- /dev/null
+++ b/test/unit/validate.test.js
@@ -0,0 +1,32 @@
+import assert from 'assert';
+import validate from '../../src/validate.js';
+import NIL from '../../src/nil.js';
+
+describe('validate', () => {
+ test('validate uuid', () => {
+ assert.strictEqual(validate(NIL), 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..9e0b8925
--- /dev/null
+++ b/test/unit/version.test.js
@@ -0,0 +1,33 @@
+import assert from 'assert';
+import version from '../../src/version.js';
+import NIL from '../../src/nil.js';
+
+describe('version', () => {
+ test('check uuid version', () => {
+ assert.strictEqual(version(NIL), 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+',
+ );
+ });
+ });
+});
diff --git a/wdio.conf.js b/wdio.conf.js
index 4381e784..483618e8 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',
};