transpiler package to replace eval package

This commit is contained in:
Felix Roos 2022-11-06 23:15:01 +01:00
parent fada7fc9cc
commit 9b2899c8fb
7 changed files with 265 additions and 90 deletions

172
package-lock.json generated
View File

@ -2133,6 +2133,10 @@
"resolved": "packages/tone",
"link": true
},
"node_modules/@strudel.cycles/transpiler": {
"resolved": "packages/transpiler",
"link": true
},
"node_modules/@strudel.cycles/webaudio": {
"resolved": "packages/webaudio",
"link": true
@ -4207,10 +4211,7 @@
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"node_modules/defaults": {
"version": "1.0.4",
@ -4948,9 +4949,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
"integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"esprima": "^4.0.1",
"estraverse": "^5.2.0",
@ -4972,9 +4970,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"optional": true,
"peer": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
@ -4991,6 +4986,11 @@
"node": ">=4.0"
}
},
"node_modules/estree-walker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.1.tgz",
"integrity": "sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g=="
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -5109,10 +5109,7 @@
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
"node_modules/fastq": {
"version": "1.13.0",
@ -7221,9 +7218,6 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
@ -8782,9 +8776,6 @@
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
@ -9525,9 +9516,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">= 0.8.0"
}
@ -10764,7 +10752,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"devOptional": true,
"engines": {
"node": ">=0.10.0"
}
@ -11576,9 +11564,6 @@
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"prelude-ls": "~1.1.2"
},
@ -12151,9 +12136,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -12486,7 +12468,7 @@
},
"packages/eval": {
"name": "@strudel.cycles/eval",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
@ -12513,10 +12495,10 @@
},
"packages/midi": {
"name": "@strudel.cycles/midi",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/tone": "^0.3.1",
"tone": "^14.7.77",
"webmidi": "^3.0.21"
}
@ -12537,12 +12519,12 @@
},
"packages/mini": {
"name": "@strudel.cycles/mini",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/eval": "^0.3.0",
"@strudel.cycles/tone": "^0.3.0"
"@strudel.cycles/eval": "^0.3.1",
"@strudel.cycles/tone": "^0.3.1"
},
"devDependencies": {
"peggy": "^2.0.1"
@ -12558,13 +12540,13 @@
},
"packages/react": {
"name": "@strudel.cycles/react",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/eval": "^0.3.0",
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/eval": "^0.3.1",
"@strudel.cycles/tone": "^0.3.1",
"@uiw/codemirror-themes": "^4.12.4",
"@uiw/react-codemirror": "^4.12.4",
"react-hook-inview": "^4.5.0"
@ -12639,11 +12621,11 @@
},
"packages/soundfonts": {
"name": "@strudel.cycles/soundfonts",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/webaudio": "^0.3.0",
"@strudel.cycles/webaudio": "^0.3.1",
"sfumato": "^0.1.2",
"soundfont2": "^0.4.0"
},
@ -12671,7 +12653,7 @@
},
"packages/tonal": {
"name": "@strudel.cycles/tonal",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
@ -12695,7 +12677,7 @@
},
"packages/tone": {
"name": "@strudel.cycles/tone",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
@ -12703,9 +12685,31 @@
"tone": "^14.7.77"
}
},
"packages/transpiler": {
"name": "@strudel.cycles/transpiler",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
"acorn": "^8.8.1",
"escodegen": "^2.0.0",
"estree-walker": "^3.0.1"
}
},
"packages/transpiler/node_modules/acorn": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"packages/webaudio": {
"name": "@strudel.cycles/webaudio",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1"
@ -12713,7 +12717,7 @@
},
"packages/webdirt": {
"name": "@strudel.cycles/webdirt",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
@ -12722,7 +12726,7 @@
},
"packages/xen": {
"name": "@strudel.cycles/xen",
"version": "0.3.0",
"version": "0.3.1",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@strudel.cycles/core": "^0.3.1"
@ -14423,7 +14427,7 @@
"@strudel.cycles/midi": {
"version": "file:packages/midi",
"requires": {
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/tone": "^0.3.1",
"tone": "^14.7.77",
"webmidi": "^3.0.21"
},
@ -14443,8 +14447,8 @@
"version": "file:packages/mini",
"requires": {
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/eval": "^0.3.0",
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/eval": "^0.3.1",
"@strudel.cycles/tone": "^0.3.1",
"peggy": "^2.0.1"
}
},
@ -14459,8 +14463,8 @@
"requires": {
"@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/eval": "^0.3.0",
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/eval": "^0.3.1",
"@strudel.cycles/tone": "^0.3.1",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"@uiw/codemirror-themes": "^4.12.4",
@ -14516,7 +14520,7 @@
"version": "file:packages/soundfonts",
"requires": {
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/webaudio": "^0.3.0",
"@strudel.cycles/webaudio": "^0.3.1",
"node-fetch": "^3.2.6",
"sfumato": "^0.1.2",
"soundfont2": "^0.4.0"
@ -14562,6 +14566,22 @@
"tone": "^14.7.77"
}
},
"@strudel.cycles/transpiler": {
"version": "file:packages/transpiler",
"requires": {
"@strudel.cycles/core": "^0.3.1",
"acorn": "^8.8.1",
"escodegen": "^2.0.0",
"estree-walker": "^3.0.1"
},
"dependencies": {
"acorn": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA=="
}
}
},
"@strudel.cycles/webaudio": {
"version": "file:packages/webaudio",
"requires": {
@ -16271,10 +16291,7 @@
"deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"defaults": {
"version": "1.0.4",
@ -16749,9 +16766,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
"integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
"dev": true,
"optional": true,
"peer": true,
"requires": {
"esprima": "^4.0.1",
"estraverse": "^5.2.0",
@ -16763,16 +16777,18 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
},
"estree-walker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.1.tgz",
"integrity": "sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g=="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -16869,10 +16885,7 @@
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
"fastq": {
"version": "1.13.0",
@ -18473,9 +18486,6 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
"dev": true,
"optional": true,
"peer": true,
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
@ -19696,9 +19706,6 @@
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"dev": true,
"optional": true,
"peer": true,
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
@ -20227,10 +20234,7 @@
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w=="
},
"process-nextick-args": {
"version": "2.0.1",
@ -20339,8 +20343,8 @@
"requires": {
"@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.1",
"@strudel.cycles/eval": "^0.3.0",
"@strudel.cycles/tone": "^0.3.0",
"@strudel.cycles/eval": "^0.3.1",
"@strudel.cycles/tone": "^0.3.1",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"@uiw/codemirror-themes": "^4.12.4",
@ -21237,7 +21241,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
"devOptional": true
},
"source-map-generator": {
"version": "0.8.0",
@ -21893,9 +21897,6 @@
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
"dev": true,
"optional": true,
"peer": true,
"requires": {
"prelude-ls": "~1.1.2"
}
@ -22294,10 +22295,7 @@
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
},
"wordwrap": {
"version": "1.0.0",

View File

@ -1,6 +1,6 @@
import { controls, repl, evalScope } from '@strudel.cycles/core';
import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio';
import shapeshifter from '@strudel.cycles/eval/shapeshifter.mjs';
import { transpiler } from '@strudel.cycles/transpiler';
import tune from './tune.mjs';
const ctx = getAudioContext();
@ -18,7 +18,7 @@ evalScope(
const { evaluate } = repl({
defaultOutput: webaudioOutput,
getTime: () => ctx.currentTime,
transpiler: shapeshifter,
transpiler,
});
document.getElementById('start').addEventListener('click', () => {
ctx.resume();

View File

@ -0,0 +1,5 @@
import { evaluate as _evaluate } from '@strudel.cycles/core';
import { transpiler } from './transpiler.mjs';
export * from './transpiler.mjs';
export const evaluate = (code) => _evaluate(code, transpiler);

View File

@ -0,0 +1,32 @@
{
"name": "@strudel.cycles/transpiler",
"version": "0.3.1",
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
"main": "index.mjs",
"scripts": {
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tidalcycles/strudel.git"
},
"keywords": [
"tidalcycles",
"strudel",
"pattern",
"livecoding",
"algorave"
],
"author": "Felix Roos <flix91@gmail.com>",
"license": "AGPL-3.0-or-later",
"bugs": {
"url": "https://github.com/tidalcycles/strudel/issues"
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.3.1",
"acorn": "^8.8.1",
"escodegen": "^2.0.0",
"estree-walker": "^3.0.1"
}
}

View File

@ -0,0 +1,39 @@
/*
transpiler.test.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/transpiler/test/transpiler.test.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { describe, it, expect } from 'vitest';
import { transpiler } from '../transpiler.mjs';
describe('transpiler', () => {
it('wraps double quote string with mini and adds location', () => {
expect(transpiler('"c3"', { wrapAsync: false, addReturn: false })).toEqual("mini('c3').withMiniLocation(0, 4);");
expect(transpiler('stack("c3","bd sd")', { wrapAsync: false, addReturn: false })).toEqual(
"stack(mini('c3').withMiniLocation(6, 10), mini('bd sd').withMiniLocation(11, 18));",
);
});
it('wraps backtick string with mini and adds location', () => {
expect(transpiler('`c3`', { wrapAsync: false, addReturn: false })).toEqual("mini('c3').withMiniLocation(0, 4);");
});
it('replaces note variables with note strings', () => {
expect(transpiler('seq(c3, d3)', { wrapAsync: false, addReturn: false })).toEqual("seq('c3', 'd3');");
});
it('keeps tagged template literal as is', () => {
expect(transpiler('xxx`c3`', { wrapAsync: false, addReturn: false })).toEqual('xxx`c3`;');
});
it('supports top level await', () => {
expect(transpiler("await samples('xxx');", { wrapAsync: false, addReturn: false })).toEqual(
"await samples('xxx');",
);
});
/* it('parses dynamic imports', () => {
expect(
transpiler("const { default: foo } = await import('https://bar.com/foo.js');", {
wrapAsync: false,
addReturn: false,
}),
).toEqual("const {default: foo} = await import('https://bar.com/foo.js');");
}); */
});

View File

@ -0,0 +1,100 @@
import escodegen from 'escodegen';
import { parse } from 'acorn';
import { walk } from 'estree-walker';
import { isNote } from '@strudel.cycles/core';
export function transpiler(input, options = {}) {
const { wrapAsync = true, addReturn = true } = options;
let ast = parse(input, {
ecmaVersion: 2022,
allowAwaitOutsideFunction: true,
});
walk(ast, {
enter(node, parent, prop, index) {
if (isBackTickString(node, parent)) {
const { quasis, start, end } = node;
const { raw } = quasis[0].value;
this.skip();
return this.replace(miniWithLocation(raw, start, end));
}
if (isStringWithDoubleQuotes(node)) {
const { value, start, end } = node;
this.skip();
return this.replace(miniWithLocation(value, start, end));
}
if (node.type === 'Identifier' && isNote(node.name)) {
this.skip();
return this.replace({ type: 'Literal', value: node.name });
}
// TODO:
},
leave(node, parent, prop, index) {},
});
const { body } = ast;
if (!body?.[body.length - 1]?.expression) {
throw new Error('unexpected ast format without body expression');
}
// add return to last statement
if (addReturn) {
const { expression } = body[body.length - 1];
body[body.length - 1] = {
type: 'ReturnStatement',
argument: expression,
};
}
const output = escodegen.generate(ast);
if (wrapAsync) {
return `(async ()=>{${output}})()`;
}
return output;
}
function isStringWithDoubleQuotes(node, locations, code) {
const { raw, type } = node;
if (type !== 'Literal') {
return false;
}
return raw[0] === '"';
}
function isBackTickString(node, parent) {
return node.type === 'TemplateLiteral' && parent.type !== 'TaggedTemplateExpression';
}
function miniWithLocation(value, start, end) {
// with location
return {
type: 'CallExpression',
callee: {
type: 'MemberExpression',
object: {
type: 'CallExpression',
callee: {
type: 'Identifier',
name: 'mini',
},
arguments: [{ type: 'Literal', value }],
optional: false,
},
property: {
type: 'Identifier',
name: 'withMiniLocation',
},
},
arguments: [
{
type: 'Literal',
value: start,
},
{
type: 'Literal',
value: end,
},
],
optional: false,
};
}

View File

@ -3,7 +3,8 @@
// it might require mocking more stuff when tunes added that use other functions
// import * as tunes from './tunes.mjs';
import { evaluate } from '@strudel.cycles/eval';
// import { evaluate } from '@strudel.cycles/eval';
import { evaluate } from '@strudel.cycles/transpiler';
import { evalScope } from '@strudel.cycles/core';
import * as strudel from '@strudel.cycles/core';
import * as webaudio from '@strudel.cycles/webaudio';