##// END OF EJS Templates
core/Uuid rewritten in typescript
cin -
r8:e1c664dbc684 default
parent child
Show More
@@ -0,0 +1,280
1 // Typescript port of the uuid.js
2 // Copyright (c) 2018 Sergey Smirnov
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 //
5 // uuid.js
6 // Copyright (c) 2010-2012 Robert Kieffer
7 // MIT License - http://opensource.org/licenses/mit-license.php
8
9 let _window : any = 'undefined' !== typeof window ? window : null;
10
11 // Unique ID creation requires a high quality random # generator. We
12 // feature
13 // detect to determine the best RNG source, normalizing to a function
14 // that
15 // returns 128-bits of randomness, since that's what's usually required
16 let _rng;
17
18 function setupBrowser() {
19 // Allow for MSIE11 msCrypto
20 let _crypto = _window.crypto || _window.msCrypto;
21
22 if (!_rng && _crypto && _crypto.getRandomValues) {
23 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
24 //
25 // Moderately fast, high quality
26 try {
27 let _rnds8 = new Uint8Array(16);
28 _rng = function whatwgRNG() {
29 _crypto.getRandomValues(_rnds8);
30 return _rnds8;
31 };
32 _rng();
33 } catch (e) { /**/ }
34 }
35
36 if (!_rng) {
37 // Math.random()-based (RNG)
38 //
39 // If all else fails, use Math.random(). It's fast, but is of
40 // unspecified
41 // quality.
42 let _rnds = new Array(16);
43 _rng = function () {
44 for (var i = 0, r; i < 16; i++) {
45 if ((i & 0x03) === 0) {
46 r = Math.random() * 0x100000000;
47 }
48 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
49 }
50
51 return _rnds;
52 };
53 if ('undefined' !== typeof console && console.warn) {
54 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
55 }
56 }
57 }
58
59 function setupNode() {
60 // Node.js crypto-based RNG -
61 // http://nodejs.org/docs/v0.6.2/api/crypto.html
62 //
63 // Moderately fast, high quality
64 if ('function' === typeof require) {
65 try {
66 let _rb = require('crypto').randomBytes;
67 _rng = _rb && function () {
68 return _rb(16);
69 };
70 _rng();
71 } catch (e) { /**/ }
72 }
73 }
74
75 if (_window) {
76 setupBrowser();
77 } else {
78 setupNode();
79 }
80
81 // Buffer class to use
82 let BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
83
84 // Maps for number <-> hex string conversion
85 let _byteToHex = [];
86 let _hexToByte = {};
87 for (let i = 0; i < 256; i++) {
88 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
89 _hexToByte[_byteToHex[i]] = i;
90 }
91
92 // **`parse()` - Parse a UUID into it's component bytes**
93 function parse(s, buf?, offset?) : Array<string> {
94 let i = (buf && offset) || 0, ii = 0;
95
96 buf = buf || [];
97 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
98 if (ii < 16) { // Don't overflow!
99 buf[i + ii++] = _hexToByte[oct];
100 }
101 });
102
103 // Zero out remaining bytes if string was short
104 while (ii < 16) {
105 buf[i + ii++] = 0;
106 }
107
108 return buf;
109 }
110
111 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
112 function unparse(buf, offset?) : string {
113 let i = offset || 0, bth = _byteToHex;
114 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
115 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' +
116 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] +
117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] +
118 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
119 }
120
121 // **`v1()` - Generate time-based UUID**
122 //
123 // Inspired by https://github.com/LiosK/UUID.js
124 // and http://docs.python.org/library/uuid.html
125
126 // random #'s we need to init node and clockseq
127 let _seedBytes = _rng();
128
129 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
130 // 1)
131 let _nodeId = [
132 _seedBytes[0] | 0x01,
133 _seedBytes[1],
134 _seedBytes[2],
135 _seedBytes[3],
136 _seedBytes[4],
137 _seedBytes[5]
138 ];
139
140 // Per 4.2.2, randomize (14 bit) clockseq
141 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
142
143 // Previous uuid creation time
144 let _lastMSecs = 0, _lastNSecs = 0;
145
146 // See https://github.com/broofa/node-uuid for API details
147 function v1(options?, buf?, offset?) : string {
148 let i = buf && offset || 0;
149 let b = buf || [];
150
151 options = options || {};
152
153 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
154
155 // UUID timestamps are 100 nano-second units since the Gregorian
156 // epoch,
157 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
158 // time is handled internally as 'msecs' (integer milliseconds) and
159 // 'nsecs'
160 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
161 // 00:00.
162 let msecs = (options.msecs != null) ? options.msecs : new Date()
163 .getTime();
164
165 // Per 4.2.1.2, use count of uuid's generated during the current
166 // clock
167 // cycle to simulate higher resolution clock
168 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
169
170 // Time since last uuid creation (in msecs)
171 let dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
172
173 // Per 4.2.1.2, Bump clockseq on clock regression
174 if (dt < 0 && options.clockseq == null) {
175 clockseq = clockseq + 1 & 0x3fff;
176 }
177
178 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
179 // a new
180 // time interval
181 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
182 nsecs = 0;
183 }
184
185 // Per 4.2.1.2 Throw error if too many uuids are requested
186 if (nsecs >= 10000) {
187 throw new Error(
188 'uuid.v1(): Can\'t create more than 10M uuids/sec');
189 }
190
191 _lastMSecs = msecs;
192 _lastNSecs = nsecs;
193 _clockseq = clockseq;
194
195 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
196 msecs += 12219292800000;
197
198 // `time_low`
199 let tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
200 b[i++] = tl >>> 24 & 0xff;
201 b[i++] = tl >>> 16 & 0xff;
202 b[i++] = tl >>> 8 & 0xff;
203 b[i++] = tl & 0xff;
204
205 // `time_mid`
206 let tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
207 b[i++] = tmh >>> 8 & 0xff;
208 b[i++] = tmh & 0xff;
209
210 // `time_high_and_version`
211 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
212 b[i++] = tmh >>> 16 & 0xff;
213
214 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
215 b[i++] = clockseq >>> 8 | 0x80;
216
217 // `clock_seq_low`
218 b[i++] = clockseq & 0xff;
219
220 // `node`
221 let node = options.node || _nodeId;
222 for (let n = 0; n < 6; n++) {
223 b[i + n] = node[n];
224 }
225
226 return buf ? buf : unparse(b);
227 }
228
229 // **`v4()` - Generate random UUID**
230
231 // See https://github.com/broofa/node-uuid for API details
232 function v4(options?, buf?, offset?) : string {
233 // Deprecated - 'format' argument, as supported in v1.2
234 let i = buf && offset || 0;
235
236 if (typeof (options) === 'string') {
237 buf = (options === 'binary') ? new BufferClass(16) : null;
238 options = null;
239 }
240 options = options || {};
241
242 let rnds = options.random || (options.rng || _rng)();
243
244 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
245 rnds[6] = (rnds[6] & 0x0f) | 0x40;
246 rnds[8] = (rnds[8] & 0x3f) | 0x80;
247
248 // Copy bytes to buffer, if provided
249 if (buf) {
250 for (let ii = 0; ii < 16; ii++) {
251 buf[i + ii] = rnds[ii];
252 }
253 }
254
255 return buf || unparse(rnds);
256 }
257
258 // Export public API
259 const empty = "00000000-0000-0000-0000-000000000000";
260
261 interface uuid {
262 (options?, buf?, offset?) : string;
263 v1(options?, buf?, offset?) : string;
264 v4(options?, buf?, offset?) : string;
265 readonly empty: string;
266 parse(s, buf?, offset?) : Array<string>;
267 unparse(buf, offset?) : string;
268 }
269
270 export = <uuid>(() =>{
271 var f : any = function(options?, buf?, offset?) : string {
272 return v4(options, buf, offset);
273 };
274 f.v1 = v1;
275 f.v4 = v4;
276 f.empty = empty;
277 f.parse = parse;
278 f.unparse = unparse;
279 return f;
280 })(); No newline at end of file
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,12
1 {
2 "compilerOptions": {
3 "target": "es5",
4 "module": "amd",
5 "sourceMap": true,
6 "outDir" : "build/dist",
7 "declaration": true
8 },
9 "include" : [
10 "src/ts/**/*.ts"
11 ]
12 } No newline at end of file
@@ -31,6 +31,14 task _legacyJs(type:Copy) {
31 into distDir
31 into distDir
32 }
32 }
33
33
34 task _buildTs(dependsOn: _npmInstall, type:Exec) {
35 inputs.dir('src/ts')
36 inputs.file('tsc.json')
37 outputs.dir(distDir)
38
39 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json'
40 }
41
34 task _packageMeta(type: Copy) {
42 task _packageMeta(type: Copy) {
35 inputs.property("version", version)
43 inputs.property("version", version)
36 from('.') {
44 from('.') {
@@ -45,13 +53,15 task _packageMeta(type: Copy) {
45 }
53 }
46 }
54 }
47
55
48 task build(dependsOn: [_npmInstall, _legacyJs, _packageMeta]) {
56 task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) {
49
57
50 }
58 }
51
59
52 task _localInstall(dependsOn: build, type: Exec) {
60 task _localInstall(dependsOn: build, type: Exec) {
53 inputs.file("$distDir/package.json")
61 inputs.file("$distDir/package.json")
54 outputs.upToDateWhen { true }
62 outputs.upToDateWhen {
63 new File("$projectDir/node_modules/@implab/core").exists()
64 }
55
65
56 commandLine 'npm', 'install', '--no-save', '--force', distDir
66 commandLine 'npm', 'install', '--no-save', '--force', distDir
57 }
67 }
@@ -25,5 +25,6
25 "@types/tape": "latest",
25 "@types/tape": "latest",
26 "requirejs": "latest",
26 "requirejs": "latest",
27 "faucet": "latest"
27 "faucet": "latest"
28 },
29 "types": "main.d.ts"
28 }
30 }
29 }
@@ -2,6 +2,11 var requirejs = require('requirejs');
2
2
3 requirejs.config({
3 requirejs.config({
4 baseUrl: '.',
4 baseUrl: '.',
5 map: {
6 "*": {
7 "@implab/core": "core"
8 }
9 },
5 packages: [{
10 packages: [{
6 name: "core",
11 name: "core",
7 location: "build/dist"
12 location: "build/dist"
@@ -1,10 +1,12
1 import * as tape from 'tape';
1 import * as tape from 'tape';
2 import * as uuid from '@implab/core/Uuid';
2
3
3 tape('simple', function(t){
4 tape('simple', function(t){
4 t.pass("sync assert");
5 t.pass("sync assert");
5 setTimeout(() => {
6 setTimeout(() => {
6 t.pass("async assert");
7 t.pass("async assert");
7
8 t.comment(uuid());
9 t.ok(uuid() != uuid());
8 // end should be called after the last assertion
10 // end should be called after the last assertion
9 t.end();
11 t.end();
10 }, 100);
12 }, 100);
@@ -4,7 +4,7
4 "module": "amd",
4 "module": "amd",
5 "sourceMap": true,
5 "sourceMap": true,
6 "outDir" : "build/test",
6 "outDir" : "build/test",
7 "allowJs": true
7 "moduleResolution": "node"
8 },
8 },
9 "include" : [
9 "include" : [
10 "test/ts/**/*.ts"
10 "test/ts/**/*.ts"
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now