Skip to content

Commit

Permalink
self-references (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Mar 4, 2017
1 parent f799cae commit 0f60242
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/generators/Generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import getOutro from './shared/utils/getOutro.js';
import annotateWithScopes from './annotateWithScopes.js';

export default class Generator {
constructor ( parsed, source, names, visitors ) {
constructor ( parsed, source, name, names, visitors ) {
this.parsed = parsed;
this.source = source;
this.name = name;
this.names = names;
this.visitors = visitors;

Expand Down
6 changes: 3 additions & 3 deletions src/generators/dom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import Generator from '../Generator.js';
import * as shared from '../../shared/index.js';

class DomGenerator extends Generator {
constructor ( parsed, source, names, visitors ) {
super( parsed, source, names, visitors );
constructor ( parsed, source, name, names, visitors ) {
super( parsed, source, name, names, visitors );
this.renderers = [];
this.uses = {};

Expand Down Expand Up @@ -152,7 +152,7 @@ export default function dom ( parsed, source, options, names ) {
const format = options.format || 'es';
const name = options.name || 'SvelteComponent';

const generator = new DomGenerator( parsed, source, names, visitors );
const generator = new DomGenerator( parsed, source, name, names, visitors );

const { computations, templateProperties } = generator.parseJs();

Expand Down
10 changes: 8 additions & 2 deletions src/generators/dom/visitors/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import deindent from '../../../utils/deindent.js';
import CodeBuilder from '../../../utils/CodeBuilder.js';
import addComponentAttributes from './attributes/addComponentAttributes.js';

function capDown ( name ) {
return `${name[0].toLowerCase()}${name.slice( 1 )}`;
}

export default {
enter ( generator, node ) {
const hasChildren = node.children.length > 0;
const name = generator.current.getUniqueName( `${node.name[0].toLowerCase()}${node.name.slice( 1 )}` );
const name = generator.current.getUniqueName( capDown( node.name === ':Self' ? generator.name : node.name ) );

const local = {
name,
Expand Down Expand Up @@ -104,9 +108,11 @@ export default {
componentInitProperties.push(`data: ${name}_initialData`);
}

const expression = node.name === ':Self' ? generator.name : `template.components.${node.name}`;

local.init.addBlockAtStart( deindent`
${statements.join( '\n\n' )}
var ${name} = new template.components.${node.name}({
var ${name} = new ${expression}({
${componentInitProperties.join(',\n')}
});
` );
Expand Down
2 changes: 1 addition & 1 deletion src/generators/dom/visitors/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Component from './Component.js';

export default {
enter ( generator, node ) {
const isComponent = node.name in generator.components;
const isComponent = node.name in generator.components || node.name === ':Self';
if ( isComponent ) {
return Component.enter( generator, node );
}
Expand Down
8 changes: 4 additions & 4 deletions src/generators/server-side-rendering/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import visitors from './visitors/index.js';
import Generator from '../Generator.js';

class SsrGenerator extends Generator {
constructor ( parsed, source, names, visitors ) {
super( parsed, source, names, visitors );
constructor ( parsed, source, name, names, visitors ) {
super( parsed, source, name, names, visitors );
this.bindings = [];
this.renderCode = '';
}
Expand All @@ -18,7 +18,7 @@ class SsrGenerator extends Generator {

this.bindings.push( deindent`
if ( ${conditions.join( '&&' )} ) {
tmp = template.components.${name}.data();
tmp = ${name}.data();
if ( '${binding.value}' in tmp ) {
root.${binding.name} = tmp.${binding.value};
settled = false;
Expand All @@ -36,7 +36,7 @@ export default function ssr ( parsed, source, options, names ) {
const format = options.format || 'cjs';
const name = options.name || 'SvelteComponent';

const generator = new SsrGenerator( parsed, source, names, visitors );
const generator = new SsrGenerator( parsed, source, name, names, visitors );

const { computations, templateProperties } = generator.parseJs();

Expand Down
6 changes: 4 additions & 2 deletions src/generators/server-side-rendering/visitors/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ export default {
})
.join( ', ' );

const expression = node.name === ':Self' ? generator.name : `template.components.${node.name}`;

bindings.forEach( binding => {
generator.addBinding( binding, node.name );
generator.addBinding( binding, expression );
});

let open = `\${template.components.${node.name}.render({${props}}`;
let open = `\${${expression}.render({${props}}`;

if ( node.children.length ) {
open += `, { yield: () => \``;
Expand Down
4 changes: 2 additions & 2 deletions src/generators/server-side-rendering/visitors/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import voidElementNames from '../../../utils/voidElementNames.js';

export default {
enter ( generator, node ) {
if ( node.name in generator.components ) {
if ( node.name in generator.components || node.name === ':Self' ) {
Component.enter( generator, node );
return;
}
Expand Down Expand Up @@ -39,7 +39,7 @@ export default {
},

leave ( generator, node ) {
if ( node.name in generator.components ) {
if ( node.name in generator.components || node.name === ':Self' ) {
Component.leave( generator, node );
return;
}
Expand Down
23 changes: 23 additions & 0 deletions src/parse/state/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import voidElementNames from '../../utils/voidElementNames.js';
const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const invalidUnquotedAttributeCharacters = /[\s"'=<>\/`]/;

const SELF = ':Self';

const specials = {
script: {
read: readScript,
Expand Down Expand Up @@ -170,6 +172,27 @@ export default function tag ( parser ) {
function readTagName ( parser ) {
const start = parser.index;

if ( parser.eat( SELF ) ) {
// check we're inside a block, otherwise this
// will cause infinite recursion
let i = parser.stack.length;
let legal = false;

while ( i-- ) {
const fragment = parser.stack[i];
if ( fragment.type === 'IfBlock' || fragment.type === 'ElseBlock' ) {
legal = true;
break;
}
}

if ( !legal ) {
parser.error( `<${SELF}> components can only exist inside if-blocks or each-blocks`, start );
}

return SELF;
}

const name = parser.readUntil( /(\s|\/|>)/ );
if ( !validTagName.test( name ) ) {
parser.error( `Expected valid tag name`, start );
Expand Down
14 changes: 14 additions & 0 deletions test/generator/self-reference/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default {
data: {
depth: 5
},

html: `
<span>5</span>
<span>4</span>
<span>3</span>
<span>2</span>
<span>1</span>
<span>0</span>
`
};
4 changes: 4 additions & 0 deletions test/generator/self-reference/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<span>{{depth}}</span>
{{#if depth > 0}}
<:Self depth='{{depth - 1}}'/>
{{/if}}
8 changes: 8 additions & 0 deletions test/parser/error-self-reference/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"message": "<:Self> components can only exist inside if-blocks or each-blocks",
"loc": {
"line": 1,
"column": 1
},
"pos": 1
}
1 change: 1 addition & 0 deletions test/parser/error-self-reference/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<:Self/>
3 changes: 3 additions & 0 deletions test/parser/self-reference/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{#if depth > 1}}
<:Self depth='{{depth - 1}}'/>
{{/if}}
79 changes: 79 additions & 0 deletions test/parser/self-reference/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"hash": 1792372370,
"html": {
"start": 0,
"end": 57,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 57,
"type": "IfBlock",
"expression": {
"type": "BinaryExpression",
"start": 6,
"end": 15,
"left": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "depth"
},
"operator": ">",
"right": {
"type": "Literal",
"start": 14,
"end": 15,
"value": 1,
"raw": "1"
}
},
"children": [
{
"start": 19,
"end": 49,
"type": "Element",
"name": ":Self",
"attributes": [
{
"start": 26,
"end": 47,
"type": "Attribute",
"name": "depth",
"value": [
{
"start": 33,
"end": 46,
"type": "MustacheTag",
"expression": {
"type": "BinaryExpression",
"start": 35,
"end": 44,
"left": {
"type": "Identifier",
"start": 35,
"end": 40,
"name": "depth"
},
"operator": "-",
"right": {
"type": "Literal",
"start": 43,
"end": 44,
"value": 1,
"raw": "1"
}
}
}
]
}
],
"children": []
}
]
}
]
},
"css": null,
"js": null
}

0 comments on commit 0f60242

Please sign in to comment.