Repository: teleporthq/teleport-code-generators
Pull request #271 (2019-06-12 07:21:45)

Refactor/247 change set generator


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ed0857bc..5a7e72f4 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -114,24 +114,6 @@
       "contributions": [
         "code"
       ]
-    },
-    {
-      "login": "andreiTnu",
-      "name": "andreiTnu",
-      "avatar_url": "https://avatars1.githubusercontent.com/u/51601382?v=4",
-      "profile": "https://github.com/andreiTnu",
-      "contributions": [
-        "code"
-      ]
-    },
-    {
-      "login": "xavxyz",
-      "name": "Xavier Cazalot",
-      "avatar_url": "https://avatars0.githubusercontent.com/u/13962779?v=4",
-      "profile": "https://codepen.io/xavxyz",
-      "contributions": [
-        "code"
-      ]
     }
   ],
   "contributorsPerLine": 7
diff --git a/.gitignore b/.gitignore
index 3a7cc136..beede561 100755
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,4 @@ node_modules/
 
 .changelog
 
-examples/project-exporters/yarn.lock
-
-packages/teleport-project-packer-test/src/config.json
\ No newline at end of file
+packages/teleport-project-packer-test/config.json
\ No newline at end of file
diff --git a/README.md b/README.md
index 33a970b4..281e8d04 100755
--- a/README.md
+++ b/README.md
@@ -393,7 +393,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
 
 <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
 <!-- prettier-ignore -->
-<table><tr><td align="center"><a href="https://medium.com/@alexnm"><img src="https://avatars0.githubusercontent.com/u/9945366?v=4" width="100px;" alt="Alex Moldovan"/><br /><sub><b>Alex Moldovan</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexnm" title="Code">💻</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexnm" title="Documentation">📖</a> <a href="#ideas-alexnm" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/vladnicula"><img src="https://avatars3.githubusercontent.com/u/126038?v=4" width="100px;" alt="Vlad Nicula"/><br /><sub><b>Vlad Nicula</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=vladnicula" title="Code">💻</a> <a href="#ideas-vladnicula" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/paulbrie"><img src="https://avatars2.githubusercontent.com/u/3997538?v=4" width="100px;" alt="Paul BRIE"/><br /><sub><b>Paul BRIE</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/issues?q=author%3Apaulbrie" title="Bug reports">🐛</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=paulbrie" title="Documentation">📖</a> <a href="#ideas-paulbrie" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/mihaitaba"><img src="https://avatars3.githubusercontent.com/u/45386599?v=4" width="100px;" alt="mihaitaba"/><br /><sub><b>mihaitaba</b></sub></a><br /><a href="#design-mihaitaba" title="Design">🎨</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaitaba" title="Documentation">📖</a></td><td align="center"><a href="https://github.com/mihaiserban"><img src="https://avatars2.githubusercontent.com/u/3420526?v=4" width="100px;" alt="Mihai Serban"/><br /><sub><b>Mihai Serban</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaiserban" title="Code">💻</a></td><td align="center"><a href="https://twitter.com/askjkrishna"><img src="https://avatars0.githubusercontent.com/u/11075561?v=4" width="100px;" alt="Jaya Krishna Namburu"/><br /><sub><b>Jaya Krishna Namburu</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=JayaKrishnaNamburu" title="Code">💻</a> <a href="https://github.com/teleporthq/teleport-code-generators/issues?q=author%3AJayaKrishnaNamburu" title="Bug reports">🐛</a></td><td align="center"><a href="https://github.com/anamariaoros"><img src="https://avatars0.githubusercontent.com/u/17590608?v=4" width="100px;" alt="Anamaria Oros"/><br /><sub><b>Anamaria Oros</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=anamariaoros" title="Code">💻</a></td></tr><tr><td align="center"><a href="https://github.com/ovidiuionut94"><img src="https://avatars3.githubusercontent.com/u/11486739?v=4" width="100px;" alt="ovidiuionut94"/><br /><sub><b>ovidiuionut94</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=ovidiuionut94" title="Code">💻</a></td><td align="center"><a href="https://github.com/alexpausan"><img src="https://avatars0.githubusercontent.com/u/3284064?v=4" width="100px;" alt="alexpausan"/><br /><sub><b>alexpausan</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexpausan" title="Code">💻</a></td><td align="center"><a href="https://github.com/mihaisampaleanu"><img src="https://avatars1.githubusercontent.com/u/6763756?v=4" width="100px;" alt="Mihai Sampaleanu"/><br /><sub><b>Mihai Sampaleanu</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaisampaleanu" title="Code">💻</a></td><td align="center"><a href="http://utwo.ro"><img src="https://avatars1.githubusercontent.com/u/282668?v=4" width="100px;" alt="Utwo"/><br /><sub><b>Utwo</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=Utwo" title="Code">💻</a></td><td align="center"><a href="https://github.com/andreiTnu"><img src="https://avatars1.githubusercontent.com/u/51601382?v=4" width="100px;" alt="andreiTnu"/><br /><sub><b>andreiTnu</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=andreiTnu" title="Code">💻</a></td><td align="center"><a href="https://codepen.io/xavxyz"><img src="https://avatars0.githubusercontent.com/u/13962779?v=4" width="100px;" alt="Xavier Cazalot"/><br /><sub><b>Xavier Cazalot</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=xavxyz" title="Code">💻</a></td></tr></table>
+<table><tr><td align="center"><a href="https://medium.com/@alexnm"><img src="https://avatars0.githubusercontent.com/u/9945366?v=4" width="100px;" alt="Alex Moldovan"/><br /><sub><b>Alex Moldovan</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexnm" title="Code">💻</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexnm" title="Documentation">📖</a> <a href="#ideas-alexnm" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/vladnicula"><img src="https://avatars3.githubusercontent.com/u/126038?v=4" width="100px;" alt="Vlad Nicula"/><br /><sub><b>Vlad Nicula</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=vladnicula" title="Code">💻</a> <a href="#ideas-vladnicula" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/paulbrie"><img src="https://avatars2.githubusercontent.com/u/3997538?v=4" width="100px;" alt="Paul BRIE"/><br /><sub><b>Paul BRIE</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/issues?q=author%3Apaulbrie" title="Bug reports">🐛</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=paulbrie" title="Documentation">📖</a> <a href="#ideas-paulbrie" title="Ideas, Planning, & Feedback">🤔</a></td><td align="center"><a href="https://github.com/mihaitaba"><img src="https://avatars3.githubusercontent.com/u/45386599?v=4" width="100px;" alt="mihaitaba"/><br /><sub><b>mihaitaba</b></sub></a><br /><a href="#design-mihaitaba" title="Design">🎨</a> <a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaitaba" title="Documentation">📖</a></td><td align="center"><a href="https://github.com/mihaiserban"><img src="https://avatars2.githubusercontent.com/u/3420526?v=4" width="100px;" alt="Mihai Serban"/><br /><sub><b>Mihai Serban</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaiserban" title="Code">💻</a></td><td align="center"><a href="https://twitter.com/askjkrishna"><img src="https://avatars0.githubusercontent.com/u/11075561?v=4" width="100px;" alt="Jaya Krishna Namburu"/><br /><sub><b>Jaya Krishna Namburu</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=JayaKrishnaNamburu" title="Code">💻</a> <a href="https://github.com/teleporthq/teleport-code-generators/issues?q=author%3AJayaKrishnaNamburu" title="Bug reports">🐛</a></td><td align="center"><a href="https://github.com/anamariaoros"><img src="https://avatars0.githubusercontent.com/u/17590608?v=4" width="100px;" alt="Anamaria Oros"/><br /><sub><b>Anamaria Oros</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=anamariaoros" title="Code">💻</a></td></tr><tr><td align="center"><a href="https://github.com/ovidiuionut94"><img src="https://avatars3.githubusercontent.com/u/11486739?v=4" width="100px;" alt="ovidiuionut94"/><br /><sub><b>ovidiuionut94</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=ovidiuionut94" title="Code">💻</a></td><td align="center"><a href="https://github.com/alexpausan"><img src="https://avatars0.githubusercontent.com/u/3284064?v=4" width="100px;" alt="alexpausan"/><br /><sub><b>alexpausan</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=alexpausan" title="Code">💻</a></td><td align="center"><a href="https://github.com/mihaisampaleanu"><img src="https://avatars1.githubusercontent.com/u/6763756?v=4" width="100px;" alt="Mihai Sampaleanu"/><br /><sub><b>Mihai Sampaleanu</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=mihaisampaleanu" title="Code">💻</a></td><td align="center"><a href="http://utwo.ro"><img src="https://avatars1.githubusercontent.com/u/282668?v=4" width="100px;" alt="Utwo"/><br /><sub><b>Utwo</b></sub></a><br /><a href="https://github.com/teleporthq/teleport-code-generators/commits?author=Utwo" title="Code">💻</a></td></tr></table>
 
 <!-- ALL-CONTRIBUTORS-LIST:END -->
 
