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