pull/1348/head
Rich Harris 7 years ago
parent 8eb4adc7e6
commit a2759604cb

@ -84,7 +84,6 @@ export default class Generator {
source: string; source: string;
name: string; name: string;
options: CompileOptions; options: CompileOptions;
v2: boolean;
customElement: CustomElementOptions; customElement: CustomElementOptions;
tag: string; tag: string;
@ -133,8 +132,6 @@ export default class Generator {
stats.start('compile'); stats.start('compile');
this.stats = stats; this.stats = stats;
this.v2 = options.parser === 'v2';
this.ast = clone(parsed); this.ast = clone(parsed);
this.parsed = parsed; this.parsed = parsed;
@ -560,9 +557,7 @@ export default class Generator {
const key = getName(prop.key); const key = getName(prop.key);
const value = prop.value; const value = prop.value;
const deps = this.v2 const deps = value.params[0].properties.map(prop => prop.key.name);
? value.params[0].properties.map(prop => prop.key.name)
: value.params.map(param => param.type === 'AssignmentPattern' ? param.left.name : param.name);
deps.forEach(dep => { deps.forEach(dep => {
this.expectedProperties.add(dep); this.expectedProperties.add(dep);
@ -621,12 +616,10 @@ export default class Generator {
this.namespace = namespaces[ns] || ns; this.namespace = namespaces[ns] || ns;
} }
if (templateProperties.onrender) templateProperties.oncreate = templateProperties.onrender; // remove after v2
if (templateProperties.oncreate && dom) { if (templateProperties.oncreate && dom) {
addDeclaration('oncreate', templateProperties.oncreate.value); addDeclaration('oncreate', templateProperties.oncreate.value);
} }
if (templateProperties.onteardown) templateProperties.ondestroy = templateProperties.onteardown; // remove after v2
if (templateProperties.ondestroy && dom) { if (templateProperties.ondestroy && dom) {
addDeclaration('ondestroy', templateProperties.ondestroy.value); addDeclaration('ondestroy', templateProperties.ondestroy.value);
} }

@ -99,11 +99,7 @@ export default function dom(
const condition = `${deps.map(dep => `changed.${dep}`).join(' || ')}`; const condition = `${deps.map(dep => `changed.${dep}`).join(' || ')}`;
const call = generator.v2 const statement = `if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;`;
? `%computed-${key}(state)`
: `%computed-${key}(${deps.map(dep => `state.${dep}`).join(', ')})`;
const statement = `if (this._differs(state.${key}, (state.${key} = ${call}))) changed.${key} = true;`;
computationBuilder.addConditional(condition, statement); computationBuilder.addConditional(condition, statement);
}); });

@ -137,7 +137,7 @@ export default function ssr(
${computations.map( ${computations.map(
({ key, deps }) => ({ key, deps }) =>
`state.${key} = %computed-${key}(${deps.map(dep => `state.${dep}`).join(', ')});` `state.${key} = %computed-${key}(state);`
)} )}
${generator.bindings.length && ${generator.bindings.length &&

@ -65,8 +65,6 @@ export interface CompileOptions {
onerror?: (error: Error) => void; onerror?: (error: Error) => void;
onwarn?: (warning: Warning) => void; onwarn?: (warning: Warning) => void;
parser?: 'v2';
} }
export interface GenerateOptions { export interface GenerateOptions {

@ -13,13 +13,11 @@ import error from '../utils/error';
interface ParserOptions { interface ParserOptions {
filename?: string; filename?: string;
bind?: boolean; bind?: boolean;
parser?: 'v2';
} }
type ParserState = (parser: Parser) => (ParserState | void); type ParserState = (parser: Parser) => (ParserState | void);
export class Parser { export class Parser {
readonly v2: boolean;
readonly template: string; readonly template: string;
readonly filename?: string; readonly filename?: string;
@ -34,8 +32,6 @@ export class Parser {
allowBindings: boolean; allowBindings: boolean;
constructor(template: string, options: ParserOptions) { constructor(template: string, options: ParserOptions) {
this.v2 = options.parser === 'v2';
if (typeof template !== 'string') { if (typeof template !== 'string') {
throw new TypeError('Template must be a string'); throw new TypeError('Template must be a string');
} }

@ -165,10 +165,10 @@ export function readDirective(
// assume the mistake was wrapping the directive arguments. // assume the mistake was wrapping the directive arguments.
// this could yield false positives! but hopefully not too many // this could yield false positives! but hopefully not too many
let message = 'directive values should not be wrapped'; let message = 'directive values should not be wrapped';
const expressionEnd = parser.template.indexOf((parser.v2 ? '}' : '}}'), expressionStart); const expressionEnd = parser.template.indexOf('}', expressionStart);
if (expressionEnd !== -1) { if (expressionEnd !== -1) {
const value = parser.template.slice(expressionStart + (parser.v2 ? 1 : 2), expressionEnd); const value = parser.template.slice(expressionStart + 1, expressionEnd);
message += ` — use '${value}', not '${parser.v2 ? `{${value}}` : `{{${value}}}`}'`; message += ` — use '${value}', not '{${value}}'`;
} }
parser.error({ parser.error({
code: `invalid-directive-value`, code: `invalid-directive-value`,

@ -6,7 +6,7 @@ const literals = new Map([['true', true], ['false', false], ['null', null]]);
export default function readExpression(parser: Parser) { export default function readExpression(parser: Parser) {
const start = parser.index; const start = parser.index;
const name = parser.readUntil(parser.v2 ? /\s*}/ : /\s*}}/); const name = parser.readUntil(/\s*}/);
if (name && /^[a-z]+$/.test(name)) { if (name && /^[a-z]+$/.test(name)) {
const end = start + name.length; const end = start + name.length;

@ -8,7 +8,7 @@ export default function fragment(parser: Parser) {
return tag; return tag;
} }
if (parser.match(parser.v2 ? '{' : '{{')) { if (parser.match('{')) {
return mustache; return mustache;
} }

@ -32,7 +32,7 @@ function trimWhitespace(block: Node, trimBefore: boolean, trimAfter: boolean) {
export default function mustache(parser: Parser) { export default function mustache(parser: Parser) {
const start = parser.index; const start = parser.index;
parser.index += parser.v2 ? 1 : 2; parser.index += 1;
parser.allowWhitespace(); parser.allowWhitespace();
@ -64,7 +64,7 @@ export default function mustache(parser: Parser) {
parser.eat(expected, true); parser.eat(expected, true);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
while (block.elseif) { while (block.elseif) {
block.end = parser.index; block.end = parser.index;
@ -86,7 +86,7 @@ export default function mustache(parser: Parser) {
block.end = parser.index; block.end = parser.index;
parser.stack.pop(); parser.stack.pop();
} else if (parser.eat(parser.v2 ? ':elseif' : 'elseif')) { } else if (parser.eat(':elseif')) {
const block = parser.current(); const block = parser.current();
if (block.type !== 'IfBlock') if (block.type !== 'IfBlock')
parser.error({ parser.error({
@ -99,7 +99,7 @@ export default function mustache(parser: Parser) {
const expression = readExpression(parser); const expression = readExpression(parser);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
block.else = { block.else = {
start: parser.index, start: parser.index,
@ -118,7 +118,7 @@ export default function mustache(parser: Parser) {
}; };
parser.stack.push(block.else.children[0]); parser.stack.push(block.else.children[0]);
} else if (parser.eat(parser.v2 ? ':else' : 'else')) { } else if (parser.eat(':else')) {
const block = parser.current(); const block = parser.current();
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') { if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
parser.error({ parser.error({
@ -128,7 +128,7 @@ export default function mustache(parser: Parser) {
} }
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
block.else = { block.else = {
start: parser.index, start: parser.index,
@ -138,7 +138,7 @@ export default function mustache(parser: Parser) {
}; };
parser.stack.push(block.else); parser.stack.push(block.else);
} else if (parser.eat(parser.v2 ? ':then' : 'then')) { } else if (parser.eat(':then')) {
// TODO DRY out this and the next section // TODO DRY out this and the next section
const pendingBlock = parser.current(); const pendingBlock = parser.current();
if (pendingBlock.type === 'PendingBlock') { if (pendingBlock.type === 'PendingBlock') {
@ -150,7 +150,7 @@ export default function mustache(parser: Parser) {
awaitBlock.value = parser.readIdentifier(); awaitBlock.value = parser.readIdentifier();
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
const thenBlock: Node = { const thenBlock: Node = {
start, start,
@ -162,7 +162,7 @@ export default function mustache(parser: Parser) {
awaitBlock.then = thenBlock; awaitBlock.then = thenBlock;
parser.stack.push(thenBlock); parser.stack.push(thenBlock);
} }
} else if (parser.eat(parser.v2 ? ':catch' : 'catch')) { } else if (parser.eat(':catch')) {
const thenBlock = parser.current(); const thenBlock = parser.current();
if (thenBlock.type === 'ThenBlock') { if (thenBlock.type === 'ThenBlock') {
thenBlock.end = start; thenBlock.end = start;
@ -173,7 +173,7 @@ export default function mustache(parser: Parser) {
awaitBlock.error = parser.readIdentifier(); awaitBlock.error = parser.readIdentifier();
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
const catchBlock: Node = { const catchBlock: Node = {
start, start,
@ -336,7 +336,7 @@ export default function mustache(parser: Parser) {
parser.allowWhitespace(); parser.allowWhitespace();
} }
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
parser.current().children.push(block); parser.current().children.push(block);
parser.stack.push(block); parser.stack.push(block);
@ -346,44 +346,12 @@ export default function mustache(parser: Parser) {
childBlock.start = parser.index; childBlock.start = parser.index;
parser.stack.push(childBlock); parser.stack.push(childBlock);
} }
} else if (parser.eat('yield')) { } else if (parser.eat('@html')) {
// {{yield}}
// TODO deprecate
parser.allowWhitespace();
if (parser.v2) {
const expressionEnd = parser.index;
parser.eat('}', true);
parser.current().children.push({
start,
end: parser.index,
type: 'MustacheTag',
expression: {
start: expressionEnd - 5,
end: expressionEnd,
type: 'Identifier',
name: 'yield'
}
});
} else {
parser.eat('}}', true);
parser.current().children.push({
start,
end: parser.index,
type: 'Element',
name: 'slot',
attributes: [],
children: []
});
}
} else if (parser.eat(parser.v2 ? '@html' : '{')) {
// {{{raw}}} mustache // {{{raw}}} mustache
const expression = readExpression(parser); const expression = readExpression(parser);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}}', true); parser.eat('}', true);
parser.current().children.push({ parser.current().children.push({
start, start,
@ -395,7 +363,7 @@ export default function mustache(parser: Parser) {
const expression = readExpression(parser); const expression = readExpression(parser);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
parser.current().children.push({ parser.current().children.push({
start, start,

@ -11,8 +11,6 @@ import { Node } from '../../interfaces';
const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const metaTags = new Map([ const metaTags = new Map([
[':Window', 'Window'],
[':Head', 'Head'],
['svelte:window', 'Window'], ['svelte:window', 'Window'],
['svelte:head', 'Head'] ['svelte:head', 'Head']
]); ]);
@ -34,6 +32,9 @@ const specials = new Map([
], ],
]); ]);
const SELF = 'svelte:self';
const COMPONENT = 'svelte:component';
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission // based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowedContents = new Map([ const disallowedContents = new Map([
['li', new Set(['li'])], ['li', new Set(['li'])],
@ -198,7 +199,7 @@ export default function tag(parser: Parser) {
parser.allowWhitespace(); parser.allowWhitespace();
} }
if (parser.v2 && name === 'svelte:component') { if (name === 'svelte:component') {
// TODO post v2, treat this just as any other attribute // TODO post v2, treat this just as any other attribute
const index = element.attributes.findIndex(attr => attr.name === 'this'); const index = element.attributes.findIndex(attr => attr.name === 'this');
if (!~index) { if (!~index) {
@ -264,21 +265,11 @@ export default function tag(parser: Parser) {
element.end = parser.index; element.end = parser.index;
} else if (name === 'style') { } else if (name === 'style') {
// special case // special case
if (parser.v2) {
const start = parser.index; const start = parser.index;
const data = parser.readUntil(/<\/style>/); const data = parser.readUntil(/<\/style>/);
const end = parser.index; const end = parser.index;
element.children.push({ start, end, type: 'Text', data }); element.children.push({ start, end, type: 'Text', data });
parser.eat('</style>', true); parser.eat('</style>', true);
} else {
element.children = readSequence(
parser,
() =>
parser.template.slice(parser.index, parser.index + 8) === '</style>'
);
parser.read(/<\/style>/);
element.end = parser.index;
}
} else { } else {
parser.stack.push(element); parser.stack.push(element);
} }
@ -287,10 +278,6 @@ export default function tag(parser: Parser) {
function readTagName(parser: Parser) { function readTagName(parser: Parser) {
const start = parser.index; const start = parser.index;
// TODO hoist these back to the top, post-v2
const SELF = parser.v2 ? 'svelte:self' : ':Self';
const COMPONENT = parser.v2 ? 'svelte:component' : ':Component';
if (parser.eat(SELF)) { if (parser.eat(SELF)) {
// check we're inside a block, otherwise this // check we're inside a block, otherwise this
// will cause infinite recursion // will cause infinite recursion
@ -334,14 +321,14 @@ function readTagName(parser: Parser) {
function readAttribute(parser: Parser, uniqueNames: Set<string>) { function readAttribute(parser: Parser, uniqueNames: Set<string>) {
const start = parser.index; const start = parser.index;
if (parser.eat(parser.v2 ? '{' : '{{')) { if (parser.eat('{')) {
parser.allowWhitespace(); parser.allowWhitespace();
if (parser.eat('...')) { if (parser.eat('...')) {
const expression = readExpression(parser); const expression = readExpression(parser);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
return { return {
start, start,
@ -350,13 +337,6 @@ function readAttribute(parser: Parser, uniqueNames: Set<string>) {
expression expression
}; };
} else { } else {
if (!parser.v2) {
parser.error({
code: `expected-spread`,
message: 'Expected spread operator (...)'
});
}
const valueStart = parser.index; const valueStart = parser.index;
const name = parser.readIdentifier(); const name = parser.readIdentifier();
@ -449,7 +429,7 @@ function readSequence(parser: Parser, done: () => boolean) {
}); });
return chunks; return chunks;
} else if (parser.eat(parser.v2 ? '{' : '{{')) { } else if (parser.eat('{')) {
if (currentChunk.data) { if (currentChunk.data) {
currentChunk.end = index; currentChunk.end = index;
chunks.push(currentChunk); chunks.push(currentChunk);
@ -457,7 +437,7 @@ function readSequence(parser: Parser, done: () => boolean) {
const expression = readExpression(parser); const expression = readExpression(parser);
parser.allowWhitespace(); parser.allowWhitespace();
parser.eat(parser.v2 ? '}' : '}}', true); parser.eat('}', true);
chunks.push({ chunks.push({
start: index, start: index,

@ -9,7 +9,7 @@ export default function text(parser: Parser) {
while ( while (
parser.index < parser.template.length && parser.index < parser.template.length &&
!parser.match('<') && !parser.match('<') &&
!parser.match(parser.v2 ? '{' : '{{') !parser.match('{')
) { ) {
data += parser.template[parser.index++]; data += parser.template[parser.index++];
} }

@ -2,29 +2,28 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { compile } from '../index.ts'; import { compile } from '../index.ts';
let compileOptions = {}; let compileOptions = {
extensions: ['.html']
};
function capitalise(name) { function capitalise(name) {
return name[0].toUpperCase() + name.slice(1); return name[0].toUpperCase() + name.slice(1);
} }
export default function register(options) { export default function register(options) {
const { extensions } = options; if (options.extensions) {
compileOptions.extensions.forEach(deregisterExtension);
if (extensions) { options.extensions.forEach(registerExtension);
_deregister('.html');
extensions.forEach(_register);
} }
// TODO make this the default and remove in v2 compileOptions = options;
if (options) compileOptions = options;
} }
function _deregister(extension) { function deregisterExtension(extension) {
delete require.extensions[extension]; delete require.extensions[extension];
} }
function _register(extension) { function registerExtension(extension) {
require.extensions[extension] = function(module, filename) { require.extensions[extension] = function(module, filename) {
const name = path.basename(filename) const name = path.basename(filename)
.slice(0, -path.extname(filename).length) .slice(0, -path.extname(filename).length)
@ -43,4 +42,4 @@ function _register(extension) {
}; };
} }
_register('.html'); registerExtension('.html');

@ -19,8 +19,7 @@ export default function validateElement(
} }
if (!isComponent && /^[A-Z]/.test(node.name[0])) { if (!isComponent && /^[A-Z]/.test(node.name[0])) {
// TODO upgrade to validator.error in v2 validator.error(node, {
validator.warn(node, {
code: `missing-component`, code: `missing-component`,
message: `${node.name} component is not defined` message: `${node.name} component is not defined`
}); });

@ -11,7 +11,6 @@ import { Node, Parsed, CompileOptions, Warning } from '../interfaces';
export class Validator { export class Validator {
readonly source: string; readonly source: string;
readonly filename: string; readonly filename: string;
readonly v2: boolean;
readonly stats: Stats; readonly stats: Stats;
options: CompileOptions; options: CompileOptions;
@ -41,7 +40,6 @@ export class Validator {
this.filename = options.filename; this.filename = options.filename;
this.options = options; this.options = options;
this.v2 = options.parser === 'v2';
this.namespace = null; this.namespace = null;
this.defaultExport = null; this.defaultExport = null;

@ -75,7 +75,6 @@ export default function computed(validator: Validator, prop: Node) {
}); });
} }
if (validator.v2) {
if (params.length > 1) { if (params.length > 1) {
validator.error(computation.value, { validator.error(computation.value, {
code: `invalid-computed-arguments`, code: `invalid-computed-arguments`,
@ -85,27 +84,11 @@ export default function computed(validator: Validator, prop: Node) {
const param = params[0]; const param = params[0];
if (param.type !== 'ObjectPattern') { if (param.type !== 'ObjectPattern') {
// TODO in v2, allow the entire object to be passed in // TODO post-v2, allow the entire object to be passed in
validator.error(computation.value, { validator.error(computation.value, {
code: `invalid-computed-argument`, code: `invalid-computed-argument`,
message: `Computed property argument must be a destructured object pattern` message: `Computed property argument must be a destructured object pattern`
}); });
} }
} else {
params.forEach((param: Node) => {
const valid =
param.type === 'Identifier' ||
(param.type === 'AssignmentPattern' &&
param.left.type === 'Identifier');
if (!valid) {
// TODO change this for v2
validator.error(param, {
code: `invalid-computed-arguments`,
message: `Computed properties cannot use destructuring in function parameters`
});
}
});
}
}); });
} }

@ -110,9 +110,7 @@ describe("ssr", () => {
delete require.cache[resolved]; delete require.cache[resolved];
}); });
const compileOptions = Object.assign(config.compileOptions || {}, { const compileOptions = config.compileOptions || {};
store: !!config.store
});
require("../../ssr/register")(compileOptions); require("../../ssr/register")(compileOptions);

@ -1 +1 @@
<div style='font-family: {{font}}; color: {{color}};'>{{color}} {{font}}</div> <div style='font-family: {font}; color: {color};'>{color} {font}</div>

@ -1,4 +1,4 @@
{{y}}<Foo bind:y='x'/>{{y}} {y}<Foo bind:y='x'/>{y}
<script> <script>
import Foo from './Foo.html'; import Foo from './Foo.html';

@ -1,4 +1,4 @@
{{x}}<Foo bind:x/>{{x}} {x}<Foo bind:x/>{x}
<script> <script>
import Foo from './Foo.html'; import Foo from './Foo.html';

@ -1,4 +1,4 @@
<p>foo: {{foo}}</p> <p>foo: {foo}</p>
<p>baz: {{baz}} ({{typeof baz}})</p> <p>baz: {baz} ({typeof baz})</p>
<p>qux: {{qux}}</p> <p>qux: {qux}</p>
<p>quux: {{quux}}</p> <p>quux: {quux}</p>

@ -1,5 +1,5 @@
<div> <div>
<Widget foo='{{bar}}' baz='{{40 + x}}' qux='this is a {{compound}} string' quux='{{go.deeper}}'/> <Widget foo='{bar}' baz='{40 + x}' qux='this is a {compound} string' quux='{go.deeper}'/>
</div> </div>
<script> <script>

@ -1,2 +1,2 @@
<p>foo: {{foo}}</p> <p>foo: {foo}</p>
<p>baz: {{baz}} ({{typeof baz}})</p> <p>baz: {baz} ({typeof baz})</p>

@ -1,4 +1,4 @@
<div><Widget ref:widget foo='{{foo}}'/></div> <div><Widget ref:widget foo='{foo}'/></div>
<script> <script>
import Widget from './Widget.html'; import Widget from './Widget.html';

@ -1,4 +1,4 @@
<p>{{yield}}</p> <p><slot></slot></p>
<script> <script>
export default { export default {

@ -1,5 +1,5 @@
<div> <div>
<Widget>{{data}}</Widget> <Widget>{data}</Widget>
</div> </div>
<script> <script>

@ -1,11 +1,11 @@
<p>{{a}} + {{b}} = {{c}}</p> <p>{a} + {b} = {c}</p>
<p>{{c}} * {{c}} = {{cSquared}}</p> <p>{c} * {c} = {cSquared}</p>
<script> <script>
export default { export default {
computed: { computed: {
c: ( a, b ) => a + b, c: ({ a, b }) => a + b,
cSquared: c => c * c cSquared: ({ c }) => c * c
} }
}; };
</script> </script>

@ -1,4 +1,4 @@
<p>{{foo}}</p> <p>{foo}</p>
<script> <script>
export default { export default {

@ -1,4 +1,4 @@
<p>{{foo}}</p> <p>{foo}</p>
<script> <script>
export default { export default {

@ -1,3 +1,3 @@
{{#each animals as animal, i}} {#each animals as animal, i}
<p>{{i + 1}}: {{animal}}</p> <p>{i + 1}: {animal}</p>
{{/each}} {/each}

@ -1,3 +1,3 @@
<:Head> <svelte:head>
<title>a {{adjective}} title</title> <title>a {adjective} title</title>
</:Head> </svelte:head>

@ -1,4 +1,4 @@
<p>{{thrice(foo)}}</p> <p>{thrice(foo)}</p>
<script> <script>
export default { export default {

@ -1,3 +1,3 @@
{{#if foo}} {#if foo}
<p>foo is true</p> <p>foo is true</p>
{{/if}} {/if}

@ -1,3 +1,3 @@
{{#if foo}} {#if foo}
<p>foo is true</p> <p>foo is true</p>
{{/if}} {/if}

@ -1,5 +1,5 @@
<div>i got {{problems}} problems</div> <div>i got {problems} problems</div>
<div>the answer is {{answer}}</div> <div>the answer is {answer}</div>
<script> <script>
import answer from './answer.js'; import answer from './answer.js';

@ -1 +1 @@
before{{{raw}}}after before{@html raw}after

@ -1,4 +1,4 @@
<div>green: {{message}}</div> <div>green: {message}</div>
<!-- Two styles should *not* be included --> <!-- Two styles should *not* be included -->
<!-- <Two message='{{message}}'/> --> <!-- <Two message='{{message}}'/> -->

@ -1,4 +1,4 @@
<div>blue: {{message}}</div> <div>blue: {message}</div>
<style> <style>
div { div {

@ -1,5 +1,5 @@
<textarea> <textarea>
<p>not actually an element. {{foo}}</p> <p>not actually an element. {foo}</p>
</textarea> </textarea>
<script> <script>

@ -1,4 +1,4 @@
<textarea value='{{foo}}'/> <textarea value='{foo}'/>
<script> <script>
export default { export default {

@ -1,4 +1,4 @@
<div>{{{triple}}}</div> <div>{@html triple}</div>
<script> <script>
export default { export default {

Loading…
Cancel
Save