@tabkit/parser 0.1.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 ADDED
@@ -0,0 +1,97 @@
1
+ # @tabkit/parser
2
+
3
+ Parse ASCII tablature and MusicXML into structured JSON for use with [tabkit](../tabkit).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @tabkit/parser
9
+ ```
10
+
11
+ ## ASCII Tab Parser
12
+
13
+ Convert classic text-based tablature into `TabMeasure[]`:
14
+
15
+ ```typescript
16
+ import { parseAsciiTab } from '@tabkit/parser'
17
+
18
+ const measures = parseAsciiTab(`
19
+ e|---0---1---3---|---0---1---3---|
20
+ B|---1---1---0---|---1---1---0---|
21
+ G|---0---2---0---|---0---2---0---|
22
+ D|---2---3---0---|---2---3---0---|
23
+ A|---3---3---2---|---3---3---2---|
24
+ E|---x---1---3---|---x---1---3---|
25
+ `)
26
+ ```
27
+
28
+ ### Supported syntax
29
+
30
+ - Single and double-digit fret numbers (`0`-`24`)
31
+ - Multiple measures separated by `|`
32
+ - Muted strings (`x` or `X`)
33
+ - Technique markers:
34
+ - `h` — hammer-on
35
+ - `p` — pull-off
36
+ - `/` or `\` — slide
37
+ - `b` — bend
38
+ - `~` — vibrato
39
+
40
+ ### Options
41
+
42
+ ```typescript
43
+ parseAsciiTab(input, {
44
+ defaultDuration: '4n', // default: '8n'
45
+ })
46
+ ```
47
+
48
+ ## MusicXML Parser
49
+
50
+ Parse MusicXML tablature notation into `TabMeasure[]`:
51
+
52
+ ```typescript
53
+ import { parseMusicXML } from '@tabkit/parser'
54
+
55
+ const measures = parseMusicXML(xmlString)
56
+ ```
57
+
58
+ Extracts:
59
+ - Notes with string/fret from `<technical>` elements (handles tags with attributes, e.g. `<string placement="above">`)
60
+ - Time signatures from `<time>`
61
+ - Tempo from `<sound tempo="...">`
62
+ - Labels from `<direction>/<words>`
63
+ - Techniques: hammer-on, pull-off, slide, bend, harmonic, tap
64
+ - Chord notation (simultaneous notes via `<chord/>`)
65
+
66
+ ### Options
67
+
68
+ ```typescript
69
+ parseMusicXML(xmlString, {
70
+ maxMeasures: 10, // limit number of measures parsed
71
+ })
72
+ ```
73
+
74
+ ## Output Format
75
+
76
+ Both parsers return `TabMeasure[]`, compatible with `@tabkit/core`:
77
+
78
+ ```typescript
79
+ import { parseAsciiTab } from '@tabkit/parser'
80
+ import { TabRenderer } from '@tabkit/core'
81
+
82
+ const measures = parseAsciiTab(asciiTab)
83
+ const svg = TabRenderer.svg({ measures, instrument: 'guitar', theme: 'dark' })
84
+ ```
85
+
86
+ ## Ecosystem
87
+
88
+ | Package | Description |
89
+ |---------|-------------|
90
+ | [`@tabkit/core`](../tabkit) | Core SVG tablature renderer |
91
+ | [`@tabkit/player`](../player) | Playback with cursor and metronome |
92
+ | [`@tabkit/audio`](../audio) | Web Audio API synthesis |
93
+ | [`@tabkit/react`](../react) | React components and hooks |
94
+
95
+ ## License
96
+
97
+ MIT
@@ -0,0 +1,39 @@
1
+ import * as _tabkit_core from '@tabkit/core';
2
+ import { TabMeasure } from '@tabkit/core';
3
+
4
+ interface AsciiParseOptions {
5
+ /** Default duration for parsed notes (default: '8n') */
6
+ defaultDuration?: _tabkit_core.Duration;
7
+ }
8
+ interface MusicXMLParseOptions {
9
+ /** Only parse the first N measures */
10
+ maxMeasures?: number;
11
+ }
12
+
13
+ /**
14
+ * Parse a block of ASCII tablature text into TabMeasure[].
15
+ *
16
+ * Supports the classic format:
17
+ * ```
18
+ * e|---0---1---3---|---0---1---3---|
19
+ * B|---1---1---0---|---1---1---0---|
20
+ * G|---0---2---0---|---0---2---0---|
21
+ * D|---2---3---0---|---2---3---0---|
22
+ * A|---3---3---2---|---3---3---2---|
23
+ * E|---x---1---3---|---x---1---3---|
24
+ * ```
25
+ */
26
+ declare function parseAsciiTab(input: string, options?: AsciiParseOptions): TabMeasure[];
27
+
28
+ /**
29
+ * Parse a MusicXML string containing tablature notation into TabMeasure[].
30
+ *
31
+ * This is a lightweight parser that handles the subset of MusicXML relevant
32
+ * to tablature: <note>, <technical>/<string>, <technical>/<fret>, <type>,
33
+ * <time>, and <direction>/<words> for labels.
34
+ *
35
+ * For full MusicXML compliance, consider a dedicated parser.
36
+ */
37
+ declare function parseMusicXML(xml: string, options?: MusicXMLParseOptions): TabMeasure[];
38
+
39
+ export { type AsciiParseOptions, type MusicXMLParseOptions, parseAsciiTab, parseMusicXML };
@@ -0,0 +1,39 @@
1
+ import * as _tabkit_core from '@tabkit/core';
2
+ import { TabMeasure } from '@tabkit/core';
3
+
4
+ interface AsciiParseOptions {
5
+ /** Default duration for parsed notes (default: '8n') */
6
+ defaultDuration?: _tabkit_core.Duration;
7
+ }
8
+ interface MusicXMLParseOptions {
9
+ /** Only parse the first N measures */
10
+ maxMeasures?: number;
11
+ }
12
+
13
+ /**
14
+ * Parse a block of ASCII tablature text into TabMeasure[].
15
+ *
16
+ * Supports the classic format:
17
+ * ```
18
+ * e|---0---1---3---|---0---1---3---|
19
+ * B|---1---1---0---|---1---1---0---|
20
+ * G|---0---2---0---|---0---2---0---|
21
+ * D|---2---3---0---|---2---3---0---|
22
+ * A|---3---3---2---|---3---3---2---|
23
+ * E|---x---1---3---|---x---1---3---|
24
+ * ```
25
+ */
26
+ declare function parseAsciiTab(input: string, options?: AsciiParseOptions): TabMeasure[];
27
+
28
+ /**
29
+ * Parse a MusicXML string containing tablature notation into TabMeasure[].
30
+ *
31
+ * This is a lightweight parser that handles the subset of MusicXML relevant
32
+ * to tablature: <note>, <technical>/<string>, <technical>/<fret>, <type>,
33
+ * <time>, and <direction>/<words> for labels.
34
+ *
35
+ * For full MusicXML compliance, consider a dedicated parser.
36
+ */
37
+ declare function parseMusicXML(xml: string, options?: MusicXMLParseOptions): TabMeasure[];
38
+
39
+ export { type AsciiParseOptions, type MusicXMLParseOptions, parseAsciiTab, parseMusicXML };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';function I(a,f){let p=f?.defaultDuration??"8n",c=a.split(`
2
+ `).map(n=>n.trim()).filter(Boolean),g=[];for(let n of c){let u=n.match(/^([A-Ga-g#b]?)\s*\|(.+)/);u&&g.push({content:u[2]});}if(g.length===0)return [];let r=[];for(let n of g){let l=n.content.split("|").filter(t=>t.length>0).map(t=>t.replace(/\|$/,""));if(r.length===0)for(let t of l)r.push([]);for(let t=0;t<l.length&&t<r.length;t++)r[t].push(l[t]);for(let t=r.length;t<l.length;t++)r.push([l[t]]);}let h=[];for(let n of r){let u=[];if(n.length===0)continue;let l=Math.max(...n.map(m=>m.length)),t=0;for(;t<l;){let m=[];for(let o=0;o<n.length;o++){let s=n[o][t];if(!s||s==="-"||s===" ")continue;if(s==="x"||s==="X"){m.push({string:o+1,fret:0,duration:p,technique:"mute"});continue}if(s==="h"||s==="H"||s==="p"||s==="P"||s==="/"||s==="\\"||s==="b"||s==="~")continue;let d=s;if(t+1<n[o].length){let i=n[o][t+1];i>="0"&&i<="9"&&(d+=i);}let T=parseInt(d,10);if(!isNaN(T)){let i,e=n[o][t+d.length];e==="h"||e==="H"?i="hammer":e==="p"||e==="P"?i="pull":e==="/"||e==="\\"?i="slide":e==="b"?i="bend":e==="~"&&(i="vibrato"),m.push({string:o+1,fret:T,duration:p,technique:i});}}for(m.length>0&&u.push(m.length===1?m[0]:m),t++;t<l;){let o=false;for(let s=0;s<n.length;s++){let d=n[s][t-1],T=n[s][t];d>="0"&&d<="9"&&T>="0"&&T<="9"&&(o=true);}if(o)t++;else break}}u.length>0&&h.push({beats:u});}return h}function N(a){switch(a){case "whole":return "1n";case "half":return "2n";case "quarter":return "4n";case "eighth":return "8n";case "16th":return "16n";case "32nd":return "32n";default:return "4n"}}function y(a,f){let p=[],c=`<${f}`,g=`</${f}>`,r=0;for(;r<a.length;){let h=a.indexOf(c,r);if(h===-1)break;let n=a.indexOf(g,h);if(n===-1)break;p.push(a.slice(h,n+g.length)),r=n+g.length;}return p}function M(a,f){let p=new RegExp(`<${f}(?:\\s[^>]*)?>([^<]*)</${f}>`),c=a.match(p);return c?c[1].trim():void 0}function O(a,f){let p=new RegExp(`${f}\\s*=\\s*"([^"]*)"`),c=a.match(p);return c?c[1]:void 0}function P(a,f){let p=f?.maxMeasures??1/0,c=y(a,"measure"),g=[];for(let r=0;r<c.length&&r<p;r++){let h=c[r],n=[],u,l=y(h,"time")[0];if(l){let e=M(l,"beats"),b=M(l,"beat-type");e&&b&&(u=[parseInt(e,10),parseInt(b,10)]);}let t,m=y(h,"direction");for(let e of m){let b=M(e,"words");if(b){t=b;break}}let o,s=/<sound\b[^>]*>/g,d;for(;(d=s.exec(h))!==null;){let e=O(d[0],"tempo");if(e){o=parseFloat(e);break}}let T=y(h,"note"),i=[];for(let e of T){if(e.includes("<rest"))continue;let b=M(e,"string"),w=M(e,"fret");if(!b||!w)continue;let L=M(e,"type"),A=L?N(L):"4n",D=e.includes("<chord"),x;e.includes("<hammer-on")?x="hammer":e.includes("<pull-off")?x="pull":e.includes("<slide")?x="slide":e.includes("<bend")?x="bend":e.includes("<harmonic")?x="harmonic":e.includes("<tap")&&(x="tap");let X={string:parseInt(b,10),fret:parseInt(w,10),duration:A,technique:x};D?i.push(X):(i.length>0&&n.push(i.length===1?i[0]:i),i=[X]);}if(i.length>0&&n.push(i.length===1?i[0]:i),n.length>0||u||t){let e={beats:n};u&&(e.timeSignature=u),t&&(e.label=t),o&&(e.tempo=o),g.push(e);}}return g}exports.parseAsciiTab=I;exports.parseMusicXML=P;//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ascii.ts","../src/musicxml.ts"],"names":["parseAsciiTab","input","options","defaultDuration","lines","l","stringLines","line","match","measureSegments","sl","cleaned","s","_","mi","measures","segment","beats","maxLen","col","columnNotes","strIdx","ch","fretStr","next","fret","technique","after","hasDigit","prev","curr","xmlTypeToDuration","type","findTags","source","tagName","results","openTag","closeTag","idx","start","end","getTagContent","xml","re","m","getAttr","attr","parseMusicXML","maxMeasures","measureXmls","mXml","timeSignature","timeTag","beatsVal","beatType","label","dirTags","dir","words","tempo","soundRe","soundMatch","t","noteTags","chordGroup","noteXml","stringVal","fretVal","typeVal","duration","isChord","note","measure"],"mappings":"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","file":"index.js","sourcesContent":["import type { TabMeasure, TabNote, TabBeat, Duration } from '@tabkit/core'\nimport type { AsciiParseOptions } from './types.js'\n\ninterface RawStringLine {\n content: string\n}\n\n/**\n * Parse a block of ASCII tablature text into TabMeasure[].\n *\n * Supports the classic format:\n * ```\n * e|---0---1---3---|---0---1---3---|\n * B|---1---1---0---|---1---1---0---|\n * G|---0---2---0---|---0---2---0---|\n * D|---2---3---0---|---2---3---0---|\n * A|---3---3---2---|---3---3---2---|\n * E|---x---1---3---|---x---1---3---|\n * ```\n */\nexport function parseAsciiTab(\n input: string,\n options?: AsciiParseOptions,\n): TabMeasure[] {\n const defaultDuration: Duration = options?.defaultDuration ?? '8n'\n const lines = input.split('\\n').map((l) => l.trim()).filter(Boolean)\n\n // Extract string lines (lines that match \"X|...\" pattern)\n const stringLines: RawStringLine[] = []\n for (const line of lines) {\n const match = line.match(/^([A-Ga-g#b]?)\\s*\\|(.+)/)\n if (match) {\n stringLines.push({ content: match[2] })\n }\n }\n\n if (stringLines.length === 0) return []\n\n // Split each string line by barlines (|) into measure segments\n const measureSegments: string[][] = []\n for (const sl of stringLines) {\n const segments = sl.content.split('|').filter((s) => s.length > 0)\n // Trim trailing pipe content\n const cleaned = segments.map((s) => s.replace(/\\|$/, ''))\n if (measureSegments.length === 0) {\n for (const _ of cleaned) measureSegments.push([])\n }\n for (let mi = 0; mi < cleaned.length && mi < measureSegments.length; mi++) {\n measureSegments[mi].push(cleaned[mi])\n }\n // Handle case where this line has more measures\n for (let mi = measureSegments.length; mi < cleaned.length; mi++) {\n measureSegments.push([cleaned[mi]])\n }\n }\n\n // Parse each measure segment\n const measures: TabMeasure[] = []\n\n for (const segment of measureSegments) {\n const beats: TabBeat[] = []\n\n // Find note positions across all strings\n // A \"column\" in the ASCII tab is a vertical slice\n if (segment.length === 0) continue\n\n const maxLen = Math.max(...segment.map((s) => s.length))\n\n let col = 0\n while (col < maxLen) {\n const columnNotes: TabNote[] = []\n\n for (let strIdx = 0; strIdx < segment.length; strIdx++) {\n const ch = segment[strIdx][col]\n if (!ch || ch === '-' || ch === ' ') continue\n\n if (ch === 'x' || ch === 'X') {\n // Muted note\n columnNotes.push({\n string: strIdx + 1,\n fret: 0,\n duration: defaultDuration,\n technique: 'mute',\n })\n continue\n }\n\n if (ch === 'h' || ch === 'H') continue // skip technique markers\n if (ch === 'p' || ch === 'P') continue\n if (ch === '/' || ch === '\\\\') continue\n if (ch === 'b') continue\n if (ch === '~') continue\n\n // Try to parse a fret number (could be 1 or 2 digits)\n let fretStr = ch\n if (col + 1 < segment[strIdx].length) {\n const next = segment[strIdx][col + 1]\n if (next >= '0' && next <= '9') {\n fretStr += next\n }\n }\n\n const fret = parseInt(fretStr, 10)\n if (!isNaN(fret)) {\n // Look ahead/behind for technique markers\n let technique: TabNote['technique'] | undefined\n const after = segment[strIdx][col + fretStr.length]\n if (after === 'h' || after === 'H') technique = 'hammer'\n else if (after === 'p' || after === 'P') technique = 'pull'\n else if (after === '/' || after === '\\\\') technique = 'slide'\n else if (after === 'b') technique = 'bend'\n else if (after === '~') technique = 'vibrato'\n\n columnNotes.push({\n string: strIdx + 1,\n fret,\n duration: defaultDuration,\n technique,\n })\n }\n }\n\n if (columnNotes.length > 0) {\n beats.push(columnNotes.length === 1 ? columnNotes[0] : columnNotes)\n }\n\n col++\n // Skip ahead past multi-digit fret numbers\n while (col < maxLen) {\n let hasDigit = false\n for (let strIdx = 0; strIdx < segment.length; strIdx++) {\n const prev = segment[strIdx][col - 1]\n const curr = segment[strIdx][col]\n if (prev >= '0' && prev <= '9' && curr >= '0' && curr <= '9') {\n hasDigit = true\n }\n }\n if (hasDigit) col++\n else break\n }\n }\n\n if (beats.length > 0) {\n measures.push({ beats })\n }\n }\n\n return measures\n}\n","import type { TabMeasure, TabNote, TabBeat, Duration } from '@tabkit/core'\nimport type { MusicXMLParseOptions } from './types.js'\n\n/**\n * Map MusicXML <type> values to tabkit Duration tokens.\n */\nfunction xmlTypeToDuration(type: string): Duration {\n switch (type) {\n case 'whole':\n return '1n'\n case 'half':\n return '2n'\n case 'quarter':\n return '4n'\n case 'eighth':\n return '8n'\n case '16th':\n return '16n'\n case '32nd':\n return '32n'\n default:\n return '4n'\n }\n}\n\n/**\n * Minimal DOM-independent XML tag extractor.\n * Finds all occurrences of <tagName>...</tagName> within a source string.\n */\nfunction findTags(source: string, tagName: string): string[] {\n const results: string[] = []\n const openTag = `<${tagName}`\n const closeTag = `</${tagName}>`\n let idx = 0\n\n while (idx < source.length) {\n const start = source.indexOf(openTag, idx)\n if (start === -1) break\n\n const end = source.indexOf(closeTag, start)\n if (end === -1) break\n\n results.push(source.slice(start, end + closeTag.length))\n idx = end + closeTag.length\n }\n\n return results\n}\n\n/**\n * Extract the text content of the first occurrence of <tagName> within xml.\n * Handles tags with attributes (e.g. `<string placement=\"above\">6</string>`).\n */\nfunction getTagContent(xml: string, tagName: string): string | undefined {\n const re = new RegExp(`<${tagName}(?:\\\\s[^>]*)?>([^<]*)</${tagName}>`)\n const m = xml.match(re)\n return m ? m[1].trim() : undefined\n}\n\n/**\n * Extract attribute value from an XML tag string.\n */\nfunction getAttr(xml: string, attr: string): string | undefined {\n const re = new RegExp(`${attr}\\\\s*=\\\\s*\"([^\"]*)\"`)\n const m = xml.match(re)\n return m ? m[1] : undefined\n}\n\n/**\n * Parse a MusicXML string containing tablature notation into TabMeasure[].\n *\n * This is a lightweight parser that handles the subset of MusicXML relevant\n * to tablature: <note>, <technical>/<string>, <technical>/<fret>, <type>,\n * <time>, and <direction>/<words> for labels.\n *\n * For full MusicXML compliance, consider a dedicated parser.\n */\nexport function parseMusicXML(\n xml: string,\n options?: MusicXMLParseOptions,\n): TabMeasure[] {\n const maxMeasures = options?.maxMeasures ?? Infinity\n const measureXmls = findTags(xml, 'measure')\n const measures: TabMeasure[] = []\n\n for (let mi = 0; mi < measureXmls.length && mi < maxMeasures; mi++) {\n const mXml = measureXmls[mi]\n const beats: TabBeat[] = []\n\n // Time signature\n let timeSignature: [number, number] | undefined\n const timeTag = findTags(mXml, 'time')[0]\n if (timeTag) {\n const beatsVal = getTagContent(timeTag, 'beats')\n const beatType = getTagContent(timeTag, 'beat-type')\n if (beatsVal && beatType) {\n timeSignature = [parseInt(beatsVal, 10), parseInt(beatType, 10)]\n }\n }\n\n // Label from <direction><words>\n let label: string | undefined\n const dirTags = findTags(mXml, 'direction')\n for (const dir of dirTags) {\n const words = getTagContent(dir, 'words')\n if (words) {\n label = words\n break\n }\n }\n\n // Tempo — <sound> is often self-closing: <sound tempo=\"120\"/>\n let tempo: number | undefined\n const soundRe = /<sound\\b[^>]*>/g\n let soundMatch: RegExpExecArray | null\n while ((soundMatch = soundRe.exec(mXml)) !== null) {\n const t = getAttr(soundMatch[0], 'tempo')\n if (t) {\n tempo = parseFloat(t)\n break\n }\n }\n\n // Notes\n const noteTags = findTags(mXml, 'note')\n let chordGroup: TabNote[] = []\n\n for (const noteXml of noteTags) {\n // Rest\n if (noteXml.includes('<rest')) continue\n\n const stringVal = getTagContent(noteXml, 'string')\n const fretVal = getTagContent(noteXml, 'fret')\n if (!stringVal || !fretVal) continue\n\n const typeVal = getTagContent(noteXml, 'type')\n const duration = typeVal ? xmlTypeToDuration(typeVal) : '4n'\n const isChord = noteXml.includes('<chord')\n\n // Technique detection\n let technique: TabNote['technique'] | undefined\n if (noteXml.includes('<hammer-on')) technique = 'hammer'\n else if (noteXml.includes('<pull-off')) technique = 'pull'\n else if (noteXml.includes('<slide')) technique = 'slide'\n else if (noteXml.includes('<bend')) technique = 'bend'\n else if (noteXml.includes('<harmonic')) technique = 'harmonic'\n else if (noteXml.includes('<tap')) technique = 'tap'\n\n const note: TabNote = {\n string: parseInt(stringVal, 10),\n fret: parseInt(fretVal, 10),\n duration,\n technique,\n }\n\n if (isChord) {\n chordGroup.push(note)\n } else {\n // Flush previous chord group\n if (chordGroup.length > 0) {\n beats.push(chordGroup.length === 1 ? chordGroup[0] : chordGroup)\n }\n chordGroup = [note]\n }\n }\n\n // Flush final group\n if (chordGroup.length > 0) {\n beats.push(chordGroup.length === 1 ? chordGroup[0] : chordGroup)\n }\n\n if (beats.length > 0 || timeSignature || label) {\n const measure: TabMeasure = { beats }\n if (timeSignature) measure.timeSignature = timeSignature\n if (label) measure.label = label\n if (tempo) measure.tempo = tempo\n measures.push(measure)\n }\n }\n\n return measures\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ function I(a,f){let p=f?.defaultDuration??"8n",c=a.split(`
2
+ `).map(n=>n.trim()).filter(Boolean),g=[];for(let n of c){let u=n.match(/^([A-Ga-g#b]?)\s*\|(.+)/);u&&g.push({content:u[2]});}if(g.length===0)return [];let r=[];for(let n of g){let l=n.content.split("|").filter(t=>t.length>0).map(t=>t.replace(/\|$/,""));if(r.length===0)for(let t of l)r.push([]);for(let t=0;t<l.length&&t<r.length;t++)r[t].push(l[t]);for(let t=r.length;t<l.length;t++)r.push([l[t]]);}let h=[];for(let n of r){let u=[];if(n.length===0)continue;let l=Math.max(...n.map(m=>m.length)),t=0;for(;t<l;){let m=[];for(let o=0;o<n.length;o++){let s=n[o][t];if(!s||s==="-"||s===" ")continue;if(s==="x"||s==="X"){m.push({string:o+1,fret:0,duration:p,technique:"mute"});continue}if(s==="h"||s==="H"||s==="p"||s==="P"||s==="/"||s==="\\"||s==="b"||s==="~")continue;let d=s;if(t+1<n[o].length){let i=n[o][t+1];i>="0"&&i<="9"&&(d+=i);}let T=parseInt(d,10);if(!isNaN(T)){let i,e=n[o][t+d.length];e==="h"||e==="H"?i="hammer":e==="p"||e==="P"?i="pull":e==="/"||e==="\\"?i="slide":e==="b"?i="bend":e==="~"&&(i="vibrato"),m.push({string:o+1,fret:T,duration:p,technique:i});}}for(m.length>0&&u.push(m.length===1?m[0]:m),t++;t<l;){let o=false;for(let s=0;s<n.length;s++){let d=n[s][t-1],T=n[s][t];d>="0"&&d<="9"&&T>="0"&&T<="9"&&(o=true);}if(o)t++;else break}}u.length>0&&h.push({beats:u});}return h}function N(a){switch(a){case "whole":return "1n";case "half":return "2n";case "quarter":return "4n";case "eighth":return "8n";case "16th":return "16n";case "32nd":return "32n";default:return "4n"}}function y(a,f){let p=[],c=`<${f}`,g=`</${f}>`,r=0;for(;r<a.length;){let h=a.indexOf(c,r);if(h===-1)break;let n=a.indexOf(g,h);if(n===-1)break;p.push(a.slice(h,n+g.length)),r=n+g.length;}return p}function M(a,f){let p=new RegExp(`<${f}(?:\\s[^>]*)?>([^<]*)</${f}>`),c=a.match(p);return c?c[1].trim():void 0}function O(a,f){let p=new RegExp(`${f}\\s*=\\s*"([^"]*)"`),c=a.match(p);return c?c[1]:void 0}function P(a,f){let p=f?.maxMeasures??1/0,c=y(a,"measure"),g=[];for(let r=0;r<c.length&&r<p;r++){let h=c[r],n=[],u,l=y(h,"time")[0];if(l){let e=M(l,"beats"),b=M(l,"beat-type");e&&b&&(u=[parseInt(e,10),parseInt(b,10)]);}let t,m=y(h,"direction");for(let e of m){let b=M(e,"words");if(b){t=b;break}}let o,s=/<sound\b[^>]*>/g,d;for(;(d=s.exec(h))!==null;){let e=O(d[0],"tempo");if(e){o=parseFloat(e);break}}let T=y(h,"note"),i=[];for(let e of T){if(e.includes("<rest"))continue;let b=M(e,"string"),w=M(e,"fret");if(!b||!w)continue;let L=M(e,"type"),A=L?N(L):"4n",D=e.includes("<chord"),x;e.includes("<hammer-on")?x="hammer":e.includes("<pull-off")?x="pull":e.includes("<slide")?x="slide":e.includes("<bend")?x="bend":e.includes("<harmonic")?x="harmonic":e.includes("<tap")&&(x="tap");let X={string:parseInt(b,10),fret:parseInt(w,10),duration:A,technique:x};D?i.push(X):(i.length>0&&n.push(i.length===1?i[0]:i),i=[X]);}if(i.length>0&&n.push(i.length===1?i[0]:i),n.length>0||u||t){let e={beats:n};u&&(e.timeSignature=u),t&&(e.label=t),o&&(e.tempo=o),g.push(e);}}return g}export{I as parseAsciiTab,P as parseMusicXML};//# sourceMappingURL=index.mjs.map
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ascii.ts","../src/musicxml.ts"],"names":["parseAsciiTab","input","options","defaultDuration","lines","l","stringLines","line","match","measureSegments","sl","cleaned","s","_","mi","measures","segment","beats","maxLen","col","columnNotes","strIdx","ch","fretStr","next","fret","technique","after","hasDigit","prev","curr","xmlTypeToDuration","type","findTags","source","tagName","results","openTag","closeTag","idx","start","end","getTagContent","xml","re","m","getAttr","attr","parseMusicXML","maxMeasures","measureXmls","mXml","timeSignature","timeTag","beatsVal","beatType","label","dirTags","dir","words","tempo","soundRe","soundMatch","t","noteTags","chordGroup","noteXml","stringVal","fretVal","typeVal","duration","isChord","note","measure"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { TabMeasure, TabNote, TabBeat, Duration } from '@tabkit/core'\nimport type { AsciiParseOptions } from './types.js'\n\ninterface RawStringLine {\n content: string\n}\n\n/**\n * Parse a block of ASCII tablature text into TabMeasure[].\n *\n * Supports the classic format:\n * ```\n * e|---0---1---3---|---0---1---3---|\n * B|---1---1---0---|---1---1---0---|\n * G|---0---2---0---|---0---2---0---|\n * D|---2---3---0---|---2---3---0---|\n * A|---3---3---2---|---3---3---2---|\n * E|---x---1---3---|---x---1---3---|\n * ```\n */\nexport function parseAsciiTab(\n input: string,\n options?: AsciiParseOptions,\n): TabMeasure[] {\n const defaultDuration: Duration = options?.defaultDuration ?? '8n'\n const lines = input.split('\\n').map((l) => l.trim()).filter(Boolean)\n\n // Extract string lines (lines that match \"X|...\" pattern)\n const stringLines: RawStringLine[] = []\n for (const line of lines) {\n const match = line.match(/^([A-Ga-g#b]?)\\s*\\|(.+)/)\n if (match) {\n stringLines.push({ content: match[2] })\n }\n }\n\n if (stringLines.length === 0) return []\n\n // Split each string line by barlines (|) into measure segments\n const measureSegments: string[][] = []\n for (const sl of stringLines) {\n const segments = sl.content.split('|').filter((s) => s.length > 0)\n // Trim trailing pipe content\n const cleaned = segments.map((s) => s.replace(/\\|$/, ''))\n if (measureSegments.length === 0) {\n for (const _ of cleaned) measureSegments.push([])\n }\n for (let mi = 0; mi < cleaned.length && mi < measureSegments.length; mi++) {\n measureSegments[mi].push(cleaned[mi])\n }\n // Handle case where this line has more measures\n for (let mi = measureSegments.length; mi < cleaned.length; mi++) {\n measureSegments.push([cleaned[mi]])\n }\n }\n\n // Parse each measure segment\n const measures: TabMeasure[] = []\n\n for (const segment of measureSegments) {\n const beats: TabBeat[] = []\n\n // Find note positions across all strings\n // A \"column\" in the ASCII tab is a vertical slice\n if (segment.length === 0) continue\n\n const maxLen = Math.max(...segment.map((s) => s.length))\n\n let col = 0\n while (col < maxLen) {\n const columnNotes: TabNote[] = []\n\n for (let strIdx = 0; strIdx < segment.length; strIdx++) {\n const ch = segment[strIdx][col]\n if (!ch || ch === '-' || ch === ' ') continue\n\n if (ch === 'x' || ch === 'X') {\n // Muted note\n columnNotes.push({\n string: strIdx + 1,\n fret: 0,\n duration: defaultDuration,\n technique: 'mute',\n })\n continue\n }\n\n if (ch === 'h' || ch === 'H') continue // skip technique markers\n if (ch === 'p' || ch === 'P') continue\n if (ch === '/' || ch === '\\\\') continue\n if (ch === 'b') continue\n if (ch === '~') continue\n\n // Try to parse a fret number (could be 1 or 2 digits)\n let fretStr = ch\n if (col + 1 < segment[strIdx].length) {\n const next = segment[strIdx][col + 1]\n if (next >= '0' && next <= '9') {\n fretStr += next\n }\n }\n\n const fret = parseInt(fretStr, 10)\n if (!isNaN(fret)) {\n // Look ahead/behind for technique markers\n let technique: TabNote['technique'] | undefined\n const after = segment[strIdx][col + fretStr.length]\n if (after === 'h' || after === 'H') technique = 'hammer'\n else if (after === 'p' || after === 'P') technique = 'pull'\n else if (after === '/' || after === '\\\\') technique = 'slide'\n else if (after === 'b') technique = 'bend'\n else if (after === '~') technique = 'vibrato'\n\n columnNotes.push({\n string: strIdx + 1,\n fret,\n duration: defaultDuration,\n technique,\n })\n }\n }\n\n if (columnNotes.length > 0) {\n beats.push(columnNotes.length === 1 ? columnNotes[0] : columnNotes)\n }\n\n col++\n // Skip ahead past multi-digit fret numbers\n while (col < maxLen) {\n let hasDigit = false\n for (let strIdx = 0; strIdx < segment.length; strIdx++) {\n const prev = segment[strIdx][col - 1]\n const curr = segment[strIdx][col]\n if (prev >= '0' && prev <= '9' && curr >= '0' && curr <= '9') {\n hasDigit = true\n }\n }\n if (hasDigit) col++\n else break\n }\n }\n\n if (beats.length > 0) {\n measures.push({ beats })\n }\n }\n\n return measures\n}\n","import type { TabMeasure, TabNote, TabBeat, Duration } from '@tabkit/core'\nimport type { MusicXMLParseOptions } from './types.js'\n\n/**\n * Map MusicXML <type> values to tabkit Duration tokens.\n */\nfunction xmlTypeToDuration(type: string): Duration {\n switch (type) {\n case 'whole':\n return '1n'\n case 'half':\n return '2n'\n case 'quarter':\n return '4n'\n case 'eighth':\n return '8n'\n case '16th':\n return '16n'\n case '32nd':\n return '32n'\n default:\n return '4n'\n }\n}\n\n/**\n * Minimal DOM-independent XML tag extractor.\n * Finds all occurrences of <tagName>...</tagName> within a source string.\n */\nfunction findTags(source: string, tagName: string): string[] {\n const results: string[] = []\n const openTag = `<${tagName}`\n const closeTag = `</${tagName}>`\n let idx = 0\n\n while (idx < source.length) {\n const start = source.indexOf(openTag, idx)\n if (start === -1) break\n\n const end = source.indexOf(closeTag, start)\n if (end === -1) break\n\n results.push(source.slice(start, end + closeTag.length))\n idx = end + closeTag.length\n }\n\n return results\n}\n\n/**\n * Extract the text content of the first occurrence of <tagName> within xml.\n * Handles tags with attributes (e.g. `<string placement=\"above\">6</string>`).\n */\nfunction getTagContent(xml: string, tagName: string): string | undefined {\n const re = new RegExp(`<${tagName}(?:\\\\s[^>]*)?>([^<]*)</${tagName}>`)\n const m = xml.match(re)\n return m ? m[1].trim() : undefined\n}\n\n/**\n * Extract attribute value from an XML tag string.\n */\nfunction getAttr(xml: string, attr: string): string | undefined {\n const re = new RegExp(`${attr}\\\\s*=\\\\s*\"([^\"]*)\"`)\n const m = xml.match(re)\n return m ? m[1] : undefined\n}\n\n/**\n * Parse a MusicXML string containing tablature notation into TabMeasure[].\n *\n * This is a lightweight parser that handles the subset of MusicXML relevant\n * to tablature: <note>, <technical>/<string>, <technical>/<fret>, <type>,\n * <time>, and <direction>/<words> for labels.\n *\n * For full MusicXML compliance, consider a dedicated parser.\n */\nexport function parseMusicXML(\n xml: string,\n options?: MusicXMLParseOptions,\n): TabMeasure[] {\n const maxMeasures = options?.maxMeasures ?? Infinity\n const measureXmls = findTags(xml, 'measure')\n const measures: TabMeasure[] = []\n\n for (let mi = 0; mi < measureXmls.length && mi < maxMeasures; mi++) {\n const mXml = measureXmls[mi]\n const beats: TabBeat[] = []\n\n // Time signature\n let timeSignature: [number, number] | undefined\n const timeTag = findTags(mXml, 'time')[0]\n if (timeTag) {\n const beatsVal = getTagContent(timeTag, 'beats')\n const beatType = getTagContent(timeTag, 'beat-type')\n if (beatsVal && beatType) {\n timeSignature = [parseInt(beatsVal, 10), parseInt(beatType, 10)]\n }\n }\n\n // Label from <direction><words>\n let label: string | undefined\n const dirTags = findTags(mXml, 'direction')\n for (const dir of dirTags) {\n const words = getTagContent(dir, 'words')\n if (words) {\n label = words\n break\n }\n }\n\n // Tempo — <sound> is often self-closing: <sound tempo=\"120\"/>\n let tempo: number | undefined\n const soundRe = /<sound\\b[^>]*>/g\n let soundMatch: RegExpExecArray | null\n while ((soundMatch = soundRe.exec(mXml)) !== null) {\n const t = getAttr(soundMatch[0], 'tempo')\n if (t) {\n tempo = parseFloat(t)\n break\n }\n }\n\n // Notes\n const noteTags = findTags(mXml, 'note')\n let chordGroup: TabNote[] = []\n\n for (const noteXml of noteTags) {\n // Rest\n if (noteXml.includes('<rest')) continue\n\n const stringVal = getTagContent(noteXml, 'string')\n const fretVal = getTagContent(noteXml, 'fret')\n if (!stringVal || !fretVal) continue\n\n const typeVal = getTagContent(noteXml, 'type')\n const duration = typeVal ? xmlTypeToDuration(typeVal) : '4n'\n const isChord = noteXml.includes('<chord')\n\n // Technique detection\n let technique: TabNote['technique'] | undefined\n if (noteXml.includes('<hammer-on')) technique = 'hammer'\n else if (noteXml.includes('<pull-off')) technique = 'pull'\n else if (noteXml.includes('<slide')) technique = 'slide'\n else if (noteXml.includes('<bend')) technique = 'bend'\n else if (noteXml.includes('<harmonic')) technique = 'harmonic'\n else if (noteXml.includes('<tap')) technique = 'tap'\n\n const note: TabNote = {\n string: parseInt(stringVal, 10),\n fret: parseInt(fretVal, 10),\n duration,\n technique,\n }\n\n if (isChord) {\n chordGroup.push(note)\n } else {\n // Flush previous chord group\n if (chordGroup.length > 0) {\n beats.push(chordGroup.length === 1 ? chordGroup[0] : chordGroup)\n }\n chordGroup = [note]\n }\n }\n\n // Flush final group\n if (chordGroup.length > 0) {\n beats.push(chordGroup.length === 1 ? chordGroup[0] : chordGroup)\n }\n\n if (beats.length > 0 || timeSignature || label) {\n const measure: TabMeasure = { beats }\n if (timeSignature) measure.timeSignature = timeSignature\n if (label) measure.label = label\n if (tempo) measure.tempo = tempo\n measures.push(measure)\n }\n }\n\n return measures\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@tabkit/parser",
3
+ "version": "0.1.2",
4
+ "description": "Parse ASCII tabs and MusicXML into tabkit-compatible JSON",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "clean": "rm -rf dist"
29
+ },
30
+ "peerDependencies": {
31
+ "@tabkit/core": "^0.1.2"
32
+ },
33
+ "keywords": [
34
+ "tablature",
35
+ "parser",
36
+ "ascii-tab",
37
+ "musicxml",
38
+ "tabkit"
39
+ ],
40
+ "license": "MIT",
41
+ "author": "Julio Carneiro",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/juliocarneiro/tabkit",
45
+ "directory": "packages/parser"
46
+ },
47
+ "homepage": "https://github.com/juliocarneiro/tabkit#readme",
48
+ "bugs": {
49
+ "url": "https://github.com/juliocarneiro/tabkit/issues"
50
+ },
51
+ "sideEffects": false
52
+ }