Skip to content

Commit

Permalink
Add some implicit type checking (ignorable) (#92)
Browse files Browse the repository at this point in the history
* format

* dont format assets

* add (optional) automatic type checking

* Revert "format"

This reverts commit 4e09b44.

* ignore some stuff

* readme
  • Loading branch information
TodePond authored Feb 15, 2025
1 parent 454048a commit cd428c2
Show file tree
Hide file tree
Showing 19 changed files with 205 additions and 100 deletions.
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
*-min.js
public/assets/*
pnpm-lock.yaml
package-lock.json
*.md
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ this project has been born out of a jam session, so let's carry that ethos into

<br>

there is some automatic type checking that goes on in the code, but you can just ignore it if u want.

<br>

# Technical stuff

welcome to the spaghetti of nudel
Expand Down
12 changes: 12 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"checkJs": true,
"lib": ["esnext", "dom"],
"target": "ESNext",
"moduleResolution": "nodenext",
"module": "NodeNext",
"strict": true,
"noImplicitAny": false
},
"exclude": []
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"codeformat": "prettier --write ."
"format": "prettier --write .",
"lint": "prettier --check ."
},
"devDependencies": {
"prettier": "^3.3.3",
Expand Down
2 changes: 2 additions & 0 deletions src/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const alertDialog = document.querySelector('#alert-dialog');
const alertMessageSpan = document.querySelector('#alert-message');

export async function nudelAlert(alertMessage = 'alert!') {
if (!alertDialog) throw new Error('alert-dialog not found');
if (!alertMessageSpan) throw new Error('alert-message not found');
alertMessageSpan.innerHTML = alertMessage;
alertDialog.showModal();
}
4 changes: 4 additions & 0 deletions src/confirm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const noButton = document.querySelector('#you-sure-no-button');
const actionDescriptionSpan = document.querySelector('#you-sure-action-description');

export async function nudelConfirm(message = 'Are you sure you want to do that???') {
if (!actionDescriptionSpan) throw new Error('you-sure-action-description not found');
if (!youSureDialog) throw new Error('you-sure-dialog not found');
if (!yesButton) throw new Error('you-sure-yes-button not found');
if (!noButton) throw new Error('you-sure-no-button not found');
actionDescriptionSpan.textContent = message;
youSureDialog.showModal();

Expand Down
36 changes: 36 additions & 0 deletions src/declare.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
interface Window {
updateMiniLocations: any;
highlightMiniLocations: any;
strudel: any;
strudelWindow: any;
editorViews: any;
useStrudelCanvas: any;
H: any;
fft: any;
P: any;
getSettings: any;
setSettings: any;
changeSettings: any;
setSettingsFromDom: any;
kabel: any;
kabelsalat: any;
}

// Pattern.prototype.p
interface p {
p: any;
}

// Some common properties to remove need for excessive typing
interface Element {
value?: string;
checked?: boolean;
showModal?: any;
focus?: any;
style: any;
showPopover?: any;
onclick?: any;
close?: any;
href?: string;
click?: any;
}
73 changes: 42 additions & 31 deletions src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ export class PastaMirror {
lineNumbers: (on) => (on ? lineNumbers() : []),
closeBrackets: (on) => (on ? closeBrackets() : []),
strudelAutocomplete: (on) =>
// @ts-expect-error
on ? autocompletion({ override: [strudelAutocomplete] }) : autocompletion({ override: [] }),
};
strudelOnlyExtensions = ['strudelAutocomplete']; // these extension keys are only active for strudel panes
compartments = {};
constructor() {
this.compartments = Object.fromEntries(Object.keys(this.extensions).map((key) => [key, new Compartment()]));
}
Expand Down Expand Up @@ -175,6 +177,7 @@ export class PastaMirror {
});

const slotsEl = document.querySelector('.slots');
if (!slotsEl) throw new Error('slots element not found');

const side = parseInt(doc.id) % 2 == 0 ? 'right' : 'left';

Expand All @@ -192,48 +195,53 @@ export class PastaMirror {
);

const tabsEl = document.querySelector(`.tabs .${side}`);
if (!tabsEl) throw new Error('tabs element not found');
tabsEl.insertAdjacentHTML(
'beforeend',
`<button class="tab ${side}" id="tab-${doc.id}">
${doc.id} ${doc.target}
</button>`,
);

document.querySelector(`#tab-${doc.id}`).addEventListener('click', () => {
document.querySelector(`#tab-${doc.id}`)?.addEventListener('click', () => {
tabsEl.querySelectorAll('.tab').forEach((tab) => {
tab.classList.remove('active');
});
document.querySelector(`#tab-${doc.id}`).classList.add('active');
document.querySelector(`#tab-${doc.id}`)?.classList.add('active');
this.editorViews.get(doc.id)?.focus();

slotsEl.querySelectorAll(`.slot.${side}`).forEach((slot) => {
slot.classList.remove('active');
});
slotsEl.querySelector(`#slot-${doc.id}`).classList.add('active');
slotsEl.querySelector(`#slot-${doc.id}`)?.classList.add('active');
});

const editorEl = document.querySelector(`#slot-${doc.id} .editor`);
if (!editorEl) throw new Error('editor element not found');
const view = new EditorView({
state,
parent: editorEl,
});
this.editorViews.set(doc.id, view);

// jsdoc to say its a select element
const targetEl = document.querySelector(`#slot-${doc.id} .target`);
if (!targetEl) throw new Error('target element not found');
if (!this.supportedTargets.includes(doc.target)) {
targetEl.insertAdjacentHTML('beforeend', `<option value="${doc.target}">? ${doc.target} ?</option>`);
console.warn(`unsupported target "${doc.target}" in doc "${doc.id}". evaluations will be ignored`);
}
targetEl.value = doc.target;

targetEl.addEventListener('change', (e) => {
doc.target = e.target.value;
doc.target = e.target?.['value'];
});
doc.session.on(`change-target:${doc.id}`, () => {
targetEl.value = doc.target;
});

const runButton = document.querySelector(`#slot-${doc.id} .run`);
if (!runButton) throw new Error('run button not found');
runButton.addEventListener('click', () => {
doc.evaluate(doc.content, { from: 0, to: doc.content.length });
});
Expand Down Expand Up @@ -265,47 +273,50 @@ export class PastaMirror {
deleteEditor(id) {
this.editorViews.delete(id);
this.currentEditors.delete(id);
document.querySelector(`#slot-${id}`).remove();
document.querySelector(`#slot-${id}`)?.remove();
}
reconfigureExtension(key, value, view) {
view.dispatch({
effects: this.compartments[key].reconfigure(this.extensions[key](value)),
effects: this.compartments[key]?.reconfigure(this.extensions[key](value)),
});
}
enableRemoteCursorTracking(session) {
const docs = session.getDocuments();
console.log('enable', docs);
//--
// CURRENTLY UNCALLED FUNCTIONS
// enableRemoteCursorTracking(session) {
// const docs = session.getDocuments();
// console.log('enable', docs);

docs.forEach((doc) => {
const collab = yCollab(text, doc.session.awareness, {
undoManager,
showLocalCaret: true,
scrollIntoView: true,
});
// const ext = doc.collabCompartment.of(collab);
// docs.forEach((doc) => {
// const collab = yCollab(text, doc.session.awareness, {
// // undoManager,
// showLocalCaret: true,
// scrollIntoView: true,
// });
// // const ext = doc.collabCompartment.of(collab);

view.dispatch({
effects: doc.collabCompartment.reconfigure(collab),
});
});
// view.dispatch({
// effects: doc.collabCompartment.reconfigure(collab),
// });
// });

// walk over
/* view.dispatch({
effects: this.reconfigure(this.extensions[key](value)),
}); */
}
disableRemoteCursorTracking(session) {
console.log('disable', session); /* view.dispatch({
effects: this.reconfigure(this.extensions[key](value)),
}); */
}
// // walk over
// /* view.dispatch({
// effects: this.reconfigure(this.extensions[key](value)),
// }); */
// }
// disableRemoteCursorTracking(session) {
// console.log('disable', session); /* view.dispatch({
// effects: this.reconfigure(this.extensions[key](value)),
// }); */
// }

