@peteanderson/ansi 0.2.1 → 0.2.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.
package/README.md CHANGED
@@ -19,6 +19,7 @@ console.log(ansi.style.bold("important"));
19
19
  console.log(ansi.fg.rgb(5, 2, 0)("custom color"));
20
20
  console.log(ansi.strip("styled text")); // remove all ANSI codes
21
21
  console.log(ansi.slice("styled text", 0, 5)); // slice by visible length
22
+ console.log(ansi.simplify(styledText)); // combine adjacent SGR sequences
22
23
  ```
23
24
 
24
25
  ## API
@@ -52,8 +53,7 @@ Functions that wrap text with style codes:
52
53
  `bold` `dim` `italic` `underline` `inverse` `hidden` `strikethrough` `doubleUnderline` `framed`
53
54
  `encircled` `overline`
54
55
 
55
- All return functions with `open` and `close` properties for raw sequences. SGR functions also have a
56
- `combine()` method for appending additional styles.
56
+ All return functions with `open` and `close` properties for raw sequences.
57
57
 
58
58
  ### `caret`
59
59
 
@@ -90,6 +90,11 @@ but counts only visible characters.
90
90
 
91
91
  Removes "unsafe" CSI sequences (non-SGR), leaving only color and style codes.
92
92
 
93
+ ### `simplify(text)`
94
+
95
+ Simplifies ANSI SGR sequences by combining adjacent sequences and removing redundant codes. Useful
96
+ for optimizing styled strings.
97
+
93
98
  ## License
94
99
 
95
100
  MIT
package/dist/ansi.d.ts CHANGED
@@ -8,4 +8,5 @@ import { bg } from "./sgr/color";
8
8
  import { strip } from "./strip";
9
9
  import { sanitize } from "./strip";
10
10
  import { slice } from "./strip";
11
- export { caret, erase, scroll, reset, style, fg, bg, strip, sanitize, slice };
11
+ import { simplify } from "./simplify/simplify";
12
+ export { caret, erase, scroll, reset, style, fg, bg, strip, sanitize, slice, simplify };
package/dist/ansi.js CHANGED
@@ -3,6 +3,7 @@ const caret = require("./caret");
3
3
  const erase = require("./erase");
4
4
  const scroll = require("./scroll");
5
5
  const { bg, fg, reset, style } = require("./sgr");
6
+ const { simplify } = require("./simplify");
6
7
  const { sanitize, slice, strip } = require("./strip");
7
8
  const ansi = {
8
9
  caret,
@@ -15,5 +16,6 @@ const ansi = {
15
16
  strip,
16
17
  sanitize,
17
18
  slice,
19
+ simplify,
18
20
  };
19
21
  module.exports = ansi;
package/dist/index.d.ts CHANGED
@@ -101,5 +101,6 @@ declare const _exports: {
101
101
  strip: (text: string) => string;
102
102
  sanitize: (text: string) => string;
103
103
  slice: typeof import("./strip").slice;
104
+ simplify: typeof import("./simplify/simplify").simplify;
104
105
  };
105
106
  export = _exports;
@@ -0,0 +1,3 @@
1
+ export type BuildAtom = import("./types").BuildAtom;
2
+ export function buildExtendedColorAtom(attribute: import("./types").Attribute, codes: number[], index: number, state: import("./types").AttributeMap): import("./types").Atom;
3
+ export function buildIntensityAtom(attribute: import("./types").Attribute, codes: number[], index: number, state: import("./types").AttributeMap): import("./types").Atom;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /** @typedef {import("./types").BuildAtom} BuildAtom */
3
+ /** @type {BuildAtom} */
4
+ function buildExtendedColorAtom(attribute, codes, index) {
5
+ switch (codes[index + 1]) {
6
+ case 2:
7
+ if (index + 5 >= codes.length)
8
+ return { attribute, code: codes.slice(index), skip: codes.length - index - 1 };
9
+ return { attribute, code: codes.slice(index, index + 5), skip: 4 };
10
+ case 5:
11
+ if (index + 3 >= codes.length)
12
+ return { attribute, code: codes.slice(index), skip: codes.length - index - 1 };
13
+ return { attribute, code: codes.slice(index, index + 3), skip: 2 };
14
+ default:
15
+ return { attribute, code: codes.slice(index, index + 2), skip: 1 };
16
+ }
17
+ }
18
+ /** @type {BuildAtom} */
19
+ function buildIntensityAtom(attribute, codes, index, state) {
20
+ const code = codes[index];
21
+ if (code === 22)
22
+ return { attribute, code: [code] };
23
+ const current = state.get("intensity");
24
+ if (!current || current.length == 1 && current[0] === code || current[0] === 22)
25
+ return { attribute, code: [code] };
26
+ return { attribute, code: [1, 2] };
27
+ }
28
+ module.exports = { buildExtendedColorAtom, buildIntensityAtom };
@@ -0,0 +1,2 @@
1
+ declare const _exports: typeof import("./simplify");
2
+ export = _exports;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ module.exports = require("./simplify");
@@ -0,0 +1,5 @@
1
+ export type Atom = import("./types").Atom;
2
+ export type Attribute = import("./types").Attribute;
3
+ export type AttributeMap = import("./types").AttributeMap;
4
+ export type BuildAtom = import("./types").BuildAtom;
5
+ export function lookUpAtom(codes: number[], index: number, state: AttributeMap): Atom;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ const { buildExtendedColorAtom, buildIntensityAtom } = require("./atom");
3
+ /** @typedef {import("./types").Atom} Atom */
4
+ /** @typedef {import("./types").Attribute} Attribute */
5
+ /** @typedef {import("./types").AttributeMap} AttributeMap */
6
+ /** @typedef {import("./types").BuildAtom} BuildAtom */
7
+ /** @type {Record<number, [attribute: Attribute, buildAtom?: BuildAtom]>} */
8
+ const codeMap = {
9
+ 0: ["reset"],
10
+ 1: ["intensity", buildIntensityAtom],
11
+ 2: ["intensity", buildIntensityAtom],
12
+ 3: ["italic"],
13
+ 4: ["underline"],
14
+ 7: ["inverse"],
15
+ 8: ["hidden"],
16
+ 9: ["strikethrough"],
17
+ 21: ["underline"],
18
+ 22: ["intensity", buildIntensityAtom],
19
+ 23: ["italic"],
20
+ 24: ["underline"],
21
+ 27: ["inverse"],
22
+ 28: ["hidden"],
23
+ 29: ["strikethrough"],
24
+ 30: ["fg"],
25
+ 31: ["fg"],
26
+ 32: ["fg"],
27
+ 33: ["fg"],
28
+ 34: ["fg"],
29
+ 35: ["fg"],
30
+ 36: ["fg"],
31
+ 37: ["fg"],
32
+ 38: ["fg", buildExtendedColorAtom],
33
+ 39: ["fg"],
34
+ 40: ["bg"],
35
+ 41: ["bg"],
36
+ 42: ["bg"],
37
+ 43: ["bg"],
38
+ 44: ["bg"],
39
+ 45: ["bg"],
40
+ 46: ["bg"],
41
+ 47: ["bg"],
42
+ 48: ["bg", buildExtendedColorAtom],
43
+ 49: ["bg"],
44
+ 51: ["frame"],
45
+ 52: ["frame"],
46
+ 53: ["overline"],
47
+ 54: ["frame"],
48
+ 55: ["overline"],
49
+ 90: ["fg"],
50
+ 91: ["fg"],
51
+ 92: ["fg"],
52
+ 93: ["fg"],
53
+ 94: ["fg"],
54
+ 95: ["fg"],
55
+ 96: ["fg"],
56
+ 97: ["fg"],
57
+ 100: ["bg"],
58
+ 101: ["bg"],
59
+ 102: ["bg"],
60
+ 103: ["bg"],
61
+ 104: ["bg"],
62
+ 105: ["bg"],
63
+ 106: ["bg"],
64
+ 107: ["bg"],
65
+ };
66
+ /** @type {(codes: number[], index: number, state: AttributeMap) => Atom} */
67
+ function lookUpAtom(codes, index, state) {
68
+ const code = codes[index];
69
+ const entry = codeMap[code];
70
+ if (!entry)
71
+ return { attribute: code, code: [code] };
72
+ const [attribute, buildAtom] = entry;
73
+ if (buildAtom)
74
+ return buildAtom(attribute, codes, index, state);
75
+ return { attribute, code: [code] };
76
+ }
77
+ module.exports = { lookUpAtom };
@@ -0,0 +1 @@
1
+ export function simplify(text: string): string;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ const { State } = require("./state");
3
+ const rxSGR = /\x1b\[([0-9;]+)m/;
4
+ /** @type {(text: string) => string} */
5
+ function simplify(text) {
6
+ const parts = text.split(rxSGR);
7
+ const state = new State();
8
+ let result = parts[0];
9
+ for (let i = 1; i < parts.length;) {
10
+ let codes = parts[i++].split(";").map(Number);
11
+ let chunk = parts[i++];
12
+ while (!chunk && i < parts.length) {
13
+ // Merge consecutive SGR sequences.
14
+ codes.push(...parts[i++].split(";").map(Number));
15
+ chunk = parts[i++];
16
+ }
17
+ codes = state.update(codes);
18
+ if (codes.length)
19
+ result += `\x1b[${codes.join(";")}m`;
20
+ result += chunk;
21
+ }
22
+ return result;
23
+ }
24
+ module.exports = { simplify };
@@ -0,0 +1,10 @@
1
+ export type Attribute = import("./types").Attribute;
2
+ export type AttributeMap = import("./types").AttributeMap;
3
+ /** @type {AttributeMap} */
4
+ export class State extends Map<any, any> {
5
+ constructor();
6
+ constructor(entries?: readonly (readonly [any, any])[] | null | undefined);
7
+ constructor();
8
+ constructor(iterable?: Iterable<readonly [any, any]> | null | undefined);
9
+ update(codes: number[]): number[];
10
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ const { lookUpAtom } = require("./lookup");
3
+ const { arraysEqual, transitionIntensity } = require("./utils");
4
+ /** @typedef {import("./types").Attribute} Attribute */
5
+ /** @typedef {import("./types").AttributeMap} AttributeMap */
6
+ /** @type {Map<Attribute, number[]>} */
7
+ const defaultCodes = new Map([
8
+ ["intensity", [22]],
9
+ ["italic", [23]],
10
+ ["underline", [24]],
11
+ ["inverse", [27]],
12
+ ["hidden", [28]],
13
+ ["strikethrough", [29]],
14
+ ["fg", [39]],
15
+ ["bg", [49]],
16
+ ["frame", [54]],
17
+ ["overline", [55]],
18
+ ]);
19
+ /** @type {AttributeMap} */
20
+ class State extends Map {
21
+ /** @type {(codes: number[]) => number[]} */
22
+ update(codes) {
23
+ /** @type {AttributeMap} */
24
+ let snapshot = new Map(this);
25
+ /** @type {Set<Attribute>} */
26
+ const attributes = new Set();
27
+ for (let i = 0; i < codes.length; i++) {
28
+ const { attribute, code, skip } = lookUpAtom(codes, i, this);
29
+ if (attribute === "reset") {
30
+ attributes.clear();
31
+ this.clear();
32
+ attributes.add("reset");
33
+ for (const [attr, defaultCode] of defaultCodes)
34
+ this.set(attr, defaultCode);
35
+ snapshot = new Map(this);
36
+ continue;
37
+ }
38
+ attributes.add(attribute);
39
+ this.set(attribute, code);
40
+ if (skip)
41
+ i += skip;
42
+ }
43
+ return Array.from(attributes).flatMap(attribute => {
44
+ if (attribute === "reset")
45
+ return [0];
46
+ const code = this.get(attribute);
47
+ if (arraysEqual(code, snapshot.get(attribute)))
48
+ return [];
49
+ if (attribute === "intensity") {
50
+ const previous = snapshot.get(attribute);
51
+ return transitionIntensity(previous, code);
52
+ }
53
+ return code;
54
+ });
55
+ }
56
+ }
57
+ module.exports = { State };
@@ -0,0 +1,2 @@
1
+ export function arraysEqual<T>(a: T[] | undefined, b: T[] | undefined): boolean;
2
+ export function transitionIntensity(previous: number[] | undefined, current: number[]): number[];
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /** @type {<T>(a: T[] | undefined, b: T[] | undefined) => boolean} */
3
+ function arraysEqual(a, b) {
4
+ if (a === b)
5
+ return true;
6
+ if (!a || !b || a.length !== b.length)
7
+ return false;
8
+ for (let i = 0; i < a.length; i++) {
9
+ if (a[i] !== b[i])
10
+ return false;
11
+ }
12
+ return true;
13
+ }
14
+ /** @type {(previous: number[] | undefined, current: number[]) => number[]} */
15
+ function transitionIntensity(previous, current) {
16
+ if (!previous || previous[0] === 22 || current[0] === 22)
17
+ return current;
18
+ const oldBold = previous[0] === 1;
19
+ const newBold = current[0] === 1;
20
+ const oldDim = previous[previous.length - 1] === 2;
21
+ const newDim = current[current.length - 1] === 2;
22
+ const result = [];
23
+ if (oldBold && !newBold || oldDim && !newDim)
24
+ result.push(22);
25
+ if (newBold && (!oldBold || result[0] === 22))
26
+ result.push(1);
27
+ if (newDim && (!oldDim || result[0] === 22))
28
+ result.push(2);
29
+ return result;
30
+ }
31
+ module.exports = { arraysEqual, transitionIntensity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "@peteanderson/ansi",
3
- "version" : "0.2.1",
3
+ "version" : "0.2.2",
4
4
  "description" : "ANSI escape sequence generation with automatic feature detection",
5
5
  "author" : {
6
6
  "name" : "Pete Anderson",
package/src/ansi.js CHANGED
@@ -4,6 +4,7 @@ const caret = require("./caret");
4
4
  const erase = require("./erase");
5
5
  const scroll = require("./scroll");
6
6
  const {bg, fg, reset, style} = require("./sgr");
7
+ const {simplify} = require("./simplify");
7
8
  const {sanitize, slice, strip} = require("./strip");
8
9
 
9
10
  const ansi = {
@@ -19,6 +20,7 @@ const ansi = {
19
20
  strip,
20
21
  sanitize,
21
22
  slice,
23
+ simplify,
22
24
  };
23
25
 
24
26
  module.exports = ansi;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ /** @typedef {import("./types").BuildAtom} BuildAtom */
4
+
5
+ /** @type {BuildAtom} */
6
+ function buildExtendedColorAtom(attribute, codes, index) {
7
+ switch (codes[index + 1]) {
8
+ case 2:
9
+ if (index + 5 >= codes.length)
10
+ return {attribute, code: codes.slice(index), skip: codes.length - index - 1};
11
+ return {attribute, code: codes.slice(index, index + 5), skip: 4};
12
+ case 5:
13
+ if (index + 3 >= codes.length)
14
+ return {attribute, code: codes.slice(index), skip: codes.length - index - 1};
15
+ return {attribute, code: codes.slice(index, index + 3), skip: 2};
16
+ default:
17
+ return {attribute, code: codes.slice(index, index + 2), skip: 1};
18
+ }
19
+ }
20
+
21
+ /** @type {BuildAtom} */
22
+ function buildIntensityAtom(attribute, codes, index, state) {
23
+ const code = codes[index];
24
+ if (code === 22)
25
+ return {attribute, code: [code]};
26
+
27
+ const current = state.get("intensity");
28
+ if (!current || current.length == 1 && current[0] === code || current[0] === 22)
29
+ return {attribute, code: [code]};
30
+
31
+ return {attribute, code: [1, 2]};
32
+ }
33
+
34
+ module.exports = {buildExtendedColorAtom, buildIntensityAtom};
@@ -0,0 +1 @@
1
+ module.exports = require("./simplify");
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ const {buildExtendedColorAtom, buildIntensityAtom} = require("./atom");
4
+
5
+ /** @typedef {import("./types").Atom} Atom */
6
+ /** @typedef {import("./types").Attribute} Attribute */
7
+ /** @typedef {import("./types").AttributeMap} AttributeMap */
8
+ /** @typedef {import("./types").BuildAtom} BuildAtom */
9
+
10
+ /** @type {Record<number, [attribute: Attribute, buildAtom?: BuildAtom]>} */
11
+ const codeMap = {
12
+ 0 : ["reset"],
13
+ 1 : ["intensity", buildIntensityAtom],
14
+ 2 : ["intensity", buildIntensityAtom],
15
+ 3 : ["italic"],
16
+ 4 : ["underline"],
17
+ 7 : ["inverse"],
18
+ 8 : ["hidden"],
19
+ 9 : ["strikethrough"],
20
+ 21 : ["underline"],
21
+ 22 : ["intensity", buildIntensityAtom],
22
+ 23 : ["italic"],
23
+ 24 : ["underline"],
24
+ 27 : ["inverse"],
25
+ 28 : ["hidden"],
26
+ 29 : ["strikethrough"],
27
+ 30 : ["fg"],
28
+ 31 : ["fg"],
29
+ 32 : ["fg"],
30
+ 33 : ["fg"],
31
+ 34 : ["fg"],
32
+ 35 : ["fg"],
33
+ 36 : ["fg"],
34
+ 37 : ["fg"],
35
+ 38 : ["fg", buildExtendedColorAtom],
36
+ 39 : ["fg"],
37
+ 40 : ["bg"],
38
+ 41 : ["bg"],
39
+ 42 : ["bg"],
40
+ 43 : ["bg"],
41
+ 44 : ["bg"],
42
+ 45 : ["bg"],
43
+ 46 : ["bg"],
44
+ 47 : ["bg"],
45
+ 48 : ["bg", buildExtendedColorAtom],
46
+ 49 : ["bg"],
47
+ 51 : ["frame"],
48
+ 52 : ["frame"],
49
+ 53 : ["overline"],
50
+ 54 : ["frame"],
51
+ 55 : ["overline"],
52
+ 90 : ["fg"],
53
+ 91 : ["fg"],
54
+ 92 : ["fg"],
55
+ 93 : ["fg"],
56
+ 94 : ["fg"],
57
+ 95 : ["fg"],
58
+ 96 : ["fg"],
59
+ 97 : ["fg"],
60
+ 100 : ["bg"],
61
+ 101 : ["bg"],
62
+ 102 : ["bg"],
63
+ 103 : ["bg"],
64
+ 104 : ["bg"],
65
+ 105 : ["bg"],
66
+ 106 : ["bg"],
67
+ 107 : ["bg"],
68
+ };
69
+
70
+ /** @type {(codes: number[], index: number, state: AttributeMap) => Atom} */
71
+ function lookUpAtom(codes, index, state) {
72
+ const code = codes[index];
73
+ const entry = codeMap[code];
74
+
75
+ if (!entry)
76
+ return {attribute: code, code: [code]};
77
+
78
+ const [attribute, buildAtom] = entry;
79
+
80
+ if (buildAtom)
81
+ return buildAtom(attribute, codes, index, state);
82
+
83
+ return {attribute, code: [code]};
84
+ }
85
+
86
+ module.exports = {lookUpAtom};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ const {State} = require("./state");
4
+
5
+ const rxSGR = /\x1b\[([0-9;]+)m/;
6
+
7
+ /** @type {(text: string) => string} */
8
+ function simplify(text) {
9
+ const parts = text.split(rxSGR);
10
+
11
+ const state = new State();
12
+ let result = parts[0];
13
+
14
+ for (let i = 1; i < parts.length; ) {
15
+ let codes = parts[i++].split(";").map(Number);
16
+ let chunk = parts[i++];
17
+
18
+ while (!chunk && i < parts.length) {
19
+ // Merge consecutive SGR sequences.
20
+ codes.push(...parts[i++].split(";").map(Number));
21
+ chunk = parts[i++];
22
+ }
23
+
24
+ codes = state.update(codes);
25
+ if (codes.length)
26
+ result += `\x1b[${codes.join(";")}m`;
27
+ result += chunk;
28
+ }
29
+
30
+ return result;
31
+ }
32
+
33
+ module.exports = {simplify};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ const {lookUpAtom} = require("./lookup");
4
+ const {arraysEqual, transitionIntensity} = require("./utils");
5
+
6
+ /** @typedef {import("./types").Attribute} Attribute */
7
+ /** @typedef {import("./types").AttributeMap} AttributeMap */
8
+
9
+ /** @type {Map<Attribute, number[]>} */
10
+ const defaultCodes = new Map([
11
+ ["intensity", [22]],
12
+ ["italic", [23]],
13
+ ["underline", [24]],
14
+ ["inverse", [27]],
15
+ ["hidden", [28]],
16
+ ["strikethrough",[29]],
17
+ ["fg", [39]],
18
+ ["bg", [49]],
19
+ ["frame", [54]],
20
+ ["overline", [55]],
21
+ ]);
22
+
23
+ /** @type {AttributeMap} */
24
+ class State extends Map {
25
+ /** @type {(codes: number[]) => number[]} */
26
+ update(codes) {
27
+ /** @type {AttributeMap} */
28
+ let snapshot = new Map(this);
29
+
30
+ /** @type {Set<Attribute>} */
31
+ const attributes = new Set();
32
+
33
+ for (let i = 0; i < codes.length; i++) {
34
+ const {attribute, code, skip} = lookUpAtom(codes, i, this);
35
+
36
+ if (attribute === "reset") {
37
+ attributes.clear();
38
+ this.clear();
39
+ attributes.add("reset");
40
+ for (const [attr, defaultCode] of defaultCodes)
41
+ this.set(attr, defaultCode);
42
+
43
+ snapshot = new Map(this);
44
+ continue;
45
+ }
46
+
47
+ attributes.add(attribute);
48
+ this.set(attribute, code);
49
+
50
+ if (skip)
51
+ i += skip;
52
+ }
53
+
54
+ return Array.from(attributes).flatMap(attribute => {
55
+ if (attribute === "reset")
56
+ return [0];
57
+
58
+ const code = this.get(attribute);
59
+
60
+ if (arraysEqual(code, snapshot.get(attribute)))
61
+ return [];
62
+
63
+ if (attribute === "intensity") {
64
+ const previous = snapshot.get(attribute);
65
+ return transitionIntensity(previous, code);
66
+ }
67
+
68
+ return code;
69
+ });
70
+ }
71
+ }
72
+
73
+ module.exports = {State};
@@ -0,0 +1,28 @@
1
+ export type Attribute =
2
+ | "intensity"
3
+ | "italic"
4
+ | "underline"
5
+ | "inverse"
6
+ | "hidden"
7
+ | "strikethrough"
8
+ | "fg"
9
+ | "bg"
10
+ | "frame"
11
+ | "overline"
12
+ | "reset"
13
+ | number;
14
+
15
+ type AttributeMap = Map<Attribute, number[]>;
16
+
17
+ export interface Atom {
18
+ attribute : Attribute;
19
+ code : number[];
20
+ skip? : number;
21
+ }
22
+
23
+ export type BuildAtom = (
24
+ attribute: Attribute,
25
+ codes : number[],
26
+ index : number,
27
+ state : AttributeMap,
28
+ ) => Atom;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ /** @type {<T>(a: T[] | undefined, b: T[] | undefined) => boolean} */
4
+ function arraysEqual(a, b) {
5
+ if (a === b)
6
+ return true;
7
+
8
+ if (!a || !b || a.length !== b.length)
9
+ return false;
10
+
11
+ for (let i = 0; i < a.length; i++) {
12
+ if (a[i] !== b[i])
13
+ return false;
14
+ }
15
+
16
+ return true;
17
+ }
18
+
19
+ /** @type {(previous: number[] | undefined, current: number[]) => number[]} */
20
+ function transitionIntensity(previous, current) {
21
+ if (!previous || previous[0] === 22 || current[0] === 22)
22
+ return current;
23
+
24
+ const oldBold = previous[0] === 1;
25
+ const newBold = current[0] === 1;
26
+ const oldDim = previous[previous.length - 1] === 2;
27
+ const newDim = current[current.length - 1] === 2;
28
+
29
+ const result = [];
30
+
31
+ if (oldBold && !newBold || oldDim && !newDim)
32
+ result.push(22);
33
+ if (newBold && (!oldBold || result[0] === 22))
34
+ result.push(1);
35
+ if (newDim && (!oldDim || result[0] === 22))
36
+ result.push(2);
37
+
38
+ return result;
39
+ }
40
+
41
+ module.exports = {arraysEqual, transitionIntensity};