@figliolia/chalk-animation 1.0.0 → 1.0.2

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.
Files changed (44) hide show
  1. package/README.md +11 -56
  2. package/dist/cjs/Animation.d.ts +8 -12
  3. package/dist/cjs/Animation.js +25 -36
  4. package/dist/cjs/ChalkAnimation.d.ts +18 -7
  5. package/dist/cjs/ChalkAnimation.js +26 -21
  6. package/dist/cjs/Decor.d.ts +5 -0
  7. package/dist/cjs/Decor.js +18 -0
  8. package/dist/cjs/Effects.d.ts +2 -2
  9. package/dist/cjs/Effects.js +28 -3
  10. package/dist/cjs/FrameRate.d.ts +11 -0
  11. package/dist/cjs/FrameRate.js +26 -0
  12. package/dist/cjs/InstanceTracker.d.ts +1 -0
  13. package/dist/cjs/InstanceTracker.js +4 -2
  14. package/dist/cjs/index.d.ts +1 -0
  15. package/dist/cjs/types.d.ts +5 -0
  16. package/dist/mjs/Animation.d.ts +8 -12
  17. package/dist/mjs/Animation.js +20 -33
  18. package/dist/mjs/ChalkAnimation.d.ts +18 -7
  19. package/dist/mjs/ChalkAnimation.js +24 -21
  20. package/dist/mjs/Decor.d.ts +5 -0
  21. package/dist/mjs/Decor.js +14 -0
  22. package/dist/mjs/Effects.d.ts +2 -2
  23. package/dist/mjs/Effects.js +27 -2
  24. package/dist/mjs/FrameRate.d.ts +11 -0
  25. package/dist/mjs/FrameRate.js +24 -0
  26. package/dist/mjs/InstanceTracker.d.ts +1 -0
  27. package/dist/mjs/InstanceTracker.js +2 -2
  28. package/dist/mjs/index.d.ts +1 -0
  29. package/dist/mjs/types.d.ts +5 -0
  30. package/package.json +1 -1
  31. package/src/Animation.ts +20 -34
  32. package/src/ChalkAnimation.ts +25 -26
  33. package/src/Decor.ts +24 -0
  34. package/src/Effects.ts +14 -6
  35. package/src/FrameRate.ts +28 -0
  36. package/src/InstanceTracker.ts +5 -3
  37. package/src/__tests__/ChalkAnimation.test.ts +108 -0
  38. package/src/index.ts +1 -0
  39. package/src/types.ts +14 -0
  40. package/dist/cjs/animateString.d.ts +0 -2
  41. package/dist/cjs/animateString.js +0 -18
  42. package/dist/mjs/animateString.d.ts +0 -2
  43. package/dist/mjs/animateString.js +0 -14
  44. package/src/animateString.ts +0 -15
@@ -1,26 +1,29 @@
1
1
  import { Effects } from "./Effects";
2
2
  import { Animation } from "./Animation";
