All files / renderers RendererBase.ts

80.77% Statements 42/52
63.64% Branches 14/22
80% Functions 8/10
85.71% Lines 42/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                                1059x           24x 53x       53x 53x 53x     24x 53x 53x 53x     24x 17x                                       24x           39x 2x   37x 14x 7x   7x     23x     39x   39x   39x 30x   30x             39x   39x 39x   39x 39x                     24x   2095x 2118x   1059x 1059x         1059x       24x 39x   39x       24x             24x             24x  
import * as riot from 'riot';
import Renderer, { RiotElement } from './Renderer';
import EvalContext from '../tags/EvalContext';
 
export interface MountFunction {
  (
    this: typeof riot,
    element: Element,
    tagName: string,
    opts: any
  ): riot.TagInstance[];
}
 
function createElementToMountTo(tagName: string) {
  // TODO: SVG
  // TODO: fallback "data-is"
  return document.createElement(tagName);
}
 
/**
 * base class of some shallow renderer for `riot`
 */
export default class RiotRendererBase implements Renderer {
  private context = new EvalContext();
  private instance: riot.TagInstance | null;
  private rendered: RiotElement | null;
 
  constructor(private mount: MountFunction) {
    this.instance = null;
    this.rendered = null;
  }
 
  loadTags(source: string) {
    const tagjs = riot.compile(source);
    const result = this.context.evalTag(tagjs);
    return result.tagNames;
  }
 
  unloadTag(tagName: string) {
    riot.unregister(tagName);
  }
 
  /**
   * Execute mount and rendering
   *
   * @param src multiple tag sources
   * @param name name of the tag to render
   * @param opts tag interface
   * @returns mounted element
   */
  render(src: string, name: string, opts?: riot.TagOpts): RiotElement;
  /**
   * Execute shallow rendering
   *
   * @param src single tag source or tag name preloaded to render
   * @param opts tag interface
   * @returns rendered tree
   */
  render(src: string, opts?: riot.TagOpts): RiotElement;
  render(): RiotElement {
    let src: string;
    let tagName: string | undefined;
    let opts: riot.TagOpts | undefined;
    // compile
    // tslint:disable-next-line:no-magic-numbers
    if (arguments.length === 3) {
      [src, tagName, opts] = <any>arguments;
      // tslint:disable-next-line:no-magic-numbers
    } else if (arguments.length === 2) {
      if (typeof arguments[1] === 'string') {
        [src, tagName, opts] = <any>arguments;
      } else {
        [src, opts] = <any>arguments;
      }
    } else {
      [src] = <any>arguments;
    }
 
    Eif (/^\s*</m.test(src)) {
      // Case: src is tag source
      const tagNames = this.loadTags(src);
      // Select tagName when single tag use.
      if (tagName === undefined) {
        Iif (tagNames.length !== 1) throw new Error('Tag source must be single');
 
        tagName = tagNames[0] as string;
      }
    } else {
      // Case: src is tag name
      tagName = src;
    }
 
    const tagInstance = this.createInstance(tagName, opts);
 
    tagInstance.mount();
    const rendered = tagInstance.root!;
 
    this.instance = tagInstance;
    return (this.rendered = rendered as HTMLElement | SVGElement);
  }
 
  /**
   * instanciate tag
   *
   * @param name tag name
   * @param opts tag interface
   * @param children children to yield. Ignored currently
   * @returns created instance unmounted
   */
  createInstance(
    name: string,
    opts: riot.TagOpts = {},
    Echildren: ReadonlyArray<RiotElement> = []
  ) {
    const element = createElementToMountTo(name);
    const rendered: riot.TagInstance[] = this.mount.apply(riot, [
      element,
      name,
      opts,
    ]);
    return rendered[0];
  }
 
  /** Get created instance of `render` */
  getMountedInstance() {
    Iif (this.instance === null) throw new Error('Call after render');
 
    return this.instance!;
  }
 
  /** Get latest result of `render` */
  getRenderedOutput() {
    // TODO: rename to getRenderOutput
    if (this.rendered === null) throw new Error('Call after render');
 
    return this.rendered!;
  }
 
  unmount() {
    if (this.instance !== null) {
      this.instance.unmount();
    }
    this.rendered = null;
    this.instance = null;
  }
}