rrule-rust 1.0.0 → 1.1.3

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/.eslintrc.js ADDED
@@ -0,0 +1,58 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: [
4
+ 'eslint:recommended',
5
+ 'plugin:@typescript-eslint/recommended',
6
+ 'plugin:prettier/recommended',
7
+ 'plugin:import/recommended',
8
+ 'plugin:import/typescript',
9
+ 'plugin:eslint-comments/recommended',
10
+ ],
11
+ plugins: ['@typescript-eslint'],
12
+ ignorePatterns: ['node_modules', '/target', '/index.d.ts', '/index.js'],
13
+ env: {
14
+ node: true,
15
+ },
16
+ overrides: [
17
+ {
18
+ files: ['*.ts'],
19
+ extends: [
20
+ 'eslint:recommended',
21
+ 'plugin:@typescript-eslint/recommended',
22
+ 'plugin:prettier/recommended',
23
+ 'plugin:import/recommended',
24
+ 'plugin:import/typescript',
25
+ ],
26
+ parserOptions: {
27
+ project: ['tsconfig.eslint.json'],
28
+ },
29
+ rules: {
30
+ '@typescript-eslint/interface-name-prefix': 'off',
31
+ '@typescript-eslint/explicit-function-return-type': 'off',
32
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
33
+ '@typescript-eslint/no-explicit-any': 'off',
34
+ '@typescript-eslint/ban-ts-comment': 'off',
35
+ 'import/no-cycle': 'error',
36
+ 'import/no-unresolved': 'error',
37
+ '@typescript-eslint/no-for-in-array': 'error',
38
+ 'no-implied-eval': 'off',
39
+ '@typescript-eslint/no-implied-eval': 'error',
40
+ '@typescript-eslint/no-misused-promises': 'error',
41
+ 'require-await': 'off',
42
+ '@typescript-eslint/require-await': 'error',
43
+ '@typescript-eslint/restrict-plus-operands': 'error',
44
+ '@typescript-eslint/unbound-method': 'error',
45
+ 'import/no-default-export': 'error',
46
+ 'eslint-comments/require-description': 'error',
47
+ 'eslint-comments/disable-enable-pair': 'off',
48
+ 'eslint-comments/no-unlimited-disable': 'off',
49
+ },
50
+ settings: {
51
+ 'import/parsers': {
52
+ '@typescript-eslint/parser': ['.ts'],
53
+ },
54
+ },
55
+ reportUnusedDisableDirectives: true,
56
+ },
57
+ ],
58
+ };
package/.prettierrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all"
4
+ }
package/README.md CHANGED
@@ -10,15 +10,14 @@
10
10
 
11
11
 
