add basic repl

This commit is contained in:
Felix Roos 2022-02-04 13:32:42 +01:00
parent 83d06ec2af
commit 71a3bdfeac
16 changed files with 15175 additions and 0 deletions

4
repl/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.snowpack
build
node_modules
.DS_Store

25
repl/README.md Normal file
View File

@ -0,0 +1,25 @@
# Strudel REPL
> ✨ Bootstrapped with Create Snowpack App (CSA).
## Available Scripts
### npm start
Runs the app in the development mode.
Open http://localhost:8080 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
### npm run build
Builds a static copy of your site to the `build/` folder.
Your app is ready to be deployed!
**For the best production performance:** Add a build bundler plugin like "@snowpack/plugin-webpack" to your `snowpack.config.mjs` config file.
### npm test
Launches the application test runner.
Run with the `--watch` flag (`npm test -- --watch`) to run in interactive watch mode.

14828
repl/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
repl/package.json Normal file
View File

@ -0,0 +1,35 @@
{
"scripts": {
"start": "snowpack dev",
"build": "snowpack build",
"test": "web-test-runner \"src/**/*.test.tsx\"",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\""
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@snowpack/plugin-dotenv": "^2.1.0",
"@snowpack/plugin-postcss": "^1.4.3",
"@snowpack/plugin-react-refresh": "^2.5.0",
"@snowpack/plugin-typescript": "^1.2.1",
"@snowpack/web-test-runner-plugin": "^0.2.2",
"@tailwindcss/forms": "^0.4.0",
"@testing-library/react": "^11.2.6",
"@types/chai": "^4.2.17",
"@types/mocha": "^8.2.2",
"@types/react": "^17.0.4",
"@types/react-dom": "^17.0.3",
"@types/snowpack-env": "^2.3.3",
"@web/test-runner": "^0.13.3",
"autoprefixer": "^10.4.2",
"chai": "^4.3.4",
"postcss": "^8.4.6",
"prettier": "^2.2.1",
"snowpack": "^3.3.7",
"tailwindcss": "^3.0.18",
"typescript": "^4.2.4"
}
}

8
repl/postcss.config.js Normal file
View File

@ -0,0 +1,8 @@
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
// other plugins can go here, such as autoprefixer
},
};

BIN
repl/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

3
repl/public/global.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

16
repl/public/index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/global.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Strudel REPL" />
<title>Strudel REPL</title>
</head>
<body>
<div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script type="module" src="/dist/index.js"></script>
</body>
</html>

38
repl/snowpack.config.mjs Normal file
View File

@ -0,0 +1,38 @@
/** @type {import("snowpack").SnowpackUserConfig } */
export default {
workspaceRoot: '..',
mount: {
public: { url: '/', static: false },
src: { url: '/dist' },
},
plugins: [
'@snowpack/plugin-postcss',
'@snowpack/plugin-react-refresh',
'@snowpack/plugin-dotenv',
[
'@snowpack/plugin-typescript',
{
/* Yarn PnP workaround: see https://www.npmjs.com/package/@snowpack/plugin-typescript */
...(process.versions.pnp ? { tsc: 'yarn pnpify tsc' } : {}),
},
],
],
routes: [
/* Enable an SPA Fallback in development: */
// {"match": "routes", "src": ".*", "dest": "/index.html"},
],
optimize: {
/* Example: Bundle your final build: */
// "bundle": true,
},
packageOptions: {
/* ... */
knownEntrypoints: ['fraction.js'],
},
devOptions: {
tailwindConfig: './tailwind.config.js',
},
buildOptions: {
/* ... */
},
};

71
repl/src/App.tsx Normal file
View File

