@k-l-lambda/lilylet 0.1.63 → 0.1.64

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 (101) hide show
  1. package/lib/lilylet/meiEncoder.js +58 -40
  2. package/lib/source/abc/abc.d.ts +102 -0
  3. package/lib/source/abc/abc.js +25 -0
  4. package/lib/source/abc/parser.d.ts +3 -0
  5. package/lib/source/abc/parser.js +6 -0
  6. package/lib/source/lilylet/abcDecoder.d.ts +25 -0
  7. package/lib/source/lilylet/abcDecoder.js +1035 -0
  8. package/lib/source/lilylet/index.d.ts +10 -0
  9. package/lib/source/lilylet/index.js +10 -0
  10. package/lib/source/lilylet/lilypondDecoder.d.ts +29 -0
  11. package/lib/source/lilylet/lilypondDecoder.js +1223 -0
  12. package/lib/source/lilylet/lilypondEncoder.d.ts +34 -0
  13. package/lib/source/lilylet/lilypondEncoder.js +893 -0
  14. package/lib/source/lilylet/meiEncoder.d.ts +8 -0
  15. package/lib/source/lilylet/meiEncoder.js +1985 -0
  16. package/lib/source/lilylet/musicXmlDecoder.d.ts +20 -0
  17. package/lib/source/lilylet/musicXmlDecoder.js +1195 -0
  18. package/lib/source/lilylet/musicXmlEncoder.d.ts +15 -0
  19. package/lib/source/lilylet/musicXmlEncoder.js +701 -0
  20. package/lib/source/lilylet/musicXmlTypes.d.ts +199 -0
  21. package/lib/source/lilylet/musicXmlTypes.js +7 -0
  22. package/lib/source/lilylet/musicXmlUtils.d.ts +92 -0
  23. package/lib/source/lilylet/musicXmlUtils.js +469 -0
  24. package/lib/source/lilylet/parser.d.ts +14 -0
  25. package/lib/source/lilylet/parser.js +161 -0
  26. package/lib/source/lilylet/serializer.d.ts +11 -0
  27. package/lib/source/lilylet/serializer.js +791 -0
  28. package/lib/source/lilylet/types.d.ts +253 -0
  29. package/lib/source/lilylet/types.js +100 -0
  30. package/lib/tests/abc-abcjs-parse.d.ts +8 -0
  31. package/lib/tests/abc-abcjs-parse.js +90 -0
  32. package/lib/tests/abc-abcjs-svg.d.ts +1 -0
  33. package/lib/tests/abc-abcjs-svg.js +143 -0
  34. package/lib/tests/abc-decoder.d.ts +1 -0
  35. package/lib/tests/abc-decoder.js +67 -0
  36. package/lib/tests/abc-mei-compare.d.ts +1 -0
  37. package/lib/tests/abc-mei-compare.js +525 -0
  38. package/lib/tests/auto-beam.d.ts +9 -0
  39. package/lib/tests/auto-beam.js +151 -0
  40. package/lib/tests/computeMeiHashes.d.ts +1 -0
  41. package/lib/tests/computeMeiHashes.js +87 -0
  42. package/lib/tests/encoder-mutation.d.ts +9 -0
  43. package/lib/tests/encoder-mutation.js +110 -0
  44. package/lib/tests/gpt-review-issues.d.ts +5 -0
  45. package/lib/tests/gpt-review-issues.js +255 -0
  46. package/lib/tests/json-to-lyl.d.ts +1 -0
  47. package/lib/tests/json-to-lyl.js +18 -0
  48. package/lib/tests/lilypond-roundtrip.d.ts +7 -0
  49. package/lib/tests/lilypond-roundtrip.js +558 -0
  50. package/lib/tests/lilypondDecoder.d.ts +6 -0
  51. package/lib/tests/lilypondDecoder.js +95 -0
  52. package/lib/tests/ly-to-lyl.d.ts +1 -0
  53. package/lib/tests/ly-to-lyl.js +12 -0
  54. package/lib/tests/mei.d.ts +1 -0
  55. package/lib/tests/mei.js +278 -0
  56. package/lib/tests/musicxml-decoder.d.ts +4 -0
  57. package/lib/tests/musicxml-decoder.js +61 -0
  58. package/lib/tests/musicxml-detail.d.ts +4 -0
  59. package/lib/tests/musicxml-detail.js +85 -0
  60. package/lib/tests/musicxml-fprod.d.ts +9 -0
  61. package/lib/tests/musicxml-fprod.js +153 -0
  62. package/lib/tests/musicxml-roundtrip.d.ts +7 -0
  63. package/lib/tests/musicxml-roundtrip.js +296 -0
  64. package/lib/tests/musicxml-to-mei.d.ts +6 -0
  65. package/lib/tests/musicxml-to-mei.js +115 -0
  66. package/lib/tests/parser.d.ts +1 -0
  67. package/lib/tests/parser.js +17 -0
  68. package/lib/tests/render-k283.d.ts +1 -0
  69. package/lib/tests/render-k283.js +33 -0
  70. package/lib/tests/render-lyl.d.ts +1 -0
  71. package/lib/tests/render-lyl.js +35 -0
  72. package/lib/tests/unit/afterGraceInsideTuplet.test.d.ts +23 -0
  73. package/lib/tests/unit/afterGraceInsideTuplet.test.js +186 -0
  74. package/lib/tests/unit/changeStaffBeforeTuplet.test.d.ts +21 -0
  75. package/lib/tests/unit/changeStaffBeforeTuplet.test.js +356 -0
  76. package/lib/tests/unit/crossStaffDecoder.test.d.ts +15 -0
  77. package/lib/tests/unit/crossStaffDecoder.test.js +147 -0
  78. package/lib/tests/unit/crossStaffEdgeCases.test.d.ts +1 -0
  79. package/lib/tests/unit/crossStaffEdgeCases.test.js +209 -0
  80. package/lib/tests/unit/crossStaffMultiMeasure.test.d.ts +15 -0
  81. package/lib/tests/unit/crossStaffMultiMeasure.test.js +231 -0
  82. package/lib/tests/unit/fullMeasureRestDecoder.test.d.ts +11 -0
  83. package/lib/tests/unit/fullMeasureRestDecoder.test.js +154 -0
  84. package/lib/tests/unit/gptReviewIssues.test.d.ts +8 -0
  85. package/lib/tests/unit/gptReviewIssues.test.js +240 -0
  86. package/lib/tests/unit/parallelMusicDecoder.test.d.ts +13 -0
  87. package/lib/tests/unit/parallelMusicDecoder.test.js +261 -0
  88. package/lib/tests/unit/partialWarning.test.d.ts +4 -0
  89. package/lib/tests/unit/partialWarning.test.js +65 -0
  90. package/lib/tests/unit/serializerRoundTrip.test.d.ts +8 -0
  91. package/lib/tests/unit/serializerRoundTrip.test.js +263 -0
  92. package/lib/tests/unit/staffInsideTuplet.test.d.ts +25 -0
  93. package/lib/tests/unit/staffInsideTuplet.test.js +133 -0
  94. package/lib/tests/unit/timesFirstNoteEscape.test.d.ts +16 -0
  95. package/lib/tests/unit/timesFirstNoteEscape.test.js +152 -0
  96. package/lib/tests/unit/tupletWithBaseDuration.test.d.ts +17 -0
  97. package/lib/tests/unit/tupletWithBaseDuration.test.js +139 -0
  98. package/lib/tests/unit/voiceStaffParsing.test.d.ts +13 -0
  99. package/lib/tests/unit/voiceStaffParsing.test.js +118 -0
  100. package/package.json +1 -1
  101. package/source/lilylet/meiEncoder.ts +65 -40
