import validateJs from './js/index'; import validateHtml from './html/index'; import { getLocator, Location } from 'locate-character'; import getCodeFrame from '../utils/getCodeFrame'; import CompileError from '../utils/CompileError' import { Node, Parsed } from '../interfaces'; class ValidationError extends CompileError { constructor ( message: string, template: string, index: number, filename: string ) { super( message, template, index, filename ); this.name = 'ValidationError'; } } export class Validator { readonly source: string; readonly filename: string; onwarn: ({}) => void; locator?: (pos: number) => Location; namespace: string; defaultExport: Node; properties: Map; components: Map; methods: Map; helpers: Map; transitions: Map; constructor ( parsed: Parsed, source: string, options: { onwarn, name?: string, filename?: string } ) { this.source = source; this.filename = options !== undefined ? options.filename : undefined; this.onwarn = options !== undefined ? options.onwarn : undefined; this.namespace = null; this.defaultExport = null; this.properties = new Map(); this.components = new Map(); this.methods = new Map(); this.helpers = new Map(); this.transitions = new Map(); } error ( message: string, pos: number ) { throw new ValidationError( message, this.source, pos, this.filename ); } warn ( message: string, pos: number ) { if ( !this.locator ) this.locator = getLocator( this.source ); const { line, column } = this.locator( pos ); const frame = getCodeFrame( this.source, line, column ); this.onwarn({ message, frame, loc: { line: line + 1, column }, pos, filename: this.filename, toString: () => `${message} (${line + 1}:${column})\n${frame}` }); } } export default function validate ( parsed: Parsed, source: string, { onerror, onwarn, name, filename } ) { try { if ( name && !/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test( name ) ) { const error = new Error( `options.name must be a valid identifier` ); throw error; } if ( name && !/^[A-Z]/.test( name ) ) { const message = `options.name should be capitalised`; onwarn({ message, filename, toString: () => message }); } const validator = new Validator( parsed, source, { onwarn, name, filename }); if ( parsed.js ) { validateJs( validator, parsed.js ); } if ( parsed.html ) { validateHtml( validator, parsed.html ); } } catch ( err ) { if ( onerror ) { onerror( err ); } else { throw err; } } }