diff --git a/packages/teleport-plugin-react-base-component/src/constants.ts b/packages/teleport-plugin-react-base-component/src/constants.ts
deleted file mode 100644
index 83ed1336..00000000
--- a/packages/teleport-plugin-react-base-component/src/constants.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export const ERROR_LOG_NAME = `react-base-component`
-
-export const REACT_LIBRARY_DEPENDENCY = {
-  type: 'library',
-  path: 'react',
-  version: '16.8.3',
-}
-
-export const DEFAULT_COMPONENT_CHUNK_NAME = 'react-component'
-
-export const DEFAULT_EXPORT_CHUNK_NAME = 'export'
-
-export const DEFAULT_IMPORT_CHUNK_NAME = 'import-local'
diff --git a/packages/teleport-plugin-react-base-component/src/index.ts b/packages/teleport-plugin-react-base-component/src/index.ts
index bbcf7b93..49f85a1c 100644
--- a/packages/teleport-plugin-react-base-component/src/index.ts
+++ b/packages/teleport-plugin-react-base-component/src/index.ts
@@ -1,28 +1,31 @@
 import * as types from '@babel/types'
 import { makeDefaultExport } from '@teleporthq/teleport-shared/lib/utils/ast-js-utils'
-import { createPureComponent, createStateIdentifiers } from './utils'
-import { generateNodeSyntax } from './node-handlers'
-
+import { makePureComponent, generateNodeSyntax, createStateIdentifiers } from './utils'
 import { ComponentPluginFactory, ComponentPlugin } from '@teleporthq/teleport-types'
