@scorelabs/core 1.0.9 → 1.0.11

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.
@@ -1,6 +1,6 @@
1
- import { Measure } from './Measure';
2
- import { Part } from './Part';
3
- import { Duration, Genre, decomposeDuration } from './types';
1
+ import { Measure } from './Measure.js';
2
+ import { Part } from './Part.js';
3
+ import { Duration, Genre, decomposeDuration } from './types.js';
4
4
  /**
5
5
  * Represents a complete musical score.
6
6
  */
@@ -19,7 +19,8 @@ export class Score {
19
19
  subtitle;
20
20
  genre;
21
21
  tempoText;
22
- constructor(title, composer, timeSignature, keySignature, parts, bpm = 120, tempoDuration = Duration.Quarter, tempoIsDotted = false, copyright = '', lyricist = '', swing = false, subtitle = '', genre = Genre.Unknown, tempoText = '') {
22
+ tempoDotCount;
23
+ constructor(title, composer, timeSignature, keySignature, parts, bpm = 120, tempoDuration = Duration.Quarter, tempoIsDotted = false, copyright = '', lyricist = '', swing = false, subtitle = '', genre = Genre.Unknown, tempoText = '', tempoDotCount = 0) {
23
24
  this.title = title;
24
25
  this.composer = composer;
25
26
  this.timeSignature = timeSignature;
@@ -34,18 +35,22 @@ export class Score {
34
35
  this.subtitle = subtitle;
35
36
  this.genre = genre;
36
37
  this.tempoText = tempoText;
38
+ this.tempoDotCount = tempoDotCount;
37
39
  }
38
40
  withTitle(title) {
39
- return new Score(title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
41
+ return new Score(title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
40
42
  }
41
43
  withComposer(composer) {
42
- return new Score(this.title, composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
44
+ return new Score(this.title, composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
43
45
  }
44
46
  withSubtitle(subtitle) {
45
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, subtitle, this.genre, this.tempoText);
47
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, subtitle, this.genre, this.tempoText, this.tempoDotCount);
46
48
  }
47
49
  withGenre(genre) {
48
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, genre, this.tempoText);
50
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, genre, this.tempoText, this.tempoDotCount);
51
+ }
52
+ withBpm(bpm) {
53
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
49
54
  }
50
55
  getMeasureCount() {
51
56
  return this.parts[0]?.getMeasureCount() ?? 0;
@@ -88,7 +93,7 @@ export class Score {
88
93
  }
89
94
  static fromJSON(data) {
90
95
  const parts = data.parts.map((p) => Part.fromJSON(p));
91
- return new Score(data.title, data.composer, data.timeSignature, data.keySignature, parts, data.bpm ?? 120, data.tempoDuration ?? Duration.Quarter, data.tempoIsDotted ?? false, data.copyright ?? '', data.lyricist ?? '', data.swing ?? false, data.subtitle ?? '', data.genre || Genre.Unknown, data.tempoText ?? '');
96
+ return new Score(data.title, data.composer, data.timeSignature, data.keySignature, parts, data.bpm ?? 120, data.tempoDuration ?? Duration.Quarter, data.tempoIsDotted ?? false, data.copyright ?? '', data.lyricist ?? '', data.swing ?? false, data.subtitle ?? '', data.genre || Genre.Unknown, data.tempoText ?? '', data.tempoDotCount ?? (data.tempoIsDotted ? 1 : 0));
92
97
  }
93
98
  transpose(semitones) {
94
99
  const semitoneToFifths = {
@@ -112,7 +117,7 @@ export class Score {
112
117
  newFifths -= 12;
113
118
  while (newFifths < -7)
114
119
  newFifths += 12;
115
- return new Score(this.title, this.composer, this.timeSignature, { fifths: newFifths }, this.parts.map((p) => p.transpose(semitones)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
120
+ return new Score(this.title, this.composer, this.timeSignature, { fifths: newFifths }, this.parts.map((p) => p.transpose(semitones)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
116
121
  }
117
122
  replaceNote(partIndex, staffIndex, measureIndex, noteIndex, newNote, voiceIndex = 0) {
118
123
  if (partIndex < 0 || partIndex >= this.parts.length)
@@ -122,10 +127,10 @@ export class Score {
122
127
  return this.replaceMeasure(partIndex, staffIndex, measureIndex, updatedMeasure, true);
123
128
  }
124
129
  withKeySignature(keySig) {
125
- return new Score(this.title, this.composer, this.timeSignature, keySig, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
130
+ return new Score(this.title, this.composer, this.timeSignature, keySig, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
126
131
  }
127
132
  withTimeSignature(timeSig) {
128
- return new Score(this.title, this.composer, timeSig, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
133
+ return new Score(this.title, this.composer, timeSig, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
129
134
  }
130
135
  updateMeasureSignatures(measureIndex, signatures, autoBeam = true) {
131
136
  let score = this;
@@ -170,7 +175,7 @@ export class Score {
170
175
  for (let sIdx = 0; sIdx < currentScore.parts[pIdx].staves.length; sIdx++) {
171
176
  const staff = currentScore.parts[pIdx].staves[sIdx];
172
177
  if (staff.measures.length < maxMeasures) {
173
- let updatedMsrs = [...staff.measures];
178
+ const updatedMsrs = [...staff.measures];
174
179
  for (let i = staff.measures.length; i < maxMeasures; i++) {
175
180
  const ts = currentScore.getTimeSignatureAt(i);
176
181
  const targetDur = ts.beats * (4 / ts.beatType);
@@ -201,10 +206,10 @@ export class Score {
201
206
  const staff = this.parts[pIdx].staves[sIdx];
202
207
  const measures = staff.measures;
203
208
  const maxVoices = Math.max(...measures.map((m) => m.voices.length), 1);
204
- let updatedMeasures = [...measures];
209
+ const updatedMeasures = [...measures];
205
210
  for (let vIdx = 0; vIdx < maxVoices; vIdx++) {
206
211
  // 1. Collect notes and merge tied notes into logical streams
207
- let stream = [];
212
+ const stream = [];
208
213
  for (let mIdx = fromMeasureIndex; mIdx < measures.length; mIdx++) {
209
214
  const msr = measures[mIdx];
210
215
  const voice = msr.voices[vIdx] || [];
@@ -295,7 +300,7 @@ export class Score {
295
300
  }
296
301
  const newParts = [...this.parts];
297
302
  newParts[partIndex] = newParts[partIndex].replaceMeasure(staffIndex, measureIndex, measureToUse);
298
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
303
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
299
304
  }
300
305
  deleteNote(partIndex, staffIndex, measureIndex, noteIndex, voiceIndex = 0) {
301
306
  if (partIndex < 0 || partIndex >= this.parts.length)
@@ -311,6 +316,15 @@ export class Score {
311
316
  const updatedMeasure = measure.changeNoteDuration(noteIndex, newDuration, isDotted, voiceIndex);
312
317
  return this.replaceMeasure(partIndex, staffIndex, measureIndex, updatedMeasure, true);
313
318
  }
319
+ moveNoteToVoice(partIndex, staffIndex, measureIndex, noteIndex, fromVoiceIndex, toVoiceIndex) {
320
+ if (partIndex < 0 || partIndex >= this.parts.length)
321
+ return this;
322
+ const measure = this.parts[partIndex].staves[staffIndex].measures[measureIndex];
323
+ if (!measure)
324
+ return this;
325
+ const updatedMeasure = measure.moveNoteToVoice(fromVoiceIndex, noteIndex, toVoiceIndex);
326
+ return this.replaceMeasure(partIndex, staffIndex, measureIndex, updatedMeasure, true);
327
+ }
314
328
  pasteNotes(partIndex, staffIndex, measureIndex, noteIndex, notesToPaste) {
315
329
  if (partIndex < 0 || partIndex >= this.parts.length)
316
330
  return this;
@@ -370,22 +384,22 @@ export class Score {
370
384
  return newScore;
371
385
  }
372
386
  withTempo(bpm, duration, isDotted) {
373
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, bpm, duration, isDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
387
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, bpm, duration, isDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
374
388
  }
375
389
  withTempoText(text) {
376
390
  return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, text);
377
391
  }
378
392
  withSwing(swing) {
379
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, swing, this.subtitle, this.genre, this.tempoText);
393
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
380
394
  }
381
395
  withLyricist(lyricist) {
382
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
396
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
383
397
  }
384
398
  withCopyright(copyright) {
385
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
399
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
386
400
  }
387
401
  withParts(parts) {
388
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
402
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
389
403
  }
390
404
  toJSON() {
391
405
  return {
@@ -403,6 +417,7 @@ export class Score {
403
417
  subtitle: this.subtitle,
404
418
  genre: this.genre,
405
419
  tempoText: this.tempoText,
420
+ tempoDotCount: this.tempoDotCount,
406
421
  };
407
422
  }
408
423
  replacePart(partIndex, newPart) {
@@ -410,29 +425,29 @@ export class Score {
410
425
  return this;
411
426
  const newParts = [...this.parts];
412
427
  newParts[partIndex] = newPart;
413
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
428
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
414
429
  }
415
430
  addPart(newPart) {
416
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, [...this.parts, newPart], this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
431
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, [...this.parts, newPart], this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
417
432
  }
418
433
  removePart(partIndex) {
419
434
  if (partIndex < 0 || partIndex >= this.parts.length)
420
435
  return this;
421
436
  const newParts = this.parts.filter((_, i) => i !== partIndex);
422
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
437
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
423
438
  }
424
439
  replaceStaff(partIndex, staffIndex, newStaff) {
425
440
  if (partIndex < 0 || partIndex >= this.parts.length)
426
441
  return this;
427
442
  const newParts = [...this.parts];
428
443
  newParts[partIndex] = newParts[partIndex].replaceStaff(staffIndex, newStaff);
429
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
444
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, newParts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
430
445
  }
431
446
  addMeasure(index, measure) {
432
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts.map((p) => p.addMeasure(index, measure)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
447
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts.map((p) => p.addMeasure(index, measure)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
433
448
  }
434
449
  deleteMeasure(index) {
435
- return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts.map((p) => p.deleteMeasure(index)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
450
+ return new Score(this.title, this.composer, this.timeSignature, this.keySignature, this.parts.map((p) => p.deleteMeasure(index)), this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText, this.tempoDotCount);
436
451
  }
437
452
  getPlaybackSequence() {
438
453
  const measures = this.parts[0]?.staves[0]?.measures || [];
@@ -1,7 +1,7 @@
1
- import { Measure, MeasureJSON } from './Measure';
2
- import { Note } from './Note';
3
- import { Pitch } from './Pitch';
4
- import { Clef, Duration } from './types';
1
+ import { Measure, MeasureJSON } from './Measure.js';
2
+ import { Note } from './Note.js';
3
+ import { Pitch } from './Pitch.js';
4
+ import { Clef, Duration } from './types.js';
5
5
  /**
6
6
  * Represents a single staff (one set of 5 lines with a clef).
7
7
  */
@@ -1,5 +1,5 @@
1
- import { Measure } from './Measure';
2
- import { Pitch } from './Pitch';
1
+ import { Measure } from './Measure.js';
2
+ import { Pitch } from './Pitch.js';
3
3
  /**
4
4
  * Represents a single staff (one set of 5 lines with a clef).
5
5
  */
@@ -1,10 +1,10 @@
1
- export * from './types';
2
- export * from './Pitch';
3
- export * from './Note';
4
- export * from './NoteSet';
5
- export * from './Measure';
6
- export * from './Staff';
7
- export * from './Part';
8
- export * from './Score';
9
- export * from './Instrument';
10
- export * from './PreMeasure';
1
+ export * from './types.js';
2
+ export * from './Pitch.js';
3
+ export * from './Note.js';
4
+ export * from './NoteSet.js';
5
+ export * from './Measure.js';
6
+ export * from './Staff.js';
7
+ export * from './Part.js';
8
+ export * from './Score.js';
9
+ export * from './Instrument.js';
10
+ export * from './PreMeasure.js';
@@ -1,10 +1,10 @@
1
- export * from './types';
2
- export * from './Pitch';
3
- export * from './Note';
4
- export * from './NoteSet';
5
- export * from './Measure';
6
- export * from './Staff';
7
- export * from './Part';
8
- export * from './Score';
9
- export * from './Instrument';
10
- export * from './PreMeasure';
1
+ export * from './types.js';
2
+ export * from './Pitch.js';
3
+ export * from './Note.js';
4
+ export * from './NoteSet.js';
5
+ export * from './Measure.js';
6
+ export * from './Staff.js';
7
+ export * from './Part.js';
8
+ export * from './Score.js';
9
+ export * from './Instrument.js';
10
+ export * from './PreMeasure.js';
@@ -10,6 +10,10 @@ export declare enum Duration {
10
10
  TwoHundredFiftySixth = "two-hundred-fifty-sixth"
11
11
  }
12
12
  export declare const DURATION_VALUES: Record<Duration, number>;
13
+ /**
14
+ * Calculates the numeric duration value (quarter = 1) for a given duration and dot count.
15
+ */
16
+ export declare function calculateDurationValue(duration: Duration, dotCount?: number): number;
13
17
  /**
14
18
  * Decomposes a duration value (quarter = 1) into a list of duration/dot pairs.
15
19
  */
@@ -22,6 +22,19 @@ export const DURATION_VALUES = {
22
22
  [Duration.OneHundredTwentyEighth]: 0.03125,
23
23
  [Duration.TwoHundredFiftySixth]: 0.015625,
24
24
  };
25
+ /**
26
+ * Calculates the numeric duration value (quarter = 1) for a given duration and dot count.
27
+ */
28
+ export function calculateDurationValue(duration, dotCount = 0) {
29
+ const base = DURATION_VALUES[duration];
30
+ let multiplier = 1;
31
+ let dotValue = 0.5;
32
+ for (let i = 0; i < dotCount; i++) {
33
+ multiplier += dotValue;
34
+ dotValue /= 2;
35
+ }
36
+ return base * multiplier;
37
+ }
25
38
  /**
26
39
  * Decomposes a duration value (quarter = 1) into a list of duration/dot pairs.
27
40
  */
@@ -3,6 +3,7 @@ export interface Tempo {
3
3
  bpm: number;
4
4
  duration: Duration;
5
5
  isDotted: boolean;
6
+ dotCount?: number;
6
7
  text?: string;
7
8
  gradual?: 'ritardando' | 'accelerando';
8
9
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * WARNING: DO NOT ADD SENSITIVE LOGIC OR PRIVATE CONSTANTS TO THIS FILE.
3
+ * This package (@scorelabs/core) is used in public-facing frontend applications
4
+ * and could be exposed. Keep all token generation, verification, and encryption
5
+ * logic in the 'backend' or 'website' utilities.
6
+ */
7
+ export type UserTier = 'free' | 'premium';
8
+ export interface UserData {
9
+ accessToken?: string;
10
+ access_token?: string;
11
+ uuid?: string | number;
12
+ name?: string;
13
+ first_name?: string;
14
+ last_name?: string;
15
+ username?: string;
16
+ email?: string;
17
+ is_admin?: number | boolean;
18
+ id?: string | number;
19
+ tier?: UserTier | string;
20
+ picture?: string;
21
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * WARNING: DO NOT ADD SENSITIVE LOGIC OR PRIVATE CONSTANTS TO THIS FILE.
3
+ * This package (@scorelabs/core) is used in public-facing frontend applications
4
+ * and could be exposed. Keep all token generation, verification, and encryption
5
+ * logic in the 'backend' or 'website' utilities.
6
+ */
7
+ export {};
@@ -24,3 +24,4 @@ export * from './Pedal.js';
24
24
  export * from './Slur.js';
25
25
  export * from './Tuplet.js';
26
26
  export * from './Repeat.js';
27
+ export * from './User.js';
@@ -24,3 +24,4 @@ export * from './Pedal.js';
24
24
  export * from './Slur.js';
25
25
  export * from './Tuplet.js';
26
26
  export * from './Repeat.js';
27
+ export * from './User.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scorelabs/core",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Core logic and models for ScoreLabs music notation",
5
5
  "type": "module",
6
6
  "files": [
@@ -24,6 +24,7 @@
24
24
  "release:major": "npm version major && npm publish --access public",
25
25
  "release": "npm run release:patch",
26
26
  "test": "vitest",
27
+ "test:coverage": "vitest run --coverage",
27
28
  "lint": "eslint ."
28
29
  },
29
30
  "dependencies": {
@@ -32,6 +33,7 @@
32
33
  "devDependencies": {
33
34
  "@types/jszip": "^3.4.0",
34
35
  "@types/node": "^25.2.3",
36
+ "@vitest/coverage-v8": "^4.0.18",
35
37
  "typescript": "^5.9.3",
36
38
  "vitest": "^4.0.18"
37
39
  }