using afPlastic::SrcCodeSnippetusing concurrent::AtomicRef** Meta data about an efan template. ** ** Generated by the 'EfanCompiler'.constclass EfanMeta {** The 'Type' of the compiled efan template.const Type type** The generated fantom code of the efan template (for the inquisitive).const Str typeSrc** Where the template originated from. Example, 'file://layout.efan'. const Uri templateLoc** The original efan template source string.const Str templateSrc** The 'ctx' parameter type (if any) the template was compiled against.const Type? ctxType** The name of the 'ctx' variable (if any) the template was compiled with. const Str? ctxName** The rendering method on 'type'.const Method renderMethod// plastic will always need the concurrent pod (to store JVM unique pod name),// so we're not adding any extra dependencies hereinternalconst AtomicRef instanceRef := AtomicRef()internalconst Int srcCodePadding @NoDocnew make(|This|? in := null){ in?.call(this)if(null == this.type)this.type = Void#if(null == this.typeSrc)this.typeSrc = ""if(null == this.templateLoc)this.templateLoc = `wherever`if(null == this.templateSrc)this.templateSrc = ""}** Renders the efan template.** ** More specifically, this creates an instance of 'type' (via 'Type.make') and calls the efan ** render method with the given 'ctx' argument. ** ** Convenience for:** ** syntax: fantom** renderFrom(instance, ctx) Str render(Obj? ctx){ renderFrom(instance, ctx)}** Calls the render method on the given template. ** Any errs thrown are wrapped in an 'EfanErr' that shows where in the efan template the error occurred. Str renderFrom(Obj instance, Obj? ctx){if(instance.typeof.fits(type).not)throw ArgErr("Given instance does not fit template type: ${instance.typeof.qname} => ${type.qname}")tryreturn renderMethod.call(instance, ctx)catch(Err err)throw efanRuntimeErr(err)}** Returns an instance of 'type' via 'type.make()'. ** ** If 'type' is const and no 'ctorParams' are specified then the instance is cached and returned in later invocations. Obj instance(Obj[]? ctorParams := null){if((ctorParams == null || ctorParams.isEmpty) && type.isConst){if(instanceRef.val == null) instanceRef.val = type.makereturn instanceRef.val}return type.make(ctorParams)}** Converts the given err to a 'EfanRuntimeErr' that shows where in the efan template the error occurred.** If the given err can not be converted, it is returned as is.** ** For advanced use only. @NoDoc Err efanRuntimeErr(Err cause){ regex := Regex.fromStr("^\\s*?${type.qname}\\.${renderMethod.name}\\s\\(${type.pod.name}:([0-9]+)\\)\$") trace := cause.traceToStr srcCodeLineNo := trace.splitLines.eachWhile |line -> Int?| { reggy := regex.matcher(line)return reggy.find ? reggy.group(1).toInt : null}if(srcCodeLineNo == null)return cause templateLineNo := findTemplateLineNo(typeSrc, srcCodeLineNo) ?: throw cause srcCodeSnippet := SrcCodeSnippet(templateLoc, templateSrc)return EfanRuntimeErr(srcCodeSnippet, templateLineNo, cause.msg, srcCodePadding, cause)}internalstatic Int? findTemplateLineNo(Str typeSrc, Int srcCodeLineNo){ fanLineNo := srcCodeLineNo - 1 // from 1 to 0 based reggy := Regex<|\s+?// \(efan\) --> ([0-9]+)$|> efanLineNo := (Int?)null fanCodeLines := typeSrc.splitLineswhile(fanLineNo > 0 && efanLineNo == null){ code := fanCodeLines[fanLineNo] reg := reggy.matcher(code)if(reg.find){ efanLineNo = reg.group(1).toInt}else{ fanLineNo--}}return efanLineNo}}