JSFiddle - React, Tailwind, and code Playground

by Константин Дралюк

HTML

<textarea name="" id="pug" cols="100" rows="10"></textarea>
            
<textarea name="" id="sass" cols="100" rows="10"></textarea>

JavaScript

const getStartOffset = line => {
  return line.length - line.trimStart().length
}

const removeOffset = text => {
	const lines = text.split('\n')
	const firstLine = lines.find(line => /\b/.test(line))

  return lines.map(line => line.slice(getStartOffset(firstLine))).join('\n')
}

const removeLinesChunks = lines => {
	return lines.filter(line => {
  	return /^\+b|\+e/.test(line.trim())
  })
}

const textToLines = text => {
	const lines = text.split('\n')
  return removeLinesChunks(lines)
}

const buildBlocks = lines => {
	const blocks = []
	const items = []

  const clearLine = line => {
  	let clearedLine = line.trim().replace(/\(.*\)/, '').replace(/( |!).*$/, '')

    return clearedLine
  }

  const buildItem = line => {
  	const lineArray = clearLine(line).split('.')
    const hasTag = lineArray[1].toUpperCase() === lineArray[1]

   	const type = /^\+b/.test(line.trim()) ? 'block' : 'element'
    const name = hasTag ? lineArray[2] : lineArray[1]
    
    return {type, name, line}
  }

	const buildItems = lines.map(line => {
    const item = buildItem(line)
		
    const parent = [...items].reverse().find(item => 
    	item.type === 'block' &&
    	getStartOffset(line) > getStartOffset(item.line)
    )

    item.parent = parent ? parent.name : null

    items.push(item)
    return line
  })

  const buildBlocks = items.map((item) => {
    if (item.type === 'block') {
      const exists = blocks.find(block => item.name === block.name)
      
      if (!exists) {
        blocks.push({
          name: item.name,
          elements: [],
          content: `.${item.name}\n`
        })
      }
    } else {
      const parent = blocks.find(block => item.parent === block.name) 
      const exists = parent.elements.includes(item.name)

      if (!exists) {
	      parent.content += `  &__${item.name}\n`

        parent.elements.push(item.name)
      }
    }
  })
  
  return blocks
}

const buildSass = blocks => {
  let sass = ``

  for (let i in blocks) {
  	sass +=...