Skip to content

Instantly share code, notes, and snippets.

@stevekrouse
Last active March 7, 2017 17:50
Show Gist options
  • Select an option

  • Save stevekrouse/38346fd23e611f532604871a94119574 to your computer and use it in GitHub Desktop.

Select an option

Save stevekrouse/38346fd23e611f532604871a94119574 to your computer and use it in GitHub Desktop.
esnextbin sketch
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ESNextbin Sketch</title>
<!-- put additional styles and scripts here -->
</head>
<body>
<div id="app"></div>
</body>
</html>
var t = require('babel-types')
var generate = require('babel-generator').default
var Vue = require('vue')
var traverse = require("babel-traverse").default
var babylon = require("babylon")
// the AST explorer is helpful for inspecting stuff (dont' forget to set to babloyn6): https://astexplorer.net/
// example of generating JS code from babel nodes: https://github.com/babel/babel/blob/master/packages/babel-generator/src/generators/expressions.js
// need to create components for all the types here: https://github.com/babel/babel/tree/7.0/packages/babel-types
// array expression
// arrow function
// assignment expression
// binaryExpression (infix)
// blockStatement
// booleanLiteral
// conditionalExpression
// declareFunction
// functionDeclaration
// declareVariable
// functionExpression
// ifStatement
// logicalExpression
// newExpression
// nullLiteral
// objectExpression
// parenthesizedExpression
// regExpLiteral
// restElement
// return statement
// unaryExpression
// updateExpression
// variableDeclaration
// variableDeclarator
Vue.component('NumericLiteral', {
functional: true,
render: function (h, context) {
if (context.props.node.id == context.props.selection.id && context.props.selection.path == "EDITING") {
return h(
"input",
{
style: {
width: (Math.floor((Math.log10(Math.abs(context.props.node.value))) + 4) * 7) + 'px'
},
on: {
click: function(event) {
event.stopPropagation();
},
input: function(event) {
bus.$emit('edit-node', {id: context.props.node.id, updates: {value: event.target.value || 0}})
}
},
domProps: {
type: "number",
value: context.props.node.value
}
},
[]
)
} else {
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "hotpink",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id})
},
dblclick: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id, path: "EDITING"})
}
}
},
context.props.node.value
)
}
},
props: {
node: Object,
selection: Object
}
})
Vue.component('StringLiteral', {
functional: true,
render: function (h, context) {
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "green",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id})
}
}
},
[
"\"",
context.props.node.value,
"\""
]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('Identifier', {
functional: true,
render: function (h, context) {
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "orange",
color: "white",
padding: "5px",
margin: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id})
}
}
},
[
context.props.node.name
]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('MemberExpression', {
functional: true,
render: function (h, context) {
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "pink",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id})
}
}
},
[
h(context.props.node.object.type, {props: {node: context.props.node.object, selection: context.props.selection}}),
"'s",
h(context.props.node.property.type, {props: {node: context.props.node.property, selection: context.props.selection}})
]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('CallExpression', {
functional: true,
render: function (h, context) {
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "lightblue",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: (context.props.node.id == context.props.selection.id && !context.props.selection.path) ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id})
}
}
},
[
h(context.props.node.callee.type, {props: {node: context.props.node.callee, selection: context.props.selection}}),
h('CallParameters', {props: {node: context.props.node, selection: context.props.selection}})
]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('CallParameters', {
functional: true,
render: function (h, context) {
var children = []
children.push("(")
context.props.node.arguments.forEach(function(arg, index) {
if (index > 0) {
children.push(',')
}
children.push(h(arg.type, {props: {node: arg, selection: context.props.selection}}))
})
children.push(')')
return h(
"div",
{
style: {
display: "inline-block",
backgroundColor: "cornflowerblue",
color: "white",
padding: "5px",
margin: "5px",
borderRadius: "5px",
boxShadow: (context.props.node.id == context.props.selection.id && context.props.selection.path == "PARAMETERS") ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id, path: "PARAMETERS"})
}
}
},
children
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('ExpressionStatement', {
functional: true,
render: function (h, context) {
return h(
'div',
{
style: {
margin: "5px",
}
},
[
h(context.props.node.expression.type, {props: {node: context.props.node.expression, selection: context.props.selection}}),
h('EmptyLine', {props: {node: context.props.node, selection: context.props.selection}}),
]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('EmptyLine', {
functional: true,
render: function (h, context) {
return h(
'div',
{
style: {
marginTop: "5px",
height: "10px",
backgroundColor: "lightgray",boxShadow: (context.props.node.id == context.props.selection.id && context.props.selection.path == "LINE-BELOW") ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function(event) {
event.stopPropagation();
bus.$emit('click-node', {id: context.props.node.id, path: "LINE-BELOW"})
}
}
},
[]
)
},
props: {
node: Object,
selection: Object
}
})
Vue.component('File', {
functional: true,
render: function (h, context) {
return h(
"div",
{},
context.props.node.program.body.map(function(node) {
return h(node.type, {props: {node: node, selection: context.props.selection}})
})
)
},
props: {
node: Object,
selection: Object
}
})
const code = "sprite.move(10)\nsprite.hide()"
var ast = babylon.parse(code);
var _id = 0
traverse(ast, {
enter(path) {
if (!path.node.id) {
path.node.id = _id;
_id++;
}
}
})
// console.log(JSON.stringify(ast))
// TODO arrow key navigation
// right - next sibling to right
// left - next sibling to left
// up -- parent
// down -- first child
// click navigation -> select that node
var bus = new Vue()
bus.$on('click-node', function (selection) {
app.selection = selection
})
bus.$on('edit-node', function (selection) {
traverse(ast, {
enter(path) {
if (path.node.id == selection.id) {
Object.keys(selection.updates).forEach(function(attr) {
path.node[attr] = selection.updates[attr]
})
}
}
})
})
Vue.component('Editor', {
render: function (h) {
return h(
"div",
{},
[
h(
"input",
{},
),
h(
"div",
{},
[] // TODO options here
)
]
)
},
props: {
node: Object,
selection: Object
}
})
var app = new Vue({
el: '#app',
data: {
ast: ast,
selection: {
id: 2,
part: null
}
},
render: function(h) {
return h(
"div",
{
style: {
userSelect: 'none',
cursor: 'pointer'
}
},
[
h(this.ast.type, {props: {node: this.ast, selection: this.selection}}),
//h('Editor', {props: {node: this.ast, selection: this.selection}})
]
)
}
})
{
"name": "esnextbin-sketch",
"version": "0.0.0",
"dependencies": {
"babel-types": "6.23.0",
"babel-generator": "6.23.0",
"vue": "2.1.10",
"babel-traverse": "6.23.1",
"babylon": "6.16.1",
"babel-runtime": "6.23.0"
}
}
'use strict';
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _log = require('babel-runtime/core-js/math/log10');
var _log2 = _interopRequireDefault(_log);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var t = require('babel-types');
var generate = require('babel-generator').default;
var Vue = require('vue');
var traverse = require("babel-traverse").default;
var babylon = require("babylon");
// the AST explorer is helpful for inspecting stuff (dont' forget to set to babloyn6): https://astexplorer.net/
// example of generating JS code from babel nodes: https://github.com/babel/babel/blob/master/packages/babel-generator/src/generators/expressions.js
// need to create components for all the types here: https://github.com/babel/babel/tree/7.0/packages/babel-types
// array expression
// arrow function
// assignment expression
// binaryExpression (infix)
// blockStatement
// booleanLiteral
// conditionalExpression
// declareFunction
// functionDeclaration
// declareVariable
// functionExpression
// ifStatement
// logicalExpression
// newExpression
// nullLiteral
// objectExpression
// parenthesizedExpression
// regExpLiteral
// restElement
// return statement
// unaryExpression
// updateExpression
// variableDeclaration
// variableDeclarator
Vue.component('NumericLiteral', {
functional: true,
render: function render(h, context) {
if (context.props.node.id == context.props.selection.id && context.props.selection.path == "EDITING") {
return h("input", {
style: {
width: Math.floor((0, _log2.default)(Math.abs(context.props.node.value)) + 4) * 7 + 'px'
},
on: {
click: function click(event) {
event.stopPropagation();
},
input: function input(event) {
bus.$emit('edit-node', { id: context.props.node.id, updates: { value: event.target.value || 0 } });
}
},
domProps: {
type: "number",
value: context.props.node.value
}
}, []);
} else {
return h("div", {
style: {
display: "inline-block",
backgroundColor: "hotpink",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id });
},
dblclick: function dblclick(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id, path: "EDITING" });
}
}
}, context.props.node.value);
}
},
props: {
node: Object,
selection: Object
}
});
Vue.component('StringLiteral', {
functional: true,
render: function render(h, context) {
return h("div", {
style: {
display: "inline-block",
backgroundColor: "green",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id });
}
}
}, ["\"", context.props.node.value, "\""]);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('Identifier', {
functional: true,
render: function render(h, context) {
return h("div", {
style: {
display: "inline-block",
backgroundColor: "orange",
color: "white",
padding: "5px",
margin: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id });
}
}
}, [context.props.node.name]);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('MemberExpression', {
functional: true,
render: function render(h, context) {
return h("div", {
style: {
display: "inline-block",
backgroundColor: "pink",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id });
}
}
}, [h(context.props.node.object.type, { props: { node: context.props.node.object, selection: context.props.selection } }), "'s", h(context.props.node.property.type, { props: { node: context.props.node.property, selection: context.props.selection } })]);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('CallExpression', {
functional: true,
render: function render(h, context) {
return h("div", {
style: {
display: "inline-block",
backgroundColor: "lightblue",
color: "white",
padding: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id && !context.props.selection.path ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id });
}
}
}, [h(context.props.node.callee.type, { props: { node: context.props.node.callee, selection: context.props.selection } }), h('CallParameters', { props: { node: context.props.node, selection: context.props.selection } })]);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('CallParameters', {
functional: true,
render: function render(h, context) {
var children = [];
children.push("(");
context.props.node.arguments.forEach(function (arg, index) {
if (index > 0) {
children.push(',');
}
children.push(h(arg.type, { props: { node: arg, selection: context.props.selection } }));
});
children.push(')');
return h("div", {
style: {
display: "inline-block",
backgroundColor: "cornflowerblue",
color: "white",
padding: "5px",
margin: "5px",
borderRadius: "5px",
boxShadow: context.props.node.id == context.props.selection.id && context.props.selection.path == "PARAMETERS" ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id, path: "PARAMETERS" });
}
}
}, children);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('ExpressionStatement', {
functional: true,
render: function render(h, context) {
return h('div', {
style: {
margin: "5px"
}
}, [h(context.props.node.expression.type, { props: { node: context.props.node.expression, selection: context.props.selection } }), h('EmptyLine', { props: { node: context.props.node, selection: context.props.selection } })]);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('EmptyLine', {
functional: true,
render: function render(h, context) {
return h('div', {
style: {
marginTop: "5px",
height: "10px",
backgroundColor: "lightgray", boxShadow: context.props.node.id == context.props.selection.id && context.props.selection.path == "LINE-BELOW" ? "0 0 3pt 2pt blue" : "none"
},
on: {
click: function click(event) {
event.stopPropagation();
bus.$emit('click-node', { id: context.props.node.id, path: "LINE-BELOW" });
}
}
}, []);
},
props: {
node: Object,
selection: Object
}
});
Vue.component('File', {
functional: true,
render: function render(h, context) {
return h("div", {}, context.props.node.program.body.map(function (node) {
return h(node.type, { props: { node: node, selection: context.props.selection } });
}));
},
props: {
node: Object,
selection: Object
}
});
var code = "sprite.move(10)\nsprite.hide()";
var ast = babylon.parse(code);
var _id = 0;
traverse(ast, {
enter: function enter(path) {
if (!path.node.id) {
path.node.id = _id;
_id++;
}
}
});
// console.log(JSON.stringify(ast))
// TODO arrow key navigation
// right - next sibling to right
// left - next sibling to left
// up -- parent
// down -- first child
// click navigation -> select that node
var bus = new Vue();
bus.$on('click-node', function (selection) {
app.selection = selection;
});
bus.$on('edit-node', function (selection) {
traverse(ast, {
enter: function enter(path) {
if (path.node.id == selection.id) {
(0, _keys2.default)(selection.updates).forEach(function (attr) {
path.node[attr] = selection.updates[attr];
});
}
}
});
});
Vue.component('Editor', {
render: function render(h) {
return h("div", {}, [h("input", {}), h("div", {}, [] // TODO options here
)]);
},
props: {
node: Object,
selection: Object
}
});
var app = new Vue({
el: '#app',
data: {
ast: ast,
selection: {
id: 2,
part: null
}
},
render: function render(h) {
return h("div", {
style: {
userSelect: 'none',
cursor: 'pointer'
}
}, [h(this.ast.type, { props: { node: this.ast, selection: this.selection } })]);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment