@k-l-lambda/lilylet 0.1.71 → 0.1.73

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 (104) hide show
  1. package/lib/highlight.d.ts +1 -0
  2. package/lib/highlight.js +1 -0
  3. package/lib/lilylet/highlight.d.ts +29 -0
  4. package/lib/lilylet/highlight.js +145 -0
  5. package/package.json +8 -2
  6. package/source/lilylet/highlight.ts +192 -0
  7. package/lib/source/abc/abc.d.ts +0 -102
  8. package/lib/source/abc/abc.js +0 -25
  9. package/lib/source/abc/parser.d.ts +0 -3
  10. package/lib/source/abc/parser.js +0 -6
  11. package/lib/source/lilylet/abcDecoder.d.ts +0 -25
  12. package/lib/source/lilylet/abcDecoder.js +0 -1035
  13. package/lib/source/lilylet/index.d.ts +0 -10
  14. package/lib/source/lilylet/index.js +0 -10
  15. package/lib/source/lilylet/lilypondDecoder.d.ts +0 -29
  16. package/lib/source/lilylet/lilypondDecoder.js +0 -1223
  17. package/lib/source/lilylet/lilypondEncoder.d.ts +0 -34
  18. package/lib/source/lilylet/lilypondEncoder.js +0 -893
  19. package/lib/source/lilylet/meiEncoder.d.ts +0 -8
  20. package/lib/source/lilylet/meiEncoder.js +0 -1985
  21. package/lib/source/lilylet/musicXmlDecoder.d.ts +0 -20
  22. package/lib/source/lilylet/musicXmlDecoder.js +0 -1195
  23. package/lib/source/lilylet/musicXmlEncoder.d.ts +0 -15
  24. package/lib/source/lilylet/musicXmlEncoder.js +0 -701
  25. package/lib/source/lilylet/musicXmlTypes.d.ts +0 -199
  26. package/lib/source/lilylet/musicXmlTypes.js +0 -7
  27. package/lib/source/lilylet/musicXmlUtils.d.ts +0 -92
  28. package/lib/source/lilylet/musicXmlUtils.js +0 -469
  29. package/lib/source/lilylet/parser.d.ts +0 -14
  30. package/lib/source/lilylet/parser.js +0 -161
  31. package/lib/source/lilylet/serializer.d.ts +0 -11
  32. package/lib/source/lilylet/serializer.js +0 -791
  33. package/lib/source/lilylet/types.d.ts +0 -253
  34. package/lib/source/lilylet/types.js +0 -100
  35. package/lib/tests/abc-abcjs-parse.d.ts +0 -8
  36. package/lib/tests/abc-abcjs-parse.js +0 -90
  37. package/lib/tests/abc-abcjs-svg.d.ts +0 -1
  38. package/lib/tests/abc-abcjs-svg.js +0 -143
  39. package/lib/tests/abc-decoder.d.ts +0 -1
  40. package/lib/tests/abc-decoder.js +0 -67
  41. package/lib/tests/abc-mei-compare.d.ts +0 -1
  42. package/lib/tests/abc-mei-compare.js +0 -525
  43. package/lib/tests/auto-beam.d.ts +0 -9
  44. package/lib/tests/auto-beam.js +0 -151
  45. package/lib/tests/computeMeiHashes.d.ts +0 -1
  46. package/lib/tests/computeMeiHashes.js +0 -87
  47. package/lib/tests/encoder-mutation.d.ts +0 -9
  48. package/lib/tests/encoder-mutation.js +0 -110
  49. package/lib/tests/gpt-review-issues.d.ts +0 -5
  50. package/lib/tests/gpt-review-issues.js +0 -255
  51. package/lib/tests/json-to-lyl.d.ts +0 -1
  52. package/lib/tests/json-to-lyl.js +0 -18
  53. package/lib/tests/lilypond-roundtrip.d.ts +0 -7
  54. package/lib/tests/lilypond-roundtrip.js +0 -558
  55. package/lib/tests/lilypondDecoder.d.ts +0 -6
  56. package/lib/tests/lilypondDecoder.js +0 -95
  57. package/lib/tests/ly-to-lyl.d.ts +0 -1
  58. package/lib/tests/ly-to-lyl.js +0 -12
  59. package/lib/tests/mei.d.ts +0 -1
  60. package/lib/tests/mei.js +0 -278
  61. package/lib/tests/musicxml-decoder.d.ts +0 -4
  62. package/lib/tests/musicxml-decoder.js +0 -61
  63. package/lib/tests/musicxml-detail.d.ts +0 -4
  64. package/lib/tests/musicxml-detail.js +0 -85
  65. package/lib/tests/musicxml-fprod.d.ts +0 -9
  66. package/lib/tests/musicxml-fprod.js +0 -153
  67. package/lib/tests/musicxml-roundtrip.d.ts +0 -7
  68. package/lib/tests/musicxml-roundtrip.js +0 -296
  69. package/lib/tests/musicxml-to-mei.d.ts +0 -6
  70. package/lib/tests/musicxml-to-mei.js +0 -115
  71. package/lib/tests/parser.d.ts +0 -1
  72. package/lib/tests/parser.js +0 -17
  73. package/lib/tests/render-k283.d.ts +0 -1
  74. package/lib/tests/render-k283.js +0 -33
  75. package/lib/tests/render-lyl.d.ts +0 -1
  76. package/lib/tests/render-lyl.js +0 -35
  77. package/lib/tests/unit/afterGraceInsideTuplet.test.d.ts +0 -23
  78. package/lib/tests/unit/afterGraceInsideTuplet.test.js +0 -186
  79. package/lib/tests/unit/changeStaffBeforeTuplet.test.d.ts +0 -21
  80. package/lib/tests/unit/changeStaffBeforeTuplet.test.js +0 -356
  81. package/lib/tests/unit/crossStaffDecoder.test.d.ts +0 -15
  82. package/lib/tests/unit/crossStaffDecoder.test.js +0 -147
  83. package/lib/tests/unit/crossStaffEdgeCases.test.d.ts +0 -1
  84. package/lib/tests/unit/crossStaffEdgeCases.test.js +0 -209
  85. package/lib/tests/unit/crossStaffMultiMeasure.test.d.ts +0 -15
  86. package/lib/tests/unit/crossStaffMultiMeasure.test.js +0 -231
  87. package/lib/tests/unit/fullMeasureRestDecoder.test.d.ts +0 -11
  88. package/lib/tests/unit/fullMeasureRestDecoder.test.js +0 -154
  89. package/lib/tests/unit/gptReviewIssues.test.d.ts +0 -8
  90. package/lib/tests/unit/gptReviewIssues.test.js +0 -240
  91. package/lib/tests/unit/parallelMusicDecoder.test.d.ts +0 -13
  92. package/lib/tests/unit/parallelMusicDecoder.test.js +0 -261
  93. package/lib/tests/unit/partialWarning.test.d.ts +0 -4
  94. package/lib/tests/unit/partialWarning.test.js +0 -65
  95. package/lib/tests/unit/serializerRoundTrip.test.d.ts +0 -8
  96. package/lib/tests/unit/serializerRoundTrip.test.js +0 -263
  97. package/lib/tests/unit/staffInsideTuplet.test.d.ts +0 -25
  98. package/lib/tests/unit/staffInsideTuplet.test.js +0 -133
  99. package/lib/tests/unit/timesFirstNoteEscape.test.d.ts +0 -16
  100. package/lib/tests/unit/timesFirstNoteEscape.test.js +0 -152
  101. package/lib/tests/unit/tupletWithBaseDuration.test.d.ts +0 -17
  102. package/lib/tests/unit/tupletWithBaseDuration.test.js +0 -139
  103. package/lib/tests/unit/voiceStaffParsing.test.d.ts +0 -13
  104. package/lib/tests/unit/voiceStaffParsing.test.js +0 -118
