blob: e962dee5c4034c54fc8b2c7aefff18518683385c [file] [log] [blame]
Andrey Pavlov9b47f322020-04-05 22:31:40 +03001/*
2 * UUID-js: A js library to generate and parse UUIDs, TimeUUIDs and generate
3 * TimeUUID based on dates for range selections.
4 * @see http://www.ietf.org/rfc/rfc4122.txt
5 **/
6
7function UUIDjs() {
8};
9
10UUIDjs.maxFromBits = function(bits) {
11 return Math.pow(2, bits);
12};
13
14UUIDjs.limitUI04 = UUIDjs.maxFromBits(4);
15UUIDjs.limitUI06 = UUIDjs.maxFromBits(6);
16UUIDjs.limitUI08 = UUIDjs.maxFromBits(8);
17UUIDjs.limitUI12 = UUIDjs.maxFromBits(12);
18UUIDjs.limitUI14 = UUIDjs.maxFromBits(14);
19UUIDjs.limitUI16 = UUIDjs.maxFromBits(16);
20UUIDjs.limitUI32 = UUIDjs.maxFromBits(32);
21UUIDjs.limitUI40 = UUIDjs.maxFromBits(40);
22UUIDjs.limitUI48 = UUIDjs.maxFromBits(48);
23
24// Returns a random integer between min and max
25// Using Math.round() will give you a non-uniform distribution!
26// @see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/random
27function getRandomInt(min, max) {
28 return Math.floor(Math.random() * (max - min + 1)) + min;
29}
30
31UUIDjs.randomUI04 = function() {
32 return getRandomInt(0, UUIDjs.limitUI04-1);
33};
34UUIDjs.randomUI06 = function() {
35 return getRandomInt(0, UUIDjs.limitUI06-1);
36};
37UUIDjs.randomUI08 = function() {
38 return getRandomInt(0, UUIDjs.limitUI08-1);
39};
40UUIDjs.randomUI12 = function() {
41 return getRandomInt(0, UUIDjs.limitUI12-1);
42};
43UUIDjs.randomUI14 = function() {
44 return getRandomInt(0, UUIDjs.limitUI14-1);
45};
46UUIDjs.randomUI16 = function() {
47 return getRandomInt(0, UUIDjs.limitUI16-1);
48};
49UUIDjs.randomUI32 = function() {
50 return getRandomInt(0, UUIDjs.limitUI32-1);
51};
52UUIDjs.randomUI40 = function() {
53 return (0 | Math.random() * (1 << 30)) + (0 | Math.random() * (1 << 40 - 30)) * (1 << 30);
54};
55UUIDjs.randomUI48 = function() {
56 return (0 | Math.random() * (1 << 30)) + (0 | Math.random() * (1 << 48 - 30)) * (1 << 30);
57};
58
59UUIDjs.paddedString = function(string, length, z) {
60 string = String(string);
61 z = (!z) ? '0' : z;
62 var i = length - string.length;
63 for (; i > 0; i >>>= 1, z += z) {
64 if (i & 1) {
65 string = z + string;
66 }
67 }
68 return string;
69};
70
71UUIDjs.prototype.fromParts = function(timeLow, timeMid, timeHiAndVersion, clockSeqHiAndReserved, clockSeqLow, node) {
72 this.version = (timeHiAndVersion >> 12) & 0xF;
73 this.hex = UUIDjs.paddedString(timeLow.toString(16), 8)
74 + '-'
75 + UUIDjs.paddedString(timeMid.toString(16), 4)
76 + '-'
77 + UUIDjs.paddedString(timeHiAndVersion.toString(16), 4)
78 + '-'
79 + UUIDjs.paddedString(clockSeqHiAndReserved.toString(16), 2)
80 + UUIDjs.paddedString(clockSeqLow.toString(16), 2)
81 + '-'
82 + UUIDjs.paddedString(node.toString(16), 12);
83 return this;
84};
85
86UUIDjs.prototype.toString = function() {
87 return this.hex;
88};
89UUIDjs.prototype.toURN = function() {
90 return 'urn:uuid:' + this.hex;
91};
92
93UUIDjs.prototype.toBytes = function() {
94 var parts = this.hex.split('-');
95 var ints = [];
96 var intPos = 0;
97 for (var i = 0; i < parts.length; i++) {
98 for (var j = 0; j < parts[i].length; j+=2) {
99 ints[intPos++] = parseInt(parts[i].substr(j, 2), 16);
100 }
101 }
102 return ints;
103};
104
105UUIDjs.prototype.equals = function(uuid) {
106 if (!(uuid instanceof UUID)) {
107 return false;
108 }
109 if (this.hex !== uuid.hex) {
110 return false;
111 }
112 return true;
113};
114
115UUIDjs.getTimeFieldValues = function(time) {
116 var ts = time - Date.UTC(1582, 9, 15);
117 var hm = ((ts / 0x100000000) * 10000) & 0xFFFFFFF;
118 return { low: ((ts & 0xFFFFFFF) * 10000) % 0x100000000,
119 mid: hm & 0xFFFF, hi: hm >>> 16, timestamp: ts };
120};
121
122UUIDjs._create4 = function() {
123 return new UUIDjs().fromParts(
124 UUIDjs.randomUI32(),
125 UUIDjs.randomUI16(),
126 0x4000 | UUIDjs.randomUI12(),
127 0x80 | UUIDjs.randomUI06(),
128 UUIDjs.randomUI08(),
129 UUIDjs.randomUI48()
130 );
131};
132
133UUIDjs._create1 = function() {
134 var now = new Date().getTime();
135 var sequence = UUIDjs.randomUI14();
136 var node = (UUIDjs.randomUI08() | 1) * 0x10000000000 + UUIDjs.randomUI40();
137 var tick = UUIDjs.randomUI04();
138 var timestamp = 0;
139 var timestampRatio = 1/4;
140
141 if (now != timestamp) {
142 if (now < timestamp) {
143 sequence++;
144 }
145 timestamp = now;
146 tick = UUIDjs.randomUI04();
147 } else if (Math.random() < timestampRatio && tick < 9984) {
148 tick += 1 + UUIDjs.randomUI04();
149 } else {
150 sequence++;
151 }
152
153 var tf = UUIDjs.getTimeFieldValues(timestamp);
154 var tl = tf.low + tick;
155 var thav = (tf.hi & 0xFFF) | 0x1000;
156
157 sequence &= 0x3FFF;
158 var cshar = (sequence >>> 8) | 0x80;
159 var csl = sequence & 0xFF;
160
161 return new UUIDjs().fromParts(tl, tf.mid, thav, cshar, csl, node);
162};
163
164UUIDjs.create = function(version) {
165 version = version || 4;
166 return this['_create' + version]();
167};
168
169UUIDjs.fromTime = function(time, last) {
170 last = (!last) ? false : last;
171 var tf = UUIDjs.getTimeFieldValues(time);
172 var tl = tf.low;
173 var thav = (tf.hi & 0xFFF) | 0x1000; // set version '0001'
174 if (last === false) {
175 return new UUIDjs().fromParts(tl, tf.mid, thav, 0, 0, 0);
176 } else {
177 return new UUIDjs().fromParts(tl, tf.mid, thav, 0x80 | UUIDjs.limitUI06, UUIDjs.limitUI08 - 1, UUIDjs.limitUI48 - 1);
178 }
179};
180
181UUIDjs.firstFromTime = function(time) {
182 return UUIDjs.fromTime(time, false);
183};
184UUIDjs.lastFromTime = function(time) {
185 return UUIDjs.fromTime(time, true);
186};
187
188UUIDjs.fromURN = function(strId) {
189 var r, p = /^(?:urn:uuid:|\{)?([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})(?:\})?$/i;
190 if ((r = p.exec(strId))) {
191 return new UUIDjs().fromParts(parseInt(r[1], 16), parseInt(r[2], 16),
192 parseInt(r[3], 16), parseInt(r[4], 16),
193 parseInt(r[5], 16), parseInt(r[6], 16));
194 }
195 return null;
196};
197
198UUIDjs.fromBytes = function(ints) {
199 if (ints.length < 5) {
200 return null;
201 }
202 var str = '';
203 var pos = 0;
204 var parts = [4, 2, 2, 2, 6];
205 for (var i = 0; i < parts.length; i++) {
206 for (var j = 0; j < parts[i]; j++) {
207 var octet = ints[pos++].toString(16);
208 if (octet.length == 1) {
209 octet = '0' + octet;
210 }
211 str += octet;
212 }
213 if (parts[i] !== 6) {
214 str += '-';
215 }
216 }
217 return UUIDjs.fromURN(str);
218};
219
220UUIDjs.fromBinary = function(binary) {
221 var ints = [];
222 for (var i = 0; i < binary.length; i++) {
223 ints[i] = binary.charCodeAt(i);
224 if (ints[i] > 255 || ints[i] < 0) {
225 throw new Error('Unexpected byte in binary data.');
226 }
227 }
228 return UUIDjs.fromBytes(ints);
229};
230
231// Aliases to support legacy code. Do not use these when writing new code as
232// they may be removed in future versions!
233UUIDjs.new = function() {
234 return this.create(4);
235};
236UUIDjs.newTS = function() {
237 return this.create(1);
238};
239
240//module.exports = UUIDjs;