simpleflakes 2.2.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,24 +1,27 @@
1
1
  # simpleflakes
2
2
 
3
- [![travis status][travis-badge]][travis-link]
3
+ [![CI](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml/badge.svg)](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
4
4
  [![npm][npm-badge]][npm-link]
5
+ [![npm downloads](https://img.shields.io/npm/dm/simpleflakes.svg?style=flat)](https://www.npmjs.com/package/simpleflakes)
6
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/simpleflakes?style=flat)](https://bundlephobia.com/package/simpleflakes)
7
+ [![Performance](https://img.shields.io/badge/performance-8.8M%20ops%2Fsec-brightgreen?style=flat&logo=javascript)](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
8
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D16.0.0-brightgreen.svg?style=flat)](https://nodejs.org/)
9
+ [![Dependencies](https://img.shields.io/badge/dependencies-0-green.svg?style=flat)](https://www.npmjs.com/package/simpleflakes)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
11
+ [![Last Commit](https://img.shields.io/github/last-commit/leodutra/simpleflakes.svg?style=flat)](https://github.com/leodutra/simpleflakes)
5
12
  <!-- [![codacy quality][codacy-quality-badge]][codacy-quality-link]
6
13
  [![codacy coverage][codacy-coverage-badge]][codacy-coverage-link] -->
7
14
  [![coveralls status][coveralls-badge]][coveralls-link] [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_shield)
8
-
9
- [![tonicdev demo][demo-tonicdev-badge]][demo-tonicdev-link]
10
- [![david dep status][dependencies-badge]][dependencies-url]
11
- [![david dev dep status][dependencies-dev-badge]][dependencies-dev-url]
12
15
 
13
16
  Simpleflake is the smartest way to generate a 64-bit + time-ordered + snowflake based ID. [See the presentation!](http://akmanalp.com/simpleflake_presentation/)
14
17
 
15
18
  ### Test-driven, pure JavaScript
16
- This port is test-driven and no release goes out without tests.
19
+ This port is test-driven and no release goes out without tests.
17
20
  **Also, this library does not rely on low-level bindings, with OpenSSL, libgmp or anything beyond pure JavaScript.**
18
21
 
19
- Assumes [original Python implementation](https://simpleflake.readthedocs.org/en/latest/) as reference and fixes epoch (starts on `2000-01-01T00:00:00.000Z` (UTC) while Python API v0.1.5 epoch starts on `2000-01-01T05:00:00.000Z`).
22
+ Assumes [original Python implementation](https://simpleflake.readthedocs.org/en/latest/) as reference and fixes epoch (starts on `2000-01-01T00:00:00.000Z` (UTC) while Python API v0.1.5 epoch starts on `2000-01-01T05:00:00.000Z`).
20
23
 
21
- **simpleflakes** uses the TC39 BigInt implementation when running on newer versions of Node.js. When BigInt is not available, [Fedor Indutny's big number library (bn.js)](https://github.com/indutny/bn.js) is used as the fastest fallback for big number calculations.
24
+ **simpleflakes** uses the TC39 BigInt implementation for fast and reliable 64-bit ID generation in pure JavaScript.
22
25
 
23
26
  ### How to Install:
24
27
 
@@ -33,30 +36,50 @@ const { simpleflake } = require('simpleflakes');
33
36
  const flakeBigInt = simpleflake()
34
37
 
35
38
  // simpleflake(
36
- // timestamp = Date.now(),
37
- // random_bits = 23-bit random,
39
+ // timestamp = Date.now(),
40
+ // random_bits = 23-bit random,
38
41
  // epoch = Date.UTC(2000, 0, 1)
39
42
  // )
40
- // returns BigInt on newer Node.js or bn.js BigNum on older engines.
43
+ // returns BigInt
41
44
 
42
45
  flakeBigInt.toString(); // 4234673179811182512
43
46
  flakeBigInt.toString(16); // 3ac494d21e84f7b0
44
47
  flakeBigInt.toString(2); // 11101011000100...
45
48
  flakeBigInt.toString(36); // 20rfh5
46
49
  ```
47
- You can check the [original Python API 0.1.5](https://simpleflake.readthedocs.org/en/latest/) documentation for more info.
50
+
51
+ ### TypeScript Support:
52
+ The library is written in TypeScript and includes full type definitions:
53
+
54
+ ```typescript
55
+ import { simpleflake, SimpleFlakeStruct, parseSimpleflake } from 'simpleflakes';
56
+
57
+ // Generate a typed ID
58
+ const flakeId: bigint = simpleflake();
59
+
60
+ // Parse with full type safety
61
+ const parsed: SimpleFlakeStruct = parseSimpleflake(flakeId);
62
+ console.log(parsed.timestamp); // string
63
+ console.log(parsed.randomBits); // string
64
+
65
+ // All functions have proper type annotations
66
+ const binaryStr: string = binary(flakeId);
67
+ const bits: bigint = extractBits(flakeId, 23n, 41n);
68
+ ```
69
+
70
+ You can check the [original Python API 0.1.5](https://simpleflake.readthedocs.org/en/latest/) documentation for more info.
48
71
 
49
72
 
50
73
  ### Reference
51
74
  ```js
52
75
  // Main flake function and its defaults
53
76
  simpleflake(
54
- timestamp = Date.now(),
55
- random_bits = 23-bit random,
77
+ timestamp = Date.now(),
78
+ random_bits = 23-bit random,
56
79
  epoch = Date.UTC(2000, 0, 1)
57
80
  )
58
81
 
59
- // Static constant epoch for simpleflake timestamps, starts at the year 2000
82
+ // Static constant epoch for simpleflake timestamps, starts at the year 2000
60
83
  simpleflake.SIMPLEFLAKE_EPOCH // const = 946702800
61
84
 
62
85
  // Show binary digits of a number, pads to 64 bits unless specified.
@@ -75,31 +98,49 @@ simpleflake.simpleflakeStruct
75
98
  SimpleFlake.SimpleFlakeStruct
76
99
  ```
77
100
 
101
+ ### Development:
102
+
103
+ This project is written in TypeScript and includes comprehensive test coverage.
104
+
105
+ ```sh
106
+ # Install dependencies
107
+ npm install
108
+
109
+ # Build TypeScript to JavaScript
110
+ npm run build
111
+
112
+ # Run tests (automatically builds first)
113
+ npm test
114
+
115
+ # Run with coverage
116
+ npm run test:coverage
117
+
118
+ # Test module compatibility (CommonJS, ES Modules, TypeScript)
119
+ npm run test:compatibility
120
+
121
+ # Run all CI tests (coverage + compatibility)
122
+ npm run test:ci
123
+
124
+ # Type checking
125
+ npm run type-check
126
+
127
+ # Clean build artifacts
128
+ npm run clean
129
+ ```
130
+
131
+ ### License:
78
132
 
79
- ### License:
80
133
  [MIT](https://raw.githubusercontent.com/leodutra/simpleflakes/master/LICENSE)
81
134
 
82
135
  [npm-badge]: https://img.shields.io/npm/v/simpleflakes.svg?style=flat
83
- [travis-badge]: http://img.shields.io/travis/leodutra/simpleflakes.svg?style=flat
84
136
  [codacy-coverage-badge]: https://api.codacy.com/project/badge/Coverage/f71ef817e5f14a9ab3b8b2cb6fabf51a
85
137
  [codacy-quality-badge]: https://api.codacy.com/project/badge/Grade/f71ef817e5f14a9ab3b8b2cb6fabf51a
86
138
  [coveralls-badge]: https://img.shields.io/coveralls/leodutra/simpleflakes.svg?style=flat
87
139
 
88
140
  [npm-link]: https://www.npmjs.com/package/simpleflakes
89
- [travis-link]: https://travis-ci.org/leodutra/simpleflakes
90
141
  [codacy-quality-link]: https://www.codacy.com/app/leodutra/simpleflakes
91
-
92
142
  [codacy-coverage-link]: https://www.codacy.com/app/leodutra/simpleflakes?utm_source=github.com&utm_medium=referral&utm_content=leodutra/simpleflakes&utm_campaign=Badge_Coverage
93
- [codacy-quality-link]: https://www.codacy.com/app/leodutra/simpleflakes?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=leodutra/simpleflakes&amp;utm_campaign=Badge_Grade
94
143
  [coveralls-link]: https://coveralls.io/github/leodutra/simpleflakes
95
- [demo-tonicdev-link]: https://tonicdev.com/leodutra/simpleflakes-demo/1.0.13
96
-
97
- [dependencies-url]: https://david-dm.org/leodutra/simpleflakes
98
- [dependencies-badge]: https://img.shields.io/david/leodutra/simpleflakes.svg?style=flat
99
- [dependencies-dev-url]: https://david-dm.org/leodutra/simpleflakes#info=devDependencies&view=table
100
- [dependencies-dev-badge]: https://img.shields.io/david/dev/leodutra/simpleflakes.svg?style=flat
101
- [demo-tonicdev-badge]: https://img.shields.io/badge/demo-%40tonicdev-008bb8.svg?style=flat
102
-
103
144
 
104
145
 
105
146
  [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_large)
@@ -0,0 +1,51 @@
1
+ declare const SIMPLEFLAKE_EPOCH = 946684800000;
2
+ /**
3
+ * Generates a simpleflake ID
4
+ * @param ts - Timestamp in milliseconds (defaults to current time)
5
+ * @param randomBits - Random bits for the ID (defaults to a random value)
6
+ * @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)
7
+ * @returns Generated simpleflake as a BigInt
8
+ */
9
+ export declare function simpleflake(ts?: number, randomBits?: number, epoch?: number): bigint;
10
+ /**
11
+ * Converts a value to binary representation
12
+ * @param value - The value to convert to binary
13
+ * @param padding - Whether to pad to 64 bits (defaults to true)
14
+ * @returns Binary string representation
15
+ */
16
+ export declare function binary(value: bigint | number | string, padding?: boolean): string;
17
+ /**
18
+ * Extracts bits from a data value
19
+ * @param data - The data to extract bits from
20
+ * @param shift - Number of bits to shift
21
+ * @param length - Number of bits to extract
22
+ * @returns Extracted bits as a BigInt
23
+ */
24
+ export declare function extractBits(data: bigint | number | string, shift: bigint | number, length: bigint | number): bigint;
25
+ /**
26
+ * Structure representing a parsed simpleflake
27
+ */
28
+ export declare class SimpleFlakeStruct {
29
+ readonly timestamp: string;
30
+ readonly randomBits: string;
31
+ constructor(timestamp: string, randomBits: string);
32
+ }
33
+ /**
34
+ * Parses a simpleflake into its components
35
+ * @param flake - The simpleflake to parse
36
+ * @returns SimpleFlakeStruct containing timestamp and random bits
37
+ */
38
+ export declare function parseSimpleflake(flake: bigint | number | string): SimpleFlakeStruct;
39
+ export declare const simpleflakeStruct: typeof SimpleFlakeStruct;
40
+ export { SIMPLEFLAKE_EPOCH };
41
+ declare const _default: {
42
+ SimpleFlakeStruct: typeof SimpleFlakeStruct;
43
+ simpleflakeStruct: typeof SimpleFlakeStruct;
44
+ extractBits: typeof extractBits;
45
+ parseSimpleflake: typeof parseSimpleflake;
46
+ binary: typeof binary;
47
+ SIMPLEFLAKE_EPOCH: number;
48
+ simpleflake: typeof simpleflake;
49
+ };
50
+ export default _default;
51
+ //# sourceMappingURL=simpleflakes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simpleflakes.d.ts","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,iBAAiB,eAAe,CAAC;AAWvC;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,GAAE,MAAmB,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAA0B,GAAG,MAAM,CAGnH;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,MAAM,CAKvF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAInH;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAOlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,iBAAiB,CAQnF;AAGD,eAAO,MAAM,iBAAiB,0BAAoB,CAAC;AAGnD,OAAO,EAAE,iBAAiB,EAAE,CAAC;;;;;;;;;;AAG7B,wBAWE"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SIMPLEFLAKE_EPOCH = exports.simpleflakeStruct = exports.SimpleFlakeStruct = void 0;
4
+ exports.simpleflake = simpleflake;
5
+ exports.binary = binary;
6
+ exports.extractBits = extractBits;
7
+ exports.parseSimpleflake = parseSimpleflake;
8
+ const SIMPLEFLAKE_EPOCH = 946684800000; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00
9
+ exports.SIMPLEFLAKE_EPOCH = SIMPLEFLAKE_EPOCH;
10
+ const UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0
11
+ const SIMPLEFLAKE_TIMESTAMP_LENGTH = 41n;
12
+ const SIMPLEFLAKE_RANDOM_LENGTH = 23n;
13
+ const SIMPLEFLAKE_RANDOM_SHIFT = 0n;
14
+ const SIMPLEFLAKE_TIMESTAMP_SHIFT = 23n;
15
+ const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000000000000000';
16
+ /**
17
+ * Generates a simpleflake ID
18
+ * @param ts - Timestamp in milliseconds (defaults to current time)
19
+ * @param randomBits - Random bits for the ID (defaults to a random value)
20
+ * @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)
21
+ * @returns Generated simpleflake as a BigInt
22
+ */
23
+ function simpleflake(ts = Date.now(), randomBits, epoch = SIMPLEFLAKE_EPOCH) {
24
+ return ((BigInt(ts) - BigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) +
25
+ BigInt(randomBits ?? Math.round(Math.random() * UNSIGNED_23BIT_MAX));
26
+ }
27
+ /**
28
+ * Converts a value to binary representation
29
+ * @param value - The value to convert to binary
30
+ * @param padding - Whether to pad to 64 bits (defaults to true)
31
+ * @returns Binary string representation
32
+ */
33
+ function binary(value, padding = true) {
34
+ const binValue = BigInt(value).toString(2);
35
+ return padding && binValue.length < 64
36
+ ? CACHE_64_BIT_ZEROS.substr(0, 64 - binValue.length) + binValue
37
+ : binValue;
38
+ }
39
+ /**
40
+ * Extracts bits from a data value
41
+ * @param data - The data to extract bits from
42
+ * @param shift - Number of bits to shift
43
+ * @param length - Number of bits to extract
44
+ * @returns Extracted bits as a BigInt
45
+ */
46
+ function extractBits(data, shift, length) {
47
+ const shiftN = BigInt(shift);
48
+ const bitmask = ((1n << BigInt(length)) - 1n) << shiftN;
49
+ return (BigInt(data) & bitmask) >> shiftN;
50
+ }
51
+ /**
52
+ * Structure representing a parsed simpleflake
53
+ */
54
+ class SimpleFlakeStruct {
55
+ constructor(timestamp, randomBits) {
56
+ if (timestamp == null || randomBits == null) {
57
+ throw new Error('Missing argument for SimpleFlakeStruct.');
58
+ }
59
+ this.timestamp = timestamp;
60
+ this.randomBits = randomBits;
61
+ }
62
+ }
63
+ exports.SimpleFlakeStruct = SimpleFlakeStruct;
64
+ /**
65
+ * Parses a simpleflake into its components
66
+ * @param flake - The simpleflake to parse
67
+ * @returns SimpleFlakeStruct containing timestamp and random bits
68
+ */
69
+ function parseSimpleflake(flake) {
70
+ return new SimpleFlakeStruct(
71
+ // timestamp
72
+ (extractBits(flake, SIMPLEFLAKE_TIMESTAMP_SHIFT, SIMPLEFLAKE_TIMESTAMP_LENGTH)
73
+ + BigInt(SIMPLEFLAKE_EPOCH)).toString(10),
74
+ // random bits
75
+ extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH).toString(10));
76
+ }
77
+ // Legacy function alias for backwards compatibility
78
+ exports.simpleflakeStruct = SimpleFlakeStruct;
79
+ // Default export for CommonJS compatibility
80
+ exports.default = {
81
+ // Enhancements
82
+ SimpleFlakeStruct: SimpleFlakeStruct,
83
+ // original API
84
+ simpleflakeStruct: SimpleFlakeStruct,
85
+ extractBits: extractBits,
86
+ parseSimpleflake: parseSimpleflake,
87
+ binary: binary,
88
+ SIMPLEFLAKE_EPOCH: SIMPLEFLAKE_EPOCH,
89
+ simpleflake: simpleflake
90
+ };
91
+ //# sourceMappingURL=simpleflakes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simpleflakes.js","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"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"}
@@ -10,8 +10,8 @@ const SIMPLEFLAKE_TIMESTAMP_SHIFT = 23n;
10
10
  const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000000000000000';
11
11
 
12
12
  function simpleflake(ts = Date.now(), randomBits, epoch = SIMPLEFLAKE_EPOCH) {
13
- return (BigInt(ts - epoch) << SIMPLEFLAKE_TIMESTAMP_SHIFT) +
14
- BigInt(randomBits || Math.round(Math.random() * UNSIGNED_23BIT_MAX));
13
+ return ((BigInt(ts) - BigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) +
14
+ BigInt(randomBits ?? Math.round(Math.random() * UNSIGNED_23BIT_MAX));
15
15
  }
16
16
 
17
17
  function binary(value, padding = true) {
package/package.json CHANGED
@@ -1,11 +1,30 @@
1
1
  {
2
2
  "name": "simpleflakes",
3
- "version": "2.2.1",
3
+ "version": "3.0.0",
4
4
  "description": "Fast, and reliable, distributed 64-bit ID generation, in pure JavaScript, for Node.js.",
5
- "main": "index.js",
5
+ "main": "dist/simpleflakes.js",
6
+ "types": "dist/simpleflakes.d.ts",
7
+ "files": [
8
+ "dist/",
9
+ "lib/",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
6
13
  "scripts": {
7
- "test": "tape tests/**/*.js | faucet",
8
- "benchmark": "node benchmark/run.js"
14
+ "build": "tsc",
15
+ "build:clean": "rimraf dist",
16
+ "prebuild": "npm run build:clean",
17
+ "postbuild": "echo 'TypeScript compilation complete. Output in ./dist/'",
18
+ "type-check": "tsc --noEmit",
19
+ "test": "npm run build && tape tests/**/*.js | faucet",
20
+ "test:compatibility": "npm run build && node test-compatibility.js",
21
+ "test:ci": "npm run test:coverage && npm run test:compatibility",
22
+ "test:coverage": "nyc npm test",
23
+ "test:coverage:report": "nyc report --reporter=html && echo '\nHTML coverage report generated in ./coverage/index.html'",
24
+ "test:coverage:ci": "nyc npm test && cat ./coverage/lcov.info",
25
+ "test:coverage:clean": "rimraf coverage .nyc_output",
26
+ "benchmark": "npm run build && node benchmark/run.js",
27
+ "clean": "npm run build:clean && npm run test:coverage:clean"
9
28
  },
10
29
  "repository": {
11
30
  "type": "git",
@@ -14,12 +33,15 @@
14
33
  "keywords": [
15
34
  "simpleflake",
16
35
  "snowflake",
36
+ "flake",
17
37
  "id",
38
+ "uuidv4",
39
+ "uuidv7",
40
+ "database",
41
+ "shards",
42
+ "bigint",
18
43
  "sql",
19
44
  "nosql",
20
- "flake",
21
- "bigint",
22
- "shards",
23
45
  "partition"
24
46
  ],
25
47
  "author": {
@@ -32,12 +54,17 @@
32
54
  "url": "https://github.com/leodutra/simpleflakes/issues"
33
55
  },
34
56
  "homepage": "https://github.com/leodutra/simpleflakes#readme",
35
- "dependencies": {
36
- "bn.js": "^5.2.0"
57
+ "engines": {
58
+ "node": ">=16.0.0"
37
59
  },
38
60
  "devDependencies": {
61
+ "@types/node": "^24.3.1",
39
62
  "benchmark": "^2.1.4",
40
- "faucet": "^0.0.1",
41
- "tape": "^5.3.1"
63
+ "faucet": "^0.0.4",
64
+ "nyc": "^17.1.0",
65
+ "rimraf": "^6.0.1",
66
+ "tape": "^5.9.0",
67
+ "tsx": "^4.20.5",
68
+ "typescript": "^5.9.2"
42
69
  }
43
70
  }
package/.eslintrc.js DELETED
@@ -1,20 +0,0 @@
1
- module.exports = {
2
- env: {
3
- commonjs: true,
4
- es6: true,
5
- node: true,
6
- },
7
- extends: [
8
- 'airbnb-base',
9
- ],
10
- globals: {
11
- Atomics: 'readonly',
12
- SharedArrayBuffer: 'readonly',
13
- },
14
- parserOptions: {
15
- ecmaVersion: 2018,
16
- },
17
- rules: {
18
- "comma-dangle": ["error", "never"]
19
- },
20
- };
package/.travis.yml DELETED
@@ -1,24 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - stable
4
- - '12'
5
- - '11'
6
- - '10'
7
- - '8'
8
-
9
- before_install:
10
- - npm install -g istanbul coveralls codacy-coverage
11
-
12
- before_script:
13
- - export CODACY_PROJECT_TOKEN=becf7b26a5d84fceab4c94d0bb2bf2ec
14
-
15
- script: "istanbul cover ./node_modules/tape/bin/tape --report lcovonly -- tests/**/*.js && cat ./coverage/lcov.info | coveralls && cat ./coverage/lcov.info | codacy-coverage && rm -rf ./coverage"
16
-
17
- deploy:
18
- provider: npm
19
- email: leodutra.br@gmail.com
20
- api_key:
21
- secure: HneFWS9YKoDkLyS5m2c8KMRnjGes1zIi3VnWX5rUuFVP/W+wybcLuyAtPbNzVhz7i7GbcKbIPLSP3lGaD4zBXg8Ds4WINBH09N1EKOrrtzt+A5SNaVHCm02rB8m992gNg0s19gVJD5/6MgJQ4+CJJTIKG3VNok3voZ8mwhZc5B6FKhlm4cU1VYJkm3ZiBeBUDxUlF77uaLIRlWjlibEwTf6Uz9rHhaDd0InlLoWwLOk136vU6QVDyh/84FhDUxytyLwi0WDnhlWQjFrsGB6oZA5MerG/udPMgKTG+pdhBRTt8QtkQqnDTmMPyQyBIe/TxOysGGKP3h7j/gz7yMhkDBCzI4xOcV25ch31kti9LjZPU0KQhJ0E2qjgOMxB1VrhxmzXAVuQKAgzsfeAKoz4xjM7BSBw4nmhdxZTGZWWDldKRcA4tu3EI30nhYaxxubim9CpPRAYK6G1bt3704Lx0XAMf5me7nxAxfzKgaD2CVKdOe3WNjnO7Nb9kSH2EYXP0Tsz8zFsqD4TRBoLs6GZpiD/tlNmoiPZ0/Bqaoh8NXvnjeOaVv2SZaZZ2Ndc0SrZS/8j6tHwhlddSAoi/IAWn5s72HUveGNKdDOxccEeeWm6s1cpxby0slTCjS5i7IyXcxlYV5k+iHmi0apf4dnc4faUgk6YM5aCvWT0yKSUI90=
22
- on:
23
- tags: true
24
- repo: leodutra/simpleflakes
package/benchmark/run.js DELETED
@@ -1,59 +0,0 @@
1
- // eslint-disable-next-line import/no-extraneous-dependencies
2
- const Benchmark = require('benchmark');
3
-
4
- const suite = new Benchmark.Suite();
5
- const legacy = require('../lib/simpleflakes-legacy');
6
- const lib = require('../lib/simpleflakes');
7
-
8
- const { BigNum } = legacy;
9
-
10
- const SIMPLEFLAKE = '4242436206093260245';
11
- const SIMPLEFLAKE_EPOCH = 946702800000;
12
- const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
13
- const SIMPLEFLAKE_RANDOMBITS = 7460309;
14
-
15
- suite.add('simpleflake()', () => {
16
- lib.simpleflake();
17
- })
18
- .add('simpleflake(parameterization)', () => {
19
- lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH);
20
- })
21
- .add('binary()', () => {
22
- lib.binary(64);
23
- })
24
- .add('BigInt()', () => {
25
- // eslint-disable-next-line no-undef
26
- BigInt('4242436206093260245');
27
- })
28
- .add('parseSimpleflake()', () => {
29
- lib.parseSimpleflake(SIMPLEFLAKE);
30
- });
31
-
32
-
33
- // legacy tests
34
- suite.add('legacy simpleflake()', () => {
35
- legacy.simpleflake();
36
- })
37
- .add('legacy simpleflake(parameterization)', () => {
38
- legacy.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH);
39
- })
40
- .add('legacy binary()', () => {
41
- legacy.binary(64);
42
- })
43
- .add('legacy new BigNum()', () => {
44
- // eslint-disable-next-line no-new
45
- new BigNum('4242436206093260245', 10);
46
- })
47
- .add('legacy parseSimpleflake()', () => {
48
- legacy.parseSimpleflake(SIMPLEFLAKE);
49
- })
50
-
51
- // add listeners
52
- .on('cycle', (event) => {
53
- console.log(String(event.target));
54
- })
55
- // .on('complete', function() {
56
- // console.log('Fastest is ' + this.filter('fastest').map('name'))
57
- // })
58
- // run async
59
- .run({ async: true });
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = typeof BigInt === 'function'
2
- ? require('./lib/simpleflakes')
3
- : require('./lib/simpleflakes-legacy');
@@ -1,70 +0,0 @@
1
- const BigNum = require('bn.js');
2
-
3
- const SIMPLEFLAKE_EPOCH = 946684800000; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00
4
- const SIMPLEFLAKE_EPOCH_BIGNUM = new BigNum(SIMPLEFLAKE_EPOCH, 10);
5
- const UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0
6
-
7
- const SIMPLEFLAKE_TIMESTAMP_LENGTH = 41;
8
- const SIMPLEFLAKE_RANDOM_LENGTH = 23;
9
-
10
- const SIMPLEFLAKE_RANDOM_SHIFT = 0;
11
- const SIMPLEFLAKE_TIMESTAMP_SHIFT = 23;
12
-
13
- const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000000000000000';
14
- const CACHE_64_BIT_ONES = '1111111111111111111111111111111111111111111111111111111111111111';
15
-
16
- // cache
17
- const dateNow = Date.now || function now() { return new Date().getTime(); };
18
-
19
- function simpleflake(ts, randomBits, epoch) {
20
- return new BigNum((ts || dateNow()) - (epoch == null ? SIMPLEFLAKE_EPOCH : epoch), 10)
21
- .shln(23).add(new BigNum(randomBits || Math.round(Math.random() * UNSIGNED_23BIT_MAX), 10));
22
- }
23
-
24
- function binary(value, padding) {
25
- const bignum = new BigNum(value, 10).toString(2);
26
- return padding !== false && bignum.length < 64
27
- ? CACHE_64_BIT_ZEROS.substr(0, 64 - bignum.length) + bignum
28
- : bignum;
29
- }
30
-
31
- function extractBits(data, shift, length) {
32
- // return new BigNum(CACHE_64_BIT_ONES.substr(0, length), 2)
33
- // .shln(shift).and(new BigNum(data, 10)).shrn(shift);
34
- return (new BigNum(data, 10)).shrn(shift).and(new BigNum(CACHE_64_BIT_ONES.substr(0, length), 2));
35
- }
36
-
37
- function SimpleFlakeStruct(timestamp, randomBits) {
38
- if (this instanceof SimpleFlakeStruct) {
39
- if (timestamp == null || randomBits == null) {
40
- throw new Error('Missing argument for SimpleFlakeStruct.');
41
- }
42
- this.timestamp = timestamp;
43
- this.randomBits = randomBits;
44
- } else {
45
- return new SimpleFlakeStruct(timestamp, randomBits);
46
- }
47
- }
48
-
49
- function parseSimpleflake(flake) {
50
- return new SimpleFlakeStruct(
51
- // timestamp
52
- extractBits(flake, SIMPLEFLAKE_TIMESTAMP_SHIFT, SIMPLEFLAKE_TIMESTAMP_LENGTH)
53
- .add(SIMPLEFLAKE_EPOCH_BIGNUM).toString(10),
54
- // random bits
55
- extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH).toString(10)
56
- );
57
- }
58
-
59
- module.exports = {
60
- // Enhancements
61
- SimpleFlakeStruct,
62
-
63
- // original API
64
- simpleflakeStruct: SimpleFlakeStruct,
65
- extractBits,
66
- parseSimpleflake,
67
- binary,
68
- SIMPLEFLAKE_EPOCH,
69
- simpleflake
70
- };
@@ -1,76 +0,0 @@
1
-
2
-
3
- const test = require('tape');
4
- const BigNum = require('bn.js');
5
- const lib = require('../lib/simpleflakes-legacy');
6
-
7
- const SIMPLEFLAKE = '4242436206093260245';
8
- const SIMPLEFLAKE_EPOCH = 946702800000;
9
- const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
10
- const SIMPLEFLAKE_RANDOMBITS = 7460309;
11
-
12
- const SIMPLEFLAKE_2 = '11101011100000001010010100000010000110011100011101010111010101';
13
- const SIMPLEFLAKE_16 = '3ae029408671d5d5';
14
- const SIMPLEFLAKE_36 = 'w8cq4fjf37x1';
15
-
16
- test('testing dependency bn.js', (t) => {
17
- const bignum = new BigNum(SIMPLEFLAKE);
18
- t.equal(bignum.toString(), SIMPLEFLAKE, 'bit number lib retrieves the right stored value?');
19
- t.equal(bignum.toString(), bignum.toString(10), '<big number>.toString() aliases .toString(10)?');
20
- t.equal(bignum.toString(2), SIMPLEFLAKE_2, 'big number as base 2?');
21
- t.equal(bignum.toString(16), SIMPLEFLAKE_16, 'big number as base 16?');
22
- t.equal(bignum.toString(36), SIMPLEFLAKE_36, 'big number as base 36?');
23
- t.end();
24
- });
25
-
26
- test('testing legacy simpleflake()', (t) => {
27
- t.assert(lib.simpleflake() instanceof BigNum, 'returning correct instance of big number lib?');
28
- t.equal(lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH).toString(), '4242436206093260245', 'right timestamp, random bits and epoch parameterization?');
29
- t.end();
30
- });
31
-
32
- test('testing legacy binary()', (t) => {
33
- t.equal(lib.binary('83928382810918298'), '0000000100101010001011000110101101100100000001001000110110011010', 'valid simpleflake.binary(\'83928382810918298\') result?');
34
- t.equal(lib.binary('83928382810918298', false), '100101010001011000110101101100100000001001000110110011010', 'valid simpleflake.binary(\'83928382810918298\', false) result?');
35
- t.equal(lib.binary(7), '0000000000000000000000000000000000000000000000000000000000000111', 'valid simpleflake.binary(7) result?');
36
- t.equal(lib.binary(7, false), '111', 'valid simpleflake.binary(7, false) result?');
37
- t.equal(lib.binary(64), '0000000000000000000000000000000000000000000000000000000001000000', 'valid simpleflake.binary(64) result?');
38
- t.equal(lib.binary(64, false), '1000000', 'valid simpleflake.binary(64, false) result?');
39
- t.end();
40
- });
41
-
42
- test('testing legacy extractBits()', (t) => {
43
- t.assert(lib.extractBits(7, 0, 1) instanceof BigNum, 'returns big number object');
44
- t.equal(lib.extractBits(7, 0, 1).toString(), '1', 'extractBits(7, 0, 1)');
45
- t.equal(lib.extractBits(7, 0, 2).toString(), '3', 'extractBits(7, 0, 2)');
46
- t.equal(lib.extractBits(7, 0, 3).toString(), '7', 'extractBits(7, 0, 3)');
47
- t.equal(lib.extractBits(7, 1, 2).toString(), '3', 'extractBits(7, 1, 2)');
48
- t.equal(lib.extractBits(7, 2, 1).toString(), '1', 'extractBits(7, 2, 1)');
49
- t.equal(lib.extractBits(7, 2, 2).toString(), '1', 'extractBits(7, 2, 2)');
50
- t.end();
51
- });
52
-
53
- test('testing legacy SimpleFlakeStruct()', (t) => {
54
- t.assert(lib.SimpleFlakeStruct(SIMPLEFLAKE_TIMESTAMP.toString(), SIMPLEFLAKE_RANDOMBITS.toString()) instanceof lib.SimpleFlakeStruct, 'returning new SimpleFlakeStruct() when calling SimpleFlakeStruct()?');
55
- t.throws(() => {
56
- let undef;
57
- lib.SimpleFlakeStruct(undef, '1');
58
- }, 'throw typeError when timestamp arg is missing');
59
-
60
- t.throws(() => {
61
- lib.SimpleFlakeStruct('1');
62
- }, 'throw typeError when randomBits argument is missing');
63
-
64
- t.throws(() => {
65
- lib.SimpleFlakeStruct();
66
- }, 'throw typeError when arguments are missing');
67
-
68
- t.end();
69
- });
70
-
71
- test('testing legacy parseSimpleflake()', (t) => {
72
- const flake = lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS);
73
- t.equal(lib.parseSimpleflake(flake).timestamp, SIMPLEFLAKE_TIMESTAMP.toString(), 'correct timestamp parsing?');
74
- t.equal(lib.parseSimpleflake(flake).randomBits, SIMPLEFLAKE_RANDOMBITS.toString(), 'correct random bits parsing?');
75
- t.end();
76
- });
@@ -1,65 +0,0 @@
1
- if (typeof BigInt === 'function') {
2
- // eslint-disable-next-line global-require
3
- const test = require('tape');
4
- // eslint-disable-next-line global-require
5
- const lib = require('../lib/simpleflakes');
6
- const SIMPLEFLAKE_EPOCH = 946702800000;
7
- const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
8
- const SIMPLEFLAKE_RANDOMBITS = 7460309;
9
-
10
-
11
- test('testing simpleflake()', (t) => {
12
- // eslint-disable-next-line valid-typeof
13
- t.assert(typeof lib.simpleflake() === 'bigint', 'returning BigInt?');
14
- t.equal(lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH).toString(), '4242436206093260245', 'right timestamp, random bits and epoch parameterization?');
15
- t.end();
16
- });
17
-
18
- test('testing binary()', (t) => {
19
- t.equal(lib.binary('83928382810918298'), '0000000100101010001011000110101101100100000001001000110110011010', "valid simpleflake.binary('83928382810918298') result?");
20
- t.equal(lib.binary('83928382810918298', false), '100101010001011000110101101100100000001001000110110011010', "valid simpleflake.binary('83928382810918298', false) result?");
21
- t.equal(lib.binary(7), '0000000000000000000000000000000000000000000000000000000000000111', 'valid simpleflake.binary(7) result?');
22
- t.equal(lib.binary(7, false), '111', 'valid simpleflake.binary(7, false) result?');
23
- t.equal(lib.binary(64), '0000000000000000000000000000000000000000000000000000000001000000', 'valid simpleflake.binary(64) result?');
24
- t.equal(lib.binary(64, false), '1000000', 'valid simpleflake.binary(64, false) result?');
25
- t.end();
26
- });
27
-
28
-
29
- test('testing extractBits()', (t) => {
30
- // eslint-disable-next-line valid-typeof
31
- t.assert(typeof lib.extractBits(7, 0, 1) === 'bigint', 'returns big int');
32
- t.equal(lib.extractBits(7, 0, 1).toString(), '1', 'extractBits(7, 0, 1)');
33
- t.equal(lib.extractBits(7, 0, 2).toString(), '3', 'extractBits(7, 0, 2)');
34
- t.equal(lib.extractBits(7, 0, 3).toString(), '7', 'extractBits(7, 0, 3)');
35
- t.equal(lib.extractBits(7, 1, 2).toString(), '3', 'extractBits(7, 1, 2)');
36
- t.equal(lib.extractBits(7, 2, 1).toString(), '1', 'extractBits(7, 2, 1)');
37
- t.equal(lib.extractBits(7, 2, 2).toString(), '1', 'extractBits(7, 2, 2)');
38
- t.end();
39
- });
40
-
41
- test('testing SimpleFlakeStruct()', (t) => {
42
- t.assert(lib.SimpleFlakeStruct(SIMPLEFLAKE_TIMESTAMP.toString(), SIMPLEFLAKE_RANDOMBITS.toString()) instanceof lib.SimpleFlakeStruct, 'returning new SimpleFlakeStruct() when calling SimpleFlakeStruct()?');
43
- t.throws(() => {
44
- let undef;
45
- lib.SimpleFlakeStruct(undef, '1');
46
- }, 'throw typeError when timestamp arg is missing');
47
-
48
- t.throws(() => {
49
- lib.SimpleFlakeStruct('1');
50
- }, 'throw typeError when randomBits argument is missing');
51
-
52
- t.throws(() => {
53
- lib.SimpleFlakeStruct();
54
- }, 'throw typeError when arguments are missing');
55
-
56
- t.end();
57
- });
58
-
59
- test('testing parseSimpleflake()', (t) => {
60
- const flake = lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS);
61
- t.equal(lib.parseSimpleflake(flake).timestamp, SIMPLEFLAKE_TIMESTAMP.toString(), 'correct timestamp parsing?');
62
- t.equal(lib.parseSimpleflake(flake).randomBits, SIMPLEFLAKE_RANDOMBITS.toString(), 'correct random bits parsing?');
63
- t.end();
64
- });
65
- }