text-guitar-chart 0.0.1
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/AGENTS.md +18 -0
- package/FORMAT.md +277 -0
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/docs/app.js +172 -0
- package/docs/bundle.js +8712 -0
- package/docs/bundle.js.map +7 -0
- package/docs/index.html +93 -0
- package/index.js +7 -0
- package/lib/editableSVGuitar.js +1050 -0
- package/lib/fingeringToString.js +261 -0
- package/lib/layoutChordStrings.js +92 -0
- package/lib/splitStringInRectangles.js +132 -0
- package/lib/stringToFingering.js +435 -0
- package/package.json +43 -0
- package/scripts/build.js +30 -0
- package/test/editableSVGuitar.test.js +444 -0
- package/test/fingeringToString.test.js +705 -0
- package/test/layoutChordStrings.test.js +193 -0
- package/test/splitStringInRectangles.test.js +98 -0
- package/test/stringToFingering.test.js +1086 -0
- package/tsconfig.json +25 -0
- package/types/editableSVGuitar.d.ts +209 -0
- package/types/fingeringToString.d.ts +10 -0
- package/types/layoutChordStrings.d.ts +10 -0
- package/types/splitStringInRectangles.d.ts +18 -0
- package/types/stringToFingering.d.ts +10 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import layoutChordStrings from "../lib/layoutChordStrings.js";
|
|
6
|
+
|
|
7
|
+
describe("layoutChordStrings", () => {
|
|
8
|
+
test("handles empty string list", () => {
|
|
9
|
+
const result = layoutChordStrings([], 3);
|
|
10
|
+
const expected = "";
|
|
11
|
+
assert.equal(result, expected);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("handles single string", () => {
|
|
15
|
+
const strings = ["ABC\nDEF"];
|
|
16
|
+
const result = layoutChordStrings(strings, 1);
|
|
17
|
+
const expected = `ABC
|
|
18
|
+
DEF`;
|
|
19
|
+
assert.equal(result, expected);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("handles single string with multiple columns", () => {
|
|
23
|
+
const strings = ["ABC"];
|
|
24
|
+
const result = layoutChordStrings(strings, 3);
|
|
25
|
+
const expected = "ABC";
|
|
26
|
+
assert.equal(result, expected);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("layouts two strings of equal size in one row", () => {
|
|
30
|
+
const strings = ["ABC\nDEF", "123\n456"];
|
|
31
|
+
const result = layoutChordStrings(strings, 2);
|
|
32
|
+
const expected = `ABC 123
|
|
33
|
+
DEF 456`;
|
|
34
|
+
assert.equal(result, expected);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("layouts two strings of different widths", () => {
|
|
38
|
+
const strings = ["A\nB", "12345\n67890"];
|
|
39
|
+
const result = layoutChordStrings(strings, 2);
|
|
40
|
+
const expected = `A 12345
|
|
41
|
+
B 67890`;
|
|
42
|
+
assert.equal(result, expected);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("layouts two strings of different heights", () => {
|
|
46
|
+
const strings = ["A\nB\nC", "12\n34"];
|
|
47
|
+
const result = layoutChordStrings(strings, 2);
|
|
48
|
+
const expected = `A 12
|
|
49
|
+
B 34
|
|
50
|
+
C`;
|
|
51
|
+
assert.equal(result, expected);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("layouts strings into multiple rows", () => {
|
|
55
|
+
const strings = ["A", "B", "C", "D"];
|
|
56
|
+
const result = layoutChordStrings(strings, 2);
|
|
57
|
+
const expected = `A B
|
|
58
|
+
|
|
59
|
+
C D`;
|
|
60
|
+
assert.equal(result, expected);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("layouts strings into multiple rows with spacing 2", () => {
|
|
64
|
+
const strings = ["A", "B", "C", "D"];
|
|
65
|
+
const result = layoutChordStrings(strings, 2, 2);
|
|
66
|
+
const expected = `A B
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
C D`;
|
|
70
|
+
assert.equal(result, expected);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("layouts strings into multiple rows with spacing 3", () => {
|
|
74
|
+
const strings = ["A", "B", "C", "D"];
|
|
75
|
+
const result = layoutChordStrings(strings, 2, 3);
|
|
76
|
+
const expected = `A B
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
C D`;
|
|
81
|
+
assert.equal(result, expected);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("layouts strings into multiple rows with different sizes", () => {
|
|
85
|
+
const strings = ["ABC\nDEF", "12", "XY\nZ", "!"];
|
|
86
|
+
const result = layoutChordStrings(strings, 2);
|
|
87
|
+
const expected = `ABC 12
|
|
88
|
+
DEF
|
|
89
|
+
|
|
90
|
+
XY !
|
|
91
|
+
Z`;
|
|
92
|
+
assert.equal(result, expected);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("handles three columns", () => {
|
|
96
|
+
const strings = ["A", "B", "C", "D", "E", "F"];
|
|
97
|
+
const result = layoutChordStrings(strings, 3);
|
|
98
|
+
const expected = `A B C
|
|
99
|
+
|
|
100
|
+
D E F`;
|
|
101
|
+
assert.equal(result, expected);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("layouts with incomplete last row", () => {
|
|
105
|
+
const strings = ["A\nB", "C\nD", "E\nF", "G\nH", "I\nJ"];
|
|
106
|
+
const result = layoutChordStrings(strings, 3);
|
|
107
|
+
const expected = `A C E
|
|
108
|
+
B D F
|
|
109
|
+
|
|
110
|
+
G I
|
|
111
|
+
H J`;
|
|
112
|
+
assert.equal(result, expected);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("pads strings to match the tallest string in their row", () => {
|
|
116
|
+
const strings = ["A", "B\nC\nD", "E"];
|
|
117
|
+
const result = layoutChordStrings(strings, 3);
|
|
118
|
+
const expected = `A B E
|
|
119
|
+
C
|
|
120
|
+
D`;
|
|
121
|
+
assert.equal(result, expected);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("pads strings to match the widest string in their column", () => {
|
|
125
|
+
const strings = ["A", "LONGTEXT", "B", "X"];
|
|
126
|
+
const result = layoutChordStrings(strings, 2);
|
|
127
|
+
const expected = `A LONGTEXT
|
|
128
|
+
|
|
129
|
+
B X`;
|
|
130
|
+
assert.equal(result, expected);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("handles single character strings in grid", () => {
|
|
134
|
+
const strings = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
|
|
135
|
+
const result = layoutChordStrings(strings, 3);
|
|
136
|
+
const expected = `A B C
|
|
137
|
+
|
|
138
|
+
D E F
|
|
139
|
+
|
|
140
|
+
G H I`;
|
|
141
|
+
assert.equal(result, expected);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("handles multiline strings with varying line lengths", () => {
|
|
145
|
+
const strings = [
|
|
146
|
+
"A\nBB\nCCC",
|
|
147
|
+
"1\n22\n333\n4444",
|
|
148
|
+
"X"
|
|
149
|
+
];
|
|
150
|
+
const result = layoutChordStrings(strings, 2);
|
|
151
|
+
const expected = `A 1
|
|
152
|
+
BB 22
|
|
153
|
+
CCC 333
|
|
154
|
+
4444
|
|
155
|
+
|
|
156
|
+
X`;
|
|
157
|
+
assert.equal(result, expected);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("defaults to 3 columns when not specified", () => {
|
|
161
|
+
const strings = ["A", "B", "C", "D", "E", "F"];
|
|
162
|
+
const result = layoutChordStrings(strings);
|
|
163
|
+
const expected = `A B C
|
|
164
|
+
|
|
165
|
+
D E F`;
|
|
166
|
+
assert.equal(result, expected);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("handles single column layout", () => {
|
|
170
|
+
const strings = ["ABC", "DEF", "GHI"];
|
|
171
|
+
const result = layoutChordStrings(strings, 1);
|
|
172
|
+
const expected = `ABC
|
|
173
|
+
|
|
174
|
+
DEF
|
|
175
|
+
|
|
176
|
+
GHI`;
|
|
177
|
+
assert.equal(result, expected);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("handles strings with trailing newlines", () => {
|
|
181
|
+
const strings = ["A\n", "B\n"];
|
|
182
|
+
const result = layoutChordStrings(strings, 2);
|
|
183
|
+
const expected = `A B`;
|
|
184
|
+
assert.equal(result, expected);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("handles empty strings in the array", () => {
|
|
188
|
+
const strings = ["", "B", ""];
|
|
189
|
+
const result = layoutChordStrings(strings, 3);
|
|
190
|
+
const expected = `B`;
|
|
191
|
+
assert.equal(result, expected);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import splitStringInRectangles from "../lib/splitStringInRectangles.js";
|
|
6
|
+
|
|
7
|
+
describe("splitStringInRectangles", () => {
|
|
8
|
+
test("should return empty array for empty string", () => {
|
|
9
|
+
const result = splitStringInRectangles("");
|
|
10
|
+
assert.deepEqual(result, []);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("should return empty array for string with only spaces", () => {
|
|
14
|
+
const result = splitStringInRectangles(" \n \n ");
|
|
15
|
+
assert.deepEqual(result, []);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("should extract single rectangle", () => {
|
|
19
|
+
const input = "ABC\nDEF\nGHI";
|
|
20
|
+
const result = splitStringInRectangles(input);
|
|
21
|
+
assert.deepEqual(result, ["ABC\nDEF\nGHI"]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("should extract two rectangles separated horizontally", () => {
|
|
25
|
+
const input = "ABC XYZ\nDEF UVW";
|
|
26
|
+
const result = splitStringInRectangles(input);
|
|
27
|
+
assert.equal(result.length, 2);
|
|
28
|
+
assert.ok(result.includes("ABC\nDEF"));
|
|
29
|
+
assert.ok(result.includes("XYZ\nUVW"));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("should extract two rectangles separated vertically", () => {
|
|
33
|
+
const input = "ABC\nDEF\n\nXYZ\nUVW";
|
|
34
|
+
const result = splitStringInRectangles(input);
|
|
35
|
+
assert.equal(result.length, 2);
|
|
36
|
+
assert.ok(result.includes("ABC\nDEF"));
|
|
37
|
+
assert.ok(result.includes("XYZ\nUVW"));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("should treat diagonally adjacent characters as one rectangle", () => {
|
|
41
|
+
const input = "A \n B \n C";
|
|
42
|
+
const result = splitStringInRectangles(input);
|
|
43
|
+
assert.equal(result.length, 1);
|
|
44
|
+
assert.equal(result[0], "A \n B \n C");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("should extract multiple rectangles in complex layout", () => {
|
|
48
|
+
const input = "AA BB\nAA BB\n\n CC\n CC";
|
|
49
|
+
const result = splitStringInRectangles(input);
|
|
50
|
+
assert.equal(result.length, 3);
|
|
51
|
+
assert.ok(result.includes("AA\nAA"));
|
|
52
|
+
assert.ok(result.includes("BB\nBB"));
|
|
53
|
+
assert.ok(result.includes("CC\nCC"));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("should handle single character", () => {
|
|
57
|
+
const input = "X";
|
|
58
|
+
const result = splitStringInRectangles(input);
|
|
59
|
+
assert.deepEqual(result, ["X"]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("should handle single line with multiple rectangles", () => {
|
|
63
|
+
const input = "ABC DEF GHI";
|
|
64
|
+
const result = splitStringInRectangles(input);
|
|
65
|
+
assert.equal(result.length, 3);
|
|
66
|
+
assert.ok(result.includes("ABC"));
|
|
67
|
+
assert.ok(result.includes("DEF"));
|
|
68
|
+
assert.ok(result.includes("GHI"));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("should extract rectangles with varying heights", () => {
|
|
72
|
+
const input = "A\nA\nA\n\nBB\nBB";
|
|
73
|
+
const result = splitStringInRectangles(input);
|
|
74
|
+
assert.equal(result.length, 2);
|
|
75
|
+
assert.ok(result.includes("A\nA\nA"));
|
|
76
|
+
assert.ok(result.includes("BB\nBB"));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("should handle rectangle at different positions", () => {
|
|
80
|
+
const input = " X\n X\n X";
|
|
81
|
+
const result = splitStringInRectangles(input);
|
|
82
|
+
assert.equal(result.length, 1);
|
|
83
|
+
assert.equal(result[0], "X\nX\nX");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("should handle complex diagonal connections", () => {
|
|
87
|
+
const input = "A E\n B D \n C ";
|
|
88
|
+
const result = splitStringInRectangles(input);
|
|
89
|
+
assert.equal(result.length, 1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("should extract non-rectangular shapes as bounding rectangles", () => {
|
|
93
|
+
const input = "A \n A";
|
|
94
|
+
const result = splitStringInRectangles(input);
|
|
95
|
+
assert.equal(result.length, 1);
|
|
96
|
+
assert.equal(result[0], "A \n A");
|
|
97
|
+
});
|
|
98
|
+
})
|