Created
April 18, 2016 14:50
-
-
Save senocular/b5f7bffc1769620b21eb57dd6eb2667f to your computer and use it in GitHub Desktop.
Simple way to step through a code block with execution for demonstration purposes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FunctionSequencer { | |
constructor (genFunc) { | |
if (Object.prototype.toString.call(genFunc) !== '[object GeneratorFunction]') { | |
throw new TypeError('Failed to create FunctionSequencer instance: parameter 1 is not of type \'GeneratorFunction\'.'); | |
} | |
this._genFunc = genFunc; | |
this._codeBlocks = this._parseBlocks(this._genFunc); | |
// when attached to a DOM element | |
this._container = null; | |
this._codeEls = []; | |
this._currentClass = 'highlight'; | |
} | |
_parseBlocks (genFunc) { | |
var reNotWhite = /[^\s]+/; | |
var reNewlineCaps = /^[\r\n]+|[\r\n]+$/g; | |
// get function body text | |
var str = genFunc.toString(); | |
var starti = str.indexOf('{') + 1; | |
var endi = str.indexOf('}'); | |
var span = str.slice(starti, endi); | |
// capture individual blocks of code between yields | |
return span | |
.split(/(^\s*(?:yield|return).*$)/m) | |
.filter((code, index) => reNotWhite.test(code) && index % 2 === 0) | |
.map(code => code.replace(reNewlineCaps, '')); | |
} | |
attach (container) { | |
this._container = container; | |
this._codeEls = []; | |
// one element added for each block of code | |
for (var code of this._codeBlocks) { | |
var el = document.createElement('pre'); | |
this._container.appendChild(el); | |
el.textContent = code; | |
this._codeEls.push(el); | |
} | |
} | |
call () { | |
var iter = this._genFunc(); | |
for (var annotation of iter); | |
} | |
* [Symbol.iterator] () { | |
var index = 0; | |
var el; | |
var code; | |
var stepThroughCode = () => { | |
code = this._codeBlocks[index]; | |
if (el) el.classList.remove(this._currentClass); | |
el = this._codeEls[index]; | |
if (el) el.classList.add(this._currentClass); | |
index++; | |
} | |
var iter = this._genFunc(); | |
do { | |
var next = iter.next(); | |
var annotation = next.value; | |
stepThroughCode(); | |
yield { annotation, code }; | |
} while (!next.done); | |
// clears on done | |
stepThroughCode(); | |
} | |
entries () { | |
return this[Symbol.iterator](); | |
} | |
} | |
function * foo () { | |
console.log(1); | |
yield 'first'; | |
console.log(2.1); | |
console.log(2.2); | |
// comment | |
yield 'second'; | |
console.log(3); | |
return 'last' | |
} | |
var container = document.createElement('div'); | |
document.body.appendChild(container); | |
var seq = new FunctionSequencer(foo); | |
seq.attach(container); | |
//seq.call(); // to call the function without stepping through it | |
var iter = seq.entries(); | |
document.addEventListener('click', function() { | |
var results = iter.next(); | |
if (results.done) { | |
console.log('DONE'); | |
iter = seq.entries(); | |
} else { | |
console.log(results.value.annotation); | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment