@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
@@ -0,0 +1 @@
1
+ export * from "./lilylet/highlight.js";
@@ -0,0 +1 @@
1
+ export * from "./lilylet/highlight.js";
@@ -0,0 +1,29 @@
1
+ /** Generic highlight scopes Lilylet tokens can carry. */
2
+ export type HighlightScope = "articulation" | "bar" | "brace" | "chordBracket" | "comment" | "dynamic" | "grace" | "hairpin" | "header" | "keyword" | "markup" | "mode" | "navigation" | "number" | "octave" | "operator" | "ornament" | "paren" | "pedal" | "pitch" | "punctuation" | "rest" | "separator" | "squareBracket" | "stem" | "string" | "tie" | "tuplet";
3
+ export interface HighlightRule {
4
+ /** Sticky, case-insensitive regex anchored at the scan position. */
5
+ re: RegExp;
6
+ scope: HighlightScope;
7
+ }
8
+ export interface HighlightToken {
9
+ scope: HighlightScope;
10
+ /** Start offset within the line (inclusive). */
11
+ start: number;
12
+ /** End offset within the line (exclusive). */
13
+ end: number;
14
+ }
15
+ /**
16
+ * Ordered highlight rules. Order mirrors the grammar's lexer; the tokenizer
17
+ * applies LONGEST-match (flex semantics), using order only as a tie-breaker.
18
+ */
19
+ export declare const HIGHLIGHT_RULES: HighlightRule[];
20
+ /**
21
+ * Match a single token at `pos` in `line` using longest-match. Returns the
22
+ * winning token, or null if no rule matches (caller should advance one char).
23
+ */
24
+ export declare const matchAt: (line: string, pos: number) => HighlightToken | null;
25
+ /**
26
+ * Tokenize one line into a list of scoped spans. Characters that match no rule
27
+ * are skipped (no token emitted), mirroring the lexer's catch-all.
28
+ */
29
+ export declare const tokenizeLine: (line: string) => HighlightToken[];
@@ -0,0 +1,145 @@
1
+ // AUTO-GENERATED by tools/buildHighlight.ts from source/lilylet/grammar.jison.js.
2
+ // Do NOT edit by hand. Run `npm run build:highlight` to regenerate.
3
+ //
4
+ // Framework-agnostic syntax-highlighting definition for Lilylet, derived from
5
+ // the grammar's lexer so it never drifts from the language. No editor
6
+ // dependency: it exposes generic SCOPE names and a longest-match tokenizer.
7
+ // Downstream editors (CodeMirror, Monaco, Prism, ...) map SCOPE -> their theme.
8
+ /**
9
+ * Ordered highlight rules. Order mirrors the grammar's lexer; the tokenizer
10
+ * applies LONGEST-match (flex semantics), using order only as a tie-breaker.
11
+ */
12
+ export const HIGHLIGHT_RULES = [
13
+ { re: /(?:%.*)/iy, scope: "comment" },
14
+ { re: /(?:\[title\b)/iy, scope: "header" },
15
+ { re: /(?:\[subtitle\b)/iy, scope: "header" },
16
+ { re: /(?:\[composer\b)/iy, scope: "header" },
17
+ { re: /(?:\[arranger\b)/iy, scope: "header" },
18
+ { re: /(?:\[lyricist\b)/iy, scope: "header" },
19
+ { re: /(?:\[opus\b)/iy, scope: "header" },
20
+ { re: /(?:\[instrument-[A-Za-z0-9_]+(?:-[A-Za-z0-9_]+)*)/iy, scope: "header" },
21
+ { re: /(?:\[instrument\b)/iy, scope: "header" },
22
+ { re: /(?:\[genre\b)/iy, scope: "header" },
23
+ { re: /(?:\[staves\b)/iy, scope: "header" },
24
+ { re: /(?:\[auto-beam\b)/iy, scope: "header" },
25
+ { re: /(?:\])/iy, scope: "squareBracket" },
26
+ { re: /(?:"[^"]*")/iy, scope: "string" },
27
+ { re: /(?:\\clef\b)/iy, scope: "keyword" },
28
+ { re: /(?:\\key\b)/iy, scope: "keyword" },
29
+ { re: /(?:\\time\b)/iy, scope: "keyword" },
30
+ { re: /(?:\\partial\b)/iy, scope: "keyword" },
31
+ { re: /(?:\\numericTimeSignature\b)/iy, scope: "keyword" },
32
+ { re: /(?:\\defaultTimeSignature\b)/iy, scope: "keyword" },
33
+ { re: /(?:\\tempo\b)/iy, scope: "keyword" },
34
+ { re: /(?:\\staff\b)/iy, scope: "keyword" },
35
+ { re: /(?:\\grace\b)/iy, scope: "grace" },
36
+ { re: /(?:\\times\b)/iy, scope: "tuplet" },
37
+ { re: /(?:\\tuplet\b)/iy, scope: "tuplet" },
38
+ { re: /(?:\\repeat\b)/iy, scope: "keyword" },
39
+ { re: /(?:\\ottava\b)/iy, scope: "keyword" },
40
+ { re: /(?:\\stemUp\b)/iy, scope: "stem" },
41
+ { re: /(?:\\stemDown\b)/iy, scope: "stem" },
42
+ { re: /(?:\\stemNeutral\b)/iy, scope: "stem" },
43
+ { re: /(?:\\major\b)/iy, scope: "mode" },
44
+ { re: /(?:\\minor\b)/iy, scope: "mode" },
45
+ { re: /(?:\\sustainOn\b)/iy, scope: "pedal" },
46
+ { re: /(?:\\sustainOff\b)/iy, scope: "pedal" },
47
+ { re: /(?:\\bar\b)/iy, scope: "keyword" },
48
+ { re: /(?:\\coda\b)/iy, scope: "navigation" },
49
+ { re: /(?:\\segno\b)/iy, scope: "navigation" },
50
+ { re: /(?:\\chords\b)/iy, scope: "keyword" },
51
+ { re: /(?:\\markup\b)/iy, scope: "markup" },
52
+ { re: /(?:\\<)/iy, scope: "hairpin" },
53
+ { re: /(?:\\>)/iy, scope: "hairpin" },
54
+ { re: /(?:\\!)/iy, scope: "hairpin" },
55
+ { re: /(?:\\staccato\b)/iy, scope: "articulation" },
56
+ { re: /(?:\\staccatissimo\b)/iy, scope: "articulation" },
57
+ { re: /(?:\\tenuto\b)/iy, scope: "articulation" },
58
+ { re: /(?:\\marcato\b)/iy, scope: "articulation" },
59
+ { re: /(?:\\accent\b)/iy, scope: "articulation" },
60
+ { re: /(?:\\portato\b)/iy, scope: "articulation" },
61
+ { re: /(?:\\trill\b)/iy, scope: "ornament" },
62
+ { re: /(?:\\turn\b)/iy, scope: "ornament" },
63
+ { re: /(?:\\mordent\b)/iy, scope: "ornament" },
64
+ { re: /(?:\\prall\b)/iy, scope: "ornament" },
65
+ { re: /(?:\\fermata\b)/iy, scope: "ornament" },
66
+ { re: /(?:\\shortfermata\b)/iy, scope: "ornament" },
67
+ { re: /(?:\\arpeggio\b)/iy, scope: "ornament" },
68
+ { re: /(?:\\ppp\b)/iy, scope: "dynamic" },
69
+ { re: /(?:\\pp\b)/iy, scope: "dynamic" },
70
+ { re: /(?:\\mp\b)/iy, scope: "dynamic" },
71
+ { re: /(?:\\mf\b)/iy, scope: "dynamic" },
72
+ { re: /(?:\\fff\b)/iy, scope: "dynamic" },
73
+ { re: /(?:\\ff\b)/iy, scope: "dynamic" },
74
+ { re: /(?:\\sfz\b)/iy, scope: "dynamic" },
75
+ { re: /(?:\\rfz\b)/iy, scope: "dynamic" },
76
+ { re: /(?:\\sf\b)/iy, scope: "dynamic" },
77
+ { re: /(?:\\fp\b)/iy, scope: "dynamic" },
78
+ { re: /(?:\\p\b)/iy, scope: "dynamic" },
79
+ { re: /(?:\\f)/iy, scope: "dynamic" },
80
+ { re: /(?:\\rest\b)/iy, scope: "rest" },
81
+ { re: /(?:\\\\\\)/iy, scope: "separator" },
82
+ { re: /(?:\\\\)/iy, scope: "separator" },
83
+ { re: /(?:tremolo\b)/iy, scope: "keyword" },
84
+ { re: /(?:[a-g](ss|ff|s|f)?)/iy, scope: "pitch" },
85
+ { re: /(?:')/iy, scope: "octave" },
86
+ { re: /(?:,)/iy, scope: "octave" },
87
+ { re: /(?:[0-9]+)/iy, scope: "number" },
88
+ { re: /(?:\/)/iy, scope: "operator" },
89
+ { re: /(?:#)/iy, scope: "punctuation" },
90
+ { re: /(?:\{)/iy, scope: "brace" },
91
+ { re: /(?:\})/iy, scope: "brace" },
92
+ { re: /(?:<)/iy, scope: "chordBracket" },
93
+ { re: /(?:>)/iy, scope: "chordBracket" },
94
+ { re: /(?:\|)/iy, scope: "bar" },
95
+ { re: /(?:\[)/iy, scope: "squareBracket" },
96
+ { re: /(?:\])/iy, scope: "squareBracket" },
97
+ { re: /(?:\()/iy, scope: "paren" },
98
+ { re: /(?:\))/iy, scope: "paren" },
99
+ { re: /(?:~)/iy, scope: "tie" },
100
+ { re: /(?:\.)/iy, scope: "punctuation" },
101
+ { re: /(?:-)/iy, scope: "punctuation" },
102
+ { re: /(?:[_])/iy, scope: "punctuation" },
103
+ { re: /(?:\^)/iy, scope: "punctuation" },
104
+ { re: /(?:!)/iy, scope: "punctuation" },
105
+ { re: /(?::)/iy, scope: "operator" },
106
+ { re: /(?:=)/iy, scope: "operator" },
107
+ { re: /(?:[rR])/iy, scope: "rest" },
108
+ { re: /(?:[sS])/iy, scope: "rest" },
109
+ ];
110
+ /**
111
+ * Match a single token at `pos` in `line` using longest-match. Returns the
112
+ * winning token, or null if no rule matches (caller should advance one char).
113
+ */
114
+ export const matchAt = (line, pos) => {
115
+ let best = null;
116
+ for (const rule of HIGHLIGHT_RULES) {
117
+ rule.re.lastIndex = pos;
118
+ const m = rule.re.exec(line);
119
+ if (m && m.index === pos && m[0].length > 0) {
120
+ const end = pos + m[0].length;
121
+ if (!best || end > best.end)
122
+ best = { scope: rule.scope, start: pos, end };
123
+ }
124
+ }
125
+ return best;
126
+ };
127
+ /**
128
+ * Tokenize one line into a list of scoped spans. Characters that match no rule
129
+ * are skipped (no token emitted), mirroring the lexer's catch-all.
130
+ */
131
+ export const tokenizeLine = (line) => {
132
+ const tokens = [];
133
+ let pos = 0;
134
+ while (pos < line.length) {
135
+ const tok = matchAt(line, pos);
136
+ if (tok) {
137
+ tokens.push(tok);
138
+ pos = tok.end;
139
+ }
140
+ else {
141
+ pos++;
142
+ }
143
+ }
144
+ return tokens;
145
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-l-lambda/lilylet",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "description": "Lilylet is a lilyopnd-like sheet music language designed for Markdown rendering and symbolic music representation in AIGC applications.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -14,6 +14,10 @@
14
14
  "types": "./lib/browser.d.ts",
15
15
  "default": "./lib/browser.js"
16
16
  },
17
+ "./highlight": {
18
+ "types": "./lib/lilylet/highlight.d.ts",
19
+ "default": "./lib/lilylet/highlight.js"
20
+ },
17
21
  "./lib/lilypondDecoder.js": {
18
22
  "types": "./lib/lilypondDecoder.d.ts",
19
23
  "default": "./lib/lilypondDecoder.js"
@@ -25,7 +29,8 @@
25
29
  ],
26
30
  "scripts": {
27
31
  "build": "tsc -p tsconfig.build.json && node tools/convertGrammarToESM.cjs && node tools/fixEsmExtensions.cjs",
28
- "build:grammar": "npx tsx ./tools/buildJisonParser.ts && node tools/convertGrammarToESM.cjs",
32
+ "build:grammar": "npx tsx ./tools/buildJisonParser.ts && node tools/convertGrammarToESM.cjs && npm run build:highlight",
33
+ "build:highlight": "npx tsx ./tools/buildHighlight.ts",
29
34
  "prepublishOnly": "npm run build:grammar && npm run build",
30
35
  "test": "tsx ./tests/parser.ts",
31
36
  "test:mei": "tsx ./tests/mei.ts",
@@ -37,6 +42,7 @@
37
42
  "test:abc-svg": "tsx ./tests/abc-abcjs-svg.ts",
38
43
  "train:bpe": "tsx ./tools/trainBpeTokenizer.ts",
39
44
  "build:manual-tokenizer": "tsx ./tools/buildManualTokenizer.ts",
45
+ "build:browser-bundle": "esbuild tools/browserBundle.ts --bundle --format=iife --platform=browser --minify --outfile=dist/lilylet.bundle.js",
40
46
  "test:bpe": "tsx ./tests/unit/bpeTokenizer.test.ts",
41
47
  "build:tests": "tsc -p tsconfig.tests.json; cp source/lilylet/grammar.jison.js lib-tests/source/lilylet/ && cp source/abc/grammar.jison.js lib-tests/source/abc/ && node tools/fixEsmExtensions.cjs lib-tests && ln -sfn ../../tests/assets lib-tests/tests/assets",
42
48
  "test:roundtrip:compiled": "node lib-tests/tests/lilypond-roundtrip.js",
@@ -0,0 +1,192 @@
1
+ // AUTO-GENERATED by tools/buildHighlight.ts from source/lilylet/grammar.jison.js.
2
+ // Do NOT edit by hand. Run `npm run build:highlight` to regenerate.
3
+ //
4
+ // Framework-agnostic syntax-highlighting definition for Lilylet, derived from
5
+ // the grammar's lexer so it never drifts from the language. No editor
6
+ // dependency: it exposes generic SCOPE names and a longest-match tokenizer.
7
+ // Downstream editors (CodeMirror, Monaco, Prism, ...) map SCOPE -> their theme.
8
+
9
+ /** Generic highlight scopes Lilylet tokens can carry. */
10
+ export type HighlightScope =
11
+ | "articulation"
12
+ | "bar"
13
+ | "brace"
14
+ | "chordBracket"
15
+ | "comment"
16
+ | "dynamic"
17
+ | "grace"
18
+ | "hairpin"
19
+ | "header"
20
+ | "keyword"
21
+ | "markup"
22
+ | "mode"
23
+ | "navigation"
24
+ | "number"
25
+ | "octave"
26
+ | "operator"
27
+ | "ornament"
28
+ | "paren"
29
+ | "pedal"
30
+ | "pitch"
31
+ | "punctuation"
32
+ | "rest"
33
+ | "separator"
34
+ | "squareBracket"
35
+ | "stem"
36
+ | "string"
37
+ | "tie"
38
+ | "tuplet";
39
+
40
+ export interface HighlightRule {
41
+ /** Sticky, case-insensitive regex anchored at the scan position. */
42
+ re: RegExp;
43
+ scope: HighlightScope;
44
+ }
45
+
46
+ export interface HighlightToken {
47
+ scope: HighlightScope;
48
+ /** Start offset within the line (inclusive). */
49
+ start: number;
50
+ /** End offset within the line (exclusive). */
51
+ end: number;
52
+ }
53
+
54
+ /**
55
+ * Ordered highlight rules. Order mirrors the grammar's lexer; the tokenizer
56
+ * applies LONGEST-match (flex semantics), using order only as a tie-breaker.
57
+ */
58
+ export const HIGHLIGHT_RULES: HighlightRule[] = [
59
+ { re: /(?:%.*)/iy, scope: "comment" },
60
+ { re: /(?:\[title\b)/iy, scope: "header" },
61
+ { re: /(?:\[subtitle\b)/iy, scope: "header" },
62
+ { re: /(?:\[composer\b)/iy, scope: "header" },
63
+ { re: /(?:\[arranger\b)/iy, scope: "header" },
64
+ { re: /(?:\[lyricist\b)/iy, scope: "header" },
65
+ { re: /(?:\[opus\b)/iy, scope: "header" },
66
+ { re: /(?:\[instrument-[A-Za-z0-9_]+(?:-[A-Za-z0-9_]+)*)/iy, scope: "header" },
67
+ { re: /(?:\[instrument\b)/iy, scope: "header" },
68
+ { re: /(?:\[genre\b)/iy, scope: "header" },
69
+ { re: /(?:\[staves\b)/iy, scope: "header" },
70
+ { re: /(?:\[auto-beam\b)/iy, scope: "header" },
71
+ { re: /(?:\])/iy, scope: "squareBracket" },
72
+ { re: /(?:"[^"]*")/iy, scope: "string" },
73
+ { re: /(?:\\clef\b)/iy, scope: "keyword" },
74
+ { re: /(?:\\key\b)/iy, scope: "keyword" },
75
+ { re: /(?:\\time\b)/iy, scope: "keyword" },
76
+ { re: /(?:\\partial\b)/iy, scope: "keyword" },
77
+ { re: /(?:\\numericTimeSignature\b)/iy, scope: "keyword" },
78
+ { re: /(?:\\defaultTimeSignature\b)/iy, scope: "keyword" },
79
+ { re: /(?:\\tempo\b)/iy, scope: "keyword" },
80
+ { re: /(?:\\staff\b)/iy, scope: "keyword" },
81
+ { re: /(?:\\grace\b)/iy, scope: "grace" },
82
+ { re: /(?:\\times\b)/iy, scope: "tuplet" },
83
+ { re: /(?:\\tuplet\b)/iy, scope: "tuplet" },
84
+ { re: /(?:\\repeat\b)/iy, scope: "keyword" },
85
+ { re: /(?:\\ottava\b)/iy, scope: "keyword" },
86
+ { re: /(?:\\stemUp\b)/iy, scope: "stem" },
87
+ { re: /(?:\\stemDown\b)/iy, scope: "stem" },
88
+ { re: /(?:\\stemNeutral\b)/iy, scope: "stem" },
89
+ { re: /(?:\\major\b)/iy, scope: "mode" },
90
+ { re: /(?:\\minor\b)/iy, scope: "mode" },
91
+ { re: /(?:\\sustainOn\b)/iy, scope: "pedal" },
92
+ { re: /(?:\\sustainOff\b)/iy, scope: "pedal" },
93
+ { re: /(?:\\bar\b)/iy, scope: "keyword" },
94
+ { re: /(?:\\coda\b)/iy, scope: "navigation" },
95
+ { re: /(?:\\segno\b)/iy, scope: "navigation" },
96
+ { re: /(?:\\chords\b)/iy, scope: "keyword" },
97
+ { re: /(?:\\markup\b)/iy, scope: "markup" },
98
+ { re: /(?:\\<)/iy, scope: "hairpin" },
99
+ { re: /(?:\\>)/iy, scope: "hairpin" },
100
+ { re: /(?:\\!)/iy, scope: "hairpin" },
101
+ { re: /(?:\\staccato\b)/iy, scope: "articulation" },
102
+ { re: /(?:\\staccatissimo\b)/iy, scope: "articulation" },
103
+ { re: /(?:\\tenuto\b)/iy, scope: "articulation" },
104
+ { re: /(?:\\marcato\b)/iy, scope: "articulation" },
105
+ { re: /(?:\\accent\b)/iy, scope: "articulation" },
106
+ { re: /(?:\\portato\b)/iy, scope: "articulation" },
107
+ { re: /(?:\\trill\b)/iy, scope: "ornament" },
108
+ { re: /(?:\\turn\b)/iy, scope: "ornament" },
109
+ { re: /(?:\\mordent\b)/iy, scope: "ornament" },
110
+ { re: /(?:\\prall\b)/iy, scope: "ornament" },
111
+ { re: /(?:\\fermata\b)/iy, scope: "ornament" },
112
+ { re: /(?:\\shortfermata\b)/iy, scope: "ornament" },
113
+ { re: /(?:\\arpeggio\b)/iy, scope: "ornament" },
114
+ { re: /(?:\\ppp\b)/iy, scope: "dynamic" },
115
+ { re: /(?:\\pp\b)/iy, scope: "dynamic" },
116
+ { re: /(?:\\mp\b)/iy, scope: "dynamic" },
117
+ { re: /(?:\\mf\b)/iy, scope: "dynamic" },
118
+ { re: /(?:\\fff\b)/iy, scope: "dynamic" },
119
+ { re: /(?:\\ff\b)/iy, scope: "dynamic" },
120
+ { re: /(?:\\sfz\b)/iy, scope: "dynamic" },
121
+ { re: /(?:\\rfz\b)/iy, scope: "dynamic" },
122
+ { re: /(?:\\sf\b)/iy, scope: "dynamic" },
123
+ { re: /(?:\\fp\b)/iy, scope: "dynamic" },
124
+ { re: /(?:\\p\b)/iy, scope: "dynamic" },
125
+ { re: /(?:\\f)/iy, scope: "dynamic" },
126
+ { re: /(?:\\rest\b)/iy, scope: "rest" },
127
+ { re: /(?:\\\\\\)/iy, scope: "separator" },
128
+ { re: /(?:\\\\)/iy, scope: "separator" },
129
+ { re: /(?:tremolo\b)/iy, scope: "keyword" },
130
+ { re: /(?:[a-g](ss|ff|s|f)?)/iy, scope: "pitch" },
131
+ { re: /(?:')/iy, scope: "octave" },
132
+ { re: /(?:,)/iy, scope: "octave" },
133
+ { re: /(?:[0-9]+)/iy, scope: "number" },
134
+ { re: /(?:\/)/iy, scope: "operator" },
135
+ { re: /(?:#)/iy, scope: "punctuation" },
136
+ { re: /(?:\{)/iy, scope: "brace" },
137
+ { re: /(?:\})/iy, scope: "brace" },
138
+ { re: /(?:<)/iy, scope: "chordBracket" },
139
+ { re: /(?:>)/iy, scope: "chordBracket" },
140
+ { re: /(?:\|)/iy, scope: "bar" },
141
+ { re: /(?:\[)/iy, scope: "squareBracket" },
142
+ { re: /(?:\])/iy, scope: "squareBracket" },
143
+ { re: /(?:\()/iy, scope: "paren" },
144
+ { re: /(?:\))/iy, scope: "paren" },
145
+ { re: /(?:~)/iy, scope: "tie" },
146
+ { re: /(?:\.)/iy, scope: "punctuation" },
147
+ { re: /(?:-)/iy, scope: "punctuation" },
148
+ { re: /(?:[_])/iy, scope: "punctuation" },
149
+ { re: /(?:\^)/iy, scope: "punctuation" },
150
+ { re: /(?:!)/iy, scope: "punctuation" },
151
+ { re: /(?::)/iy, scope: "operator" },
152
+ { re: /(?:=)/iy, scope: "operator" },
153
+ { re: /(?:[rR])/iy, scope: "rest" },
154
+ { re: /(?:[sS])/iy, scope: "rest" },
155
+ ];
156
+
157
+ /**
158
+ * Match a single token at `pos` in `line` using longest-match. Returns the
159
+ * winning token, or null if no rule matches (caller should advance one char).
160
+ */
161
+ export const matchAt = (line: string, pos: number): HighlightToken | null => {
162
+ let best: HighlightToken | null = null;
163
+ for (const rule of HIGHLIGHT_RULES) {
164
+ rule.re.lastIndex = pos;
165
+ const m = rule.re.exec(line);
166
+ if (m && m.index === pos && m[0].length > 0) {
167
+ const end = pos + m[0].length;
168
+ if (!best || end > best.end)
169
+ best = { scope: rule.scope, start: pos, end };
170
+ }
171
+ }
172
+ return best;
173
+ };
174
+
175
+ /**
176
+ * Tokenize one line into a list of scoped spans. Characters that match no rule
177
+ * are skipped (no token emitted), mirroring the lexer's catch-all.
178
+ */
179
+ export const tokenizeLine = (line: string): HighlightToken[] => {
180
+ const tokens: HighlightToken[] = [];
181
+ let pos = 0;
182
+ while (pos < line.length) {
183
+ const tok = matchAt(line, pos);
184
+ if (tok) {
185
+ tokens.push(tok);
186
+ pos = tok.end;
187
+ } else {
188
+ pos++;
189
+ }
190
+ }
191
+ return tokens;
192
+ };
@@ -1,102 +0,0 @@
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, };
@@ -1,25 +0,0 @@
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, };
@@ -1,3 +0,0 @@
1
- import { ABC } from "./abc";
2
- export declare const parse: (code: string) => ABC.Document;
3
- export default parse;
@@ -1,6 +0,0 @@
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;
@@ -1,25 +0,0 @@
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;