:(\d+):(\d+)/);
- if (match)
+ if (match as RegExpMatchArray)
return {
line: parseInt(match[1], 10),
column: parseInt(match[2], 10),
diff --git a/src/API/Counter.ts b/src/API/Counter.ts
index bf87c87..92f5f98 100644
--- a/src/API/Counter.ts
+++ b/src/API/Counter.ts
@@ -36,8 +36,8 @@ export const counter = (api: UserAPI) => (name: string | number, limit?: number,
export const i = (app: Editor) => (n?: number) => {
if (n !== undefined) {
- app.universes[app.selected_universe].global.evaluations = n;
+ app.universes[app.selected_universe]!.global.evaluations = n;
return app.universes[app.selected_universe];
}
- return app.universes[app.selected_universe].global.evaluations as number;
+ return app.universes[app.selected_universe]!.global.evaluations as number;
};
diff --git a/src/API/Time/Transport.ts b/src/API/Time/Transport.ts
index 98f5c32..975aefe 100644
--- a/src/API/Time/Transport.ts
+++ b/src/API/Time/Transport.ts
@@ -43,7 +43,7 @@ export const bpb = (app: Editor) => (n?: number): number => {
/**
* Sets or returns the number of beats per bar.
*/
- if (n === undefined) return app.clock.time_signature[0];
+ if (n === undefined) return app.clock.time_signature[0] || 4;
if (n >= 1) {
app.clock.time_signature[0] = n;
@@ -103,11 +103,11 @@ export const epulse = (app: Editor) => (): number => {
};
export const nominator = (app: Editor) => (): number => {
- return app.clock.time_signature[0];
+ return app.clock.time_signature[0] || 4;
};
export const meter = (app: Editor) => (): number => {
- return app.clock.time_signature[1];
+ return app.clock.time_signature[1] || 4;
};
export const denominator = meter;
diff --git a/src/DOM/DomElements.ts b/src/DOM/DomElements.ts
index e014f91..fe5feaf 100644
--- a/src/DOM/DomElements.ts
+++ b/src/DOM/DomElements.ts
@@ -1,19 +1,7 @@
import { type Editor } from "../main";
-export type ElementMap = {
- [key: string]:
- | HTMLElement
- | HTMLButtonElement
- | HTMLDivElement
- | HTMLInputElement
- | HTMLSelectElement
- | HTMLCanvasElement
- | HTMLFormElement
- | HTMLInputElement;
-};
-
export const singleElements = {
- topos_logo: "topos-logo",
+ logo: "topos_logo",
fill_viewer: "fillviewer",
load_universe_button: "load-universe-button",
download_universe_button: "download-universes",
@@ -56,6 +44,20 @@ export const singleElements = {
error_line: "error_line",
hydra_canvas: "hydra-bg",
feedback: "feedback",
+} as const;
+
+export type SingleElementsKeys = keyof typeof singleElements;
+
+export type ElementMap = {
+ [K in SingleElementsKeys]:
+ | HTMLElement
+ | HTMLButtonElement
+ | HTMLDivElement
+ | HTMLInputElement
+ | HTMLSelectElement
+ | HTMLCanvasElement
+ | HTMLFormElement
+ | HTMLInputElement;
};
export const buttonGroups = {
diff --git a/src/DOM/UILogic.ts b/src/DOM/UILogic.ts
index a096dbc..4b154d4 100644
--- a/src/DOM/UILogic.ts
+++ b/src/DOM/UILogic.ts
@@ -50,30 +50,30 @@ export const installInterfaceLogic = (app: Editor) => {
const tabs = document.querySelectorAll('[id^="tab-"]');
// Iterate over the tabs with an index
for (let i = 0; i < tabs.length; i++) {
- tabs[i].addEventListener("click", (event) => {
+ tabs[i]!.addEventListener("click", (event) => {
// Updating the CSS accordingly
- tabs[i].classList.add("bg-foreground");
- tabs[i].classList.add("text-selection_foreground");
+ tabs[i]!.classList.add("bg-foreground");
+ tabs[i]!.classList.add("text-selection_foreground");
for (let j = 0; j < tabs.length; j++) {
- if (j != i) tabs[j].classList.remove("bg-foreground");
- if (j != i) tabs[j].classList.remove("text-selection_foreground");
+ if (j != i) tabs[j]!.classList.remove("bg-foreground");
+ if (j != i) tabs[j]!.classList.remove("text-selection_foreground");
}
app.currentFile().candidate = app.view.state.doc.toString();
let tab = event.target as HTMLElement;
let tab_id = tab.id.split("-")[1];
- app.local_index = parseInt(tab_id);
+ app.local_index = parseInt(tab_id!);
app.updateEditorView();
});
}
- app.interface.topos_logo.addEventListener("click", () => {
+ app.interface['logo'].addEventListener("click", () => {
hideDocumentation();
app.updateKnownUniversesView();
openUniverseModal();
});
- app.buttonElements.play_buttons.forEach((button) => {
+ app.buttonElements['play_buttons']!.forEach((button) => {
button.addEventListener("click", () => {
if (app.isPlaying) {
app.setButtonHighlighting("pause", true);
@@ -89,7 +89,7 @@ export const installInterfaceLogic = (app: Editor) => {
});
});
- app.buttonElements.clear_buttons.forEach((button) => {
+ app.buttonElements['clear_buttons']!.forEach((button) => {
button.addEventListener("click", () => {
app.setButtonHighlighting("clear", true);
if (confirm("Do you want to reset the current universe?")) {
@@ -239,7 +239,7 @@ export const installInterfaceLogic = (app: Editor) => {
app.flashBackground("#404040", 200);
});
- app.buttonElements.stop_buttons.forEach((button) => {
+ app.buttonElements['stop_buttons']!.forEach((button) => {
button.addEventListener("click", () => {
app.setButtonHighlighting("stop", true);
app.isPlaying = false;
@@ -516,7 +516,7 @@ export const installInterfaceLogic = (app: Editor) => {
}
});
- tryEvaluate(app, app.universes[app.selected_universe.toString()].init);
+ tryEvaluate(app, app.universes[app.selected_universe.toString()]!.init);
documentation_pages.forEach((e) => {
let name = `docs_` + e;
diff --git a/src/DOM/Visuals/Blinkers.ts b/src/DOM/Visuals/Blinkers.ts
index 666bd2f..6e3b58b 100644
--- a/src/DOM/Visuals/Blinkers.ts
+++ b/src/DOM/Visuals/Blinkers.ts
@@ -38,7 +38,7 @@ export const blinkScript = (
) => {
if (no !== undefined && no < 1 && no > 9) return;
const blinkDuration =
- (app.clock.bpm / 60 / app.clock.time_signature[1]) * 200;
+ (app.clock.bpm / 60 / app.clock.time_signature[1]!) * 200;
// @ts-ignore
const ctx = app.interface.feedback.getContext("2d");
diff --git a/src/DOM/Visuals/Oscilloscope.ts b/src/DOM/Visuals/Oscilloscope.ts
index e0be360..fe6aa02 100644
--- a/src/DOM/Visuals/Oscilloscope.ts
+++ b/src/DOM/Visuals/Oscilloscope.ts
@@ -71,7 +71,7 @@ export const runOscilloscope = (
for (let i = 0; i < numBars; i++) {
barHeight = Math.floor(
- freqDataArray[Math.floor((i * freqDataArray.length) / numBars)] *
+ freqDataArray[Math.floor((i * freqDataArray.length) / numBars)]! *
((height / 256) * app.osc.size),
);
@@ -165,9 +165,9 @@ export const runOscilloscope = (
let startIndex = 0;
for (let i = 1; i < dataArray.length; ++i) {
let currentType = null;
- if (dataArray[i] >= 0 && dataArray[i - 1] < 0) {
+ if (dataArray[i]! >= 0 && dataArray[i - 1]! < 0) {
currentType = "negToPos";
- } else if (dataArray[i] < 0 && dataArray[i - 1] >= 0) {
+ } else if (dataArray[i]! < 0 && dataArray[i - 1]! >= 0) {
currentType = "posToNeg";
}
@@ -187,8 +187,8 @@ export const runOscilloscope = (
drawFrequencyScope(WIDTH, HEIGHT, OFFSET_HEIGHT, OFFSET_WIDTH);
} else if (app.osc.mode === "3D") {
for (let i = startIndex; i < dataArray.length; i += 2) {
- const x = (dataArray[i] * WIDTH * app.osc.size) / 2 + WIDTH / 4;
- const y = (dataArray[i + 1] * HEIGHT * app.osc.size) / 2 + HEIGHT / 4;
+ const x = (dataArray[i]! * WIDTH * app.osc.size) / 2 + WIDTH / 4;
+ const y = (dataArray[i + 1]! * HEIGHT * app.osc.size) / 2 + HEIGHT / 4;
i === startIndex ? canvasCtx.moveTo(x, y) : canvasCtx.lineTo(x, y);
}
} else if (
@@ -199,7 +199,7 @@ export const runOscilloscope = (
const yOffset = HEIGHT / 4;
let x = 0;
for (let i = startIndex; i < dataArray.length; i++) {
- const v = dataArray[i] * 0.5 * HEIGHT * app.osc.size;
+ const v = dataArray[i]! * 0.5 * HEIGHT * app.osc.size;
const y = v + yOffset;
i === startIndex ? canvasCtx.moveTo(x, y) : canvasCtx.lineTo(x, y);
x += sliceWidth;
@@ -210,7 +210,7 @@ export const runOscilloscope = (
const xOffset = WIDTH / 4;
let y = 0;
for (let i = startIndex; i < dataArray.length; i++) {
- const v = dataArray[i] * 0.5 * WIDTH * app.osc.size;
+ const v = dataArray[i]! * 0.5 * WIDTH * app.osc.size;
const x = v + xOffset;
i === startIndex ? canvasCtx.moveTo(x, y) : canvasCtx.lineTo(x, y);
y += sliceHeight;
diff --git a/src/Docs/Documentation.ts b/src/Docs/Documentation.ts
index be65f5a..6d53fbd 100644
--- a/src/Docs/Documentation.ts
+++ b/src/Docs/Documentation.ts
@@ -249,7 +249,7 @@ export const updateDocumentationContent = (app: Editor, bindings: any) => {
function _update_and_assign(callback: Function) {
const converted_markdown = converter.makeHtml(
- app.docs[app.currentDocumentationPane],
+ app.docs[app.currentDocumentationPane]!,
);
callback(converted_markdown)
}
diff --git a/src/Docs/inlineHelp.ts b/src/Docs/inlineHelp.ts
index d0dd249..05ef559 100644
--- a/src/Docs/inlineHelp.ts
+++ b/src/Docs/inlineHelp.ts
@@ -940,7 +940,7 @@ const completionDatabase: CompletionDatabase = {
description: "Noise amount in the signal (0-1)",
example: "sound('triangle').noise(.25).out()",
},
-};
+} as const;
export const inlineHoveringTips = hoverTooltip(
(view: any, pos: any, side: any) => {
@@ -962,8 +962,7 @@ export const inlineHoveringTips = hoverTooltip(
) {
return { dom: document.createElement("div") };
}
- let completion =
- completionDatabase[text.slice(start - from, end - from)] || {};
+ let completion = completionDatabase[text.slice(start - from, end - from)]!;
let divContent = `
${completion.name} [${completion.category}]
${completion.description}
@@ -986,13 +985,13 @@ export const toposCompletions = (context: CompletionContext) => {
from: word.from,
options: Object.keys(completionDatabase).map((key) => ({
label: key,
- type: completionDatabase[key].category,
+ type: completionDatabase[key]!.category,
info: () => {
let div = document.createElement("div");
div.innerHTML = `
- ${completionDatabase[key].name} [${completionDatabase[key].category}]
- ${completionDatabase[key].description}
- ${completionDatabase[key].example}
+ ${completionDatabase[key]!.name} [${completionDatabase[key]!.category}]
+ ${completionDatabase[key]!.description}
+ ${completionDatabase[key]!.example}
`;
div.classList.add("px-4", "py-2", "rounded-lg", "w-92");
return div;
@@ -1000,6 +999,7 @@ export const toposCompletions = (context: CompletionContext) => {
})),
};
}
+ return null
};
export const soundCompletions = (context: CompletionContext) => {
diff --git a/src/Editor/FileManagement.ts b/src/Editor/FileManagement.ts
index 915504f..cb327b5 100644
--- a/src/Editor/FileManagement.ts
+++ b/src/Editor/FileManagement.ts
@@ -179,7 +179,7 @@ export class AppSettings {
}
get_universe() {
- this.universes.universe_name;
+ this.universes["universe_name"];
}
get data(): Settings {
@@ -356,7 +356,7 @@ export const loadUniverse = (
// Updating the editor View to reflect the selected universe
app.updateEditorView();
// Evaluating the initialisation script for the selected universe
- tryEvaluate(app, app.universes[app.selected_universe.toString()].init);
+ tryEvaluate(app, app.universes[app.selected_universe.toString()]!.init);
};
export const openUniverseModal = (): void => {
diff --git a/src/Evaluator.ts b/src/Evaluator.ts
index d2a55af..e56fd56 100644
--- a/src/Evaluator.ts
+++ b/src/Evaluator.ts
@@ -18,7 +18,7 @@ async function tryCatchWrapper(application: Editor, code: string): Promise ['wav', 'mp3'].includes(filename.split('.').slice(-1)[0]);
+export const isAudioFile = (filename: string) => {
+ const extension = filename.split('.').slice(-1)[0];
+ return extension !== undefined && ['wav', 'mp3'].includes(extension);
+};
interface samplesDBConfig {
dbName: string,
diff --git a/src/classes/ZPlayer.ts b/src/classes/ZPlayer.ts
index a8868a2..29d265e 100644
--- a/src/classes/ZPlayer.ts
+++ b/src/classes/ZPlayer.ts
@@ -30,7 +30,7 @@ export class Player extends AbstractEvent {
constructor(
input: string | number | Generator,
options: InputOptions,
- public app: Editor,
+ app: Editor,
zid: string = "",
waitTime: number = 0,
) {
@@ -191,7 +191,7 @@ export class Player extends AbstractEvent {
}
}
- sound(name?: string | string[] | SoundParams | SoundParams[]) {
+ public sound(name?: string | string[] | SoundParams | SoundParams[]) {
if (this.areWeThereYet()) {
this.checkCue();
const event = this.next() as Pitch | Chord | ZRest;
@@ -252,7 +252,7 @@ export class Player extends AbstractEvent {
}
}
- midi(value: number | undefined = undefined) {
+ public midi(value: number | undefined = undefined) {
if (this.areWeThereYet()) {
this.checkCue();
const event = this.next() as Pitch | Chord | ZRest;
diff --git a/src/clock/Clock.ts b/src/clock/Clock.ts
index 5159714..3bf7647 100644
--- a/src/clock/Clock.ts
+++ b/src/clock/Clock.ts
@@ -82,7 +82,7 @@ export class Clock {
* @returns The TimePosition object representing the converted ticks.
*/
- const beatsPerBar = this.app.clock.time_signature[0];
+ const beatsPerBar = this.app.clock.time_signature[0]!;
const ppqnPosition = ticks % this.app.clock.ppqn;
const beatNumber = Math.floor(ticks / this.app.clock.ppqn);
const barNumber = Math.floor(beatNumber / beatsPerBar);
@@ -116,7 +116,7 @@ export class Clock {
/**
* Returns the number of beats per bar.
*/
- return this.time_signature[0];
+ return this.time_signature[0] || 4;
}
get beats_since_origin(): number {
diff --git a/src/extensions/ArrayExtensions.ts b/src/extensions/ArrayExtensions.ts
index 11c3355..d089862 100644
--- a/src/extensions/ArrayExtensions.ts
+++ b/src/extensions/ArrayExtensions.ts
@@ -47,8 +47,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
const screenWidth = window.innerWidth;
const zoneWidth = screenWidth / this.length;
const zoneIndex = Math.floor(mouse_position / zoneWidth);
-
- return this[zoneIndex];
+ return this[zoneIndex]!;
};
Array.prototype.mouseY = function (this: T[]): T {
@@ -56,8 +55,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
const screenHeight = window.innerHeight;
const zoneHeight = screenHeight / this.length;
const zoneIndex = Math.floor(mouse_position / zoneHeight);
-
- return this[zoneIndex];
+ return this[zoneIndex]!;
};
Array.prototype.square = function(): number[] {
@@ -175,7 +173,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
Array.prototype.dur = function(...durations: number[]) {
const timepos = api.app.clock.pulses_since_origin;
const ppqn = api.ppqn();
- const adjustedDurations: number[] = this.map(
+ const adjustedDurations = this.map(
(_, index) => durations[index % durations.length],
);
const totalDurationInPulses = adjustedDurations.reduce(
@@ -183,7 +181,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
(acc, duration) => acc + duration * ppqn,
0,
);
- const loopPosition = timepos % totalDurationInPulses;
+ const loopPosition = timepos % totalDurationInPulses!;
let cumulativeDuration = 0;
for (let i = 0; i < this.length; i++) {
const valueDurationInPulses = (adjustedDurations[i] as any) * ppqn;
@@ -295,12 +293,12 @@ export const makeArrayExtensions = (api: UserAPI) => {
let result = [];
for (let i = 0; i < this.length; i++) {
for (let j = 0; j < amount; j++) {
- result.push(this[i]);
+ result.push(this[i] as T);
}
}
this.length = 0;
- this.push(...result);
+ this.push(...result as T[]);
return this;
};
@@ -322,15 +320,15 @@ export const makeArrayExtensions = (api: UserAPI) => {
// If the index is even, repeat the element
if (i % 2 === 0) {
for (let j = 0; j < amount; j++) {
- result.push(this[i]);
+ result.push(this[i] as T);
}
} else {
- result.push(this[i]);
+ result.push(this[i] as T);
}
}
this.length = 0;
- this.push(...result);
+ this.push(...result as T[]);
return this;
};
@@ -355,10 +353,10 @@ export const makeArrayExtensions = (api: UserAPI) => {
// If the index is odd, repeat the element
if (i % 2 !== 0) {
for (let j = 0; j < amount; j++) {
- result.push(this[i]);
+ result.push(this[i] as T);
}
} else {
- result.push(this[i]);
+ result.push(this[i] as T);
}
}
@@ -442,7 +440,7 @@ Array.prototype.scale = function(
return this.map((value) => {
const octaveShift = Math.floor(value / selected_scale.length) * 12;
return (
- selected_scale[mod(Math.floor(value), selected_scale.length)] +
+ selected_scale[mod(Math.floor(value), selected_scale.length)]! +
base_note +
octaveShift
);
diff --git a/src/extensions/StringExtensions.ts b/src/extensions/StringExtensions.ts
index 1f7d585..714abcd 100644
--- a/src/extensions/StringExtensions.ts
+++ b/src/extensions/StringExtensions.ts
@@ -187,7 +187,7 @@ export class Speaker {
utterance.pitch = this.options.pitch || 1;
utterance.volume = this.options.volume || 1;
if (this.options.voice) {
- utterance.voice = synth.getVoices()[this.options.voice];
+ utterance.voice = synth.getVoices()[this.options.voice]!;
}
if (this.options.lang) {
// Check if language has country code
diff --git a/src/main.ts b/src/main.ts
index a83d783..03ba582 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -69,7 +69,7 @@ export class Editor {
show_error: boolean = false;
currentThemeName: string = "Everblush";
buttonElements: Record = {};
- interface: ElementMap = {};
+ interface!: ElementMap;
blinkTimeouts: Record = {};
osc: OscilloscopeConfig = {
enabled: false,
@@ -126,7 +126,6 @@ export class Editor {
this.initializeElements();
this.initializeButtonGroups();
this.setCanvas(this.interface["feedback"] as HTMLCanvasElement);
- // this.loadHydraSynthAsync();
// ================================================================================
// Loading the universe from local storage
@@ -356,29 +355,29 @@ export class Editor {
this.local_index = 0;
document.getElementById("editor")!.style.height = "calc(100% - 100px)";
this.changeToLocalBuffer(this.local_index);
- changeColor(this.interface.local_button);
+ changeColor(this.interface["local_button"]);
break;
case "global":
- if (!this.interface.local_script_tabs.classList.contains("hidden")) {
- this.interface.local_script_tabs.classList.add("hidden");
+ if (!this.interface["local_script_tabs"].classList.contains("hidden")) {
+ this.interface["local_script_tabs"].classList.add("hidden");
}
this.editor_mode = "global";
document.getElementById("editor")!.style.height = "100%";
- changeColor(this.interface.global_button);
+ changeColor(this.interface["global_button"]);
break;
case "init":
- if (!this.interface.local_script_tabs.classList.contains("hidden")) {
- this.interface.local_script_tabs.classList.add("hidden");
+ if (!this.interface["local_script_tabs"].classList.contains("hidden")) {
+ this.interface["local_script_tabs"].classList.add("hidden");
}
this.editor_mode = "init";
- changeColor(this.interface.init_button);
+ changeColor(this.interface["init_button"]);
break;
case "notes":
- if (!this.interface.local_script_tabs.classList.contains("hidden")) {
- this.interface.local_script_tabs.classList.add("hidden");
+ if (!this.interface["local_script_tabs"].classList.contains("hidden")) {
+ this.interface["local_script_tabs"].classList.add("hidden");
}
this.editor_mode = "notes";
- changeColor(this.interface.note_button);
+ changeColor(this.interface["note_button"]);
break;
}
@@ -441,19 +440,26 @@ export class Editor {
selector = 3;
break;
}
- document
- .querySelectorAll(possible_selectors[selector])
- .forEach((button) => {
- if (highlight) button.children[0].classList.add("animate-pulse");
- });
+ const selectorValue = possible_selectors[selector];
+ if (selectorValue) {
+ document
+ .querySelectorAll(selectorValue)
+ .forEach((button) => {
+ if (highlight && button.children[0]) button.children[0].classList.add("animate-pulse");
+ });
+ }
// All other buttons must lose the highlighting
document
.querySelectorAll(
possible_selectors.filter((_, index) => index != selector).join(","),
)
.forEach((button) => {
- button.children[0].classList.remove("animate-pulse");
- button.children[1].classList.remove("animate-pulse");
+ if (button.children[0]) {
+ button.children[0].classList.remove("animate-pulse");
+ }
+ if (button.children[1]) {
+ button.children[1].classList.remove("animate-pulse");
+ }
});
}
@@ -525,7 +531,7 @@ export class Editor {
private initializeElements(): void {
for (const [key, value] of Object.entries(singleElements)) {
- this.interface[key] = document.getElementById(
+ this.interface[key as keyof ElementMap] = document.getElementById(
value,
) as ElementMap[keyof ElementMap];
}