@ -0,0 +1,71 @@
import React, { useEffect, useState } from 'react';
import logo from './logo.svg';
import * as strudel from '../../strudel.mjs';
import cx from './cx';
const { Fraction, TimeSpan } = strudel;
const fr = (v: number) => new Fraction(v);
const ts = (start: number, end: number) => new TimeSpan(fr(start), fr(end));
const parse = (code: string): Pattern<any> => {
const { sequence, stack, pure } = strudel; // make available to eval
return eval(code);
};
function App() {
const [code, setCode] = useState<string>("sequence('a', 'b', sequence('c', 'd'))");
const [events, setEvents] = useState<Hap<any>[]>([]);
const [error, setError] = useState<Error>();
useEffect(() => {
try {
const pattern = parse(code);
console.log('pattern', pattern);
setEvents(pattern.query(ts(0, 1)));
console.log('events', events);
setError(undefined);
} catch (err: any) {
setError(err);
}
}, [code]);
return (
<div className="h-[100vh] bg-slate-900 flex-row">
<header className="px-2 flex items-center space-x-2 border-b border-gray-200 bg-white">
<img src={logo} className="Tidal-logo w-16 h-16" alt="logo" />
<h1 className="text-2xl">Strudel REPL</h1>
</header>
<section className="grow p-2 text-gray-100">
<div className="relative">
<div className="absolute right-2 bottom-2 text-red-500">{error?.message}</div>
<textarea
className={cx('w-full h-32 bg-slate-600', error ? 'focus:ring-red-500' : 'focus:ring-slate-800')}
value={code}
onChange={(e) => setCode(e.target.value)}
/>
</div>
<textarea className="w-full h-64 bg-slate-600" value={events.map((e) => e.show()).join('\n')} readOnly />
</section>
</div>
);
}
export default App;
declare interface Fraction {
(v: number): Fraction;
d: number;
n: number;
s: number;
}
declare interface TimeSpan {
constructor: any; //?
begin: Fraction;
end: Fraction;
}
declare interface Hap<T> {
whole: TimeSpan;
part: TimeSpan;
value: T;
show: () => string;
}
declare interface Pattern<T> {
query: (span: TimeSpan) => Hap<T>[];
}

3
repl/src/cx.ts Normal file
View File

@ -0,0 +1,3 @@
export default function cx(...classes: Array<string | undefined>) {
return classes.filter(Boolean).join(' ');
}

16
repl/src/index.tsx Normal file
View File

@ -0,0 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);
// Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
// Learn more: https://snowpack.dev/concepts/hot-module-replacement
if (import.meta.hot) {
import.meta.hot.accept();
}

33
repl/src/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

8
repl/tailwind.config.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
content: ['./public/**/*.html', './src/**/*.{js,jsx,ts,tsx}'],
// specify other options here
theme: {
extend: {},
},
plugins: [require('@tailwindcss/forms')],
};

28
repl/tsconfig.json Normal file
View File

@ -0,0 +1,28 @@
{
"include": ["src", "types"],
"compilerOptions": {
"allowJs": true,
"module": "esnext",
"target": "esnext",
"moduleResolution": "node",
"jsx": "preserve",
"baseUrl": "./",
/* paths - import rewriting/resolving */
"paths": {
// If you configured any Snowpack aliases, add them here.
// Add this line to get types for streaming imports (packageOptions.source="remote"):
// "*": [".snowpack/types/*"]
// More info: https://www.snowpack.dev/guides/streaming-imports
},
/* noEmit - Snowpack builds (emits) files, not tsc. */
"noEmit": true,
/* Additional Options */
"strict": true,
"skipLibCheck": true,
"types": ["mocha", "snowpack-env"],
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"importsNotUsedAsValues": "error"
}
}

59
repl/types/static.d.ts vendored Normal file
View File

@ -0,0 +1,59 @@
/* Use this file to declare any custom file extensions for importing */
/* Use this folder to also add/extend a package d.ts file, if needed. */
/* CSS MODULES */
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.module.scss' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.module.sass' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.module.less' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.module.styl' {
const classes: { [key: string]: string };
export default classes;
}
/* CSS */
declare module '*.css';
declare module '*.scss';
declare module '*.sass';
declare module '*.less';
declare module '*.styl';
/* IMAGES */
declare module '*.svg' {
const ref: string;
export default ref;
}
declare module '*.bmp' {
const ref: string;
export default ref;
}
declare module '*.gif' {
const ref: string;
export default ref;
}
declare module '*.jpg' {
const ref: string;
export default ref;
}
declare module '*.jpeg' {
const ref: string;
export default ref;
}
declare module '*.png' {
const ref: string;
export default ref;
}
/* CUSTOM: ADD YOUR OWN HERE */