@@ -741,7 +741,8 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
741
741
  const pedals = [];
742
742
  // Track octave spans - initialize from previous measure if continuing
743
743
  const octaves = [];
744
- let currentOctave = initialOctave ? { dis: initialOctave.dis, disPlace: initialOctave.disPlace, startId: initialOctave.startId } : null;
744
+ const octaveEndReplacements = {};
745
+ let currentOctave = initialOctave ? { dis: initialOctave.dis, disPlace: initialOctave.disPlace, startId: initialOctave.startId, continued: initialOctave.continued, emitted: initialOctave.emitted, endToken: initialOctave.endToken, endFallbackId: initialOctave.endFallbackId } : null;
745
746
  let pendingOttava = null; // Track ottava to apply to next note
746
747
  let currentOttavaShift = initialOctave?.shift || 0; // Track current ottava shift for pitch encoding
747
748
  let lastNoteId = null; // Track last note id for ending ottava spans
@@ -833,6 +834,9 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
833
834
  const result = noteEventToMEI(effectiveNoteEvent, currentIndent, voice.staff, tieEnd, currentStemDirection, keyFifths, currentOttavaShift, measureAccidentals);
834
835
  xml += result.xml;
835
836
  lastNoteId = result.elementId;
837
+ if (currentOctave?.endToken) {
838
+ octaveEndReplacements[currentOctave.endToken] = result.elementId;
839
+ }
836
840
  // Flush any pending markups onto this note
