diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index b3cdd96402..0aa96ca9d2 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -17,6 +17,7 @@ import clone from '../utils/clone'; import Stylesheet from '../css/Stylesheet'; import { test } from '../config'; import nodes from './nodes/index'; +import Fragment from './nodes/Fragment'; import { Node, GenerateOptions, ShorthandImport, Parsed, CompileOptions, CustomElementOptions } from '../interfaces'; interface Computation { @@ -83,6 +84,7 @@ export default class Generator { source: string; name: string; options: CompileOptions; + fragment: Fragment; customElement: CustomElementOptions; tag: string; @@ -191,6 +193,7 @@ export default class Generator { throw new Error(`No tag name specified`); // TODO better error } + this.fragment = new Fragment(this, parsed.html); this.walkTemplate(); if (!this.customElement) this.stylesheet.reify(); } @@ -711,7 +714,6 @@ export default class Generator { expectedProperties, helpers } = this; - const { html } = this.parsed; const contextualise = ( node: Node, contextDependencies: Map, @@ -782,7 +784,7 @@ export default class Generator { return parentIsHead(node.parent); } - walk(html, { + walk(this.fragment, { enter(node: Node, parent: Node, key: string) { // TODO this is hacky as hell if (key === 'parent') return this.skip(); diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 337d23d2ed..151dea4109 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -70,8 +70,8 @@ export default function dom( namespace, } = generator; - parsed.html.build(); - const { block } = parsed.html; + generator.fragment.build(); + const { block } = generator.fragment; // prevent fragment being created twice (#1063) if (options.customElement) block.builders.create.addLine(`this.c = @noop;`); diff --git a/src/generators/nodes/Attribute.ts b/src/generators/nodes/Attribute.ts index 904c971c1d..074cc18352 100644 --- a/src/generators/nodes/Attribute.ts +++ b/src/generators/nodes/Attribute.ts @@ -12,34 +12,22 @@ export interface StyleProp { value: Node[]; } -export default class Attribute { +export default class Attribute extends Node { type: 'Attribute'; start: number; end: number; - generator: DomGenerator; + compiler: DomGenerator; parent: Element; name: string; value: true | Node[] expression: Node; - constructor({ - generator, - name, - value, - parent - }: { - generator: DomGenerator, - name: string, - value: Node[], - parent: Element - }) { - this.type = 'Attribute'; - this.generator = generator; - this.parent = parent; - - this.name = name; - this.value = value; + constructor(compiler, parent, info) { + super(compiler, parent, info); + + this.name = info.name; + this.value = info.value; } render(block: Block) { diff --git a/src/generators/nodes/Element.ts b/src/generators/nodes/Element.ts index a44c949816..eb6c01e351 100644 --- a/src/generators/nodes/Element.ts +++ b/src/generators/nodes/Element.ts @@ -17,6 +17,7 @@ import Transition from './Transition'; import Action from './Action'; import Text from './Text'; import * as namespaces from '../../utils/namespaces'; +import mapChildren from './shared/mapChildren'; export default class Element extends Node { type: 'Element'; @@ -24,6 +25,29 @@ export default class Element extends Node { attributes: (Attribute | Binding | EventHandler | Ref | Transition | Action)[]; // TODO split these up sooner children: Node[]; + constructor(compiler, parent, info: any) { + super(compiler, parent, info); + this.name = info.name; + this.children = mapChildren(compiler, parent, info.children); + + this.attributes = []; + // TODO bindings etc + + info.attributes.forEach(node => { + switch (node.type) { + case 'Attribute': + case 'Spread': + this.attributes.push(new Attribute(compiler, this, node)); + break; + + default: + throw new Error(`Not implemented: ${node.type}`); + } + }); + + // TODO break out attributes and directives here + } + init( block: Block, stripWhitespace: boolean, diff --git a/src/generators/nodes/Fragment.ts b/src/generators/nodes/Fragment.ts index e4eb559679..f82b72b3d1 100644 --- a/src/generators/nodes/Fragment.ts +++ b/src/generators/nodes/Fragment.ts @@ -1,11 +1,18 @@ import Node from './shared/Node'; import { DomGenerator } from '../dom/index'; +import Generator from '../Generator'; +import mapChildren from './shared/mapChildren'; import Block from '../dom/Block'; export default class Fragment extends Node { block: Block; children: Node[]; + constructor(compiler: Generator, info: any) { + super(compiler, info); + this.children = mapChildren(compiler, this, info.children); + } + init() { this.block = new Block({ generator: this.generator, diff --git a/src/generators/nodes/MustacheTag.ts b/src/generators/nodes/MustacheTag.ts index 06c8548136..adf806c061 100644 --- a/src/generators/nodes/MustacheTag.ts +++ b/src/generators/nodes/MustacheTag.ts @@ -6,7 +6,7 @@ export default class MustacheTag extends Tag { init(block: Block) { this.cannotUseInnerHTML(); this.var = block.getUniqueName('text'); - block.addDependencies(this.metadata.dependencies); + block.addDependencies(this.expression.dependencies); } build( diff --git a/src/generators/nodes/shared/Expression.ts b/src/generators/nodes/shared/Expression.ts new file mode 100644 index 0000000000..868ec45ab5 --- /dev/null +++ b/src/generators/nodes/shared/Expression.ts @@ -0,0 +1,11 @@ +import Generator from '../../Generator'; + +export default class Expression { + compiler: Generator; + info: any; + + constructor(compiler, info) { + this.compiler = compiler; + this.info = info; + } +} \ No newline at end of file diff --git a/src/generators/nodes/shared/Node.ts b/src/generators/nodes/shared/Node.ts index 0d268f0c13..6fb2f8cc15 100644 --- a/src/generators/nodes/shared/Node.ts +++ b/src/generators/nodes/shared/Node.ts @@ -1,28 +1,20 @@ import { DomGenerator } from '../../dom/index'; +import Generator from './../../Generator'; import Block from '../../dom/Block'; import { trimStart, trimEnd } from '../../../utils/trim'; export default class Node { - type: string; - start: number; - end: number; - [key: string]: any; - - metadata?: { - dependencies: string[]; - snippet: string; - }; - + compiler: Generator; parent: Node; prev?: Node; next?: Node; - generator: DomGenerator; canUseInnerHTML: boolean; var: string; - constructor(data: Record) { - Object.assign(this, data); + constructor(compiler: Generator, parent, info: any) { + this.compiler = compiler; + this.parent = parent; } cannotUseInnerHTML() { diff --git a/src/generators/nodes/shared/Tag.ts b/src/generators/nodes/shared/Tag.ts index e400843519..b762e09311 100644 --- a/src/generators/nodes/shared/Tag.ts +++ b/src/generators/nodes/shared/Tag.ts @@ -1,7 +1,15 @@ import Node from './Node'; +import Expression from './Expression'; import Block from '../../dom/Block'; export default class Tag extends Node { + expression: Expression; + + constructor(compiler, parent, info) { + super(compiler, parent, info); + this.expression = new Expression(compiler, info.expression); + } + renameThisMethod( block: Block, update: ((value: string) => string) diff --git a/src/generators/nodes/shared/mapChildren.ts b/src/generators/nodes/shared/mapChildren.ts new file mode 100644 index 0000000000..aaac0edc2d --- /dev/null +++ b/src/generators/nodes/shared/mapChildren.ts @@ -0,0 +1,27 @@ +import Element from '../Element'; +import Text from '../Text'; +import MustacheTag from '../MustacheTag'; +import Node from './Node'; + +function getConstructor(type): typeof Node { + switch (type) { + case 'Element': return Element; + case 'Text': return Text; + case 'MustacheTag': return MustacheTag; + default: throw new Error(`Not implemented: ${type}`); + } +} + +export default function mapChildren(compiler, parent, children: any[]) { + let last = null; + return children.map(child => { + const constructor = getConstructor(child.type); + const node = new constructor(compiler, parent, child); + + if (last) last.next = node; + node.prev = last; + last = node; + + return node; + }); +} \ No newline at end of file diff --git a/test/runtime/samples/attribute-dynamic/_config.js b/test/runtime/samples/attribute-dynamic/_config.js index 9b33022e62..f6afbeca10 100644 --- a/test/runtime/samples/attribute-dynamic/_config.js +++ b/test/runtime/samples/attribute-dynamic/_config.js @@ -1,4 +1,5 @@ export default { + solo: true, html: `
red
`, test ( assert, component, target ) { diff --git a/tsconfig.json b/tsconfig.json index 14c8034b76..fdb7367e05 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,8 @@ "noEmitOnError": true, "allowJs": true, "lib": ["es5", "es6", "dom"], - "importHelpers": true + "importHelpers": true, + "moduleResolution": "node" }, "include": [ "src"