@@ -1,253 +0,0 @@
1
- export declare enum Phonet {
2
- c = "c",
3
- d = "d",
4
- e = "e",
5
- f = "f",
6
- g = "g",
7
- a = "a",
8
- b = "b"
9
- }
10
- export declare enum Accidental {
11
- natural = "natural",
12
- sharp = "sharp",
13
- flat = "flat",
14
- doubleSharp = "doubleSharp",
15
- doubleFlat = "doubleFlat"
16
- }
17
- export declare enum Clef {
18
- treble = "treble",
19
- bass = "bass",
20
- alto = "alto"
21
- }
22
- export declare enum StemDirection {
23
- up = "up",
24
- down = "down",
25
- auto = "auto"
26
- }
27
- export declare enum ArticulationType {
28
- staccato = "staccato",
29
- staccatissimo = "staccatissimo",
30
- tenuto = "tenuto",
31
- marcato = "marcato",
32
- accent = "accent",
33
- portato = "portato"
34
- }
35
- export declare enum OrnamentType {
36
- trill = "trill",
37
- turn = "turn",
38
- mordent = "mordent",
39
- prall = "prall",
40
- fermata = "fermata",
41
- shortFermata = "shortFermata",
42
- arpeggio = "arpeggio"
43
- }
44
- export declare enum DynamicType {
45
- ppp = "ppp",
46
- pp = "pp",
47
- p = "p",
48
- mp = "mp",
49
- mf = "mf",
50
- f = "f",
51
- ff = "ff",
52
- fff = "fff",
53
- sfz = "sfz",
54
- rfz = "rfz",
55
- fp = "fp"
56
- }
57
- export declare enum HairpinType {
58
- crescendoStart = "crescendoStart",
59
- crescendoEnd = "crescendoEnd",
60
- diminuendoStart = "diminuendoStart",
61
- diminuendoEnd = "diminuendoEnd"
62
- }
63
- export declare enum PedalType {
64
- sustainOn = "sustainOn",
65
- sustainOff = "sustainOff",
66
- sostenutoOn = "sostenutoOn",
67
- sostenutoOff = "sostenutoOff",
68
- unaCordaOn = "unaCordaOn",
69
- unaCordaOff = "unaCordaOff"
70
- }
71
- export declare enum BarlineType {
72
- single = "|",
73
- double = "||",
74
- end = "|.",
75
- repeatStart = ".|:",
76
- repeatEnd = ":|.",
77
- repeatBoth = ":..:"
78
- }
79
- export declare enum NavigationMarkType {
80
- coda = "coda",
81
- segno = "segno"
82
- }
83
- export interface Fraction {
84
- numerator: number;
85
- denominator: number;
86
- }
87
- export interface TimeSig extends Fraction {
88
- symbol?: 'common' | 'cut';
89
- }
90
- export interface Pitch {
91
- phonet: Phonet;
92
- accidental?: Accidental;
93
- octave: number;
94
- courtesy?: boolean;
95
- }
96
- export interface Duration {
97
- division: number;
98
- dots: number;
99
- tuplet?: Fraction;
100
- }
101
- export declare enum Placement {
102
- above = "above",
103
- below = "below"
104
- }
105
- export interface Articulation {
106
- markType: 'articulation';
107
- type: ArticulationType;
108
- placement?: Placement;
109
- }
110
- export interface Ornament {
111
- markType: 'ornament';
112
- type: OrnamentType;
113
- }
114
- export interface Dynamic {
115
- markType: 'dynamic';
116
- type: DynamicType;
117
- }
118
- export interface Hairpin {
119
- markType: 'hairpin';
120
- type: HairpinType;
121
- }
122
- export interface Tie {
123
- markType: 'tie';
124
- start: boolean;
125
- }
126
- export interface Slur {
127
- markType: 'slur';
128
- start: boolean;
129
- }
130
- export interface Beam {
131
- markType: 'beam';
132
- start: boolean;
133
- }
134
- export interface Pedal {
135
- markType: 'pedal';
136
- type: PedalType;
137
- }
138
- export interface Fingering {
139
- markType: 'fingering';
140
- finger: number;
141
- placement?: Placement;
142
- }
143
- export interface NavigationMark {
144
- markType: 'navigation';
145
- type: NavigationMarkType;
146
- }
147
- export interface MarkupMark {
148
- markType: 'markup';
149
- content: string;
150
- placement?: Placement;
151
- }
152
- export type Mark = Articulation | Ornament | Dynamic | Hairpin | Tie | Slur | Beam | Pedal | Fingering | NavigationMark | MarkupMark;
153
- export interface KeySignature {
154
- pitch: Phonet;
155
- accidental?: Accidental;
156
- mode: 'major' | 'minor';
157
- }
158
- export interface Tempo {
159
- text?: string;
160
- beat?: Duration;
161
- bpm?: number;
162
- }
163
- export interface NoteEvent {
164
- type: 'note';
165
- pitches: Pitch[];
166
- duration: Duration;
167
- marks?: Mark[];
168
- grace?: boolean;
169
- tremolo?: number;
170
- staff?: number;
171
- stemDirection?: StemDirection;
172
- }
173
- export interface RestEvent {
174
- type: 'rest';
175
- duration: Duration;
176
- invisible?: boolean;
177
- fullMeasure?: boolean;
178
- pitch?: Pitch;
179
- }
180
- export interface ContextChange {
181
- type: 'context';
182
- key?: KeySignature;
183
- time?: Fraction;
184
- partial?: Duration;
185
- clef?: Clef;
186
- ottava?: number;
187
- stemDirection?: StemDirection;
188
- tempo?: Tempo;
189
- staff?: number;
190
- }
191
- export interface TremoloEvent {
192
- type: 'tremolo';
193
- pitchA: Pitch[];
194
- pitchB: Pitch[];
195
- count: number;
196
- division: number;
197
- }
198
- export interface TupletEvent {
199
- type: 'tuplet';
200
- ratio: Fraction;
201
- events: (NoteEvent | RestEvent | ContextChange)[];
202
- }
203
- export interface TimesEvent {
204
- type: 'times';
205
- ratio: Fraction;
206
- events: (NoteEvent | RestEvent | ContextChange)[];
207
- }
208
- export interface PitchResetEvent {
209
- type: 'pitchReset';
210
- }
211
- export interface BarlineEvent {
212
- type: 'barline';
213
- style: string;
214
- }
215
- export interface HarmonyEvent {
216
- type: 'harmony';
217
- text: string;
218
- }
219
- export interface MarkupEvent {
220
- type: 'markup';
221
- content: string;
222
- placement?: Placement;
223
- }
224
- export type Event = NoteEvent | RestEvent | ContextChange | TremoloEvent | TupletEvent | TimesEvent | PitchResetEvent | BarlineEvent | HarmonyEvent | MarkupEvent;
225
- export interface Voice {
226
- staff: number;
227
- events: Event[];
228
- }
229
- export interface Metadata {
230
- title?: string;
231
- subtitle?: string;
232
- composer?: string;
233
- arranger?: string;
234
- lyricist?: string;
235
- opus?: string;
236
- instrument?: string;
237
- genre?: string;
238
- autoBeam?: 'auto' | 'on' | 'off';
239
- }
240
- export interface Part {
241
- name?: string;
242
- voices: Voice[];
243
- }
244
- export interface Measure {
245
- key?: KeySignature;
246
- timeSig?: TimeSig;
247
- parts: Part[];
248
- partial?: boolean;
249
- }
250
- export interface LilyletDoc {
251
- metadata?: Metadata;
252
- measures: Measure[];
253
- }
@@ -1,100 +0,0 @@
1
- // === Enums ===
2
- export var Phonet;
3
- (function (Phonet) {
4
- Phonet["c"] = "c";
5
- Phonet["d"] = "d";
6
- Phonet["e"] = "e";
7
- Phonet["f"] = "f";
8
- Phonet["g"] = "g";
9
- Phonet["a"] = "a";
10
- Phonet["b"] = "b";
11
- })(Phonet || (Phonet = {}));
12
- export var Accidental;
13
- (function (Accidental) {
14
- Accidental["natural"] = "natural";
15
- Accidental["sharp"] = "sharp";
16
- Accidental["flat"] = "flat";
17
- Accidental["doubleSharp"] = "doubleSharp";
18
- Accidental["doubleFlat"] = "doubleFlat";
19
- })(Accidental || (Accidental = {}));
20
- export var Clef;
21
- (function (Clef) {
22
- Clef["treble"] = "treble";
23
- Clef["bass"] = "bass";
24
- Clef["alto"] = "alto";
25
- })(Clef || (Clef = {}));
26
- export var StemDirection;
27
- (function (StemDirection) {
28
- StemDirection["up"] = "up";
29
- StemDirection["down"] = "down";
30
- StemDirection["auto"] = "auto";
31
- })(StemDirection || (StemDirection = {}));
32
- export var ArticulationType;
33
- (function (ArticulationType) {
34
- ArticulationType["staccato"] = "staccato";
35
- ArticulationType["staccatissimo"] = "staccatissimo";
36
- ArticulationType["tenuto"] = "tenuto";
37
- ArticulationType["marcato"] = "marcato";
38
- ArticulationType["accent"] = "accent";
39
- ArticulationType["portato"] = "portato";
40
- })(ArticulationType || (ArticulationType = {}));
41
- export var OrnamentType;
42
- (function (OrnamentType) {
43
- OrnamentType["trill"] = "trill";
44
- OrnamentType["turn"] = "turn";
45
- OrnamentType["mordent"] = "mordent";
46
- OrnamentType["prall"] = "prall";
47
- OrnamentType["fermata"] = "fermata";
48
- OrnamentType["shortFermata"] = "shortFermata";
49
- OrnamentType["arpeggio"] = "arpeggio";
50
- })(OrnamentType || (OrnamentType = {}));
51
- export var DynamicType;
52
- (function (DynamicType) {
53
- DynamicType["ppp"] = "ppp";
54
- DynamicType["pp"] = "pp";
55
- DynamicType["p"] = "p";
56
- DynamicType["mp"] = "mp";
57
- DynamicType["mf"] = "mf";
58
- DynamicType["f"] = "f";
59
- DynamicType["ff"] = "ff";
60
- DynamicType["fff"] = "fff";
61
- DynamicType["sfz"] = "sfz";
62
- DynamicType["rfz"] = "rfz";
63
- DynamicType["fp"] = "fp";
64
- })(DynamicType || (DynamicType = {}));
65
- export var HairpinType;
66
- (function (HairpinType) {
67
- HairpinType["crescendoStart"] = "crescendoStart";
68
- HairpinType["crescendoEnd"] = "crescendoEnd";
69
- HairpinType["diminuendoStart"] = "diminuendoStart";
70
- HairpinType["diminuendoEnd"] = "diminuendoEnd";
71
- })(HairpinType || (HairpinType = {}));
72
- export var PedalType;
73
- (function (PedalType) {
74
- PedalType["sustainOn"] = "sustainOn";
75
- PedalType["sustainOff"] = "sustainOff";
76
- PedalType["sostenutoOn"] = "sostenutoOn";
77
- PedalType["sostenutoOff"] = "sostenutoOff";
78
- PedalType["unaCordaOn"] = "unaCordaOn";
79
- PedalType["unaCordaOff"] = "unaCordaOff";
80
- })(PedalType || (PedalType = {}));
81
- export var BarlineType;
82
- (function (BarlineType) {
83
- BarlineType["single"] = "|";
84
- BarlineType["double"] = "||";
85
- BarlineType["end"] = "|.";
86
- BarlineType["repeatStart"] = ".|:";
87
- BarlineType["repeatEnd"] = ":|.";
88
- BarlineType["repeatBoth"] = ":..:";
89
- })(BarlineType || (BarlineType = {}));
90
- export var NavigationMarkType;
91
- (function (NavigationMarkType) {
92
- NavigationMarkType["coda"] = "coda";
93
- NavigationMarkType["segno"] = "segno";
94
- })(NavigationMarkType || (NavigationMarkType = {}));
95
- // === Placement Direction ===
96
- export var Placement;
97
- (function (Placement) {
98
- Placement["above"] = "above";
99
- Placement["below"] = "below";
100
- })(Placement || (Placement = {}));
@@ -1,8 +0,0 @@
1
- /**
2
- * Parse all tests/assets/abc/*.abc files with abcjs and report:
3
- * - warnings / parse errors from abcjs
4
- * - note / rest / bar counts
5
- * This acts as a ground-truth reference: files abcjs parses cleanly are
6
- * valid ABC; failures indicate either invalid ABC or abcjs limitations.
7
- */
8
- export {};
@@ -1,90 +0,0 @@
1
- /**
2
- * Parse all tests/assets/abc/*.abc files with abcjs and report:
3
- * - warnings / parse errors from abcjs
4
- * - note / rest / bar counts
5
- * This acts as a ground-truth reference: files abcjs parses cleanly are
6
- * valid ABC; failures indicate either invalid ABC or abcjs limitations.
7
- */
8
- import fs from "fs";
9
- import path from "path";
10
- import { fileURLToPath } from "url";
11
- import { createRequire } from "module";
12
- const require = createRequire(import.meta.url);
13
- const abcjs = require("abcjs");
14
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
- const ABC_DIR = path.join(__dirname, "assets/abc");
16
- function countElements(tune) {
17
- const stats = [];
18
- for (const line of tune.lines) {
19
- if (!line.staff)
20
- continue;
21
- for (const staff of line.staff) {
22
- for (let vi = 0; vi < staff.voices.length; vi++) {
23
- if (!stats[vi])
24
- stats[vi] = { notes: 0, rests: 0, bars: 0 };
25
- for (const el of staff.voices[vi]) {
26
- if (el.el_type === "note") {
27
- if (el.rest)
28
- stats[vi].rests++;
29
- else
30
- stats[vi].notes++;
31
- }
32
- else if (el.el_type === "bar") {
33
- stats[vi].bars++;
34
- }
35
- }
36
- }
37
- }
38
- }
39
- return stats;
40
- }
41
- const files = fs.readdirSync(ABC_DIR)
42
- .filter(f => f.endsWith(".abc"))
43
- .sort();
44
- console.log(`Parsing ${files.length} ABC files with abcjs\n`);
45
- console.log("=".repeat(60));
46
- let pass = 0;
47
- let warn = 0;
48
- const results = [];
49
- for (const file of files) {
50
- const content = fs.readFileSync(path.join(ABC_DIR, file), "utf-8");
51
- let tunes;
52
- try {
53
- tunes = abcjs.parseOnly(content);
54
- }
55
- catch (e) {
56
- console.log(`CRASH ${file}`);
57
- // known abcjs bug: cross-bar slur continuation in inline multi-voice format
58
- console.log(` ${e.message.split("\n")[0]}`);
59
- continue;
60
- }
61
- const tune = tunes[0];
62
- const voices = countElements(tune);
63
- const totalNotes = voices.reduce((s, v) => s + v.notes, 0);
64
- const totalRests = voices.reduce((s, v) => s + v.rests, 0);
65
- const totalBars = voices.reduce((s, v) => s + v.bars, 0);
66
- const warnings = tune.warnings;
67
- results.push({ file, warnings, voices, totalNotes, totalRests, totalBars });
68
- const tag = warnings ? "WARN" : "OK ";
69
- if (warnings)
70
- warn++;
71
- else
72
- pass++;
73
- console.log(`${tag} ${file}`);
74
- console.log(` notes=${totalNotes} rests=${totalRests} bars=${totalBars} voices=${voices.length}`);
75
- if (warnings) {
76
- for (const w of warnings) {
77
- console.log(` ⚠ ${w}`);
78
- }
79
- }
80
- }
81
- console.log("\n" + "=".repeat(60));
82
- console.log(`Results: ${pass} clean, ${warn} with warnings, out of ${files.length} files`);
83
- // Summary: files that abcjs WARNS on — these are the ones to fix in lilylet
84
- if (warn > 0) {
85
- console.log("\nFiles with abcjs warnings:");
86
- for (const r of results) {
87
- if (r.warnings)
88
- console.log(` ${r.file}`);
89
- }
90
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,143 +0,0 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
- import { fileURLToPath } from "url";
4
- import { DOMImplementation, XMLSerializer } from "@xmldom/xmldom";
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
- // Setup DOM mock for abcjs (browser DOM required)
7
- const domImpl = new DOMImplementation();
8
- const doc = domImpl.createDocument("http://www.w3.org/1999/xhtml", "html", null);
9
- const body = doc.createElement("body");
10
- (doc.documentElement || doc).appendChild(body);
11
- const NodeProto = Object.getPrototypeOf(doc.createElement("span"));
12
- function patchEl(el) {
13
- if (!el || el._patched)
14
- return el;
15
- el._patched = true;
16
- if (!el.style)
17
- el.style = {};
18
- el.addEventListener = () => { };
19
- el.removeEventListener = () => { };
20
- el.getBBox = () => ({ width: 8, height: 12, x: 0, y: 0 });
21
- const origAC = el.appendChild.bind(el);
22
- el.appendChild = (child) => { patchEl(child); return origAC(child); };
23
- const origIB = el.insertBefore.bind(el);
24
- el.insertBefore = (child, ref) => { patchEl(child); return origIB(child, ref); };
25
- return el;
26
- }
27
- const origCE = doc.createElement.bind(doc);
28
- const origCENS = doc.createElementNS.bind(doc);
29
- doc.createElement = (tag) => patchEl(origCE(tag));
30
- doc.createElementNS = (ns, tag) => patchEl(origCENS(ns, tag));
31
- if (!Object.getOwnPropertyDescriptor(NodeProto, "children")) {
32
- Object.defineProperty(NodeProto, "children", {
33
- get() {
34
- const a = [];
35
- let c = this.firstChild;
36
- while (c) {
37
- if (c.nodeType === 1)
38
- a.push(c);
39
- c = c.nextSibling;
40
- }
41
- return a;
42
- },
43
- configurable: true,
44
- });
45
- }
46
- if (!Object.getOwnPropertyDescriptor(NodeProto, "parentElement")) {
47
- Object.defineProperty(NodeProto, "parentElement", {
48
- get() { return (this.parentNode?.nodeType === 1) ? this.parentNode : null; },
49
- configurable: true,
50
- });
51
- }
52
- if (!Object.getOwnPropertyDescriptor(NodeProto, "textContent")) {
53
- Object.defineProperty(NodeProto, "textContent", {
54
- get() { return this.nodeValue || ""; },
55
- set(v) {
56
- while (this.firstChild)
57
- this.removeChild(this.firstChild);
58
- this.appendChild(doc.createTextNode(v));
59
- },
60
- configurable: true,
61
- });
62
- }
63
- doc.querySelector = (sel) => sel === "body" ? body : null;
64
- doc.querySelectorAll = () => [];
65
- global.document = doc;
66
- global.window = { addEventListener: () => { } };
67
- // Now import abcjs (after DOM is set up)
68
- const abcjsMod = await import("abcjs");
69
- const abcjs = abcjsMod.default ?? abcjsMod;
70
- const ABC_DIR = path.join(__dirname, "assets/abc");
71
- const OUT_DIR = path.join(__dirname, "output/from-abc-svg");
72
- const LOG_FILE = path.join(__dirname, "output/abc-abcjs-svg.log");
73
- fs.mkdirSync(OUT_DIR, { recursive: true });
74
- const abcFiles = fs.readdirSync(ABC_DIR).filter(f => f.endsWith(".abc")).sort();
75
- const serializer = new XMLSerializer();
76
- const logLines = [];
77
- let passCount = 0;
78
- let skipCount = 0;
79
- for (const fname of abcFiles) {
80
- const abcPath = path.join(ABC_DIR, fname);
81
- const abcContent = fs.readFileSync(abcPath, "utf-8");
82
- const baseName = fname.replace(/\.abc$/, "");
83
- const svgPath = path.join(OUT_DIR, baseName + ".svg");
84
- try {
85
- // Create a fresh div container for each file
86
- const div = doc.createElement("div");
87
- patchEl(div);
88
- abcjs.renderAbc(div, abcContent, {});
89
- // Collect all non-empty SVGs (abcjs may produce one per tune + empty placeholders)
90
- const svgs = [];
91
- collectSvgs(div, svgs);
92
- const nonEmpty = svgs.filter(s => s.childNodes?.length > 0);
93
- if (nonEmpty.length === 0) {
94
- throw new Error("No non-empty SVG element found in output");
95
- }
96
- const svgStr = nonEmpty.map(s => serializer.serializeToString(s)).join("\n");
97
- fs.writeFileSync(svgPath, svgStr, "utf-8");
98
- console.log(`PASS ${fname}`);
99
- passCount++;
100
- }
101
- catch (err) {
102
- const msg = err?.message || String(err);
103
- console.error(`SKIP ${fname} — ${msg}`);
104
- logLines.push(`${fname}: ${msg}`);
105
- skipCount++;
106
- }
107
- }
108
- fs.writeFileSync(LOG_FILE, logLines.join("\n") + (logLines.length ? "\n" : ""), "utf-8");
109
- console.log(`\nResults: ${passCount} pass, ${skipCount} skip out of ${abcFiles.length}`);
110
- if (logLines.length) {
111
- console.log(`Error log: ${LOG_FILE}`);
112
- }
113
- function findLastNonEmptySvg(el) {
114
- const svgs = [];
115
- collectSvgs(el, svgs);
116
- // Return the last SVG that has children
117
- for (let i = svgs.length - 1; i >= 0; i--) {
118
- if (svgs[i].childNodes?.length > 0)
119
- return svgs[i];
120
- }
121
- return svgs[svgs.length - 1] ?? null;
122
- }
123
- function collectSvgs(el, out) {
124
- if (el.tagName === "svg" || el.localName === "svg")
125
- out.push(el);
126
- let c = el.firstChild;
127
- while (c) {
128
- collectSvgs(c, out);
129
- c = c.nextSibling;
130
- }
131
- }
132
- function findFirstSvg(el) {
133
- if (el.tagName === "svg" || el.localName === "svg")
134
- return el;
135
- let c = el.firstChild;
136
- while (c) {
137
- const found = findFirstSvg(c);
138
- if (found)
139
- return found;
140
- c = c.nextSibling;
141
- }
142
- return null;
143
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,67 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { fileURLToPath } from "url";
4
- import { abcDecoder, parseCode } from "../source/lilylet/index.js";
5
- import { serializeLilyletDoc } from "../source/lilylet/serializer.js";
6
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
- const ABC_DIR = path.join(__dirname, "assets/abc");
8
- const OUTPUT_DIR = path.join(__dirname, "output/from-abc");
9
- const main = () => {
10
- const files = fs.readdirSync(ABC_DIR).filter(f => f.endsWith(".abc")).sort();
11
- console.log(`Found ${files.length} ABC files\n`);
12
- // Ensure output directory exists
13
- fs.mkdirSync(OUTPUT_DIR, { recursive: true });
14
- let pass = 0;
15
- let fail = 0;
16
- const errors = [];
17
- for (const file of files) {
18
- const filePath = path.join(ABC_DIR, file);
19
- const baseName = path.basename(file, ".abc");
20
- try {
21
- const content = fs.readFileSync(filePath, "utf-8");
22
- const doc = abcDecoder.decode(content);
23
- if (!doc.measures || doc.measures.length === 0) {
24
- throw new Error("No measures produced");
25
- }
26
- // Write JSON output
27
- const jsonPath = path.join(OUTPUT_DIR, `${baseName}.json`);
28
- fs.writeFileSync(jsonPath, JSON.stringify(doc, null, 2));
29
- // Write .lyl output
30
- const lylContent = serializeLilyletDoc(doc);
31
- const lylPath = path.join(OUTPUT_DIR, `${baseName}.lyl`);
32
- fs.writeFileSync(lylPath, lylContent);
33
- const measureCount = doc.measures.length;
34
- const noteCount = doc.measures.reduce((sum, m) => sum + m.parts.reduce((psum, p) => psum + p.voices.reduce((vsum, v) => vsum + v.events.filter(e => e.type === "note").length, 0), 0), 0);
35
- // Verify .lyl can be parsed back
36
- const reparsed = parseCode(lylContent);
37
- const reparsedMeasures = reparsed.measures.length;
38
- console.log(` ${file}`);
39
- console.log(` Measures: ${measureCount}, Notes: ${noteCount}, Reparsed: ${reparsedMeasures} measures`);
40
- console.log(` -> ${baseName}.json, ${baseName}.lyl`);
41
- pass++;
42
- }
43
- catch (err) {
44
- fail++;
45
- errors.push({ file, error: err.message || String(err) });
46
- console.log(`FAIL: ${file}`);
47
- console.log(` ${err.message?.substring(0, 200)}\n`);
48
- }
49
- }
50
- console.log(`\n${"=".repeat(60)}`);
51
- console.log(`Results: ${pass} pass, ${fail} fail out of ${files.length}`);
52
- console.log(`Output: ${OUTPUT_DIR}`);
53
- if (fail > 0) {
54
- const errorTypes = new Map();
55
- for (const e of errors) {
56
- const key = e.error.substring(0, 80);
57
- errorTypes.set(key, (errorTypes.get(key) || 0) + 1);
58
- }
59
- console.log(`\nError distribution:`);
60
- const sorted = Array.from(errorTypes.entries()).sort((a, b) => b[1] - a[1]);
61
- for (const [msg, count] of sorted.slice(0, 15)) {
62
- console.log(` ${count}x: ${msg}`);
63
- }
64
- }
65
- process.exit(fail > 0 ? 1 : 0);
66
- };
67
- main();
@@ -1 +0,0 @@
1
- export {};