837
841
  flushPendingMarkups(result.elementId);
838
842
  // If there's a pending ottava, start the span on this note
@@ -841,9 +845,14 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
841
845
  const disPlace = pendingOttava > 0 ? 'above' : 'below';
842
846
  // Close existing span first if it has a different value
843
847
  if (currentOctave && (currentOctave.dis !== dis || currentOctave.disPlace !== disPlace)) {
844
- // Different value - close the old span
845
- // Use the lastNoteId from before this note (which we saved before processing)
846
- // Note: The span from previous measure will be closed by encodeMeasure
848
+ if (lastNoteId) {
849
+ octaves.push({
850
+ dis: currentOctave.dis,
851
+ disPlace: currentOctave.disPlace,
852
+ startId: currentOctave.startId,
853
+ endId: lastNoteId,
854
+ });
855
+ }
847
856
  currentOctave = null;
848
857
  }
849
858
  // Start new span if we don't already have one with the same value
@@ -852,6 +861,12 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
852
861
  }
853
862
  pendingOttava = null;
854
863
  }
864
+ else if (currentOctave?.continued) {
865
+ if (!currentOctave.endToken) {
866
+ currentOctave.startId = result.elementId;
867
+ }
868
+ currentOctave.continued = false;
869
+ }
855
870
  // Update pending tie pitches
