UNPKG

7.19 kBJavaScriptView Raw
1// uuid.js
2//
3// Copyright (c) 2010-2012 Robert Kieffer
4// MIT License - http://opensource.org/licenses/mit-license.php
5
6(function() {
7 var _global = this;
8
9 // Unique ID creation requires a high quality random # generator. We feature
10 // detect to determine the best RNG source, normalizing to a function that
11 // returns 128-bits of randomness, since that's what's usually required
12 var _rng;
13
14 // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
15 //
16 // Moderately fast, high quality
17 if (typeof(require) == 'function') {
18 try {
19 var _rb = require('crypto').randomBytes;
20 _rng = _rb && function() {return _rb(16);};
21 } catch(e) {}
22 }
23
24 if (!_rng && _global.crypto && crypto.getRandomValues) {
25 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
26 //
27 // Moderately fast, high quality
28 var _rnds8 = new Uint8Array(16);
29 _rng = function whatwgRNG() {
30 crypto.getRandomValues(_rnds8);
31 return _rnds8;
32 };
33 }
34
35 if (!_rng) {
36 // Math.random()-based (RNG)
37 //
38 // If all else fails, use Math.random(). It's fast, but is of unspecified
39 // quality.
40 var _rnds = new Array(16);
41 _rng = function() {
42 for (var i = 0, r; i < 16; i++) {
43 if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
44 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
45 }
46
47 return _rnds;
48 };
49 }
50
51 // Buffer class to use
52 var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
53
54 // Maps for number <-> hex string conversion
55 var _byteToHex = [];
56 var _hexToByte = {};
57 for (var i = 0; i < 256; i++) {
58 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
59 _hexToByte[_byteToHex[i]] = i;
60 }
61
62 // **`parse()` - Parse a UUID into it's component bytes**
63 function parse(s, buf, offset) {
64 var i = (buf && offset) || 0, ii = 0;
65
66 buf = buf || [];
67 s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
68 if (ii < 16) { // Don't overflow!
69 buf[i + ii++] = _hexToByte[oct];
70 }
71 });
72
73 // Zero out remaining bytes if string was short
74 while (ii < 16) {
75 buf[i + ii++] = 0;
76 }
77
78 return buf;
79 }
80
81 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
82 function unparse(buf, offset) {
83 var i = offset || 0, bth = _byteToHex;
84 return bth[buf[i++]] + bth[buf[i++]] +
85 bth[buf[i++]] + bth[buf[i++]] + '-' +
86 bth[buf[i++]] + bth[buf[i++]] + '-' +
87 bth[buf[i++]] + bth[buf[i++]] + '-' +
88 bth[buf[i++]] + bth[buf[i++]] + '-' +
89 bth[buf[i++]] + bth[buf[i++]] +
90 bth[buf[i++]] + bth[buf[i++]] +
91 bth[buf[i++]] + bth[buf[i++]];
92 }
93
94 // **`v1()` - Generate time-based UUID**
95 //
96 // Inspired by https://github.com/LiosK/UUID.js
97 // and http://docs.python.org/library/uuid.html
98
99 // random #'s we need to init node and clockseq
100 var _seedBytes = _rng();
101
102 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
103 var _nodeId = [
104 _seedBytes[0] | 0x01,
105 _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
106 ];
107
108 // Per 4.2.2, randomize (14 bit) clockseq
109 var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
110
111 // Previous uuid creation time
112 var _lastMSecs = 0, _lastNSecs = 0;
113
114 // See https://github.com/broofa/node-uuid for API details
115 function v1(options, buf, offset) {
116 var i = buf && offset || 0;
117 var b = buf || [];
118
119 options = options || {};
120
121 var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
122
123 // UUID timestamps are 100 nano-second units since the Gregorian epoch,
124 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
125 // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
126 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
127 var msecs = options.msecs != null ? options.msecs : new Date().getTime();
128
129 // Per 4.2.1.2, use count of uuid's generated during the current clock
130 // cycle to simulate higher resolution clock
131 var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
132
133 // Time since last uuid creation (in msecs)
134 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
135
136 // Per 4.2.1.2, Bump clockseq on clock regression
137 if (dt < 0 && options.clockseq == null) {
138 clockseq = clockseq + 1 & 0x3fff;
139 }
140
141 // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
142 // time interval
143 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
144 nsecs = 0;
145 }
146
147 // Per 4.2.1.2 Throw error if too many uuids are requested
148 if (nsecs >= 10000) {
149 throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
150 }
151
152 _lastMSecs = msecs;
153 _lastNSecs = nsecs;
154 _clockseq = clockseq;
155
156 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
157 msecs += 12219292800000;
158
159 // `time_low`
160 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
161 b[i++] = tl >>> 24 & 0xff;
162 b[i++] = tl >>> 16 & 0xff;
163 b[i++] = tl >>> 8 & 0xff;
164 b[i++] = tl & 0xff;
165
166 // `time_mid`
167 var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
168 b[i++] = tmh >>> 8 & 0xff;
169 b[i++] = tmh & 0xff;
170
171 // `time_high_and_version`
172 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
173 b[i++] = tmh >>> 16 & 0xff;
174
175 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
176 b[i++] = clockseq >>> 8 | 0x80;
177
178 // `clock_seq_low`
179 b[i++] = clockseq & 0xff;
180
181 // `node`
182 var node = options.node || _nodeId;
183 for (var n = 0; n < 6; n++) {
184 b[i + n] = node[n];
185 }
186
187 return buf ? buf : unparse(b);
188 }
189
190 // **`v4()` - Generate random UUID**
191
192 // See https://github.com/broofa/node-uuid for API details
193 function v4(options, buf, offset) {
194 // Deprecated - 'format' argument, as supported in v1.2
195 var i = buf && offset || 0;
196
197 if (typeof(options) == 'string') {
198 buf = options == 'binary' ? new BufferClass(16) : null;
199 options = null;
200 }
201 options = options || {};
202
203 var rnds = options.random || (options.rng || _rng)();
204
205 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
206 rnds[6] = (rnds[6] & 0x0f) | 0x40;
207 rnds[8] = (rnds[8] & 0x3f) | 0x80;
208
209 // Copy bytes to buffer, if provided
210 if (buf) {
211 for (var ii = 0; ii < 16; ii++) {
212 buf[i + ii] = rnds[ii];
213 }
214 }
215
216 return buf || unparse(rnds);
217 }
218
219 // Export public API
220 var uuid = v4;
221 uuid.v1 = v1;
222 uuid.v4 = v4;
223 uuid.parse = parse;
224 uuid.unparse = unparse;
225 uuid.BufferClass = BufferClass;
226
227 if (_global.define && define.amd) {
228 // Publish as AMD module
229 define(function() {return uuid;});
230 } else if (typeof(module) != 'undefined' && module.exports) {
231 // Publish as node.js module
232 module.exports = uuid;
233 } else {
234 // Publish as global (in browsers)
235 var _previousRoot = _global.uuid;
236
237 // **`noConflict()` - (browser only) to reset global 'uuid' var**
238 uuid.noConflict = function() {
239 _global.uuid = _previousRoot;
240 return uuid;
241 };
242
243 _global.uuid = uuid;
244 }
245}).call(this);