| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- function hello(one, two, three) {
- console.log(`one: ${one}; two: ${two}; three: ${three}`)
- console.log(`one: ${one[two(three)]}; two: ${two(three[one])}; three: [({${three}})]`)
- one[two(three)]
- //two(three[one])
- ;[(three)]
- while (nested) {
- function nested() {
- if (nested) {
- console.log('I am nested');
- } else {
- console.log('I am not')
- }
- }
- }
- }
- const dogfoodRegex = /(\(|\)|\{|\}|\[|\]|\:|\;|\.|\s+|\`|\'|\"|[^\(\)\{\}\[\]\:\;\.\s\,\`\'\"]+)/gm
- console.clear()
- const sampleCode = `
- console.log(\`hello \${(world)}\`)
- console.log('hello \${(world)}')
- function hello(one, two, three) {
- console.log(\`one: \${one}; two: \${two}; three: \${three}\`)
- console.log(\`one: \${one[two(three)]}; two: \${two(three[one])}; three: [({\${three}\})]\`)
- one[two(three)]
- // two(three[one])
- ;[(three)]
- while (nested) {
- function nested() {
- if (nested) {
- console.log('I am nested');
- } else {
- console.log('I am not')
- }
- /*
- if (nested) {
- console.log('I am nested');
- } else {
- console.log('I am not')
- }
- */
- }
- }
- }
- const dogfoodRegex = /(\\(|\\)|\\{|\\}|\\[|\\]|\\:|\\;|\\.|\\s+|\\\`|\\'|\\"|[^\\(\\)\\{\\}\\[\\]\\:\\;\\.\\s\\,\\\`\\'\\"]+)/gm
- `
- const keywordRegex = /^(do|if|in|for|let|new|try|var|case|else|enum|eval|null|this|true|void|with|break|catch|class|const|false|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/
- const parse = code => {
- const regex = /(\/\/|\/\*|\*\/|\${|\,|\/|\\|\(|\)|\{|\}|\[|\]|\`|\'|\"|\n| +|\w+|[^\w\s]+)/gm
- let match
- const ret = []
- while (match = regex.exec(code)) {
- ret.push(match[1])
- }
- return ret
- }
- const defaultScope = ['root', 'paren', 'bracket', 'square', 'interpolation']
- const pairs = [
- { open: '(', close: ')', name: 'paren', scope: defaultScope },
- { open: '{', close: '}', name: 'bracket', scope: defaultScope },
- { open: '[', close: ']', name: 'square', scope: defaultScope },
- { open: "'", close: "'", name: 'string', scope: defaultScope },
- { open: '"', close: '"', name: 'string', scope: defaultScope },
- { open: '`', close: '`', name: 'template', scope: defaultScope },
- { open: '${', close: '}', name: 'interpolation', scope: ['template'] },
- { open: '//', close: '\n', name: 'comment', scope: defaultScope },
- { open: '/*', close: '*/', name: 'block-comment', scope: defaultScope }
- ]
- const organize = codes => {
- codes = codes.slice().reverse()
-
- const read = (closer, scope) => {
- const ret = []
- let escaped = false
- while (codes.length) {
- const c = codes.pop()
- if (c === '\\' && !escaped) {
- escaped = true
- ret.push({
- text: c,
- type: 'default'
- })
- continue
- } else if (c === closer && !escaped) {
- ret.push({
- text: c,
- type: scope
- })
- return ret
- } else {
- const pair = pairs.find(pair => pair.open === c && pair.scope.includes(scope))
- if (!escaped && pair) {
- const next = codes[codes.length - 1]
- if (/^\s/.test(next)) {
- // Block begins with whitespace. Concatenate.
- ret.push({
- text: c + codes.pop(),
- type: 'open-' + pair.name
- })
- } else {
- // Block begins with character. Append only block opener
- ret.push({
- text: c,
- type: 'open-' + pair.name
- })
- }
- const children = read(pair.close, pair.name)
- ret.push({
- children,
- type: pair.name
- })
- const blockEnd = []
- if (peek(children).text === pair.close) {
- const blockCloser = children.pop()
- blockEnd.push(blockCloser.text)
- }
- while (/^\s+$/.test(peek(children).text)) {
- blockEnd.unshift(children.pop().text)
- }
- if (blockEnd.length) {
- ret.push({
- text: blockEnd.join(''),
- type: 'close-' + pair.name
- })
- }
- } else {
- ret.push({
- text: c,
- type: 'default'
- })
- }
- }
- escaped = false
- } // while
- return ret
- }
- return read(null, 'root')
- }
- const toDom = (codes) => {
- const toDom = (codes) => {
- return codes.map(code => {
- if (Array.isArray(code)) {
- const container = document.createElement('span')
- toDom(code).forEach(child => container.appendChild(child))
- return container
- } else {
- const textNode = document.createTextNode(code)
- const container = document.createElement('span')
- container.appendChild(textNode)
- return container
- }
- })
- }
- return toDom([codes])[0]
- }
- const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
- const anim = ms => Promise.all([ sleep(ms), new Promise(requestAnimationFrame) ])
- const peek = (a => a && a.length && a[a.length - 1]) || {}
- const isBlock = x => x && x.children
- const toDomAsync = async (codes, target, delay) => {
- const toDom = async (codes, target) => {
- codes = codes.slice().reverse()
- const wrap = async (code, target, instant) => {
- const container = document.createElement('span')
- target.appendChild(container)
- container.className = 'code-' + code.type
- const checkKeyword = () => {
- if (keywordRegex.test(container.innerText)) {
- container.classList.add('code-keyword')
- } else {
- container.classList.remove('code-keyword')
- }
- }
- if (instant) {
- container.setAttribute('text', code.text)
- container.appendChild(document.createTextNode(code.text))
- checkKeyword()
- } else {
- for (let i = 0; i <= code.text.length; i++) {
- container.innerText = ''
- container.setAttribute('text', code.text.substr(0, i))
- container.appendChild(document.createTextNode(code.text.substr(0, i)))
- checkKeyword()
- await anim(delay)
- }
- }
- return container
- }
- while(codes.length) {
- const code = codes.pop()
- if (Array.isArray(code.children)) {
- await toDom(code.children, target)
- } else if (isBlock(peek(codes))) {
- await wrap(code, target, true)
- const container = document.createElement('span')
- const children = codes.pop()
- container.className = 'code-' + children.type
- const next = codes.pop()
- target.appendChild(container)
- if (next) {
- await wrap(next, target, true)
- }
- await anim(delay)
- await toDom(children.children, container)
- } else {
- await wrap(code, target)
- }
- await anim(delay)
- }
- }
- target.classList.add('code-root')
- await toDom(codes, target)
- }
- const animateCode =async ({code, target}) => {
- const codes = parse(code)
- const organized = organize(codes)
- await toDomAsync(organized, target, 0)
- }
- const main = async () => {
- const target = document.querySelector('pre')
- target.innerHTML = ''
- await animateCode({code: sampleCode, target})
- await sleep(15000)
- await main()
- }
- main()
|