| @@ -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 { |
|
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 | } |
|
28 | }, | |
|
|
29 | "types": "main.d.ts" | |||
| 29 | } |
|
30 | } | |
| @@ -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
