Skip to content

Commit

Permalink
add new sketch verifier to FES; it currently can read all user-define…
Browse files Browse the repository at this point in the history
…d variables and functions
  • Loading branch information
sproutleaf committed Sep 30, 2024
1 parent 34d41a5 commit 2b59d49
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 45 deletions.
76 changes: 54 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"version": "1.9.4",
"dependencies": {
"colorjs.io": "^0.5.2",
"espree": "^10.2.0",
"file-saver": "^1.3.8",
"gifenc": "^1.0.3",
"libtess": "^1.2.2",
Expand Down Expand Up @@ -82,4 +83,4 @@
"pre-commit": "lint-staged"
}
}
}
}
52 changes: 30 additions & 22 deletions preview/index.html
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
<!DOCTYPE html>
<html>

<head>
<title>P5 test</title>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta charset="utf-8">

<style>
body{
margin:0;
overflow: hidden;
}
body {
margin: 0;
overflow: hidden;
}
</style>
</head>

<body>
<script type="module">
import p5 from '../src/app.js';
// import calculation from './src/math/calculation.js';
<script type="module">
import p5 from '../src/app.js';
// import calculation from './src/math/calculation.js';

// p5.registerAddon(calculation);
// p5.registerAddon(calculation);

const sketch = function(p){
p.setup = function(){
p.createCanvas(200, 200);
};
let apple = 10;
function banana() {
console.log('banana');
}
const sketch = function (p) {
p.setup = function () {
p.createCanvas(200, 200);
p.run();
};

p.draw = function(){
p.background(0, 50, 50);
p.circle(100, 100, 50);
p.draw = function () {
p.background(0, 50, 50);
p.circle(100, 100, 50);

p.fill('white');
p.textSize(30);
p.text('hello', 10, 30);
};
};
p.fill('white');
p.textSize(30);
p.text('hello', 10, 30);
};
};

new p5(sketch);
</script>
new p5(sketch);
</script>
</body>

</html>
2 changes: 2 additions & 0 deletions src/core/friendly_errors/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import validateParams from './param_validator.js';
import sketchVerifier from './sketch_verifier.js';

export default function (p5) {
p5.registerAddon(validateParams);
p5.registerAddon(sketchVerifier);
}
107 changes: 107 additions & 0 deletions src/core/friendly_errors/sketch_verifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as espree from 'espree';

/**
* @for p5
* @requires core
*/
function sketchVerifier(p5, fn) {
/**
* Fetches the contents of a script element in the user's sketch.
*
* @method fetchScript
* @param {HTMLScriptElement} script
* @returns {Promise<string>}
*/
fn.fetchScript = async function (script) {
if (script.src) {
const contents = await fetch(script.src).then((res) => res.text());
return contents;
} else {
return script.textContent;
}
}

/**
* Extracts the user's code from the script fetched. Note that this method
* assumes that the user's code is always the last script element in the
* sketch.
*
* @method getUserCode
* @returns {Promise<string>} The user's code as a string.
*/
fn.getUserCode = async function () {
const scripts = document.querySelectorAll('script');
const userCodeScript = scripts[scripts.length - 1];
const userCode = await fn.fetchScript(userCodeScript);

return userCode;
}

fn.extractUserDefinedVariablesAndFuncs = function (codeStr) {
const userDefinitions = {
variables: [],
functions: []
};

try {
const ast = espree.parse(codeStr, {
ecmaVersion: 2021,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
});

function traverse(node) {
switch (node.type) {
case 'VariableDeclaration':
node.declarations.forEach(declaration => {
if (declaration.id.type === 'Identifier') {
userDefinitions.variables.push(declaration.id.name);
}
});
break;
case 'FunctionDeclaration':
if (node.id && node.id.type === 'Identifier') {
userDefinitions.functions.push(node.id.name);
}
break;
case 'ArrowFunctionExpression':
case 'FunctionExpression':
if (node.parent && node.parent.type === 'VariableDeclarator') {
userDefinitions.functions.push(node.parent.id.name);
}
break;
}

for (const key in node) {
if (node[key] && typeof node[key] === 'object') {
if (Array.isArray(node[key])) {
node[key].forEach(child => traverse(child));
} else {
traverse(node[key]);
}
}
}
}

traverse(ast);
} catch (error) {
console.error('Error parsing code:', error);
}

return userDefinitions;
}

fn.run = async function () {
const userCode = await fn.getUserCode();
const userDefinedVariablesAndFuncs = fn.extractUserDefinedVariablesAndFuncs(userCode);
console.log(userDefinedVariablesAndFuncs);
}
}

export default sketchVerifier;

if (typeof p5 !== 'undefined') {
sketchVerifier(p5, p5.prototype);
}

0 comments on commit 2b59d49

Please sign in to comment.