import { locate } from 'locate-character'; import fragment from './state/fragment.js'; const whitespace = /\s/; export default function parse ( template ) { const parser = { index: 0, template, stack: [], current () { return this.stack[ this.stack.length - 1 ]; }, error ( message ) { const { line, column } = locate( this.template, this.index ); throw new Error( `${message} (${line}:${column})` ); }, eat ( str, required ) { if ( this.match( str ) ) { this.index += str.length; return true; } if ( required ) { this.error( `Expected ${str}` ); } }, match ( str ) { return this.template.slice( this.index, this.index + str.length ) === str; }, allowWhitespace () { while ( this.index < this.template.length && whitespace.test( this.template[ this.index ] ) ) { this.index++; } }, read ( pattern ) { const match = pattern.exec( this.template.slice( this.index ) ); if ( !match || match.index !== 0 ) return null; parser.index += match[0].length; return match[0]; }, readUntil ( pattern ) { const match = pattern.exec( this.template.slice( this.index ) ); return this.template.slice( this.index, match ? ( this.index += match.index ) : this.template.length ); }, remaining () { return this.template.slice( this.index ); }, requireWhitespace () { if ( !whitespace.test( this.template[ this.index ] ) ) { this.error( `Expected whitespace` ); } this.allowWhitespace(); }, html: { start: 0, end: null, type: 'Fragment', children: [] }, css: null, js: null }; parser.stack.push( parser.html ); let state = fragment; while ( parser.index < parser.template.length ) { state = state( parser ) || fragment; } const lastTemplateItem = parser.html.children[ parser.html.children.length - 1 ]; parser.html.end = lastTemplateItem ? lastTemplateItem.end : 0; return { html: parser.html, css: parser.css, js: parser.js }; }