@vibuca/synth8-core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/compiler/compiler.d.ts +2 -0
- package/dist/compiler/index.d.ts +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +302 -0
- package/dist/model/ast.d.ts +37 -0
- package/dist/model/event.d.ts +7 -0
- package/dist/model/index.d.ts +3 -0
- package/dist/model/pattern.d.ts +5 -0
- package/dist/parser/beat-pattern-parser.d.ts +2 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/melody-pattern-parser.d.ts +2 -0
- package/dist/parser/notes.d.ts +1 -0
- package/dist/parser/parser.d.ts +2 -0
- package/dist/parser/tokenizer.d.ts +14 -0
- package/package.json +23 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sven Hemmer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @vibuca/synth8-core
|
|
2
|
+
|
|
3
|
+
Core parser and compiler for Synt8, an MIT-licensed pattern music toolkit written in TypeScript.
|
|
4
|
+
|
|
5
|
+
Synt8 defines its own small pattern DSL for rhythmic and melodic music patterns.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @vibuca/synth8-core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { compile } from "@vibuca/synth8-core";
|
|
17
|
+
|
|
18
|
+
const pattern = compile(`
|
|
19
|
+
song(
|
|
20
|
+
beat("kick+hihat snare hihat snare"),
|
|
21
|
+
melody("c4 e4 g4 _")
|
|
22
|
+
)
|
|
23
|
+
`);
|
|
24
|
+
|
|
25
|
+
console.log(pattern);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Supported syntax
|
|
29
|
+
|
|
30
|
+
### Beat patterns
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
beat("kick snare hihat hihat")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Melody patterns
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
melody("c4 e4 g4 _")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Songs
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
song(
|
|
46
|
+
beat("kick snare"),
|
|
47
|
+
melody("c4 e4")
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Rate
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
beat("kick snare").rate(2)
|
|
55
|
+
melody("c4 e4 g4").rate(2)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Rests
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
beat("kick _ snare hihat")
|
|
62
|
+
melody("c4 _ e4 g4")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Groups
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
beat("kick [snare hihat] kick")
|
|
69
|
+
melody("c4 [e4 g4] c5")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Parallel drum hits
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
beat("kick+hihat snare hihat snare")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Output
|
|
79
|
+
|
|
80
|
+
`compile()` returns a pattern:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
type Pattern = {
|
|
84
|
+
length: number;
|
|
85
|
+
events: Event[];
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Events are stored in beats, not seconds.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
type Event =
|
|
93
|
+
| {
|
|
94
|
+
time: number;
|
|
95
|
+
dur: number;
|
|
96
|
+
type: "drum";
|
|
97
|
+
value: string;
|
|
98
|
+
}
|
|
99
|
+
| {
|
|
100
|
+
time: number;
|
|
101
|
+
dur: number;
|
|
102
|
+
type: "note";
|
|
103
|
+
value: string;
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Supported drum sounds
|
|
108
|
+
|
|
109
|
+
```txt
|
|
110
|
+
kick
|
|
111
|
+
snare
|
|
112
|
+
clap
|
|
113
|
+
hihat
|
|
114
|
+
openhat
|
|
115
|
+
tom
|
|
116
|
+
rim
|
|
117
|
+
cowbell
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use `_` for rests.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './compiler';
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
//#region src/parser/beat-pattern-parser.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
let t = e.split("+").filter(Boolean);
|
|
4
|
+
return t.length === 1 ? {
|
|
5
|
+
kind: "BeatSound",
|
|
6
|
+
value: t[0]
|
|
7
|
+
} : {
|
|
8
|
+
kind: "BeatParallel",
|
|
9
|
+
sounds: t.map((e) => ({
|
|
10
|
+
kind: "BeatSound",
|
|
11
|
+
value: e
|
|
12
|
+
}))
|
|
13
|
+
};
|
|
14
|
+
}, t = (t) => {
|
|
15
|
+
let n = 0, r = (i) => {
|
|
16
|
+
let a = [];
|
|
17
|
+
for (; n < t.length;) {
|
|
18
|
+
let o = t[n];
|
|
19
|
+
if (/\s/.test(o)) {
|
|
20
|
+
n++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (i && o === i) return n++, a;
|
|
24
|
+
if (o === "[") {
|
|
25
|
+
n++, a.push({
|
|
26
|
+
kind: "BeatGroup",
|
|
27
|
+
steps: r("]")
|
|
28
|
+
});
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (o === "]") throw Error("Unexpected closing group ']'.");
|
|
32
|
+
let s = "";
|
|
33
|
+
for (; n < t.length && !/\s/.test(t[n]) && t[n] !== "[" && t[n] !== "]";) s += t[n], n++;
|
|
34
|
+
s.length > 0 && a.push(e(s));
|
|
35
|
+
}
|
|
36
|
+
if (i) throw Error("Unterminated group '['.");
|
|
37
|
+
return a;
|
|
38
|
+
};
|
|
39
|
+
return r();
|
|
40
|
+
}, n = /^[a-gA-G](#|b)?[0-8]$/, r = (e) => e === "_" || n.test(e);
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/parser/melody-pattern-parser.ts
|
|
43
|
+
function i(e) {
|
|
44
|
+
let t = [...e], n = 0;
|
|
45
|
+
function i() {
|
|
46
|
+
for (; t[n] === " ";) n++;
|
|
47
|
+
}
|
|
48
|
+
function a(e) {
|
|
49
|
+
let o = [];
|
|
50
|
+
for (; n < t.length;) {
|
|
51
|
+
if (i(), e && t[n] === e) return n++, o;
|
|
52
|
+
if (t[n] === "[") {
|
|
53
|
+
n++, o.push({
|
|
54
|
+
kind: "MelodyGroup",
|
|
55
|
+
notes: a("]")
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
let s = "";
|
|
60
|
+
for (; n < t.length && t[n] !== " " && t[n] !== "[" && t[n] !== "]";) s += t[n++];
|
|
61
|
+
if (!s) break;
|
|
62
|
+
if (!r(s)) throw Error(`Unknown note: ${s}`);
|
|
63
|
+
o.push({
|
|
64
|
+
kind: "MelodyNote",
|
|
65
|
+
value: s
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (e) throw Error("Unclosed melody group");
|
|
69
|
+
return o;
|
|
70
|
+
}
|
|
71
|
+
return a();
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/parser/tokenizer.ts
|
|
75
|
+
var a = (e) => {
|
|
76
|
+
let t = [], n = 0;
|
|
77
|
+
for (; n < e.length;) {
|
|
78
|
+
let r = e[n];
|
|
79
|
+
if (/\s/.test(r)) {
|
|
80
|
+
n++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (/[a-zA-Z_]/.test(r)) {
|
|
84
|
+
let r = "";
|
|
85
|
+
for (; /[a-zA-Z0-9_]/.test(e[n] ?? "");) r += e[n], n++;
|
|
86
|
+
t.push({
|
|
87
|
+
type: "identifier",
|
|
88
|
+
value: r
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (r === "\"") {
|
|
93
|
+
n++;
|
|
94
|
+
let r = "";
|
|
95
|
+
for (; n < e.length && e[n] !== "\"";) r += e[n], n++;
|
|
96
|
+
if (e[n] !== "\"") throw Error("Unterminated string literal.");
|
|
97
|
+
n++, t.push({
|
|
98
|
+
type: "string",
|
|
99
|
+
value: r
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (/\d/.test(r)) {
|
|
104
|
+
let r = "";
|
|
105
|
+
for (; /[\d.]/.test(e[n] ?? "");) r += e[n], n++;
|
|
106
|
+
t.push({
|
|
107
|
+
type: "number",
|
|
108
|
+
value: Number(r)
|
|
109
|
+
});
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (r === "(" || r === ")" || r === "." || r === ",") {
|
|
113
|
+
t.push({
|
|
114
|
+
type: "symbol",
|
|
115
|
+
value: r
|
|
116
|
+
}), n++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
throw Error(`Unexpected character: ${r}`);
|
|
120
|
+
}
|
|
121
|
+
return t;
|
|
122
|
+
}, o = class {
|
|
123
|
+
tokens;
|
|
124
|
+
index = 0;
|
|
125
|
+
constructor(e) {
|
|
126
|
+
this.tokens = e;
|
|
127
|
+
}
|
|
128
|
+
parse() {
|
|
129
|
+
let e = this.parseExpression();
|
|
130
|
+
if (!this.isAtEnd()) throw Error("Unexpected tokens after expression.");
|
|
131
|
+
return e;
|
|
132
|
+
}
|
|
133
|
+
parseExpression() {
|
|
134
|
+
let e = this.peek();
|
|
135
|
+
if (e?.type !== "identifier") throw Error("Expected expression.");
|
|
136
|
+
if (e.value === "beat") return this.parseBeatExpression();
|
|
137
|
+
if (e.value === "melody") return this.parseMelodyExpression();
|
|
138
|
+
if (e.value === "song") return this.parseSongExpression();
|
|
139
|
+
throw Error(`Unknown expression: ${e.value}`);
|
|
140
|
+
}
|
|
141
|
+
parseOptionalRate() {
|
|
142
|
+
let e = 1;
|
|
143
|
+
if (this.matchSymbol(".") && (this.expectIdentifier("rate"), this.expectSymbol("("), e = this.expectNumber(), this.expectSymbol(")")), !Number.isFinite(e) || e <= 0) throw Error(`Invalid rate: ${e}`);
|
|
144
|
+
return e;
|
|
145
|
+
}
|
|
146
|
+
parseBeatExpression() {
|
|
147
|
+
this.expectIdentifier("beat"), this.expectSymbol("(");
|
|
148
|
+
let e = this.expectString();
|
|
149
|
+
this.expectSymbol(")");
|
|
150
|
+
let n = this.parseOptionalRate();
|
|
151
|
+
return {
|
|
152
|
+
kind: "BeatExpression",
|
|
153
|
+
steps: t(e),
|
|
154
|
+
rate: n
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
parseMelodyExpression() {
|
|
158
|
+
this.expectIdentifier("melody"), this.expectSymbol("(");
|
|
159
|
+
let e = this.expectString();
|
|
160
|
+
this.expectSymbol(")");
|
|
161
|
+
let t = this.parseOptionalRate();
|
|
162
|
+
return {
|
|
163
|
+
kind: "MelodyExpression",
|
|
164
|
+
notes: i(e),
|
|
165
|
+
rate: t
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
parseSongExpression() {
|
|
169
|
+
this.expectIdentifier("song"), this.expectSymbol("(");
|
|
170
|
+
let e = [];
|
|
171
|
+
if (!this.matchSymbol(")")) {
|
|
172
|
+
do
|
|
173
|
+
e.push(this.parseExpression());
|
|
174
|
+
while (this.matchSymbol(","));
|
|
175
|
+
this.expectSymbol(")");
|
|
176
|
+
}
|
|
177
|
+
if (e.length === 0) throw Error("song() requires at least one track.");
|
|
178
|
+
return {
|
|
179
|
+
kind: "SongExpression",
|
|
180
|
+
tracks: e
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
expectIdentifier(e) {
|
|
184
|
+
let t = this.advance();
|
|
185
|
+
if (t?.type !== "identifier" || t.value !== e) throw Error(`Expected identifier "${e}".`);
|
|
186
|
+
}
|
|
187
|
+
expectString() {
|
|
188
|
+
let e = this.advance();
|
|
189
|
+
if (e?.type !== "string") throw Error("Expected string.");
|
|
190
|
+
return e.value;
|
|
191
|
+
}
|
|
192
|
+
expectNumber() {
|
|
193
|
+
let e = this.advance();
|
|
194
|
+
if (e?.type !== "number") throw Error("Expected number.");
|
|
195
|
+
return e.value;
|
|
196
|
+
}
|
|
197
|
+
expectSymbol(e) {
|
|
198
|
+
let t = this.advance();
|
|
199
|
+
if (t?.type !== "symbol" || t.value !== e) throw Error(`Expected "${e}".`);
|
|
200
|
+
}
|
|
201
|
+
matchSymbol(e) {
|
|
202
|
+
let t = this.peek();
|
|
203
|
+
return t?.type === "symbol" && t.value === e ? (this.advance(), !0) : !1;
|
|
204
|
+
}
|
|
205
|
+
advance() {
|
|
206
|
+
return this.tokens[this.index++];
|
|
207
|
+
}
|
|
208
|
+
peek() {
|
|
209
|
+
return this.tokens[this.index];
|
|
210
|
+
}
|
|
211
|
+
isAtEnd() {
|
|
212
|
+
return this.index >= this.tokens.length;
|
|
213
|
+
}
|
|
214
|
+
}, s = (e) => new o(a(e)).parse(), c = "_", l = new Set([
|
|
215
|
+
"kick",
|
|
216
|
+
"snare",
|
|
217
|
+
"clap",
|
|
218
|
+
"hihat",
|
|
219
|
+
"openhat",
|
|
220
|
+
"tom",
|
|
221
|
+
"rim",
|
|
222
|
+
"cowbell"
|
|
223
|
+
]), u = (e) => {
|
|
224
|
+
if (e !== c && !l.has(e)) throw Error(`Unknown drum sound: ${e}`);
|
|
225
|
+
}, d = (e) => {
|
|
226
|
+
if (e.kind === "BeatGroup") {
|
|
227
|
+
for (let t of e.steps) d(t);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (e.kind === "BeatParallel") {
|
|
231
|
+
for (let t of e.sounds) u(t.value);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
u(e.value);
|
|
235
|
+
}, f = (e, t, n) => {
|
|
236
|
+
if (e.length === 0) return [];
|
|
237
|
+
let r = [], i = n / e.length;
|
|
238
|
+
return e.forEach((e, n) => {
|
|
239
|
+
let a = t + n * i;
|
|
240
|
+
switch (e.kind) {
|
|
241
|
+
case "BeatGroup":
|
|
242
|
+
r.push(...f(e.steps, a, i));
|
|
243
|
+
break;
|
|
244
|
+
case "BeatParallel":
|
|
245
|
+
for (let t of e.sounds) t.value !== c && r.push({
|
|
246
|
+
time: a,
|
|
247
|
+
dur: i,
|
|
248
|
+
type: "drum",
|
|
249
|
+
value: t.value
|
|
250
|
+
});
|
|
251
|
+
break;
|
|
252
|
+
case "BeatSound":
|
|
253
|
+
if (e.value === c) break;
|
|
254
|
+
r.push({
|
|
255
|
+
time: a,
|
|
256
|
+
dur: i,
|
|
257
|
+
type: "drum",
|
|
258
|
+
value: e.value
|
|
259
|
+
});
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}), r;
|
|
263
|
+
}, p = (e) => {
|
|
264
|
+
switch (e.kind) {
|
|
265
|
+
case "BeatExpression": {
|
|
266
|
+
for (let t of e.steps) d(t);
|
|
267
|
+
let t = 1 / e.rate, n = e.steps.length * t;
|
|
268
|
+
return {
|
|
269
|
+
length: n,
|
|
270
|
+
events: f(e.steps, 0, n)
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
case "MelodyExpression": {
|
|
274
|
+
let t = 1 / e.rate, n = e.notes.length * t;
|
|
275
|
+
return {
|
|
276
|
+
length: n,
|
|
277
|
+
events: m(e.notes, 0, n)
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
case "SongExpression": {
|
|
281
|
+
let t = e.tracks.map(p);
|
|
282
|
+
return {
|
|
283
|
+
length: Math.max(...t.map((e) => e.length)),
|
|
284
|
+
events: t.flatMap((e) => e.events)
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
default: throw Error("Unknown AST node");
|
|
288
|
+
}
|
|
289
|
+
}, m = (e, t, n) => {
|
|
290
|
+
let r = n / e.length;
|
|
291
|
+
return e.flatMap((e, n) => {
|
|
292
|
+
let i = t + n * r;
|
|
293
|
+
return e.kind === "MelodyNote" ? e.value === "_" ? [] : [{
|
|
294
|
+
time: i,
|
|
295
|
+
dur: r,
|
|
296
|
+
type: "note",
|
|
297
|
+
value: e.value
|
|
298
|
+
}] : m(e.notes, i, r);
|
|
299
|
+
});
|
|
300
|
+
}, h = (e) => p(s(e)), g = "0.1.0";
|
|
301
|
+
//#endregion
|
|
302
|
+
export { g as VERSION, h as compile, s as parse, a as tokenize };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type AstNode = BeatExpression | MelodyExpression | SongExpression;
|
|
2
|
+
export type BeatExpression = {
|
|
3
|
+
kind: "BeatExpression";
|
|
4
|
+
steps: BeatStep[];
|
|
5
|
+
rate: number;
|
|
6
|
+
};
|
|
7
|
+
export type SongExpression = {
|
|
8
|
+
kind: "SongExpression";
|
|
9
|
+
tracks: AstNode[];
|
|
10
|
+
};
|
|
11
|
+
export type MelodyExpression = {
|
|
12
|
+
kind: "MelodyExpression";
|
|
13
|
+
notes: MelodyStep[];
|
|
14
|
+
rate: number;
|
|
15
|
+
};
|
|
16
|
+
export type MelodyStep = MelodyNote | MelodyGroup;
|
|
17
|
+
export type MelodyNote = {
|
|
18
|
+
kind: "MelodyNote";
|
|
19
|
+
value: string;
|
|
20
|
+
};
|
|
21
|
+
export type MelodyGroup = {
|
|
22
|
+
kind: "MelodyGroup";
|
|
23
|
+
notes: MelodyStep[];
|
|
24
|
+
};
|
|
25
|
+
export type BeatStep = BeatSound | BeatGroup | BeatParallel;
|
|
26
|
+
export type BeatSound = {
|
|
27
|
+
kind: "BeatSound";
|
|
28
|
+
value: string;
|
|
29
|
+
};
|
|
30
|
+
export type BeatGroup = {
|
|
31
|
+
kind: "BeatGroup";
|
|
32
|
+
steps: BeatStep[];
|
|
33
|
+
};
|
|
34
|
+
export type BeatParallel = {
|
|
35
|
+
kind: "BeatParallel";
|
|
36
|
+
sounds: BeatSound[];
|
|
37
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isSupportedNote: (value: string) => boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Token = {
|
|
2
|
+
type: "identifier";
|
|
3
|
+
value: string;
|
|
4
|
+
} | {
|
|
5
|
+
type: "string";
|
|
6
|
+
value: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: "number";
|
|
9
|
+
value: number;
|
|
10
|
+
} | {
|
|
11
|
+
type: "symbol";
|
|
12
|
+
value: '(' | ')' | '.' | ',';
|
|
13
|
+
};
|
|
14
|
+
export declare const tokenize: (source: string) => Token[];
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibuca/synth8-core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "vite build",
|
|
21
|
+
"test": "vitest run"
|
|
22
|
+
}
|
|
23
|
+
}
|