updateExtensions({ previous, next }) {
const appliedSettings = previous;
const settings = next;
const keys = Object.keys(this.extensions);
for (let index in keys) {
const key = keys[index];
if (!key) continue;
for (let [_, view] of this.editorViews) {
if (settings[key] !== appliedSettings[key]) {
// console.log('reconfigure', key, settings[key]);
Expand All @@ -325,7 +336,7 @@ export class PastaMirror {
messageContainer.style = `position:fixed;top:${pos.top}px;left:${pos.left}px`;
messageContainer.classList.add('rising-animation');
messageContainer.classList.add('message-container');
chatContainer.appendChild(messageContainer);
chatContainer?.appendChild(messageContainer);
setTimeout(() => {
messageContainer.remove();
}, 7000);
Expand Down
9 changes: 7 additions & 2 deletions src/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ const errorField = StateField.define({
},
update(errors, tr) {
errors = errors.map(tr.changes);
for (let e of tr.effects) {
for (let _e of tr.effects) {
/** @type {any} */
const e = _e;
if (e.is(addError)) {
const doc = tr.state.doc;
const afterLineIndex = doc.line(e.value.msg.lineno).to + 1;
Expand All @@ -67,7 +69,9 @@ const errorField = StateField.define({
export function displayInlineErrors(docId, msg) {
const view = window.editorViews.get(docId);
const effects = [];
effects.push(addError.of(new ErrorWidget(docId, msg)));
/** @type {any} */
const errorWidget = new ErrorWidget(docId, msg);
effects.push(addError.of(errorWidget));

if (!view.state.field(errorField, false)) {
effects.push(StateEffect.appendConfig.of(errorField));
Expand All @@ -78,5 +82,6 @@ export function displayInlineErrors(docId, msg) {

export function clearInlineErrors(docId) {
const view = window.editorViews.get(docId);
// @ts-expect-error
view.dispatch({ effects: [clearErrors.of()] });
}
16 changes: 9 additions & 7 deletions src/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ const exportOpenFlokButton = document.querySelector('#export-open-flok-button');
const exportOpenStrudelButton = document.querySelector('#export-open-strudel-button');
const exportOpenHydraButton = document.querySelector('#export-open-hydra-button');

if (!exportButton) throw new Error('export button not found');
exportButton.addEventListener('click', () => {
exportDialog.showModal();
exportDialog?.showModal();
if (!exportOpenFlokButton) throw new Error('Open in flok button not found');
exportOpenFlokButton.href = `https://${getFlokLink()}`;
exportCloseButton.focus();
exportCloseButton?.focus();
});

let stdSource = '';
Expand Down Expand Up @@ -53,7 +55,7 @@ export function getFlokLink() {
)}&${panels.map((it, index) => `c${index}=${btoa(unescape(encodeURIComponent(it)))}`).join('&')}`;
}

export function copyToClipboard(txt, { message } = {}) {
export function copyToClipboard(txt, { message }) {
// Copy to the clipboard
navigator.clipboard.writeText(txt);
if (message) {
Expand Down Expand Up @@ -88,12 +90,12 @@ export function getCode(filter) {
);
}

exportCopyButton.addEventListener('click', () => {
exportCopyButton?.addEventListener('click', () => {
const txt = getCode();
copyToClipboard(txt, { message: 'code' });
});

exportDownloadButton.addEventListener('click', () => {
exportDownloadButton?.addEventListener('click', () => {
const txt = getCode();
downloadAsFile(txt);
});
Expand All @@ -107,12 +109,12 @@ export function code2hash(code) {
return encodeURIComponent(unicodeToBase64(code));
}

exportOpenStrudelButton.addEventListener('click', () => {
exportOpenStrudelButton?.addEventListener('click', () => {
const code = getCode((doc) => doc.target === 'strudel');
window.open(`https://strudel.cc/#${code2hash(code)}`);
});

exportOpenHydraButton.addEventListener('click', () => {
exportOpenHydraButton?.addEventListener('click', () => {
const code = getCode((doc) => doc.target === 'hydra');
window.open(`https://hydra.ojack.xyz/?code=${code2hash(code)}`);
});
5 changes: 3 additions & 2 deletions src/hydra.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class HydraSession {
if (this.initialized) {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this._hydra.setResolution(window.innerWidth, window.innerHeight);
this._hydra?.setResolution(window.innerWidth, window.innerHeight);
}
}

Expand All @@ -24,6 +24,7 @@ export class HydraSession {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this._hydra = new HydraRenderer({
// @ts-expect-error
canvas: this.canvas,
enableAudio: false,
});
Expand All @@ -34,7 +35,7 @@ export class HydraSession {
}

window.H = this._hydra;
const HydraSource = this._hydra.s[0].constructor;
const HydraSource = this._hydra.s?.[0].constructor;

// Enable using strudel style mini-patterns for argument control on Hydra.
// strudel needs to be loaded first, otherwise this will cause warnings, and rendering will not
Expand Down
1 change: 1 addition & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PastaMirror } from './editor.js';
import { clearInlineErrors, displayInlineErrors } from './error.js';
import './style.css';
import { getStdSource } from './export.js';
import { updateMiniLocations } from '@strudel/codemirror';

export const pastamirror = new PastaMirror();
window.editorViews = pastamirror.editorViews;
Expand Down
Loading

0 comments on commit cd428c2

Please sign in to comment.