3
- import { animateString } from "./animateString";
3
+ /**
4
+ * Chalk Animation
5
+ *
6
+ * Console animations for your CLI tools
7
+ *
8
+ * ```typescript
9
+ * const animation = ChalkAnimation.rainbow("hello!");
10
+ * animation.stop();
11
+ * animation.start();
12
+ * ```
13
+ */
4
14
  export class ChalkAnimation {
5
- static rainbow(str, speed = 1) {
6
- return animateString(Effects.rainbow, str, 15, speed);
7
- }
8
- static pulse(str, speed = 1) {
9
- return animateString(Effects.pulse, str, 16, speed);
10
- }
11
- static glitch(str, speed = 1) {
12
- return animateString(Effects.glitch, str, 55, speed);
13
- }
14
- static radar(str, speed = 1) {
15
- return animateString(Effects.radar, str, 50, speed);
16
- }
17
- static neon(str, speed = 1) {
18
- return animateString(Effects.neon, str, 500, speed);
19
- }
20
- static karaoke(str, speed = 1) {
21
- return animateString(Effects.karaoke, str, 50, speed);
22
- }
23
- static clearAllAnimations() {
24
- return Animation.clearAll();
15
+ static neon = this.configure("neon", 500);
16
+ static radar = this.configure("radar", 50);
17
+ static pulse = this.configure("pulse", 16);
18
+ static glitch = this.configure("glitch", 55);
19
+ static rainbow = this.configure("rainbow", 15);
20
+ static karaoke = this.configure("karaoke", 50);
21
+ static configure(effect, delay) {
22
+ return (str, speed = 1) => {
23
+ if (!speed || speed <= 0) {
24
+ throw new Error("Expected `speed` to be an number greater than 0");
25
+ }
26
+ return new Animation(Effects[effect], str, delay, speed).start();
27
+ };
25
28
  }
26
29
  }
@@ -0,0 +1,5 @@
1
+ import type { MethodKeys, MethodLike } from "./types";
2
+ export declare class Decor {
3
+ static bound<T, K extends MethodKeys<T>>(target: T, _propertyKey: K, descriptor: TypedPropertyDescriptor<MethodLike>): void;
4
+ static chainable<I, F extends (...args: any[]) => any>(instance: I, func: F): (...params: Parameters<F>) => I;
5
+ }
@@ -0,0 +1,14 @@
1
+ export class Decor {
2
+ static bound(target, _propertyKey, descriptor) {
3
+ const operation = descriptor.value;
4
+ if (operation) {
5
+ descriptor.value = operation.bind(target);
6
+ }
7
+ }
8
+ static chainable(instance, func) {
9
+ return (...params) => {
10
+ func(...params);
11
+ return instance;
12
+ };
13
+ }
14
+ }
@@ -1,9 +1,9 @@
1
1
  export declare class Effects {
2
- static longHsv: {
2
+ static readonly longHsv: {
3
3
  interpolation: string;
4
4
  hsvSpin: string;
5
5
  };
6
- static glitchChars: string;
6
+ static readonly glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
7
7
  static rainbow(str: string, frame: number): string;
8
8
  static pulse(str: string, frame: number): string;
9
9
  static glitch(str: string, frame: number): string;
@@ -1,5 +1,12 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
1
7
  import chalk from "chalk";
2
8
  import gradient from "gradient-string";
9
+ import { Decor } from "./Decor";
3
10
  export class Effects {
4
11
  static longHsv = { interpolation: "hsv", hsvSpin: "long" };
5
12
  static glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
@@ -7,7 +14,7 @@ export class Effects {
7
14
  const hue = 5 * frame;
8
15
  const leftColor = { h: hue % 360, s: 1, v: 1 };
9
16
  const rightColor = { h: (hue + 1) % 360, s: 1, v: 1 };
10
- return gradient(leftColor, rightColor)(str, Effects.longHsv);
17
+ return gradient(leftColor, rightColor)(str, this.longHsv);
11
18
  }
12
19
  static pulse(str, frame) {
13
20
  frame = (frame % 120) + 1;
@@ -52,7 +59,7 @@ export class Effects {
52
59
  i += skip;
53
60
  if (str[i]) {
54
61
  if (str[i] !== "\n" && str[i] !== "\r" && Math.random() > 0.995) {
55
- chunks.push(Effects.glitchChars[Math.floor(Math.random() * Effects.glitchChars.length)]);
62
+ chunks.push(this.glitchChars[Math.floor(Math.random() * this.glitchChars.length)]);
56
63
  }
57
64
  else if (Math.random() > 0.005) {
58
65
  chunks.push(str[i]);
@@ -100,3 +107,21 @@ export class Effects {
100
107
  chalk.white(str.substr(chars)));
101
108
  }
102
109
  }
110
+ __decorate([
111
+ Decor.bound
112
+ ], Effects, "rainbow", null);
113
+ __decorate([
114
+ Decor.bound
115
+ ], Effects, "pulse", null);
116
+ __decorate([
117
+ Decor.bound
118
+ ], Effects, "glitch", null);
119
+ __decorate([
120
+ Decor.bound
121
+ ], Effects, "radar", null);
122
+ __decorate([
123
+ Decor.bound
124
+ ], Effects, "neon", null);
125
+ __decorate([
126
+ Decor.bound
127
+ ], Effects, "karaoke", null);
@@ -0,0 +1,11 @@
1
+ import { InstanceTracker } from "./InstanceTracker";
2
+ export declare class FrameRate extends InstanceTracker {
3
+ current: number;
4
+ speed: number;
5
+ delay: number;
6
+ controller: ReturnType<typeof setTimeout> | null;
7
+ constructor(delay: number, speed: number);
8
+ schedule<F extends () => any>(func: F): void;
9
+ increment(): void;
10
+ clearFrames(): void;
11
+ }
@@ -0,0 +1,24 @@
1
+ import { InstanceTracker } from "./InstanceTracker";
2
+ export class FrameRate extends InstanceTracker {
3
+ current = 0;
4
+ speed;
5
+ delay;
6
+ controller = null;
7
+ constructor(delay, speed) {
8
+ super();
9
+ this.delay = delay;
10
+ this.speed = speed;
11
+ }
12
+ schedule(func) {
13
+ this.controller = setTimeout(func, this.delay / this.speed);
14
+ }
15
+ increment() {
16
+ this.current++;
17
+ }
18
+ clearFrames() {
19
+ if (this.controller) {
20
+ clearTimeout(this.controller);
21
+ this.controller = null;
22
+ }
23
+ }
24
+ }
@@ -8,6 +8,7 @@ export declare class InstanceTracker {
8
8
  };
9
9
  static IDs: AutoIncrementingID;
10
10
  static bucket: Map<string, Animation>;
11
+ static loggers: readonly ["log", "warn", "info", "error"];
11
12
  constructor();
12
13
  get instance(): Animation;
13
14
  static clearAll(): void;
@@ -4,14 +4,14 @@ export class InstanceTracker {
4
4
  static LOG = console.log;
5
5
  static IDs = new AutoIncrementingID();
6
6
  static bucket = new Map();
7
+ static loggers = ["log", "warn", "info", "error"];
7
8
  constructor() {
8
9
  InstanceTracker.clearAll();
9
10
  this.ID = InstanceTracker.IDs.get();
10
11
  InstanceTracker.bucket.set(this.ID, this.instance);
11
12
  }
12
13
  static {
13
- const methods = ["log", "warn", "info", "error"];
14
- methods.forEach((method) => {
14
+ this.loggers.forEach(method => {
15
15
  const original = console[method];
16
16
  console[method] = function (...args) {
17
17
  InstanceTracker.clearAll();
@@ -1,4 +1,5 @@
1
1
  export { ChalkAnimation } from "./ChalkAnimation";
2
+ export type { Effects } from "./Effects";
2
3
  export type { Animation } from "./Animation";
3
4
  export type { InstanceTracker } from "./InstanceTracker";
4
5
  export * from "./types";
@@ -1 +1,6 @@
1
1
  export type AnimationFN = (str: string, frame: number) => string;
2
+ export type AnimationName = "rainbow" | "pulse" | "glitch" | "radar" | "neon" | "karaoke";
3
+ export type MethodLike<T = any> = (...args: any[]) => T;
4
+ export type MethodKeys<T, R = any> = keyof {
5
+ [K in keyof T as Required<T>[K] extends MethodLike<R> ? K : never]: T[K];
6
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@figliolia/chalk-animation",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "An ESM/Common.js compatible typescript port of the popular 'chalk-animation' library",
5
5
  "keywords": [
6
6
  "animation",
package/src/Animation.ts CHANGED
@@ -1,22 +1,18 @@
1
1
  import type { AnimationFN } from "./types";
2
- import { InstanceTracker } from "./InstanceTracker";
2
+ import { FrameRate } from "./FrameRate";
3
+ import { Decor } from "./Decor";
3
4
 
4
- export class Animation extends InstanceTracker {
5
- effect: any;
5
+ export class Animation extends FrameRate {
6
6
  lines: number;
7
- speed: number;
8
- delay: number;
9
7
  text: string[];
10
8
  stopped = false;
11
- currentFrame = 0;
12
9
  initialized = false;
13
- controller: ReturnType<typeof setTimeout> | null = null;
10
+ effect: AnimationFN;
11
+ static readonly LINE_BREAKS = /\r\n|\r|\n/;
14
12
  constructor(effect: AnimationFN, str: string, delay = 0, speed = 0) {
15
- super();
13
+ super(delay, speed);
16
14
  this.effect = effect;
17
- this.speed = speed;
18
- this.delay = delay;
19
- this.text = str.split(/\r\n|\r|\n/);
15
+ this.text = str.split(Animation.LINE_BREAKS);
20
16
  this.lines = this.text.length;
21
17
  }
22
18
 
@@ -25,47 +21,37 @@ export class Animation extends InstanceTracker {
25
21
  Animation.LOG("\n".repeat(this.lines - 1));
26
22
  this.initialized = true;
27
23
  }
28
- Animation.LOG(this.frame());
29
- this.controller = setTimeout(() => {
24
+ Animation.LOG(this.nextFrame());
25
+ this.schedule(() => {
30
26
  if (!this.stopped) {
31
27
  this.render();
32
28
  }
33
- }, this.delay / this.speed);
29
+ });
34
30
  }
35
31
 
36
- public frame() {
37
- this.currentFrame++;
32
+ public nextFrame() {
33
+ this.increment();
38
34
  return (
39
35
  "\u001B[" +
40
36
  `${this.lines}` +
41
37
  "F\u001B[G\u001B[2K" +
42
- this.text.map((str) => this.effect(str, this.currentFrame)).join("\n")
38
+ this.text.map(str => this.effect(str, this.current)).join("\n")
43
39
  );
44
40
  }
45
41
 
46
- public replace(str: string) {
47
- this.text = str.split(/\r\n|\r|\n/);
42
+ public readonly replace = Decor.chainable(this, (str: string) => {
43
+ this.text = str.split(Animation.LINE_BREAKS);
48
44
  this.lines = this.text.length;
49
- return this;
50
- }
45
+ });
51
46
 
52
- public stop() {
47
+ public readonly stop = Decor.chainable(this, () => {
53
48
  this.clearFrames();
54
49
  this.stopped = true;
55
- return this;
56
- }
50
+ });
57
51
 
58
- public start() {
52
+ public readonly start = Decor.chainable(this, () => {
59
53
  this.clearFrames();
60
54
  this.stopped = false;
61
55
  this.render();
62
- return this;
63
- }
64
-
65
- private clearFrames() {
66
- if (this.controller) {
67
- clearTimeout(this.controller);
68
- this.controller = null;
69
- }
70
- }
56
+ });
71
57
  }
@@ -1,33 +1,32 @@
1
1
  import { Effects } from "./Effects";
2
2
  import { Animation } from "./Animation";
3
- import { animateString } from "./animateString";
3
+ import type { AnimationName } from "./types";
4
4
 
5
+ /**
6
+ * Chalk Animation
7
+ *
8
+ * Console animations for your CLI tools
9
+ *
10
+ * ```typescript
11
+ * const animation = ChalkAnimation.rainbow("hello!");
12
+ * animation.stop();
13
+ * animation.start();
14
+ * ```
15
+ */
5
16
  export class ChalkAnimation {
6
- public static rainbow(str: string, speed = 1) {
7
- return animateString(Effects.rainbow, str, 15, speed);
8
- }
9
-
10
- public static pulse(str: string, speed = 1) {
11
- return animateString(Effects.pulse, str, 16, speed);
12
- }
13
-
14
- public static glitch(str: string, speed = 1) {
15
- return animateString(Effects.glitch, str, 55, speed);
16
- }
17
-
18
- public static radar(str: string, speed = 1) {
19
- return animateString(Effects.radar, str, 50, speed);
20
- }
21
-
22
- public static neon(str: string, speed = 1) {
23
- return animateString(Effects.neon, str, 500, speed);
24
- }
25
-
26
- public static karaoke(str: string, speed = 1) {
27
- return animateString(Effects.karaoke, str, 50, speed);
28
- }
17
+ public static readonly neon = this.configure("neon", 500);
18
+ public static readonly radar = this.configure("radar", 50);
19
+ public static readonly pulse = this.configure("pulse", 16);
20
+ public static readonly glitch = this.configure("glitch", 55);
21
+ public static readonly rainbow = this.configure("rainbow", 15);
22
+ public static readonly karaoke = this.configure("karaoke", 50);
29
23
 
30
- public static clearAllAnimations() {
31
- return Animation.clearAll();
24
+ private static configure(effect: AnimationName, delay: number) {
25
+ return (str: string, speed = 1) => {
26
+ if (!speed || speed <= 0) {
27
+ throw new Error("Expected `speed` to be an number greater than 0");
28
+ }
29
+ return new Animation(Effects[effect], str, delay, speed).start();
30
+ };
32
31
  }
33
32
  }
package/src/Decor.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { MethodKeys, MethodLike } from "./types";
2
+
3
+ export class Decor {
4
+ public static bound<T, K extends MethodKeys<T>>(
5
+ target: T,
6
+ _propertyKey: K,
7
+ descriptor: TypedPropertyDescriptor<MethodLike>,
8
+ ) {
9
+ const operation = descriptor.value;
10
+ if (operation) {
11
+ descriptor.value = operation.bind(target);
12
+ }
13
+ }
14
+
15
+ public static chainable<I, F extends (...args: any[]) => any>(
16
+ instance: I,
17
+ func: F,
18
+ ) {
19
+ return (...params: Parameters<F>): I => {
20
+ func(...params);
21
+ return instance;
22
+ };
23
+ }
24
+ }
package/src/Effects.ts CHANGED
@@ -1,17 +1,21 @@
1
1
  import chalk from "chalk";
2
2
  import gradient from "gradient-string";
3
+ import { Decor } from "./Decor";
3
4
 
4
5
  export class Effects {
5
- public static longHsv = { interpolation: "hsv", hsvSpin: "long" };
6
- public static glitchChars =
6
+ public static readonly longHsv = { interpolation: "hsv", hsvSpin: "long" };
7
+ public static readonly glitchChars =
7
8
  "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
9
+
10
+ @Decor.bound
8
11
  public static rainbow(str: string, frame: number) {
9
12
  const hue = 5 * frame;
10
13
  const leftColor = { h: hue % 360, s: 1, v: 1 };
11
14
  const rightColor = { h: (hue + 1) % 360, s: 1, v: 1 };
12
- return gradient(leftColor, rightColor)(str, Effects.longHsv);
15
+ return gradient(leftColor, rightColor)(str, this.longHsv);
13
16
  }
14
17
 
18
+ @Decor.bound
15
19
  public static pulse(str: string, frame: number) {
16
20
  frame = (frame % 120) + 1;
17
21
  const transition = 6;
@@ -48,6 +52,7 @@ export class Effects {
48
52
  return g(str);
49
53
  }
50
54
 
55
+ @Decor.bound
51
56
  public static glitch(str: string, frame: number) {
52
57
  if (
53
58
  (frame % 2) + (frame % 3) + (frame % 11) + (frame % 29) + (frame % 37) >
@@ -66,9 +71,9 @@ export class Effects {
66
71
  if (str[i]) {
67
72
  if (str[i] !== "\n" && str[i] !== "\r" && Math.random() > 0.995) {
68
73
  chunks.push(
69
- Effects.glitchChars[
70
- Math.floor(Math.random() * Effects.glitchChars.length)
71
- ]
74
+ this.glitchChars[
75
+ Math.floor(Math.random() * this.glitchChars.length)
76
+ ],
72
77
  );
73
78
  } else if (Math.random() > 0.005) {
74
79
  chunks.push(str[i]);
@@ -86,6 +91,7 @@ export class Effects {
86
91
  return result;
87
92
  }
88
93
 
94
+ @Decor.bound
89
95
  public static radar(str: string, frame: number) {
90
96
  const depth = Math.floor(Math.min(str.length, str.length * 0.2));
91
97
  const step = Math.floor(255 / depth);
@@ -106,6 +112,7 @@ export class Effects {
106
112
  return chars.join("");
107
113
  }
108
114
 
115
+ @Decor.bound
109
116
  public static neon(str: string, frame: number) {
110
117
  const color =
111
118
  frame % 2 === 0
@@ -114,6 +121,7 @@ export class Effects {
114
121
  return color(str);
115
122
  }
116
123
 
124
+ @Decor.bound
117
125
  public static karaoke(str: string, frame: number) {
118
126
  const chars = (frame % (str.length + 20)) - 10;
119
127
  if (chars < 0) {
@@ -0,0 +1,28 @@
1
+ import { InstanceTracker } from "./InstanceTracker";
2
+
3
+ export class FrameRate extends InstanceTracker {
4
+ current = 0;
5
+ speed: number;
6
+ delay: number;
7
+ controller: ReturnType<typeof setTimeout> | null = null;
8
+ constructor(delay: number, speed: number) {
9
+ super();
10
+ this.delay = delay;
11
+ this.speed = speed;
12
+ }
13
+
14
+ public schedule<F extends () => any>(func: F) {
15
+ this.controller = setTimeout(func, this.delay / this.speed);
16
+ }
17
+
18
+ public increment() {
19
+ this.current++;
20
+ }
21
+
22
+ public clearFrames() {
23
+ if (this.controller) {
24
+ clearTimeout(this.controller);
25
+ this.controller = null;
26
+ }
27
+ }
28
+ }
@@ -6,6 +6,7 @@ export class InstanceTracker {
6
6
  static readonly LOG = console.log;
7
7
  static IDs = new AutoIncrementingID();
8
8
  static bucket = new Map<string, Animation>();
9
+ static loggers = ["log", "warn", "info", "error"] as const;
9
10
  constructor() {
10
11
  InstanceTracker.clearAll();
11
12
  this.ID = InstanceTracker.IDs.get();
@@ -13,10 +14,11 @@ export class InstanceTracker {
13
14
  }
14
15
 
15
16
  static {
16
- const methods = ["log", "warn", "info", "error"] as const;
17
- methods.forEach((method) => {
17
+ this.loggers.forEach(method => {
18
18
  const original = console[method];
19
- console[method] = function (...args: Parameters<typeof console.log>) {
19
+ console[method] = function (
20
+ ...args: Parameters<(typeof console)[typeof method]>
21
+ ) {
20
22
  InstanceTracker.clearAll();
21
23
  return original.apply(console, args);
22
24
  };
@@ -0,0 +1,108 @@
1
+ import { ChalkAnimation } from "../ChalkAnimation";
2
+ import { Effects } from "../Effects";
3
+ import { InstanceTracker } from "../InstanceTracker";
4
+
5
+ const animations = [
6
+ "rainbow",
7
+ "pulse",
8
+ "glitch",
9
+ "radar",
10
+ "neon",
11
+ "karaoke",
12
+ ] as const;
13
+
14
+ describe("Chalk Animation", () => {
15
+ afterAll(() => {
16
+ jest.restoreAllMocks();
17
+ });
18
+
19
+ describe("Spawn", () => {
20
+ beforeAll(() => {
21
+ jest.spyOn(InstanceTracker, "LOG").mockImplementation(() => {});
22
+ });
23
+
24
+ afterEach(() => {
25
+ InstanceTracker.clearAll();
26
+ InstanceTracker.IDs.reset();
27
+ });
28
+
29
+ animations.forEach(name => {
30
+ it(`ChalkAnimation.${name} - returns an initialized animation instance`, () => {
31
+ const animation = ChalkAnimation[name]("hello");
32
+ expect(animation.effect).toEqual(Effects[name]);
33
+ expect(typeof animation.ID).toEqual("string");
34
+ expect(animation.text).toEqual(["hello"]);
35
+ expect(animation.lines).toEqual(1);
36
+ expect(animation.speed).toEqual(1);
37
+ expect(animation.current).toEqual(1);
38
+ expect(animation.initialized).toEqual(true);
39
+ expect(animation.stopped).toEqual(false);
40
+ expect(animation.controller).not.toEqual(null);
41
+ expect(InstanceTracker.bucket.size).toEqual(1);
42
+ animation.stop();
43
+ expect(animation.stopped).toEqual(true);
44
+ expect(animation.controller).toEqual(null);
45
+ });
46
+
47
+ InstanceTracker.loggers.forEach(method => {
48
+ it(`ChalkAnimation.${name} - subsequent console.${method} stop the animation`, () => {
49
+ const animation = ChalkAnimation[name]("hello");
50
+ expect(animation.stopped).toEqual(false);
51
+ console[method]("");
52
+ expect(animation.stopped).toEqual(true);
53
+ });
54
+ });
55
+
56
+ it(`ChalkAnimation.${name} - can be stopped and restarted`, () => {
57
+ const animation = ChalkAnimation[name]("hello");
58
+ animation.stop();
59
+ expect(animation.stopped).toEqual(true);
60
+ animation.start();
61
+ expect(animation.current).toEqual(2);
62
+ });
63
+
64
+ it(`ChalkAnimation.${name} - can be manually rendered at a desired frame rate`, () => {
65
+ const animation = ChalkAnimation[name]("hello").stop();
66
+ expect(animation.current).toEqual(1);
67
+ animation.render();
68
+ expect(animation.current).toEqual(2);
69
+ animation.render();
70
+ expect(animation.current).toEqual(3);
71
+ });
72
+
73
+ it(`ChalkAnimation.${name} - text can be replaced`, () => {
74
+ if (name === "radar") {
75
+ return;
76
+ }
77
+ const animation = ChalkAnimation[name]("Y Y Y").stop();
78
+ const f1 = animation.nextFrame();
79
+ animation.replace("Z Z Z");
80
+ const f2 = animation.nextFrame();
81
+ expect(f1.includes("Y")).toEqual(true);
82
+ expect(f1.includes("Z")).toEqual(false);
83
+ expect(f2.includes("Y")).toEqual(false);
84
+ expect(f2.includes("Z")).toEqual(true);
85
+ });
86
+
87
+ it(`ChalkAnimation.${name} - supports multiline strings`, () => {
88
+ const animation = ChalkAnimation[name](
89
+ "Lorem\nipsum\ndolor\nsit\namet",
90
+ ).stop();
91
+ const frame = animation.nextFrame();
92
+ expect(animation.lines).toEqual(5);
93
+ expect(frame.split("\n")).toHaveLength(5);
94
+ });
95
+
96
+ it(`ChalkAnimation.${name} - supports 5K+ frames`, () => {
97
+ const animation = ChalkAnimation[name](
98
+ "Lorem\nipsum\ndolor\nsit\namet",
99
+ ).stop();
100
+ for (let i = 0; i < 5000; i++) {
101
+ expect(() => {
102
+ animation.nextFrame();
103
+ }).not.toThrow();
104
+ }
105
+ });
106
+ });
107
+ });
108
+ });
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { ChalkAnimation } from "./ChalkAnimation";
2
+ export type { Effects } from "./Effects";
2
3
  export type { Animation } from "./Animation";
3
4
  export type { InstanceTracker } from "./InstanceTracker";
4
5
  export * from "./types";
package/src/types.ts CHANGED
@@ -1 +1,15 @@
1
1
  export type AnimationFN = (str: string, frame: number) => string;
2
+
3
+ export type AnimationName =
4
+ | "rainbow"
5
+ | "pulse"
6
+ | "glitch"
7
+ | "radar"
8
+ | "neon"
9
+ | "karaoke";
10
+
11
+ export type MethodLike<T = any> = (...args: any[]) => T;
12
+
13
+ export type MethodKeys<T, R = any> = keyof {
14
+ [K in keyof T as Required<T>[K] extends MethodLike<R> ? K : never]: T[K];
15
+ };
@@ -1,2 +0,0 @@
1
- import { Animation } from "./Animation";
2
- export declare function animateString(effect: any, str: string, delay?: number, speed?: number): Animation;