856
871
  if (result.hasTieStart) {
857
872
  pendingTiePitches = result.pitches;
@@ -997,12 +1012,14 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
997
1012
  if (ctx.ottava === 0) {
998
1013
  // End current ottava span
999
1014
  if (currentOctave && lastNoteId) {
1000
- octaves.push({
1001
- dis: currentOctave.dis,
1002
- disPlace: currentOctave.disPlace,
1003
- startId: currentOctave.startId,
1004
- endId: lastNoteId,
1005
- });
1015
+ if (!currentOctave.emitted) {
1016
+ octaves.push({
1017
+ dis: currentOctave.dis,
1018
+ disPlace: currentOctave.disPlace,
1019
+ startId: currentOctave.startId,
1020
+ endId: lastNoteId,
1021
+ });
1022
+ }
1006
1023
  currentOctave = null;
1007
1024
  ottavaExplicitlyClosed = true; // Mark that we explicitly closed the span
1008
1025
  }
@@ -1015,7 +1032,7 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
1015
1032
  const dis = Math.abs(ctx.ottava) === 2 ? 15 : 8;
1016
1033
  const disPlace = ctx.ottava > 0 ? 'above' : 'below';
1017
1034
  if (currentOctave && currentOctave.dis === dis && currentOctave.disPlace === disPlace) {
1018
- // Continuation - restore the shift but don't change the span
1035
+ // Continuation - restore the shift and let the existing 8va line reach this measure's first note
1019
1036
  currentOttavaShift = ctx.ottava;
1020
1037
  }
1021
1038
  else {
@@ -1091,13 +1108,24 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
1091
1108
  if (beamElementOpen) {
1092
1109
  xml += `${baseIndent}</beam>\n`;
1093
1110
  }
1094
- // Don't close ottava span at measure end - it may continue in the next measure
1095
- // Build pending octave state to return
1111
+ // Emit one visible octave span for a continuing ottava; a repeated same-value command can extend it to the next measure.
1112
+ if (currentOctave && lastNoteId && !currentOctave.emitted) {
1113
+ const endToken = `__OTTAVA_END_${generateId('octaveEnd')}__`;
1114
+ octaves.push({
1115
+ dis: currentOctave.dis,
1116
+ disPlace: currentOctave.disPlace,
1117
+ startId: currentOctave.startId,
1118
+ endId: endToken,
1119
+ });
1120
+ currentOctave.emitted = true;
1121
+ currentOctave.endToken = endToken;
1122
+ currentOctave.endFallbackId = lastNoteId;
1123
+ }
1096
1124
  const pendingOctave = currentOctave
1097
- ? { dis: currentOctave.dis, disPlace: currentOctave.disPlace, startId: currentOctave.startId, shift: currentOttavaShift }
1125
+ ? { dis: currentOctave.dis, disPlace: currentOctave.disPlace, startId: currentOctave.startId, shift: currentOttavaShift, continued: true, emitted: currentOctave.emitted, endToken: currentOctave.endToken, endFallbackId: currentOctave.endFallbackId }
1098
1126
  : null;
1099
1127
  xml += `${indent}</layer>\n`;
1100
- return { xml, hairpins, pedals, octaves, slurs, arpeggios, fermatas, trills, mordents, turns, dynamics, fingerings, navigations, harmonies, barlines, markups, pendingTiePitches, pendingSlur: currentSlur?.startId || null, pendingHairpin: currentHairpin, pendingOctave, ottavaExplicitlyClosed, endingClef: currentClef, lastNoteId, currentOttavaShift };
1128
+ return { xml, hairpins, pedals, octaves, slurs, arpeggios, fermatas, trills, mordents, turns, dynamics, fingerings, navigations, harmonies, barlines, markups, pendingTiePitches, pendingSlur: currentSlur?.startId || null, pendingHairpin: currentHairpin, pendingOctave, ottavaExplicitlyClosed, endingClef: currentClef, lastNoteId, currentOttavaShift, octaveEndReplacements };
1101
1129
  };
1102
1130
  // Encode a staff
1103
1131
  const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hairpinState = {}, ottavaState = {}, keyFifths = 0, initialClef) => {
@@ -1124,6 +1152,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
1124
1152
  const pendingOctaves = {};
1125
1153
  const ottavaExplicitlyClosed = {};
1126
1154
  const lastNoteIds = {};
1155
+ const octaveEndReplacements = {};
1127
1156
  let endingClef = initialClef;
1128
1157
  if (voices.length === 0) {
1129
1158
  xml += `${indent} <layer xml:id="${generateId('layer')}" n="1" />\n`;
@@ -1153,6 +1182,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
1153
1182
  allHarmonies.push(...result.harmonies);
1154
1183
  allBarlines.push(...result.barlines);
1155
1184
  allMarkups.push(...result.markups);
1185
+ Object.assign(octaveEndReplacements, result.octaveEndReplacements);
1156
1186
  // Track pending ties for this layer
1157
1187
  if (result.pendingTiePitches.length > 0) {
1158
1188
  pendingTies[tieKey] = result.pendingTiePitches;
@@ -1205,6 +1235,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
1205
1235
  pendingOctaves,
1206
1236
  ottavaExplicitlyClosed,
1207
1237
  lastNoteIds,
1238
+ octaveEndReplacements,
1208
1239
  endingClef,
1209
1240
  };
1210
1241
  };
@@ -1280,7 +1311,7 @@ const BARLINE_TO_MEI = {
1280
1311
  };
1281
1312
  // Encode a measure
1282
1313
  // encodeMeasure accepts mutable tieState, slurState, hairpinState, ottavaState and clefState that persist across measures
1283
- const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurState, hairpinState, ottavaState, keyFifths = 0, partInfos = [], clefState = {}) => {
1314
+ const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurState, hairpinState, ottavaState, keyFifths = 0, partInfos = [], clefState = {}, octaveEndReplacements = {}) => {
1284
1315
  const measureId = generateId("measure");
1285
1316
  let staffContent = ''; // Build staff content first, then add measure tag with barline
1286
1317
  const allHairpins = [];
@@ -1353,39 +1384,22 @@ const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurSta
1353
1384
  allHarmonies.push(...result.harmonies);
1354
1385
  allBarlines.push(...result.barlines);
1355
1386
  allMarkups.push(...result.markups);
1387
+ Object.assign(octaveEndReplacements, result.octaveEndReplacements);
1356
1388
  // Update tie state with pending ties from this staff
1357
1389
  Object.assign(tieState, result.pendingTies);
1358
1390
  // Update slur state with pending slurs from this staff
1359
1391
  Object.assign(slurState, result.pendingSlurs);
1360
1392
  // Update hairpin state with pending hairpins from this staff
1361
1393
  Object.assign(hairpinState, result.pendingHairpins);
1362
- // Update ottava state with pending octaves from this staff
1363
- // Also handle closing spans when ottava ends
1394
+ // Update ottava state with pending octaves from this staff.
1395
+ // encodeLayer already emits measure-local octave spans, so keep the next measure's start independent.
1364
1396
  const currentStaffPrefix = `${si}-`;
1365
1397
  for (const [key, pending] of Object.entries(result.pendingOctaves)) {
1366
1398
  if (pending) {
1367
- // Check if this is a continuation or a new span
1368
- const prevPending = ottavaState[key];
1369
- if (prevPending && prevPending.shift === pending.shift) {
1370
- // Same ottava value continues - keep the original startId
1371
- ottavaState[key] = { ...pending, startId: prevPending.startId };
1372
- }
1373
- else {
1374
- // Different ottava value - close the old span first if exists
1375
- if (prevPending) {
1376
- const lastNoteId = result.lastNoteIds[key];
1377
- if (lastNoteId) {
1378
- allOctaves.push({
1379
- dis: prevPending.dis,
1380
- disPlace: prevPending.disPlace,
1381
- startId: prevPending.startId,
1382
- endId: lastNoteId,
1383
- });
1384
- }
1385
- }
1386
- // Start new span
1387
- ottavaState[key] = pending;
1399
+ if (pending.endToken && pending.endFallbackId && !octaveEndReplacements[pending.endToken]) {
1400
+ octaveEndReplacements[pending.endToken] = pending.endFallbackId;
1388
1401
  }
1402
+ ottavaState[key] = pending;
1389
1403
  }
1390
1404
  }
1391
1405
  // For layers in this staff that had pending octaves but didn't in this measure, close the spans
@@ -1912,6 +1926,7 @@ const encode = (doc, options = {}) => {
1912
1926
  const hairpinState = {};
1913
1927
  // Track ottava state across measures for cross-measure ottava spans
1914
1928
  const ottavaState = {};
1929
+ const octaveEndReplacements = {};
1915
1930
  // Initialize clef state from partInfos (convert local staff to global staff)
1916
1931
  const clefState = {};
1917
1932
  for (let pi = 0; pi < partInfos.length; pi++) {
@@ -1967,7 +1982,7 @@ const encode = (doc, options = {}) => {
1967
1982
  mei += `${indent}${indent}${indent}${indent}${indent}${indent}<scoreDef xml:id="${generateId('scoredef')}"${meterSymAttr} meter.count="${currentTimeNum}" meter.unit="${currentTimeDen}" />\n`;
1968
1983
  }
1969
1984
  }
1970
- mei += encodeMeasure(measure, mi + 1, `${indent}${indent}${indent}${indent}${indent}${indent}`, totalStaves, tieState, slurState, hairpinState, ottavaState, currentKey, partInfos, clefState);
1985
+ mei += encodeMeasure(measure, mi + 1, `${indent}${indent}${indent}${indent}${indent}${indent}`, totalStaves, tieState, slurState, hairpinState, ottavaState, currentKey, partInfos, clefState, octaveEndReplacements);
1971
1986
  });
1972
1987
  mei += `${indent}${indent}${indent}${indent}${indent}</section>\n`;
1973
1988
  mei += `${indent}${indent}${indent}${indent}</score>\n`;
@@ -1975,6 +1990,9 @@ const encode = (doc, options = {}) => {
1975
1990
  mei += `${indent}${indent}</body>\n`;
1976
1991
  mei += `${indent}</music>\n`;
1977
1992
  mei += '</mei>\n';
1993
+ for (const [token, endId] of Object.entries(octaveEndReplacements)) {
1994
+ mei = mei.replaceAll(token, endId);
1995
+ }
1978
1996
  return mei;
1979
1997
  };
1980
1998
  // Escape XML special characters
@@ -0,0 +1,102 @@
1
+ interface Fraction {
2
+ numerator: number;
3
+ denominator: number;
4
+ }
5
+ declare namespace ABC {
6
+ type Token = string;
7
+ interface KeyValue {
8
+ name: string;
9
+ value: any;
10
+ }
11
+ export interface ControlTerm {
12
+ control: KeyValue;
13
+ }
14
+ export interface Triplet {
15
+ triplet: number;
16
+ multiplier?: number;
17
+ n?: number;
18
+ }
19
+ export interface OctaveShift {
20
+ octaveShift: number;
21
+ }
22
+ export interface Fingering {
23
+ fingering: string;
24
+ }
25
+ export interface Tremolo {
26
+ tremolo: number;
27
+ }
28
+ interface Grace {
29
+ grace: boolean;
30
+ acciaccatura: Token;
31
+ events: GraceMusicTerm[];
32
+ }
33
+ interface Comment {
34
+ comment: string;
35
+ }
36
+ export interface Articulation {
37
+ articulation: Token;
38
+ scope?: '(' | ')';
39
+ }
40
+ export type Expressive = Articulation | {
41
+ express: Token;
42
+ };
43
+ export interface TextTerm {
44
+ text: string;
45
+ }
46
+ export interface Pitch {
47
+ acc: number | null;
48
+ phonet: Token;
49
+ quotes: number;
50
+ tie?: boolean;
51
+ }
52
+ export interface Chord {
53
+ pitches: Pitch[];
54
+ tie?: any;
55
+ }
56
+ export interface EventData {
57
+ chord: Chord;
58
+ duration?: Fraction;
59
+ }
60
+ export interface EventTerm {
61
+ event: EventData;
62
+ broken?: number;
63
+ }
64
+ export type MusicTerm = Expressive | TextTerm | EventTerm | Grace | ControlTerm | Triplet | OctaveShift | Fingering | Tremolo;
65
+ export type GraceMusicTerm = Expressive | EventTerm | Fingering;
66
+ type Header = KeyValue | Comment;
67
+ export interface BarPatch {
68
+ control: {
69
+ [k: string]: any;
70
+ };
71
+ terms: MusicTerm[];
72
+ bar: Token;
73
+ }
74
+ export interface StaffGroup {
75
+ items: (StaffGroup | string)[];
76
+ bound?: 'arc' | 'square' | 'curly';
77
+ }
78
+ export interface StaffLayout {
79
+ staffLayout: StaffGroup[];
80
+ }
81
+ export interface KeySignature {
82
+ root: string;
83
+ mode?: string;
84
+ }
85
+ export interface ClefValue {
86
+ clef: string;
87
+ }
88
+ interface Measure {
89
+ index: number;
90
+ voices: BarPatch[];
91
+ }
92
+ interface Body {
93
+ measures: Measure[];
94
+ }
95
+ export interface Tune {
96
+ header: Header[];
97
+ body: Body;
98
+ }
99
+ export type Document = Tune[];
100
+ export {};
101
+ }
102
+ export { ABC, };
@@ -0,0 +1,25 @@
1
+ var ABC;
2
+ (function (ABC) {
3
+ ;
4
+ ;
5
+ ;
6
+ ;
7
+ ;
8
+ ;
9
+ ;
10
+ ;
11
+ ;
12
+ ;
13
+ ;
14
+ ;
15
+ ;
16
+ ;
17
+ ;
18
+ ;
19
+ ;
20
+ ;
21
+ ;
22
+ ;
23
+ ;
24
+ })(ABC || (ABC = {}));
25
+ export { ABC, };
@@ -0,0 +1,3 @@
1
+ import { ABC } from "./abc";
2
+ export declare const parse: (code: string) => ABC.Document;
3
+ export default parse;
@@ -0,0 +1,6 @@
1
+ // @ts-ignore - jison generated file
2
+ import grammar from "./grammar.jison.js";
3
+ export const parse = (code) => {
4
+ return grammar.parse(code);
5
+ };
6
+ export default parse;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ABC Notation Decoder for Lilylet
3
+ *
4
+ * Converts ABC notation files to Lilylet's internal LilyletDoc format.
5
+ */
6
+ import { LilyletDoc } from "./types";
7
+ /**
8
+ * Decode ABC notation string to LilyletDoc.
9
+ * If the ABC contains multiple tunes, only the first is decoded.
10
+ */
11
+ export declare const decode: (abcString: string) => LilyletDoc;
12
+ /**
13
+ * Decode ABC notation string to multiple LilyletDocs (one per tune).
14
+ */
15
+ export declare const decodeAll: (abcString: string) => LilyletDoc[];
16
+ /**
17
+ * Decode an ABC file to LilyletDoc
18
+ */
19
+ export declare const decodeFile: (filePath: string) => Promise<LilyletDoc>;
20
+ declare const _default: {
21
+ decode: (abcString: string) => LilyletDoc;
22
+ decodeAll: (abcString: string) => LilyletDoc[];
23
+ decodeFile: (filePath: string) => Promise<LilyletDoc>;
24
+ };
25
+ export default _default;