UNPKG

motion

Version:

motion - moving development forward

128 lines (102 loc) 3.98 kB
import state from '../state' import { t, options, idFn, isUpperCase, nodeToNameString, normalizeLocation, getVar } from '../lib/helpers' export default { enter(node, parent, scope, file) { const el = node.openingElement // avoid reprocessing if (node.motionJSXVisits != 2) { // add index keys for repeat elements if (node.motionJSXVisits == 1) { if (scope.hasBinding('_index')) { el.name.elements.push(t.identifier('_')) el.name.elements.push(t.identifier('_index')) } node.motionJSXVisits = 2 return } // top level JSX element if (scope.hasOwnBinding('view')) { state.viewRootNodes.push(node) } inJSX = true node.motionJSXVisits = 1 const name = nodeToNameString(el.name) // ['quotedname', key] let key if (state.keyBase[name]) key = ++state.keyBase[name] else key = state.keyBase[name] = 1 let arr = [t.literal(name), t.literal(key)] // track meta if (state.meta.views[state.currentView]) { state.meta.views[state.currentView].els[name] = { location: normalizeLocation(el.loc), key } } /* checks whether user is referencing variable or view check root to see if the variable exists Modal.Footer would have a root of Modal */ // safer, checks for file scope or view scope only let [rootName, ...children] = name.split('.') let isVariable = (scope.hasOwnBinding(rootName) || file.scope.hasOwnBinding(rootName)) && isUpperCase(rootName) // either gives <Modal> or <Modal.Header> const getVar = (rootName, name) => rootName == name ? t.identifier(name) : t.memberExpression(t.identifier(rootName), t.identifier(children.join('.'))) if (isVariable) arr = [getVar(rootName, name)].concat(arr) el.name = t.arrayExpression(arr) // process attributes if (!el.attributes) return let rpt = idFn let iff = idFn let route = idFn for (let attr of el.attributes) { const attrName = attr.name && attr.name.name const expr = attr.value && (attr.value.expression || t.literal(attr.value.value)) if (attrName == 'class' && isUpperCase(name)) state.viewHasChildWithClass = true if (options.routing && attrName == 'route') { route = _node => t.logicalExpression('&&', t.callExpression(t.identifier('Motion.routeMatch'), [expr]), _node ) // spread routeprops onto route el.attributes.push(t.JSXSpreadAttribute( t.callExpression(t.identifier('Motion.routeParams'), [expr]) )) } if (attrName == 'if') { iff = _node => t.logicalExpression('&&', t.callExpression(t.identifier('Motion.iff'), [expr]), _node) } if (attrName == 'repeat') { rpt = _node => { // remove repeat from inner node // const opening = _node.openingElement // opening.attributes = opening.attributes.filter(attr => attr.name !== 'repeat') return t.callExpression( t.memberExpression(t.callExpression(t.identifier('Motion.range'), [expr]), t.identifier('map')), [t.functionExpression(null, [t.identifier('_'), t.identifier('_index')], t.blockStatement([ t.returnStatement(_node) ]))] ) } } } // wrap outermost JSX elements (in views) in this.render() let wrap = idFn const isDirectChildOfView = scope.hasOwnBinding('view') if (isDirectChildOfView) wrap = node => t.callExpression(t.identifier('view.render'), [ t.functionExpression(null, [], t.blockStatement([ t.returnStatement(node) ])) ]) return wrap(iff(route(rpt(node)))) } } }