pull/31/head
Rich-Harris 8 years ago
parent 49a6aeb190
commit f136f951b3

@ -2,7 +2,6 @@ import MagicString from 'magic-string';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import deindent from './utils/deindent.js'; import deindent from './utils/deindent.js';
import walkHtml from './utils/walkHtml.js'; import walkHtml from './utils/walkHtml.js';
import flattenReference from './utils/flattenReference.js';
import isReference from './utils/isReference.js'; import isReference from './utils/isReference.js';
import contextualise from './utils/contextualise.js'; import contextualise from './utils/contextualise.js';
import counter from './utils/counter.js'; import counter from './utils/counter.js';
@ -54,6 +53,13 @@ export default function generate ( parsed, template ) {
} }
} }
const helpers = {};
if ( templateProperties.helpers ) {
templateProperties.helpers.properties.forEach( prop => {
helpers[ prop.key.name ] = prop.value;
});
}
const renderers = []; const renderers = [];
const expressionFunctions = []; const expressionFunctions = [];
@ -86,6 +92,10 @@ export default function generate ( parsed, template ) {
parsed.html.children.forEach( child => { parsed.html.children.forEach( child => {
walkHtml( child, { walkHtml( child, {
Comment: {
// do nothing
},
Element: { Element: {
enter ( node ) { enter ( node ) {
const name = current.counter( node.name ); const name = current.counter( node.name );
@ -105,7 +115,7 @@ export default function generate ( parsed, template ) {
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
if ( attribute.type === 'Attribute' ) { if ( attribute.type === 'Attribute' ) {
let metadata = attributeLookup[ attribute.name ]; let metadata = attributeLookup[ attribute.name ];
if ( metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null; if ( metadata && metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null;
if ( attribute.value === true ) { if ( attribute.value === true ) {
// attributes without values, e.g. <textarea readonly> // attributes without values, e.g. <textarea readonly>
@ -142,7 +152,7 @@ export default function generate ( parsed, template ) {
else { else {
// dynamic but potentially non-string attributes // dynamic but potentially non-string attributes
contextualise( code, value.expression, current.contexts ); contextualise( code, value.expression, current.contexts, helpers );
result = `[✂${value.expression.start}-${value.expression.end}✂]`; result = `[✂${value.expression.start}-${value.expression.end}✂]`;
if ( metadata ) { if ( metadata ) {
@ -163,7 +173,7 @@ export default function generate ( parsed, template ) {
if ( chunk.type === 'Text' ) { if ( chunk.type === 'Text' ) {
return JSON.stringify( chunk.data ); return JSON.stringify( chunk.data );
} else { } else {
contextualise( code, chunk.expression, current.contexts ); contextualise( code, chunk.expression, current.contexts, helpers );
return `[✂${chunk.expression.start}-${chunk.expression.end}✂]`; return `[✂${chunk.expression.start}-${chunk.expression.end}✂]`;
} }
}).join( ' + ' ) }).join( ' + ' )
@ -190,7 +200,7 @@ export default function generate ( parsed, template ) {
const usedContexts = new Set(); const usedContexts = new Set();
attribute.expression.arguments.forEach( arg => { attribute.expression.arguments.forEach( arg => {
const contexts = contextualise( code, arg, current.contexts ); const contexts = contextualise( code, arg, current.contexts, helpers );
contexts.forEach( context => { contexts.forEach( context => {
usedContexts.add( context ); usedContexts.add( context );
@ -285,7 +295,7 @@ export default function generate ( parsed, template ) {
${current.target}.appendChild( ${name} ); ${current.target}.appendChild( ${name} );
` ); ` );
const usedContexts = contextualise( code, node.expression, current.contexts ); const usedContexts = contextualise( code, node.expression, current.contexts, helpers );
const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`; const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`;
if ( isReference( node.expression ) ) { if ( isReference( node.expression ) ) {
@ -299,17 +309,17 @@ export default function generate ( parsed, template ) {
} }
` ); ` );
} else { } else {
const expressionFunction = getName( 'expression' ); // const expressionFunction = getName( 'expression' );
expressionFunctions.push( deindent` // expressionFunctions.push( deindent`
function ${expressionFunction} ( ${usedContexts.join( ', ' )} ) { // function ${expressionFunction} ( ${usedContexts.join( ', ' )} ) {
return ${snippet}; // return ${snippet};
} // }
` ); // ` );
const temp = getName( 'temp' ); const temp = getName( 'temp' );
current.updateStatements.push( deindent` current.updateStatements.push( deindent`
var ${temp} = ${expressionFunction}( ${usedContexts.join( ', ' )} ); var ${temp} = ${snippet};
if ( ${temp} !== ${name}_value ) { if ( ${temp} !== ${name}_value ) {
${name}_value = ${temp}; ${name}_value = ${temp};
${name}.data = ${name}_value; ${name}.data = ${name}_value;
@ -331,7 +341,7 @@ export default function generate ( parsed, template ) {
var ${name} = null; var ${name} = null;
` ); ` );
const usedContexts = contextualise( code, node.expression, current.contexts ); const usedContexts = contextualise( code, node.expression, current.contexts, helpers );
const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`; const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`;
let expression; let expression;
@ -371,7 +381,7 @@ export default function generate ( parsed, template ) {
} }
if ( ${name} ) { if ( ${name} ) {
${name}.update( ${current.contextChain.join( '\n' )} ); ${name}.update( ${current.contextChain.join( ', ' )} );
} }
` ); ` );
@ -417,7 +427,7 @@ export default function generate ( parsed, template ) {
const ${name}_fragment = document.createDocumentFragment(); const ${name}_fragment = document.createDocumentFragment();
` ); ` );
const usedContexts = contextualise( code, node.expression, current.contexts ); const usedContexts = contextualise( code, node.expression, current.contexts, helpers );
const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`; const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`;
let expression; let expression;

@ -2,13 +2,19 @@ import { walk } from 'estree-walker';
import isReference from './isReference.js'; import isReference from './isReference.js';
import flattenReference from './flattenReference.js'; import flattenReference from './flattenReference.js';
export default function contextualise ( code, expression, contexts ) { export default function contextualise ( code, expression, contexts, helpers ) {
const usedContexts = []; const usedContexts = [];
walk( expression, { walk( expression, {
enter ( node, parent ) { enter ( node, parent ) {
if ( isReference( node, parent ) ) { if ( isReference( node, parent ) ) {
const { name } = flattenReference( node ); const { name } = flattenReference( node );
if ( parent && parent.type === 'CallExpression' && node === parent.callee ) {
if ( helpers[ name ] ) code.insertRight( node.start, `template.helpers.` );
return;
}
if ( contexts[ name ] ) { if ( contexts[ name ] ) {
if ( !~usedContexts.indexOf( name ) ) usedContexts.push( name ); if ( !~usedContexts.indexOf( name ) ) usedContexts.push( name );
} else { } else {

@ -17,10 +17,16 @@ export default function readScript ( parser, start, attributes ) {
const source = spaces( scriptStart ) + parser.template.slice( scriptStart, scriptEnd ); const source = spaces( scriptStart ) + parser.template.slice( scriptStart, scriptEnd );
const ast = parse( source, { let ast;
ecmaVersion: 8,
sourceType: 'module' try {
}); ast = parse( source, {
ecmaVersion: 8,
sourceType: 'module'
});
} catch ( err ) {
parser.acornError( err );
}
ast.start = scriptStart; ast.start = scriptStart;

@ -0,0 +1,3 @@
export default {
html: '<p>sdrawkcab</p>'
};

@ -0,0 +1,14 @@
<p>{{reverse('backwards')}}</p>
<script>
export default {
helpers: {
reverse ( str ) {
let reversed = '';
let i = str.length;
while ( i-- ) reversed += str[i];
return reversed;
}
}
};
</script>
Loading…
Cancel
Save