From 5a721bc50f6b9b3f487bb0d742648d7a23870f67 Mon Sep 17 00:00:00 2001 From: simonppg Date: Sat, 1 Jun 2024 15:39:25 -0700 Subject: [PATCH] Add a note parser --- __tests__/NoteParser.test.ts | 59 ++++++++++++++++++++++++++++++++++++ src/NoteDTO.ts | 5 +++ src/NoteParser.ts | 28 +++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 __tests__/NoteParser.test.ts create mode 100644 src/NoteDTO.ts create mode 100644 src/NoteParser.ts diff --git a/__tests__/NoteParser.test.ts b/__tests__/NoteParser.test.ts new file mode 100644 index 0000000..650b101 --- /dev/null +++ b/__tests__/NoteParser.test.ts @@ -0,0 +1,59 @@ +import {NoteParser} from "../src/NoteParser"; + +describe("NoteParser", () => { + let noteParser: NoteParser; + + beforeEach(() => { + noteParser = new NoteParser(); + }); + + it("should parse valid note strings", () => { + expect(noteParser.parseNote("C#4")).toEqual({ name: "C", accidental: "#", octave: 4 }); + expect(noteParser.parseNote("Db0")).toEqual({ name: "D", accidental: "b", octave: 0 }); + }); + + it("should parse valid note strings", () => { + // Valid note strings with different accidentals and octaves + expect(noteParser.parseNote("C#4")).toEqual({ name: "C", accidental: "#", octave: 4 }); + expect(noteParser.parseNote("Db0")).toEqual({ name: "D", accidental: "b", octave: 0 }); + expect(noteParser.parseNote("F3")).toEqual({ name: "F", octave: 3 }); + }); + + it("should throw an error for invalid note strings", () => { + // Test invalid note strings + expect(() => noteParser.parseNote("InvalidNote")).toThrowError("InvalidArgumentException"); + expect(() => noteParser.parseNote("")).toThrowError("InvalidArgumentException"); + expect(() => noteParser.parseNote("C#4#")).toThrowError("InvalidArgumentException"); + expect(() => noteParser.parseNote("#4")).toThrowError("InvalidArgumentException"); + }); + + it("should parse valid note strings", () => { + // Test valid note strings + expect(noteParser.parseNote("C#4")).toEqual({ name: "C", accidental: "#", octave: 4 }); + expect(noteParser.parseNote("Db0")).toEqual({ name: "D", accidental: "b", octave: 0 }); + expect(noteParser.parseNote("F")).toEqual({ name: "F", octave: 0 }); + expect(noteParser.parseNote("F#")).toEqual({ name: "F", accidental: "#", octave: 0 }); + expect(noteParser.parseNote("Ab4")).toEqual({ name: "A", accidental: "b", octave: 4 }); + }); + + it("should handle lowercase note names", () => { + // Valid note strings with lowercase note names + expect(noteParser.parseNote("C#4")).toEqual({ name: "C", accidental: "#", octave: 4 }); + expect(noteParser.parseNote("Db0")).toEqual({ name: "D", accidental: "b", octave: 0 }); + expect(noteParser.parseNote("F3")).toEqual({ name: "F", octave: 3 }); + }); + + it("should handle accidental without octave", () => { + // Valid note strings with accidentals but without octave + expect(noteParser.parseNote("C#")).toEqual({ name: "C", accidental: "#", octave: 0 }); + expect(noteParser.parseNote("Db")).toEqual({ name: "D", accidental: "b", octave: 0 }); + expect(noteParser.parseNote("F")).toEqual({ name: "F", octave: 0 }); + }); + + it("should handle note without accidental", () => { + // Valid note strings without accidentals + expect(noteParser.parseNote("C4")).toEqual({ name: "C", octave: 4 }); + expect(noteParser.parseNote("D0")).toEqual({ name: "D", octave: 0 }); + expect(noteParser.parseNote("F#3")).toEqual({ name: "F", accidental: "#", octave: 3 }); + }); +}); \ No newline at end of file diff --git a/src/NoteDTO.ts b/src/NoteDTO.ts new file mode 100644 index 0000000..8476dcb --- /dev/null +++ b/src/NoteDTO.ts @@ -0,0 +1,5 @@ +export type NoteDTO = { + name: string; // The name of the note (e.g., "C", "D", "E", etc.) + octave?: number; // The octave of the note (e.g., 4, 5, 6, etc.) + accidental?: string; // The accidental of the note (e.g., "#" or "b") +}; diff --git a/src/NoteParser.ts b/src/NoteParser.ts new file mode 100644 index 0000000..14f70ff --- /dev/null +++ b/src/NoteParser.ts @@ -0,0 +1,28 @@ +import {NoteDTO} from "./NoteDTO"; + +export class NoteParser { + parseNote(noteString: string): NoteDTO { + // Regular expression to match note strings with optional accidental and octave + const regex = /^([A-G])([#b]?)(\d*)$/; + + // Execute the regular expression on the input string + const match = regex.exec(noteString); + + // If there's no match, throw an error + if (!match) { + throw new Error("InvalidArgumentException"); + } + + // Extract components from the matched groups + const name = match[1]; + const accidental = match[2] || undefined; // Accidental may be empty + const octave = match[3] ? parseInt(match[3], 10) : 0; // Parse octave if present, otherwise set to 0 + + // Create and return the NoteDTO object + return { + name, + accidental, + octave + }; + } +} \ No newline at end of file