12
12
  1. [Quick Start](#quick-start)
13
- 2. RRule
14
- 3. RRuleSet
13
+ 2. [Perfomance](#perfomance)
15
14
 
16
15
  ## Quick Start
17
16
 
18
- See [__test__ folder](https://github.com/lsndr/rrule-rust/tree/master/__test__) to see more use cases
17
+ See [test folder](https://github.com/lsndr/rrule-rust/tree/master/__test__) to find more use cases
19
18
 
20
19
  ```
21
- npm install rrule-rust
20
+ npm i rrule-rust
22
21
  ```
23
22
 
24
23
 
@@ -26,12 +25,28 @@ See [__test__ folder](https://github.com/lsndr/rrule-rust/tree/master/__test__)
26
25
  import { RRule, RRuleSet, Frequency } from 'rrule-rust';
27
26
 
28
27
  const rrule = new RRule(Frequency.Daily).setCount(5);
29
- const set = new RRuleSet(873205200000, 'US/Eastern').rrule(rrule);
28
+ const set = new RRuleSet(873205200000, 'US/Eastern').addRrule(rrule);
30
29
 
31
30
  const dates = set.all(); // [ 873205200000, 873291600000, 873378000000, 873464400000, 873550800000 ]
32
31
  const asString = set.toString(); // DTSTART;TZID=US/Eastern:19970902T090000\nFREQ=daily;COUNT=5;BYHOUR=9;BYMINUTE=0;BYSECOND=0
33
32
  ```
34
33
 
34
+ ## Perfomance
35
+
36
+ ```
37
+ Host: MacBook Pro, 13-inch, 2018
38
+ OS: macOS 13.2 (22D49)
39
+ Processor: 2,3 GHz Quad-Core Intel Core i5
40
+ Memory: 16 GB 2133 MHz LPDDR3
41
+ ```
42
+
43
+ | | rrule | rrule-rust | |
44
+ | -------- | ------------ | ------------ | ------------ |
45
+ | UTC TZ | 8 128 ops/s | 42 343 ops/s | ~5x faster |
46
+ | Other TZ | 68 ops/s | 40 549 ops/s | ~600x faster |
47
+
48
+ You can run benchmarks using `npm run benchmark`
49
+
35
50
  ## License
36
51
 
37
52
  `rrule-rust` is [MIT licensed](LICENSE.md).
@@ -0,0 +1,3 @@
1
+ *
2
+ !index.ts
3
+ !.gitignore
@@ -0,0 +1,57 @@
1
+ import b from 'benny';
2
+ import * as node from 'rrule';
3
+ import * as rust from '../';
4
+
5
+ b.suite(
6
+ 'UTC TZ',
7
+ b.add('rrule-rust', () => {
8
+ const rrule = new rust.RRule(rust.Frequency.Daily)
9
+ .setCount(30)
10
+ .setInterval(1);
11
+ const set = new rust.RRuleSet(1679428740000, 'UTC').addRrule(rrule);
12
+
13
+ set.all();
14
+ }),
15
+ b.add('rrule', () => {
16
+ const rrule = new node.RRule({
17
+ freq: node.RRule.DAILY,
18
+ dtstart: new Date(Date.UTC(2023, 2, 21, 23, 59, 0)),
19
+ tzid: 'UTC',
20
+ count: 30,
21
+ interval: 1,
22
+ });
23
+
24
+ rrule.all();
25
+ }),
26
+
27
+ b.cycle(),
28
+ b.complete(),
29
+ );
30
+
31
+ b.suite(
32
+ 'Other TZ',
33
+ b.add('rrule-rust', () => {
34
+ const rrule = new rust.RRule(rust.Frequency.Daily)
35
+ .setCount(30)
36
+ .setInterval(1);
37
+ const set = new rust.RRuleSet(1679428740000, 'Pacific/Kiritimati').addRrule(
38
+ rrule,
39
+ );
40
+
41
+ set.all();
42
+ }),
43
+ b.add('rrule', () => {
44
+ const rrule = new node.RRule({
45
+ freq: node.RRule.DAILY,
46
+ dtstart: new Date(Date.UTC(2023, 2, 21, 23, 59, 0)),
47
+ tzid: 'Pacific/Kiritimati',
48
+ count: 30,
49
+ interval: 1,
50
+ });
51
+
52
+ rrule.all();
53
+ }),
54
+
55
+ b.cycle(),
56
+ b.complete(),
57
+ );
package/index.d.ts CHANGED
@@ -70,13 +70,13 @@ export class RRule {
70
70
  export type JsRRuleSet = RRuleSet
71
71
  export class RRuleSet {
72
72
  constructor(dtstart: number, tzid: string)
73
+ static parse(str: string): RRuleSet
73
74
  toString(): string
74
- rrule(jsRrule: RRule): this
75
- exrule(jsRrule: RRule): this
76
- after(timestamp: number): this
77
- before(timestamp: number): this
78
- exdate(timestamp: number): this
79
- getDtstart(): number
80
- getTzid(): string
75
+ addRrule(jsRrule: RRule): this
76
+ addExrule(jsRrule: RRule): this
77
+ addExdate(timestamp: number): this
78
+ get dtstart(): number
79
+ get tzid(): string
81
80
  all(limit?: number | undefined | null): number[]
81
+ between(after: number, before: number, inclusive?: boolean | undefined | null): number[]
82
82
  }
package/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
1
7
  const { existsSync, readFileSync } = require('fs')
2
8
  const { join } = require('path')
3
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrule-rust",
3
- "version": "1.0.0",
3
+ "version": "1.1.3",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "keywords": [
@@ -39,11 +39,39 @@
39
39
  },
40
40
  "license": "MIT",
41
41
  "devDependencies": {
42
- "@napi-rs/cli": "^2.14.8",
43
- "ava": "^5.1.1"
42
+ "@napi-rs/cli": "^2.15.1",
43
+ "@types/node": "^18.15.5",
44
+ "@typescript-eslint/eslint-plugin": "^5.50.0",
45
+ "@typescript-eslint/parser": "^5.50.0",
46
+ "ava": "^5.1.1",
47
+ "benny": "^3.7.1",
48
+ "eslint": "^8.33.0",
49
+ "eslint-config-prettier": "^8.6.0",
50
+ "eslint-plugin-eslint-comments": "^3.2.0",
51
+ "eslint-plugin-import": "^2.27.5",
52
+ "eslint-plugin-prettier": "^4.2.1",
53
+ "lint-staged": "^13.1.0",
54
+ "pre-commit": "^1.2.2",
55
+ "prettier": "^2.8.3",
56
+ "rrule": "^2.7.2",
57
+ "ts-node": "^10.9.1",
58
+ "typescript": "^4.9.4"
59
+ },
60
+ "pre-commit": [
61
+ "lint:fix-staged",
62
+ "test"
63
+ ],
64
+ "lint-staged": {
65
+ "**/*.{js,ts,json}": "eslint --fix --max-warnings=0"
44
66
  },
45
67
  "ava": {
46
- "timeout": "3m"
68
+ "timeout": "10m",
69
+ "extensions": [
70
+ "ts"
71
+ ],
72
+ "require": [
73
+ "ts-node/register"
74
+ ]
47
75
  },
48
76
  "engines": {
49
77
  "node": ">= 10"
@@ -55,22 +83,26 @@
55
83
  "prepublishOnly": "napi prepublish -t npm",
56
84
  "test": "ava",
57
85
  "universal": "napi universal",
58
- "version": "napi version"
86
+ "version": "napi version",
87
+ "benchmark": "ts-node ./benchmark/index.ts",
88
+ "lint": "eslint \"**/*.{js,ts,json}\" --max-warnings=0",
89
+ "lint:fix": "yarn lint --fix",
90
+ "lint:fix-staged": "lint-staged"
59
91
  },
60
92
  "optionalDependencies": {
61
- "@rrule-rust/lib-win32-x64-msvc": "1.0.0",
62
- "@rrule-rust/lib-darwin-x64": "1.0.0",
63
- "@rrule-rust/lib-linux-x64-gnu": "1.0.0",
64
- "@rrule-rust/lib-darwin-arm64": "1.0.0",
65
- "@rrule-rust/lib-android-arm64": "1.0.0",
66
- "@rrule-rust/lib-linux-arm64-gnu": "1.0.0",
67
- "@rrule-rust/lib-linux-arm64-musl": "1.0.0",
68
- "@rrule-rust/lib-win32-arm64-msvc": "1.0.0",
69
- "@rrule-rust/lib-linux-arm-gnueabihf": "1.0.0",
70
- "@rrule-rust/lib-linux-x64-musl": "1.0.0",
71
- "@rrule-rust/lib-freebsd-x64": "1.0.0",
72
- "@rrule-rust/lib-win32-ia32-msvc": "1.0.0",
73
- "@rrule-rust/lib-android-arm-eabi": "1.0.0",
74
- "@rrule-rust/lib-darwin-universal": "1.0.0"
93
+ "@rrule-rust/lib-win32-x64-msvc": "1.1.3",
94
+ "@rrule-rust/lib-darwin-x64": "1.1.3",
95
+ "@rrule-rust/lib-linux-x64-gnu": "1.1.3",
96
+ "@rrule-rust/lib-darwin-arm64": "1.1.3",
97
+ "@rrule-rust/lib-android-arm64": "1.1.3",
98
+ "@rrule-rust/lib-linux-arm64-gnu": "1.1.3",
99
+ "@rrule-rust/lib-linux-arm64-musl": "1.1.3",
100
+ "@rrule-rust/lib-win32-arm64-msvc": "1.1.3",
101
+ "@rrule-rust/lib-linux-arm-gnueabihf": "1.1.3",
102
+ "@rrule-rust/lib-linux-x64-musl": "1.1.3",
103
+ "@rrule-rust/lib-freebsd-x64": "1.1.3",
104
+ "@rrule-rust/lib-win32-ia32-msvc": "1.1.3",
105
+ "@rrule-rust/lib-android-arm-eabi": "1.1.3",
106
+ "@rrule-rust/lib-darwin-universal": "1.1.3"
75
107
  }
76
108
  }
package/src/lib.rs CHANGED
@@ -284,8 +284,6 @@ impl JsRRule {
284
284
  pub struct JsRRuleSet {
285
285
  tz: Tz,
286
286
  rrule_set: RRuleSet,
287
- before: Option<i64>,
288
- after: Option<i64>,
289
287
  }
290
288
 
291
289
  #[napi]
@@ -296,12 +294,16 @@ impl JsRRuleSet {
296
294
  let date = timestamp_to_date_with_tz(dtstart, &tz);
297
295
  let rrule_set = RRuleSet::new(date);
298
296
 
299
- JsRRuleSet {
300
- rrule_set,
301
- tz,
302
- before: None,
303
- after: None,
304
- }
297
+ JsRRuleSet { rrule_set, tz }
298
+ }
299
+
300
+ #[napi(factory, ts_return_type="RRuleSet")]
301
+ pub fn parse(str: String) -> Self {
302
+ let rrule_set: RRuleSet = str.parse().unwrap();
303
+ let dtstart = rrule_set.get_dt_start();
304
+ let tz = dtstart.timezone();
305
+
306
+ JsRRuleSet { rrule_set, tz }
305
307
  }
306
308
 
307
309
  #[napi]
@@ -310,7 +312,7 @@ impl JsRRuleSet {
310
312
  }
311
313
 
312
314
  #[napi]
313
- pub fn rrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
315
+ pub fn add_rrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
314
316
  let dt_start = self.rrule_set.get_dt_start().clone();
315
317
  let rrule = js_rrule.validate(dt_start);
316
318
 
@@ -320,7 +322,7 @@ impl JsRRuleSet {
320
322
  }
321
323
 
322
324
  #[napi]
323
- pub fn exrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
325
+ pub fn add_exrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
324
326
  let rrule = js_rrule.validate(*self.rrule_set.get_dt_start());
325
327
 
326
328
  replace_with_or_abort(&mut self.rrule_set, |self_| self_.exrule(rrule));
@@ -329,21 +331,7 @@ impl JsRRuleSet {
329
331
  }
330
332
 
331
333
  #[napi]
332
- pub fn after(&mut self, timestamp: i64) -> napi::Result<&Self> {
333
- self.after = Some(timestamp);
334
-
335
- Ok(self)
336
- }
337
-
338
- #[napi]
339
- pub fn before(&mut self, timestamp: i64) -> napi::Result<&Self> {
340
- self.before = Some(timestamp);
341
-
342
- Ok(self)
343
- }
344
-
345
- #[napi]
346
- pub fn exdate(&mut self, timestamp: i64) -> napi::Result<&Self> {
334
+ pub fn add_exdate(&mut self, timestamp: i64) -> napi::Result<&Self> {
347
335
  replace_with_or_abort(&mut self.rrule_set, |self_| {
348
336
  self_.exdate(timestamp_to_date_with_tz(timestamp, &self.tz))
349
337
  });
@@ -351,13 +339,13 @@ impl JsRRuleSet {
351
339
  Ok(self)
352
340
  }
353
341
 
354
- #[napi]
355
- pub fn get_dtstart(&self) -> napi::Result<i64> {
342
+ #[napi(getter)]
343
+ pub fn dtstart(&self) -> napi::Result<i64> {
356
344
  Ok(self.rrule_set.get_dt_start().timestamp_millis())
357
345
  }
358
346
 
359
- #[napi]
360
- pub fn get_tzid(&self) -> napi::Result<String> {
347
+ #[napi(getter)]
348
+ pub fn tzid(&self) -> napi::Result<String> {
361
349
  Ok(String::from(self.tz.name()))
362
350
  }
363
351
 
@@ -375,21 +363,25 @@ impl JsRRuleSet {
375
363
  Ok(arr)
376
364
  }*/
377
365
 
378
- fn is_after(&self, timestamp: i64) -> bool {
379
- if let Some(after) = self.after {
380
- if timestamp <= after {
381
- return false;
382
- }
366
+ fn is_after(&self, timestamp: i64, after_timestamp: i64, inclusive: Option<bool>) -> bool {
367
+ let inclusive = inclusive.unwrap_or(false);
368
+
369
+ if inclusive && timestamp < after_timestamp {
370
+ return false;
371
+ } else if !inclusive && timestamp <= after_timestamp {
372
+ return false;
383
373
  }
384
374
 
385
375
  true
386
376
  }
387
377
 
388
- fn is_before(&self, timestamp: i64) -> bool {
389
- if let Some(before) = self.before {
390
- if timestamp >= before {
391
- return false;
392
- }
378
+ fn is_before(&self, timestamp: i64, before_timestamp: i64, inclusive: Option<bool>) -> bool {
379
+ let inclusive = inclusive.unwrap_or(false);
380
+
381
+ if inclusive && timestamp > before_timestamp {
382
+ return false;
383
+ } else if !inclusive && timestamp >= before_timestamp {
384
+ return false;
393
385
  }
394
386
 
395
387
  true
@@ -411,8 +403,20 @@ impl JsRRuleSet {
411
403
  }
412
404
 
413
405
  let timestamp = date.timestamp_millis();
414
- let is_after = self.is_after(timestamp);
415
- let is_before = self.is_before(timestamp);
406
+ arr.insert(timestamp).unwrap();
407
+ }
408
+
409
+ Ok(arr)
410
+ }
411
+
412
+ #[napi(ts_return_type = "number[]")]
413
+ pub fn between(&self, env: Env, after: i64, before: i64, inclusive: Option<bool>) -> napi::Result<Array> {
414
+ let mut arr = env.create_array(0).unwrap();
415
+
416
+ for date in self.rrule_set.into_iter() {
417
+ let timestamp = date.timestamp_millis();
418
+ let is_after = self.is_after(timestamp, after, inclusive);
419
+ let is_before = self.is_before(timestamp, before, inclusive);
416
420
 
417
421
  if is_after && is_before {
418
422
  arr.insert(timestamp).unwrap();
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ }
6
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": true,
5
+ "emitDecoratorMetadata": true,
6
+ "experimentalDecorators": true,
7
+ "allowSyntheticDefaultImports": true,
8
+ "target": "es2017",
9
+ "sourceMap": true,
10
+ "outDir": "./dist",
11
+ "baseUrl": "./",
12
+ "incremental": true,
13
+ "removeComments": true,
14
+ "allowUnreachableCode": false,
15
+ "allowUnusedLabels": false,
16
+ "noFallthroughCasesInSwitch": true,
17
+ "noPropertyAccessFromIndexSignature": true,
18
+ "noUncheckedIndexedAccess": true,
19
+ "noImplicitOverride": true,
20
+ "noUnusedLocals": true,
21
+ "noUnusedParameters": true,
22
+ "strict": true
23
+ }
24
+ }
File without changes