-import { JSXConfig } from './types'
-import {
-  DEFAULT_COMPONENT_CHUNK_NAME,
-  DEFAULT_EXPORT_CHUNK_NAME,
-  DEFAULT_IMPORT_CHUNK_NAME,
-  REACT_LIBRARY_DEPENDENCY,
-} from './constants'
+
+interface JSXConfig {
+  componentChunkName: string
+  exportChunkName: string
+  importChunkName: string
+}
+
+export const ERROR_LOG_NAME = `react-base-component`
 
 export const createPlugin: ComponentPluginFactory<JSXConfig> = (config) => {
   const {
-    componentChunkName = DEFAULT_COMPONENT_CHUNK_NAME,
-    exportChunkName = DEFAULT_EXPORT_CHUNK_NAME,
-    importChunkName = DEFAULT_IMPORT_CHUNK_NAME,
+    componentChunkName = 'react-component',
+    exportChunkName = 'export',
+    importChunkName = 'import-local',
   } = config || {}
 
   const reactComponentPlugin: ComponentPlugin = async (structure) => {
     const { uidl, dependencies } = structure
 
-    dependencies.React = REACT_LIBRARY_DEPENDENCY
+    dependencies.React = {
+      type: 'library',
+      path: 'react',
+      version: '16.8.3',
+    }
 
     const stateIdentifiers = uidl.stateDefinitions
       ? createStateIdentifiers(uidl.stateDefinitions, dependencies)
@@ -42,12 +45,7 @@ export const createPlugin: ComponentPluginFactory<JSXConfig> = (config) => {
 
     const jsxTagStructure = generateNodeSyntax(uidl.node, accumulators)
 
-    pureComponent = createPureComponent(
-      uidl.name,
-      stateIdentifiers,
-      jsxTagStructure,
-      uidl.node.type
-    )
+    pureComponent = makePureComponent(uidl.name, stateIdentifiers, jsxTagStructure, uidl.node.type)
 
     structure.chunks.push({
       type: 'js',
diff --git a/packages/teleport-plugin-react-base-component/src/node-handlers.ts b/packages/teleport-plugin-react-base-component/src/node-handlers.ts
deleted file mode 100644
index 33dc951a..00000000
--- a/packages/teleport-plugin-react-base-component/src/node-handlers.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import * as types from '@babel/types'
-
-import {
-  UIDLElementNode,
-  UIDLRepeatNode,
-  UIDLConditionalNode,
-  UIDLConditionalExpression,
-  UIDLDynamicReference,
-  UIDLSlotNode,
-  NodeSyntaxGenerator,
-} from '@teleporthq/teleport-types'
-import { ReactComponentAccumulators, GenerateNodeSyntaxReturnValue } from './types'
-
-import {
-  addAttributeToNode,
-  addEventHandlerToTag,
-  createRepeatStructureWithMap,
-  createConditionIdentifier,
-  createDynamicValueExpression,
-  createConditionalJSXExpression,
-} from './utils'
-
-import {
-  generateASTDefinitionForJSXTag,
-  addChildJSXText,
-  addChildJSXTag,
-} from '@teleporthq/teleport-shared/lib/utils/ast-jsx-utils'
-
-import { ERROR_LOG_NAME } from './constants'
-
-export const generateNodeSyntax: NodeSyntaxGenerator<
-  ReactComponentAccumulators,
-  GenerateNodeSyntaxReturnValue
-> = (node, accumulators) => {
-  switch (node.type) {
-    case 'static':
-      return node.content.toString()
-
-    case 'dynamic':
-      return createDynamicValueExpression(node)
-
-    case 'element':
-      return generateElementNode(node, accumulators)
-
-    case 'repeat':
-      return generateRepeatNode(node, accumulators)
-
-    case 'conditional':
-      return generateConditionalNode(node, accumulators)
-
-    case 'slot':
-      return generateSlotNode(node, accumulators)
-
-    default:
-      throw new Error(
-        `${ERROR_LOG_NAME} generateNodeSyntax encountered a node of unsupported type: ${JSON.stringify(
-          node,
-          null,
-          2
-        )}`
-      )
-  }
-}
-
-const generateElementNode = (node: UIDLElementNode, accumulators: ReactComponentAccumulators) => {
-  const { dependencies, stateIdentifiers, propDefinitions, nodesLookup } = accumulators
-  const { elementType, children, key, attrs, dependency, events } = node.content
-  const elementTag = generateASTDefinitionForJSXTag(elementType)
-
-  if (attrs) {
-    Object.keys(attrs).forEach((attrKey) => {
-      addAttributeToNode(elementTag, attrKey, attrs[attrKey])
-    })
-  }
-
-  if (dependency) {
-    // Make a copy to avoid reference leaking
-    dependencies[elementType] = { ...dependency }
-  }
-
-  if (events) {
-    Object.keys(events).forEach((eventKey) => {
-      addEventHandlerToTag(
-        elementTag,
-        eventKey,
-        events[eventKey],
-        stateIdentifiers,
-        propDefinitions
-      )
-    })
-  }
-
-  if (children) {
-    children.forEach((child) => {
-      const childTag = generateNodeSyntax(child, accumulators)
-
-      if (typeof childTag === 'string') {
-        addChildJSXText(elementTag, childTag)
-      } else if (childTag.type === 'JSXExpressionContainer') {
-        addChildJSXTag(elementTag, childTag)
-      } else {
-        addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag))
-      }
-    })
-  }
-
-  nodesLookup[key] = elementTag
-  return elementTag
-}
-
-const generateRepeatNode = (node: UIDLRepeatNode, accumulators: ReactComponentAccumulators) => {
-  const { node: repeatContent, dataSource, meta } = node.content
-
-  const contentAST = generateNodeSyntax(repeatContent, accumulators)
-
-  if (typeof contentAST === 'string' || (contentAST as types.JSXExpressionContainer).expression) {
-    throw new Error(
-      `${ERROR_LOG_NAME} generateRepeatNode found a repeat node that specified invalid content ${JSON.stringify(
-        contentAST,
-        null,
-        2
-      )}`
-    )
-  }
-
-  const repeatAST = createRepeatStructureWithMap(dataSource, contentAST as types.JSXElement, meta)
-  return repeatAST
-}
-
-const generateConditionalNode = (
-  node: UIDLConditionalNode,
-  accumulators: ReactComponentAccumulators
-) => {
-  const { reference, value } = node.content
-  const conditionIdentifier = createConditionIdentifier(reference, accumulators)
-
-  const subTree = generateNodeSyntax(node.content.node, accumulators)
-
-  const condition: UIDLConditionalExpression =
-    value !== undefined && value !== null
-      ? { conditions: [{ operand: value, operation: '===' }] }
-      : node.content.condition
-
-  return createConditionalJSXExpression(subTree, condition, conditionIdentifier)
-}
-
-const generateSlotNode = (
-  node: UIDLSlotNode,
-  accumulators: ReactComponentAccumulators,
-  t = types
-) => {
-  // TODO: Handle multiple slots with props['slot-name']
-  const childrenProp: UIDLDynamicReference = {
-    type: 'dynamic',
-    content: {
-      referenceType: 'prop',
-      id: 'children',
-    },
-  }
-
-  const childrenExpression = createDynamicValueExpression(childrenProp)
-
-  if (node.content.fallback) {
-    const fallbackContent = generateNodeSyntax(node.content.fallback, accumulators)
-    let expression: types.Expression
-
-    if (typeof fallbackContent === 'string') {
-      expression = t.stringLiteral(fallbackContent)
-    } else if ((fallbackContent as types.JSXExpressionContainer).expression) {
-      expression = (fallbackContent as types.JSXExpressionContainer).expression as types.Expression
-    } else {
-      expression = fallbackContent as types.JSXElement
-    }
-
-    // props.children with fallback
-    return t.jsxExpressionContainer(t.logicalExpression('||', childrenExpression, expression))
-  }
-
-  return t.jsxExpressionContainer(childrenExpression)
-}
diff --git a/packages/teleport-plugin-react-base-component/src/types.ts b/packages/teleport-plugin-react-base-component/src/types.ts
deleted file mode 100644
index 8f2d9df0..00000000
--- a/packages/teleport-plugin-react-base-component/src/types.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import * as types from '@babel/types'
-
-import {
-  UIDLPropDefinition,
-  StateIdentifier,
-  ComponentDependency,
-} from '@teleporthq/teleport-types'
-
-export interface JSXConfig {
-  componentChunkName: string
-  exportChunkName: string
-  importChunkName: string
-}
-
-export interface ReactComponentAccumulators {
-  propDefinitions: Record<string, UIDLPropDefinition>
-  stateIdentifiers: Record<string, StateIdentifier>
-  nodesLookup: Record<string, types.JSXElement>
-  dependencies: Record<string, ComponentDependency>
-}
-
-export type GenerateNodeSyntaxReturnValue =
-  | string
-  | types.JSXExpressionContainer
-  | types.JSXElement
-  | types.LogicalExpression
-  | types.Identifier
-  | types.MemberExpression
-
-export type ContentType =
-  | types.JSXElement
-  | types.JSXExpressionContainer
-  | types.LogicalExpression
-  | string
-  | types.Identifier
-  | types.MemberExpression
-
-export type BinaryOperator =
-  | '==='
-  | '+'
-  | '-'
-  | '/'
-  | '%'
-  | '*'
-  | '**'
-  | '&'
-  | '|'
-  | '>>'
-  | '>>>'
-  | '<<'
-  | '^'
-  | '=='
-  | '!='
-  | '!=='
-  | 'in'
-  | 'instanceof'
-  | '>'
-  | '<'
-  | '>='
-  | '<='
-
-export type UnaryOperation = '+' | '-' | 'void' | 'throw' | 'delete' | '!' | '~' | 'typeof'
diff --git a/packages/teleport-plugin-react-base-component/src/utils.ts b/packages/teleport-plugin-react-base-component/src/utils.ts
index 9baaf097..fa374b3d 100644
--- a/packages/teleport-plugin-react-base-component/src/utils.ts
+++ b/packages/teleport-plugin-react-base-component/src/utils.ts
@@ -2,32 +2,206 @@ import * as types from '@babel/types'
 
 import { convertValueToLiteral } from '@teleporthq/teleport-shared/lib/utils/ast-js-utils'
 import {
+  addChildJSXTag,
+  addChildJSXText,
   addAttributeToJSXTag,
   addDynamicAttributeOnTag,
+  createConditionalJSXExpression,
+  generateASTDefinitionForJSXTag,
 } from '@teleporthq/teleport-shared/lib/utils/ast-jsx-utils'
-import { capitalize } from '@teleporthq/teleport-shared/lib/utils/string-utils'
 
+import { capitalize } from '@teleporthq/teleport-shared/lib/utils/string-utils'
 import {
+  UIDLElementNode,
   UIDLPropDefinition,
+  UIDLRepeatNode,
+  UIDLConditionalNode,
+  UIDLConditionalExpression,
   UIDLAttributeValue,
   UIDLDynamicReference,
   ComponentDependency,
   UIDLStateDefinition,
   EventHandlerStatement,
+  UIDLSlotNode,
   StateIdentifier,
+  NodeSyntaxGenerator,
   AttributeAssignCodeMod,
   ConditionalIdentifier,
-  UIDLConditionalExpression,
 } from '@teleporthq/teleport-types'
 
-import { ERROR_LOG_NAME } from './constants'
-import {
-  GenerateNodeSyntaxReturnValue,
+import { ERROR_LOG_NAME } from '.'
+
+interface ReactComponentAccumulators {
+  propDefinitions: Record<string, UIDLPropDefinition>
+  stateIdentifiers: Record<string, StateIdentifier>
+  nodesLookup: Record<string, types.JSXElement>
+  dependencies: Record<string, ComponentDependency>
+}
+
+export const generateElementNode = (
+  node: UIDLElementNode,
+  accumulators: ReactComponentAccumulators
+) => {
+  const { dependencies, stateIdentifiers, propDefinitions, nodesLookup } = accumulators
+  const { elementType, children, key, attrs, dependency, events } = node.content
+  const elementTag = generateASTDefinitionForJSXTag(elementType)
+
+  if (attrs) {
+    Object.keys(attrs).forEach((attrKey) => {
+      addAttributeToNode(elementTag, attrKey, attrs[attrKey])
+    })
+  }
+
+  if (dependency) {
+    // Make a copy to avoid reference leaking
+    dependencies[elementType] = { ...dependency }
+  }
+
+  if (events) {
+    Object.keys(events).forEach((eventKey) => {
+      addEventHandlerToTag(
+        elementTag,
+        eventKey,
+        events[eventKey],
+        stateIdentifiers,
+        propDefinitions
+      )
+    })
+  }
+
+  if (children) {
+    children.forEach((child) => {
+      const childTag = generateNodeSyntax(child, accumulators)
+
+      if (typeof childTag === 'string') {
+        addChildJSXText(elementTag, childTag)
+      } else if (childTag.type === 'JSXExpressionContainer') {
+        addChildJSXTag(elementTag, childTag)
+      } else {
+        addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag))
+      }
+    })
+  }
+
+  nodesLookup[key] = elementTag
+  return elementTag
+}
+
+export const generateRepeatNode = (
+  node: UIDLRepeatNode,
+  accumulators: ReactComponentAccumulators
+) => {
+  const { node: repeatContent, dataSource, meta } = node.content
+
+  const contentAST = generateNodeSyntax(repeatContent, accumulators)
+
+  if (typeof contentAST === 'string' || (contentAST as types.JSXExpressionContainer).expression) {
+    throw new Error(
+      `${ERROR_LOG_NAME} generateRepeatNode found a repeat node that specified invalid content ${JSON.stringify(
+        contentAST,
+        null,
+        2
+      )}`
+    )
+  }
+
+  const repeatAST = makeRepeatStructureWithMap(dataSource, contentAST as types.JSXElement, meta)
+  return repeatAST
+}
+
+export const generateConditionalNode = (
+  node: UIDLConditionalNode,
+  accumulators: ReactComponentAccumulators
+) => {
+  const { reference, value } = node.content
+  const conditionIdentifier = createConditionIdentifier(reference, accumulators)
+
+  const subTree = generateNodeSyntax(node.content.node, accumulators)
+
+  const condition: UIDLConditionalExpression =
+    value !== undefined && value !== null
+      ? { conditions: [{ operand: value, operation: '===' }] }
+      : node.content.condition
+
+  return createConditionalJSXExpression(subTree, condition, conditionIdentifier)
+}
+
+export const generateSlotNode = (
+  node: UIDLSlotNode,
+  accumulators: ReactComponentAccumulators,
+  t = types
+) => {
+  // TODO: Handle multiple slots with props['slot-name']
+  const childrenProp: UIDLDynamicReference = {
+    type: 'dynamic',
+    content: {
+      referenceType: 'prop',
+      id: 'children',
+    },
+  }
+
+  const childrenExpression = makeDynamicValueExpression(childrenProp)
+
+  if (node.content.fallback) {
+    const fallbackContent = generateNodeSyntax(node.content.fallback, accumulators)
+    let expression: types.Expression
+
+    if (typeof fallbackContent === 'string') {
+      expression = t.stringLiteral(fallbackContent)
+    } else if ((fallbackContent as types.JSXExpressionContainer).expression) {
+      expression = (fallbackContent as types.JSXExpressionContainer).expression as types.Expression
+    } else {
+      expression = fallbackContent as types.JSXElement
+    }
+
+    // props.children with fallback
+    return t.jsxExpressionContainer(t.logicalExpression('||', childrenExpression, expression))
+  }
+
+  return t.jsxExpressionContainer(childrenExpression)
+}
+
+type GenerateNodeSyntaxReturnValue =
+  | string
+  | types.JSXExpressionContainer
+  | types.JSXElement
+  | types.LogicalExpression
+  | types.Identifier
+  | types.MemberExpression
+
+export const generateNodeSyntax: NodeSyntaxGenerator<
   ReactComponentAccumulators,
-  BinaryOperator,
-  UnaryOperation,
-  ContentType,
-} from './types'
+  GenerateNodeSyntaxReturnValue
+> = (node, accumulators) => {
+  switch (node.type) {
+    case 'static':
+      return node.content.toString()
+
+    case 'dynamic':
+      return makeDynamicValueExpression(node)
+
+    case 'element':
+      return generateElementNode(node, accumulators)
+
+    case 'repeat':
+      return generateRepeatNode(node, accumulators)
+
+    case 'conditional':
+      return generateConditionalNode(node, accumulators)
+
+    case 'slot':
+      return generateSlotNode(node, accumulators)
+
+    default:
+      throw new Error(
+        `${ERROR_LOG_NAME} generateNodeSyntax encountered a node of unsupported type: ${JSON.stringify(
+          node,
+          null,
+          2
+        )}`
+      )
+  }
+}
 
 export const createStateIdentifiers = (
   stateDefinitions: Record<string, UIDLStateDefinition>,
@@ -57,7 +231,7 @@ export const createStateIdentifiers = (
   )
 }
 
-export const createPureComponent = (
+export const makePureComponent = (
   name: string,
   stateIdentifiers: Record<string, StateIdentifier>,
   jsxTagTree: GenerateNodeSyntaxReturnValue,
@@ -74,10 +248,10 @@ export const createPureComponent = (
       arrowFunctionBody =
         Object.keys(stateIdentifiers).length === 0
           ? jsxTagTree
-          : createReturnExpressionSyntax(stateIdentifiers, jsxTagTree as types.JSXElement)
+          : generateReturnExpressionSyntax(stateIdentifiers, jsxTagTree as types.JSXElement)
       break
     default:
-      arrowFunctionBody = createReturnExpressionSyntax(
+      arrowFunctionBody = generateReturnExpressionSyntax(
         stateIdentifiers,
         jsxTagTree as types.JSXElement
       )
@@ -92,9 +266,22 @@ export const createPureComponent = (
   return component
 }
 
+const generateReturnExpressionSyntax = (
+  stateIdentifiers: Record<string, StateIdentifier>,
+  jsxTagTree: types.JSXElement,
+  t = types
+) => {
+  const returnStatement = t.returnStatement(jsxTagTree)
+  const stateHooks = Object.keys(stateIdentifiers).map((stateKey) =>
+    makeStateHookAST(stateIdentifiers[stateKey])
+  )
+
+  return t.blockStatement([...stateHooks, returnStatement] || [])
+}
+
 // Adds all the event handlers and all the instructions for each event handler
 // in case there is more than one specified in the UIDL
-export const addEventHandlerToTag = (
+const addEventHandlerToTag = (
   tag: types.JSXElement,
   eventKey: string,
   eventHandlerStatements: EventHandlerStatement[],
@@ -137,7 +324,74 @@ export const addEventHandlerToTag = (
   )
 }
 
-export const createRepeatStructureWithMap = (
+const createPropCallStatement = (
+  eventHandlerStatement: EventHandlerStatement,
+  propDefinitions: Record<string, UIDLPropDefinition>,
+  t = types
+) => {
+  const { calls: propFunctionKey, args = [] } = eventHandlerStatement
+
+  if (!propFunctionKey) {
+    console.warn(`No prop definition referenced under the "calls" field`)
+    return null
+  }
+
+  const propDefinition = propDefinitions[propFunctionKey]
+
+  if (!propDefinition || propDefinition.type !== 'func') {
+    console.warn(`No prop definition was found for "${propFunctionKey}"`)
+    return null
+  }
+
+  return t.expressionStatement(
+    t.callExpression(t.identifier('props.' + propFunctionKey), [
+      ...args.map((arg) => convertValueToLiteral(arg)),
+    ])
+  )
+}
+
+const createStateChangeStatement = (
+  eventHandlerStatement: EventHandlerStatement,
+  stateIdentifiers: Record<string, StateIdentifier>,
+  t = types
+) => {
+  if (!eventHandlerStatement.modifies) {
+    console.warn(`No state identifier referenced under the "modifies" field`)
+    return null
+  }
+
+  const stateKey = eventHandlerStatement.modifies
+  const stateIdentifier = stateIdentifiers[stateKey]
+
+  if (!stateIdentifier) {
+    console.warn(`No state hook was found for "${stateKey}"`)
+    return null
+  }
+
+  const stateSetterArgument =
+    eventHandlerStatement.newState === '$toggle'
+      ? t.unaryExpression('!', t.identifier(stateIdentifier.key))
+      : convertValueToLiteral(eventHandlerStatement.newState, stateIdentifier.type)
+
+  return t.expressionStatement(
+    t.callExpression(t.identifier(stateIdentifier.setter), [stateSetterArgument])
+  )
+}
+
+/**
+ * Creates an AST line for defining a single state hook
+ */
+const makeStateHookAST = (stateIdentifier: StateIdentifier, t = types) => {
+  const defaultValueArgument = convertValueToLiteral(stateIdentifier.default, stateIdentifier.type)
+  return t.variableDeclaration('const', [
+    t.variableDeclarator(
+      t.arrayPattern([t.identifier(stateIdentifier.key), t.identifier(stateIdentifier.setter)]),
+      t.callExpression(t.identifier('useState'), [defaultValueArgument])
+    ),
+  ])
+}
+
+const makeRepeatStructureWithMap = (
   dataSource: UIDLAttributeValue,
   content: types.JSXElement,
   meta: Record<string, any> = {},
@@ -169,7 +423,7 @@ export const createRepeatStructureWithMap = (
   )
 }
 
-export const createDynamicValueExpression = (identifier: UIDLDynamicReference, t = types) => {
+const makeDynamicValueExpression = (identifier: UIDLDynamicReference, t = types) => {
   const prefix = getReactVarNameForDynamicReference(identifier)
   return prefix === ''
     ? t.identifier(identifier.content.id)
@@ -178,7 +432,7 @@ export const createDynamicValueExpression = (identifier: UIDLDynamicReference, t
 
 // Prepares an identifier (from props or state) to be used as a conditional rendering identifier
 // Assumes the type from the corresponding props/state definitions
-export const createConditionIdentifier = (
+const createConditionIdentifier = (
   dynamicReference: UIDLDynamicReference,
   accumulators: ReactComponentAccumulators
 ): ConditionalIdentifier => {
@@ -207,12 +461,35 @@ export const createConditionIdentifier = (
   }
 }
 
+const getSourceIdentifier = (dataSource: UIDLAttributeValue, t = types) => {
+  switch (dataSource.type) {
+    case 'static':
+      return t.arrayExpression(
+        (dataSource.content as any[]).map((element) => convertValueToLiteral(element))
+      )
+    case 'dynamic': {
+      return makeDynamicValueExpression(dataSource)
+    }
+    default:
+      throw new Error(`Invalid type for dataSource: ${dataSource}`)
+  }
+}
+
+const getReactVarNameForDynamicReference = (dynamicReference: UIDLDynamicReference) => {
+  return {
+    prop: 'props',
+    state: '',
+    static: '',
+    local: '',
+  }[dynamicReference.content.referenceType]
+}
+
 /**
  * @param tag the ref to the AST tag under construction
  * @param attributeKey the key of the attribute that should be added on the current AST node
  * @param attributeValue the value(string, number, bool) of the attribute that should be added on the current AST node
  */
-export const addAttributeToNode: AttributeAssignCodeMod<types.JSXElement> = (
+const addAttributeToNode: AttributeAssignCodeMod<types.JSXElement> = (
   tag,
   attributeKey,
   attributeValue
@@ -237,211 +514,3 @@ export const addAttributeToNode: AttributeAssignCodeMod<types.JSXElement> = (
       )
   }
 }
-
-export const createConditionalJSXExpression = (
-  content: ContentType,
-  conditionalExpression: UIDLConditionalExpression,
-  conditionalIdentifier: ConditionalIdentifier,
-  t = types
-) => {
-  let contentNode: types.Expression
-
-  if (typeof content === 'string') {
-    contentNode = t.stringLiteral(content)
-  } else if (content.type === 'JSXExpressionContainer') {
-    contentNode = content.expression as types.Expression
-  } else {
-    contentNode = content
-  }
-
-  let binaryExpression:
-    | types.LogicalExpression
-    | types.BinaryExpression
-    | types.UnaryExpression
-    | types.Identifier
-    | types.MemberExpression
-
-  // When the stateValue is an object we will compute a logical/binary expression on the left side
-  const { conditions, matchingCriteria } = conditionalExpression
-  const binaryExpressions = conditions.map((condition) =>
-    createBinaryExpression(condition, conditionalIdentifier)
-  )
-
-  if (binaryExpressions.length === 1) {
-    binaryExpression = binaryExpressions[0]
-  } else {
-    // the first two binary expressions are put together as a logical expression
-    const [firstExp, secondExp] = binaryExpressions
-    const operation = matchingCriteria === 'all' ? '&&' : '||'
-    let expression: types.LogicalExpression = t.logicalExpression(operation, firstExp, secondExp)
-
-    // accumulate the rest of the expressions to the logical expression
-    for (let index = 2; index < binaryExpressions.length; index++) {
-      expression = t.logicalExpression(operation, expression, binaryExpressions[index])
-    }
-
-    binaryExpression = expression
-  }
-
-  return t.logicalExpression('&&', binaryExpression, contentNode)
-}
-
-export const createBinaryExpression = (
-  condition: {
-    operation: string
-    operand?: string | number | boolean
-  },
-  conditionalIdentifier: ConditionalIdentifier,
-  t = types
-) => {
-  const { operand, operation } = condition
-  const identifier = conditionalIdentifier.prefix
-    ? t.memberExpression(
-        t.identifier(conditionalIdentifier.prefix),
-        t.identifier(conditionalIdentifier.key)
-      )
-    : t.identifier(conditionalIdentifier.key)
-
-  if (operation === '===') {
-    if (operand === true) {
-      return identifier
-    }
-
-    if (operand === false) {
-      return t.unaryExpression('!', identifier)
-    }
-  }
-
-  if (operand !== undefined) {
-    const stateValueIdentifier = convertValueToLiteral(operand, conditionalIdentifier.type)
-
-    return t.binaryExpression(convertToBinaryOperator(operation), identifier, stateValueIdentifier)
-  } else {
-    return operation ? t.unaryExpression(convertToUnaryOperator(operation), identifier) : identifier
-  }
-}
-
-/**
- * Because of the restrictions of the AST Types we need to have a clear subset of binary operators we can use
- * @param operation - the operation defined in the UIDL for the current state branch
- */
-const convertToBinaryOperator = (operation: string): BinaryOperator => {
-  const allowedOperations = ['===', '!==', '>=', '<=', '>', '<']
-  if (allowedOperations.includes(operation)) {
-    return operation as BinaryOperator
-  } else {
-    return '==='
-  }
-}
-
-const convertToUnaryOperator = (operation: string): UnaryOperation => {
-  const allowedOperations = ['!']
-  if (allowedOperations.includes(operation)) {
-    return operation as UnaryOperation
-  } else {
-    return '!'
-  }
-}
-
-const createReturnExpressionSyntax = (
-  stateIdentifiers: Record<string, StateIdentifier>,
-  jsxTagTree: types.JSXElement,
-  t = types
-) => {
-  const returnStatement = t.returnStatement(jsxTagTree)
-  const stateHooks = Object.keys(stateIdentifiers).map((stateKey) =>
-    createStateHookAST(stateIdentifiers[stateKey])
-  )
-
-  return t.blockStatement([...stateHooks, returnStatement] || [])
-}
-
-const createPropCallStatement = (
-  eventHandlerStatement: EventHandlerStatement,
-  propDefinitions: Record<string, UIDLPropDefinition>,
-  t = types
-) => {
-  const { calls: propFunctionKey, args = [] } = eventHandlerStatement
-
-  if (!propFunctionKey) {
-    console.warn(`No prop definition referenced under the "calls" field`)
-    return null
-  }
-
-  const propDefinition = propDefinitions[propFunctionKey]
-
-  if (!propDefinition || propDefinition.type !== 'func') {
-    console.warn(`No prop definition was found for "${propFunctionKey}"`)
-    return null
-  }
-
-  return t.expressionStatement(
-    t.callExpression(t.identifier('props.' + propFunctionKey), [
-      ...args.map((arg) => convertValueToLiteral(arg)),
-    ])
-  )
-}
-
-const createStateChangeStatement = (
-  eventHandlerStatement: EventHandlerStatement,
-  stateIdentifiers: Record<string, StateIdentifier>,
-  t = types
-) => {
-  if (!eventHandlerStatement.modifies) {
-    console.warn(`No state identifier referenced under the "modifies" field`)
-    return null
-  }
-
-  const stateKey = eventHandlerStatement.modifies
-  const stateIdentifier = stateIdentifiers[stateKey]
-
-  if (!stateIdentifier) {
-    console.warn(`No state hook was found for "${stateKey}"`)
-    return null
-  }
-
-  const stateSetterArgument =
-    eventHandlerStatement.newState === '$toggle'
-      ? t.unaryExpression('!', t.identifier(stateIdentifier.key))
-      : convertValueToLiteral(eventHandlerStatement.newState, stateIdentifier.type)
-
-  return t.expressionStatement(
-    t.callExpression(t.identifier(stateIdentifier.setter), [stateSetterArgument])
-  )
-}
-
-/**
- * Creates an AST line for defining a single state hook
- */
-const createStateHookAST = (stateIdentifier: StateIdentifier, t = types) => {
-  const defaultValueArgument = convertValueToLiteral(stateIdentifier.default, stateIdentifier.type)
-  return t.variableDeclaration('const', [
-    t.variableDeclarator(
-      t.arrayPattern([t.identifier(stateIdentifier.key), t.identifier(stateIdentifier.setter)]),
-      t.callExpression(t.identifier('useState'), [defaultValueArgument])
-    ),
-  ])
-}
-
-const getSourceIdentifier = (dataSource: UIDLAttributeValue, t = types) => {
-  switch (dataSource.type) {
-    case 'static':
-      return t.arrayExpression(
-        (dataSource.content as any[]).map((element) => convertValueToLiteral(element))
-      )
-    case 'dynamic': {
-      return createDynamicValueExpression(dataSource)
-    }
-    default:
-      throw new Error(`Invalid type for dataSource: ${dataSource}`)
-  }
-}
-
-const getReactVarNameForDynamicReference = (dynamicReference: UIDLDynamicReference) => {
-  return {
-    prop: 'props',
-    state: '',
-    static: '',
-    local: '',
-  }[dynamicReference.content.referenceType]
-}
diff --git a/packages/teleport-project-packer-playground/src/index.ts b/packages/teleport-project-packer-playground/src/index.ts
index 257e588c..2b4fd66f 100644
--- a/packages/teleport-project-packer-playground/src/index.ts
+++ b/packages/teleport-project-packer-playground/src/index.ts
@@ -147,7 +147,7 @@ export const createPlaygroundPacker = (params: PackerFactoryParams = {}) => {
     const projectPublisher = publisherFactory({ ...meta })
 
     packer.setAssets(projectAssets)
-    packer.setGeneratorFunction(projectGenerator.generateProject)
+    packer.setGenerator(projectGenerator)
     packer.setPublisher(projectPublisher)
 
     const remoteGithubTemplate =
diff --git a/packages/teleport-project-packer/src/errors.ts b/packages/teleport-project-packer/src/errors.ts
index 70f9c488..192e7300 100644
--- a/packages/teleport-project-packer/src/errors.ts
+++ b/packages/teleport-project-packer/src/errors.ts
@@ -1,4 +1,4 @@
-export const NO_GENERATOR_FUNCTION_PROVIDED = 'No generator function provided'
+export const NO_GENERATOR_PROVIDED = 'No generator provided'
 export const NO_PUBLISHER_PROVIDED = 'No publisher provided'
 
 export const NO_GITHUB_REPO = 'No github repository provided'
diff --git a/packages/teleport-project-packer/src/index.ts b/packages/teleport-project-packer/src/index.ts
index 35c0cb02..a90a60bd 100644
--- a/packages/teleport-project-packer/src/index.ts
+++ b/packages/teleport-project-packer/src/index.ts
@@ -1,19 +1,19 @@
 import {
   AssetsDefinition,
   Publisher,
-  GenerateProjectFunction,
+  ProjectGenerator,
   PublisherResponse,
   ProjectUIDL,
   GeneratedFolder,
   RemoteTemplateDefinition,
 } from '@teleporthq/teleport-types'
 import { injectAssetsToProject, fetchTemplate } from './utils'
-import { NO_GENERATOR_FUNCTION_PROVIDED, NO_PUBLISHER_PROVIDED } from './errors'
+import { NO_GENERATOR_PROVIDED, NO_PUBLISHER_PROVIDED } from './errors'
 import { DEFAULT_TEMPLATE } from './constants'
 
 export interface PackerFactoryParams {
   publisher?: Publisher<any, any>
-  generatorFunction?: GenerateProjectFunction
+  generator?: ProjectGenerator
   template?: GeneratedFolder
   remoteTemplateDefinition?: RemoteTemplateDefinition
   assets?: AssetsDefinition
@@ -25,13 +25,13 @@ export type PackerFactory = (
   pack: (projectUIDL?: ProjectUIDL, params?: PackerFactoryParams) => Promise<PublisherResponse<any>>
   loadTemplate: (remoteTemplateDefinition: RemoteTemplateDefinition) => Promise<GeneratedFolder>
   setPublisher: <T, U>(publisher: Publisher<T, U>) => void
-  setGeneratorFunction: (generatorFunction: GenerateProjectFunction) => void
+  setGenerator: (generator: ProjectGenerator) => void
   setAssets: (assets: AssetsDefinition) => void
   setTemplate: (templateFolder: GeneratedFolder) => void
 }
 
 export const createProjectPacker: PackerFactory = (params: PackerFactoryParams = {}) => {
-  let { assets, generatorFunction, publisher, template } = params
+  let { assets, generator, publisher, template } = params
 
   template = template || DEFAULT_TEMPLATE
 
@@ -39,8 +39,8 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
     publisher = publisherToSet
   }
 
-  const setGeneratorFunction = (functionToSet: GenerateProjectFunction): void => {
-    generatorFunction = functionToSet
+  const setGenerator = (generatorToSet: ProjectGenerator): void => {
+    generator = generatorToSet
   }
 
   const setAssets = (assetsToSet: AssetsDefinition): void => {
@@ -65,9 +65,9 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
   const pack = async (uidl: ProjectUIDL, packParams: PackerFactoryParams = {}) => {
     const definedProjectUIDL = uidl
 
-    const packGeneratorFunction = packParams.generatorFunction || generatorFunction
-    if (!packGeneratorFunction) {
-      return { success: false, payload: NO_GENERATOR_FUNCTION_PROVIDED }
+    const packGenerator = packParams.generator || generator
+    if (!packGenerator) {
+      return { success: false, payload: NO_GENERATOR_PROVIDED }
     }
 
     const packPublisher = packParams.publisher || publisher
@@ -82,7 +82,7 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
       templateFolder = await loadTemplate(packParams.remoteTemplateDefinition)
     }
 
-    const { assetsPath, outputFolder } = await packGeneratorFunction(
+    const { assetsPath, outputFolder } = await packGenerator.generateProject(
       definedProjectUIDL,
       templateFolder
     )
@@ -94,7 +94,7 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
 
   return {
     setPublisher,
-    setGeneratorFunction,
+    setGenerator,
     setAssets,
     setTemplate,
     loadTemplate,
diff --git a/packages/teleport-publisher-now/src/errors.ts b/packages/teleport-publisher-now/src/errors.ts
index 38390fc7..8f6d2473 100644
--- a/packages/teleport-publisher-now/src/errors.ts
+++ b/packages/teleport-publisher-now/src/errors.ts
@@ -1,2 +1,2 @@
 export const NO_PROJECT_UIDL = 'No project UIDL provided.'
-export const NO_ACCESS_TOKEN = 'No access token provided'
+export const NO_DEPLOY_TOKEN = 'No deploy token provided'
diff --git a/packages/teleport-publisher-now/src/index.ts b/packages/teleport-publisher-now/src/index.ts
index f734acfa..34be6039 100644
--- a/packages/teleport-publisher-now/src/index.ts
+++ b/packages/teleport-publisher-now/src/index.ts
@@ -4,35 +4,35 @@ import {
   PublisherFactoryParams,
   PublisherFactory,
 } from '@teleporthq/teleport-types'
-import { NO_PROJECT_UIDL, NO_ACCESS_TOKEN } from './errors'
+import { NO_PROJECT_UIDL, NO_DEPLOY_TOKEN } from './errors'
 import { publishToNow, generateProjectFiles } from './utils'
 
 export interface NowFactoryParams extends PublisherFactoryParams {
-  accessToken: string
+  deployToken: string
 }
 
 export interface NowPublisher extends Publisher<NowFactoryParams, string> {
-  getAccessToken: () => string
-  setAccessToken: (token: string) => void
+  getDeployToken: () => string
+  setDeployToken: (token: string) => void
 }
 
 const defaultPublisherParams = {
-  accessToken: null,
+  deployToken: null,
 }
 
 export const createNowPublisher: PublisherFactory<NowFactoryParams, NowPublisher> = (
   params: NowFactoryParams = defaultPublisherParams
 ): NowPublisher => {
-  let { project, accessToken } = params
+  let { project, deployToken } = params
 
   const getProject = (): GeneratedFolder => project
   const setProject = (projectToSet: GeneratedFolder): void => {
     project = projectToSet
   }
 
-  const getAccessToken = (): string => accessToken
-  const setAccessToken = (token: string) => {
-    accessToken = token
+  const getDeployToken = (): string => deployToken
+  const setDeployToken = (token: string) => {
+    deployToken = token
   }
 
   const publish = async (options: NowFactoryParams = defaultPublisherParams) => {
@@ -41,14 +41,14 @@ export const createNowPublisher: PublisherFactory<NowFactoryParams, NowPublisher
       return { success: false, payload: NO_PROJECT_UIDL }
     }
 
-    const nowAccessToken = options.accessToken || accessToken
-    if (!nowAccessToken) {
-      return { success: false, payload: NO_ACCESS_TOKEN }
+    const nowDeployToken = options.deployToken || deployToken
+    if (!nowDeployToken) {
+      return { success: false, payload: NO_DEPLOY_TOKEN }
     }
 
     try {
       const projectFiles = generateProjectFiles(projectToPublish)
-      const nowUrl = await publishToNow(projectFiles, nowAccessToken)
+      const nowUrl = await publishToNow(projectFiles, nowDeployToken)
       return { success: true, payload: nowUrl }
     } catch (error) {
       return { success: false, payload: error.message }
@@ -59,8 +59,8 @@ export const createNowPublisher: PublisherFactory<NowFactoryParams, NowPublisher
     publish,
     getProject,
     setProject,
-    getAccessToken,
-    setAccessToken,
+    getDeployToken,
+    setDeployToken,
   }
 }
 
diff --git a/packages/teleport-publisher-zip/src/index.ts b/packages/teleport-publisher-zip/src/index.ts
index 64b753bb..6234a167 100644
--- a/packages/teleport-publisher-zip/src/index.ts
+++ b/packages/teleport-publisher-zip/src/index.ts
@@ -11,20 +11,18 @@ declare type ZipPublisherResponse = string | Buffer | Blob
 
 export interface ZipFactoryParams extends PublisherFactoryParams {
   outputPath?: string
-  outputZipName?: string
 }
 
 export interface ZipPublisher extends Publisher<ZipFactoryParams, ZipPublisherResponse> {
   getOutputPath: () => string
   setOutputPath: (path: string) => void
-  getOutputZipName: () => string
-  setOutputZipName: (name: string) => void
 }
 
 export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher> = (
   params: ZipFactoryParams = {}
 ): ZipPublisher => {
-  let { project, outputPath, outputZipName } = params
+  const { projectName } = params
+  let { project, outputPath } = params
 
   const getProject = () => project
   const setProject = (projectToSet: GeneratedFolder) => {
@@ -36,26 +34,18 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
     outputPath = path
   }
 
-  const getOutputZipName = () => outputZipName
-  const setOutputZipName = (name: string) => {
-    outputZipName = name
-  }
-
   const publish = async (options: ZipFactoryParams = {}) => {
+    const projectOutputPath = options.outputPath || outputPath
     const projectToPublish = options.project || project
     if (!projectToPublish) {
       return { success: false, payload: NO_PROJECT_UIDL }
     }
 
-    const projectOutputPath = options.outputPath || outputPath
-    const projectOutputZipName = options.outputZipName || outputZipName
-
     try {
       const zipContent = await generateProjectZip(projectToPublish)
 
       if (projectOutputPath && isNodeProcess()) {
-        const zipName = projectOutputZipName || projectToPublish.name
-        await writeZipToDisk(projectOutputPath, zipContent, zipName)
+        await writeZipToDisk(projectOutputPath, zipContent, projectName || projectToPublish.name)
       }
       return { success: true, payload: zipContent }
     } catch (error) {
@@ -69,8 +59,6 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
     setProject,
     getOutputPath,
     setOutputPath,
-    getOutputZipName,
-    setOutputZipName,
   }
 }
 
diff --git a/packages/teleport-shared/src/utils/ast-jsx-utils.ts b/packages/teleport-shared/src/utils/ast-jsx-utils.ts
index 8bc73863..0f9be230 100644
--- a/packages/teleport-shared/src/utils/ast-jsx-utils.ts
+++ b/packages/teleport-shared/src/utils/ast-jsx-utils.ts
@@ -1,5 +1,32 @@
 import * as types from '@babel/types'
 import { objectToObjectExpression, convertValueToLiteral } from './ast-js-utils'
+import { UIDLConditionalExpression, ConditionalIdentifier } from '@teleporthq/teleport-types'
+
+type BinaryOperator =
+  | '==='
+  | '+'
+  | '-'
+  | '/'
+  | '%'
+  | '*'
+  | '**'
+  | '&'
+  | '|'
+  | '>>'
+  | '>>>'
+  | '<<'
+  | '^'
+  | '=='
+  | '!='
+  | '!=='
+  | 'in'
+  | 'instanceof'
+  | '>'
+  | '<'
+  | '>='
+  | '<='
+
+type UnaryOperation = '+' | '-' | 'void' | 'throw' | 'delete' | '!' | '~' | 'typeof'
 
 /**
  * Adds a class definition string to an existing string of classes
@@ -191,6 +218,130 @@ export const addJSXTagStyles = (tag: types.JSXElement, styleMap: any, t = types)
   tag.openingElement.attributes.push(styleJSXAttr)
 }
 
+type ContentType =
+  | types.JSXElement
+  | types.JSXExpressionContainer
+  | types.LogicalExpression
+  | string
+  | types.Identifier
+  | types.MemberExpression
+
+export const createConditionalJSXExpression = (
+  content: ContentType,
+  conditionalExpression: UIDLConditionalExpression,
+  conditionalIdentifier: ConditionalIdentifier,
+  t = types
+) => {
+  let contentNode: types.Expression
+
+  if (typeof content === 'string') {
+    contentNode = t.stringLiteral(content)
+  } else if (content.type === 'JSXExpressionContainer') {
+    contentNode = content.expression as types.Expression
+  } else {
+    contentNode = content
+  }
+
+  let binaryExpression:
+    | types.LogicalExpression
+    | types.BinaryExpression
+    | types.UnaryExpression
+    | types.Identifier
+    | types.MemberExpression
+
+  // When the stateValue is an object we will compute a logical/binary expression on the left side
+  const { conditions, matchingCriteria } = conditionalExpression
+  const binaryExpressions = conditions.map((condition) =>
+    createBinaryExpression(condition, conditionalIdentifier)
+  )
+
+  if (binaryExpressions.length === 1) {
+    binaryExpression = binaryExpressions[0]
+  } else {
+    // the first two binary expressions are put together as a logical expression
+    const [firstExp, secondExp] = binaryExpressions
+    const operation = matchingCriteria === 'all' ? '&&' : '||'
+    let expression: types.LogicalExpression = t.logicalExpression(operation, firstExp, secondExp)
+
+    // accumulate the rest of the expressions to the logical expression
+    for (let index = 2; index < binaryExpressions.length; index++) {
+      expression = t.logicalExpression(operation, expression, binaryExpressions[index])
+    }
+
+    binaryExpression = expression
+  }
+
+  return t.logicalExpression('&&', binaryExpression, contentNode)
+}
+
+export const createBinaryExpression = (
+  condition: {
+    operation: string
+    operand?: string | number | boolean
+  },
+  conditionalIdentifier: ConditionalIdentifier,
+  t = types
+) => {
+  const { operand, operation } = condition
+  const identifier = conditionalIdentifier.prefix
+    ? t.memberExpression(
+        t.identifier(conditionalIdentifier.prefix),
+        t.identifier(conditionalIdentifier.key)
+      )
+    : t.identifier(conditionalIdentifier.key)
+
+  if (operation === '===') {
+    if (operand === true) {
+      return identifier
+    }
+
+    if (operand === false) {
+      return t.unaryExpression('!', identifier)
+    }
+  }
+
+  if (operand !== undefined) {
+    const stateValueIdentifier = convertValueToLiteral(operand, conditionalIdentifier.type)
+
+    return t.binaryExpression(convertToBinaryOperator(operation), identifier, stateValueIdentifier)
+  } else {
+    return operation ? t.unaryExpression(convertToUnaryOperator(operation), identifier) : identifier
+  }
+}
+
+/**
+ * Because of the restrictions of the AST Types we need to have a clear subset of binary operators we can use
+ * @param operation - the operation defined in the UIDL for the current state branch
+ */
+const convertToBinaryOperator = (operation: string): BinaryOperator => {
+  const allowedOperations = ['===', '!==', '>=', '<=', '>', '<']
+  if (allowedOperations.includes(operation)) {
+    return operation as BinaryOperator
+  } else {
+    return '==='
+  }
+}
+
+const convertToUnaryOperator = (operation: string): UnaryOperation => {
+  const allowedOperations = ['!']
+  if (allowedOperations.includes(operation)) {
+    return operation as UnaryOperation
+  } else {
+    return '!'
+  }
+}
+
+export const createTernaryOperation = (
+  stateKey: string,
+  leftNode: types.JSXElement | types.StringLiteral,
+  rightNode: types.JSXElement | types.StringLiteral,
+  t = types
+) => {
+  return t.jsxExpressionContainer(
+    t.conditionalExpression(t.identifier(stateKey), leftNode, rightNode)
+  )
+}
+
 export const createJSXSpreadAttribute = (name: string, t = types) => {
   return t.jsxSpreadAttribute(t.identifier(name))
 }
diff --git a/packages/teleport-types/src/generators.ts b/packages/teleport-types/src/generators.ts
index ccf5db83..131d0d3a 100644
--- a/packages/teleport-types/src/generators.ts
+++ b/packages/teleport-types/src/generators.ts
@@ -175,6 +175,10 @@ export type GenerateProjectFunction = (
   options?: GeneratorOptions
 ) => Promise<ProjectGeneratorOutput>
 
+export interface ProjectGenerator {
+  generateProject?: GenerateProjectFunction
+}
+
 export type GenerateComponentFunction = (
   // TODO rename to ComponentGeneratorOptions
   input: Record<string, unknown>,
@@ -184,7 +188,7 @@ export type GenerateComponentFunction = (
 /**
  * Interfaces used in the publishers
  */
-export type PublisherFactory<T, U> = (configuration?: Partial<T>) => U
+export type PublisherFactory<T, U> = (configuration?: Partial<T & PublisherFactoryParams>) => U
 
 export interface Publisher<T, U> {
   publish: (options?: T) => Promise<PublisherResponse<U>>
@@ -194,6 +198,7 @@ export interface Publisher<T, U> {
 
 export interface PublisherFactoryParams {
   project?: GeneratedFolder
+  projectName?: string
 }
 export interface PublisherResponse<T> {
   success: boolean


Test patch:
diff --git a/packages/teleport-plugin-react-base-component/__tests__/ast-binary-expression.ts b/packages/teleport-plugin-react-base-component/__tests__/ast-binary-expression.ts
deleted file mode 100644
index 8125f0a9..00000000
--- a/packages/teleport-plugin-react-base-component/__tests__/ast-binary-expression.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { createBinaryExpression } from '../src/utils'
-
-describe('createBinaryExpression', () => {
-  it('varName === true -> varName', () => {
-    const condition = { operation: '===', operand: true }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'boolean',
-    }
-
-    expect(createBinaryExpression(condition, conditionIdentifier)).toEqual({
-      type: 'Identifier',
-      name: 'isVisible',
-    })
-  })
-
-  it('varName === false -> !varName', () => {
-    const condition = { operation: '===', operand: false }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'boolean',
-    }
-
-    expect(createBinaryExpression(condition, conditionIdentifier)).toEqual({
-      type: 'UnaryExpression',
-      operator: '!',
-      argument: { type: 'Identifier', name: 'isVisible' },
-      prefix: true,
-    })
-  })
-
-  it('varName === text -> varName === text', () => {
-    const condition = { operation: '===', operand: 'text' }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'string',
-    }
-
-    const result = createBinaryExpression(condition, conditionIdentifier)
-
-    expect(result).toEqual({
-      type: 'BinaryExpression',
-      operator: '===',
-      left: { type: 'Identifier', name: 'isVisible' },
-      right: { type: 'StringLiteral', value: 'text' },
-    })
-  })
-
-  it('varName === undefined -> !varName', () => {
-    const condition = { operation: '===' }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'string',
-    }
-
-    const result = createBinaryExpression(condition, conditionIdentifier)
-
-    expect(result).toEqual({
-      type: 'UnaryExpression',
-      operator: '!',
-      argument: { type: 'Identifier', name: 'isVisible' },
-      prefix: true,
-    })
-  })
-
-  it('varName == text -> varName === text', () => {
-    const condition = { operation: '==,', operand: 'text' }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'string',
-    }
-
-    const result = createBinaryExpression(condition, conditionIdentifier)
-
-    expect(result).toEqual({
-      type: 'BinaryExpression',
-      operator: '===',
-      left: { type: 'Identifier', name: 'isVisible' },
-      right: { type: 'StringLiteral', value: 'text' },
-    })
-  })
-
-  it('varName === undefined -> !varName', () => {
-    const condition = { operation: '!' }
-    const conditionIdentifier = {
-      key: 'isVisible',
-      type: 'string',
-    }
-
-    const result = createBinaryExpression(condition, conditionIdentifier)
-
-    expect(result).toEqual({
-      type: 'UnaryExpression',
-      operator: '!',
-      argument: { type: 'Identifier', name: 'isVisible' },
-      prefix: true,
-    })
-  })
-})
diff --git a/packages/teleport-project-packer-test/src/config.example.json b/packages/teleport-project-packer-test/config.example.json
similarity index 100%
rename from packages/teleport-project-packer-test/src/config.example.json
rename to packages/teleport-project-packer-test/config.example.json
diff --git a/packages/teleport-project-packer-test/src/index.ts b/packages/teleport-project-packer-test/src/index.ts
index 3a1b60a5..fcb9dbbc 100644
--- a/packages/teleport-project-packer-test/src/index.ts
+++ b/packages/teleport-project-packer-test/src/index.ts
@@ -8,7 +8,7 @@ import vueNuxtGenerator from '@teleporthq/teleport-project-generator-vue-nuxt'
 import { createDiskPublisher } from '@teleporthq/teleport-publisher-disk'
 import { ProjectUIDL, RemoteTemplateDefinition } from '@teleporthq/teleport-types'
 
-import config from './config.json'
+import config from '../config.json'
 
 import {
   GITHUB_TEMPLATE_OWNER,
@@ -50,7 +50,7 @@ const packProject = async (projectType: string) => {
   }
 
   projectPacker.setPublisher(publisher)
-  projectPacker.setGeneratorFunction(generators[projectType].generateProject)
+  projectPacker.setGenerator(generators[projectType])
   await projectPacker.loadTemplate(remoteTemplate)
 
   const result = await projectPacker.pack(projectUIDL as ProjectUIDL)
diff --git a/packages/teleport-project-packer/__tests__/index.ts b/packages/teleport-project-packer/__tests__/index.ts
index aaac4c72..931f821d 100644
--- a/packages/teleport-project-packer/__tests__/index.ts
+++ b/packages/teleport-project-packer/__tests__/index.ts
@@ -13,10 +13,12 @@ import {
   ProjectGeneratorOutput,
   GeneratedFolder,
   GeneratedFile,
+  ProjectGenerator,
+  GenerateProjectFunction,
 } from '@teleporthq/teleport-types'
 
 import { createProjectPacker } from '../src'
-import { NO_GENERATOR_FUNCTION_PROVIDED, NO_PUBLISHER_PROVIDED } from '../src/errors'
+import { NO_GENERATOR_PROVIDED, NO_PUBLISHER_PROVIDED } from '../src/errors'
 import { DEFAULT_TEMPLATE } from '../src/constants'
 
 const assetFile = readFileSync(join(__dirname, 'asset.png'))
@@ -38,7 +40,7 @@ describe('teleport generic project packer', () => {
     expect(packer.loadTemplate).toBeDefined()
     expect(packer.pack).toBeDefined()
     expect(packer.setAssets).toBeDefined()
-    expect(packer.setGeneratorFunction).toBeDefined()
+    expect(packer.setGenerator).toBeDefined()
     expect(packer.setPublisher).toBeDefined()
     expect(packer.setTemplate).toBeDefined()
   })
@@ -63,12 +65,12 @@ describe('teleport generic project packer', () => {
       remoteTemplateDefinition: { provider: 'github', username: 'test', repo: 'test' },
     })
     expect(success).toBeFalsy()
-    expect(payload).toBe(NO_GENERATOR_FUNCTION_PROVIDED)
+    expect(payload).toBe(NO_GENERATOR_PROVIDED)
   })
 
   it('should fail to pack if no publisher is provider', async () => {
     const packer = createProjectPacker({
-      generatorFunction: dummyGeneratorFunction,
+      generator: dummyGenerator,
       template: templateDefinition,
     })
 
@@ -81,7 +83,7 @@ describe('teleport generic project packer', () => {
     const publisher = createDummyPublisher()
     const packer = createProjectPacker({
       publisher,
-      generatorFunction: dummyGeneratorFunction,
+      generator: dummyGenerator,
       template: templateDefinition,
       assets: assetsData,
     })
@@ -107,7 +109,7 @@ describe('teleport generic project packer', () => {
     const publisher = createDummyPublisher()
     const packer = createProjectPacker({
       publisher,
-      generatorFunction: dummyGeneratorFunction,
+      generator: dummyGenerator,
       assets: assetsData,
     })
 
@@ -149,7 +151,7 @@ const createDummyPublisher = (): Publisher<ProjectUIDL, string> => {
 }
 
 const dummyGeneratorFunction = async (
-  uidl: ProjectUIDL,
+  uidl: Record<string, unknown>,
   template: GeneratedFolder
 ): Promise<ProjectGeneratorOutput> => {
   const uidlFile: GeneratedFile = {
@@ -169,3 +171,7 @@ const dummyGeneratorFunction = async (
 
   return { assetsPath: 'static', outputFolder: template }
 }
+
+const dummyGenerator = {
+  generateProject: dummyGeneratorFunction,
+}
diff --git a/packages/teleport-publisher-now/__tests__/index.ts b/packages/teleport-publisher-now/__tests__/index.ts
index 7d5a565a..f80792d1 100644
--- a/packages/teleport-publisher-now/__tests__/index.ts
+++ b/packages/teleport-publisher-now/__tests__/index.ts
@@ -1,6 +1,6 @@
 import { createNowPublisher } from '../src'
 
-import { NO_PROJECT_UIDL, NO_ACCESS_TOKEN } from '../lib/errors'
+import { NO_PROJECT_UIDL, NO_DEPLOY_TOKEN } from '../lib/errors'
 
 // @ts-ignore
 import project from './project-files.json'
@@ -10,8 +10,8 @@ const token = 'deploy-token'
 describe('teleport publisher now', () => {
   it('creates a new instance of now publisher', () => {
     const publisher = createNowPublisher()
-    expect(publisher.getAccessToken).toBeDefined()
-    expect(publisher.setAccessToken).toBeDefined()
+    expect(publisher.getDeployToken).toBeDefined()
+    expect(publisher.setDeployToken).toBeDefined()
     expect(publisher.getProject).toBeDefined()
     expect(publisher.setProject).toBeDefined()
     expect(publisher.publish).toBeDefined()
@@ -27,15 +27,15 @@ describe('teleport publisher now', () => {
 
   it('should set deploy token', () => {
     const publisher = createNowPublisher()
-    publisher.setAccessToken(token)
+    publisher.setDeployToken(token)
 
-    const publisherDeployToken = publisher.getAccessToken()
+    const publisherDeployToken = publisher.getDeployToken()
     expect(publisherDeployToken).toBe(token)
   })
 
   it('should fail if no project is provided', async () => {
     const publisher = createNowPublisher()
-    publisher.setAccessToken(token)
+    publisher.setDeployToken(token)
 
     const { success, payload } = await publisher.publish()
     expect(success).toBeFalsy()
@@ -48,13 +48,13 @@ describe('teleport publisher now', () => {
 
     const { success, payload } = await publisher.publish()
     expect(success).toBeFalsy()
-    expect(payload).toBe(NO_ACCESS_TOKEN)
+    expect(payload).toBe(NO_DEPLOY_TOKEN)
   })
 
   it('should fail if deploy token is provided', async () => {
     const publisher = createNowPublisher()
 
-    const { success, payload } = await publisher.publish({ project, accessToken: token })
+    const { success, payload } = await publisher.publish({ project, deployToken: token })
     expect(success).toBeFalsy()
     expect(payload).toBe('Not authorized')
   })
diff --git a/packages/teleport-publisher-zip/__tests__/index.ts b/packages/teleport-publisher-zip/__tests__/index.ts
index 680f28c3..4991c844 100644
--- a/packages/teleport-publisher-zip/__tests__/index.ts
+++ b/packages/teleport-publisher-zip/__tests__/index.ts
@@ -4,10 +4,8 @@ import JSZip from 'jszip'
 
 import { createZipPublisher } from '../src'
 
-import { NO_PROJECT_UIDL } from '../src/errors'
-
-// @ts-ignore
 import project from './project-files.json'
+import { NO_PROJECT_UIDL } from '../src/errors'
 
 const projectPath = join(__dirname, 'disk-project')
 
@@ -42,15 +40,6 @@ describe('teleport publisher zip', () => {
     expect(publisherPath).toBe(path)
   })
 
-  it('should set output zip file name', () => {
-    const publisher = createZipPublisher()
-    const zipName = 'zip-name'
-    publisher.setOutputZipName(zipName)
-
-    const publisherZipName = publisher.getOutputZipName()
-    expect(publisherZipName).toBe(zipName)
-  })
-
   it('should fail if no project is provided', async () => {
     const publisher = createZipPublisher()
 
@@ -68,12 +57,11 @@ describe('teleport publisher zip', () => {
 
   it('should generate project and write the zip to disk if output is provided', async () => {
     const publisher = createZipPublisher({ project, outputPath: projectPath })
-    const zipName = 'zip-name'
 
-    const { success, payload } = await publisher.publish({ outputZipName: zipName })
+    const { success, payload } = await publisher.publish()
     expect(success).toBeTruthy()
 
-    const zipPath = join(projectPath, `${zipName}.zip`)
+    const zipPath = join(projectPath, `${project.name}.zip`)
     const zipFileExists = existsSync(zipPath)
     expect(zipFileExists).toBeTruthy()
 
@@ -98,17 +86,6 @@ describe('teleport publisher zip', () => {
   })
 })
 
-it('should generate project and write the zip to disk having the project name as follback for zip name', async () => {
-  const publisher = createZipPublisher({ project, outputPath: projectPath })
-
-  const { success } = await publisher.publish()
-  expect(success).toBeTruthy()
-
-  const zipPath = join(projectPath, `${project.name}.zip`)
-  const zipFileExists = existsSync(zipPath)
-  expect(zipFileExists).toBeTruthy()
-})
-
 const removeDirectory = (dirPath: string): void => {
   if (!existsSync(dirPath)) {
     return
diff --git a/packages/teleport-shared/__tests__/utils/ast-jsx-utils.ts b/packages/teleport-shared/__tests__/utils/ast-jsx-utils.ts
index 2a1bb0b1..d078eef2 100644
--- a/packages/teleport-shared/__tests__/utils/ast-jsx-utils.ts
+++ b/packages/teleport-shared/__tests__/utils/ast-jsx-utils.ts
@@ -1,10 +1,109 @@
 import {
   generateStyledJSXTag,
+  createBinaryExpression,
   stringAsTemplateLiteral,
   createJSXSpreadAttribute,
   generateASTDefinitionForJSXTag,
 } from '../../src/utils/ast-jsx-utils'
 
+describe('createBinaryExpression', () => {
+  it('varName === true -> varName', () => {
+    const condition = { operation: '===', operand: true }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'boolean',
+    }
+
+    expect(createBinaryExpression(condition, conditionIdentifier)).toEqual({
+      type: 'Identifier',
+      name: 'isVisible',
+    })
+  })
+
+  it('varName === false -> !varName', () => {
+    const condition = { operation: '===', operand: false }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'boolean',
+    }
+
+    expect(createBinaryExpression(condition, conditionIdentifier)).toEqual({
+      type: 'UnaryExpression',
+      operator: '!',
+      argument: { type: 'Identifier', name: 'isVisible' },
+      prefix: true,
+    })
+  })
+
+  it('varName === text -> varName === text', () => {
+    const condition = { operation: '===', operand: 'text' }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'string',
+    }
+
+    const result = createBinaryExpression(condition, conditionIdentifier)
+
+    expect(result).toEqual({
+      type: 'BinaryExpression',
+      operator: '===',
+      left: { type: 'Identifier', name: 'isVisible' },
+      right: { type: 'StringLiteral', value: 'text' },
+    })
+  })
+
+  it('varName === undefined -> !varName', () => {
+    const condition = { operation: '===' }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'string',
+    }
+
+    const result = createBinaryExpression(condition, conditionIdentifier)
+
+    expect(result).toEqual({
+      type: 'UnaryExpression',
+      operator: '!',
+      argument: { type: 'Identifier', name: 'isVisible' },
+      prefix: true,
+    })
+  })
+
+  it('varName == text -> varName === text', () => {
+    const condition = { operation: '==,', operand: 'text' }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'string',
+    }
+
+    const result = createBinaryExpression(condition, conditionIdentifier)
+
+    expect(result).toEqual({
+      type: 'BinaryExpression',
+      operator: '===',
+      left: { type: 'Identifier', name: 'isVisible' },
+      right: { type: 'StringLiteral', value: 'text' },
+    })
+  })
+
+  it('varName === undefined -> !varName', () => {
+    const condition = { operation: '!' }
+    const conditionIdentifier = {
+      key: 'isVisible',
+      type: 'string',
+    }
+
+    const result = createBinaryExpression(condition, conditionIdentifier)
+
+    expect(result).toEqual({
+      type: 'UnaryExpression',
+      operator: '!',
+      argument: { type: 'Identifier', name: 'isVisible' },
+      prefix: true,
+    })
+  })
+})
+
 describe('stringAsTemplateLiteral', () => {
   it('returns TemplateLiteral', () => {
     const result = stringAsTemplateLiteral('randomString')