Repository: teleporthq/teleport-code-generators (ts)

Issue:
Deprecate StateIdentifier in favor of ConditionalIdentifier
The interface is used only for the React specific case of handling state management with hooks, would be better for consistency to have the new `ConditionalIdentifier` across all plugins. A `meta` object can be added for the `setter` value, since it is non-standard behavior (react state hook setter function)

Pull request:
Refactor/184 deprecate state identifier
closes #184 

Patch:
diff --git a/.gitignore b/.gitignore
index beede561..3a7cc136 100755
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,6 @@ node_modules/
 
 .changelog
 
-packages/teleport-project-packer-test/config.json
\ No newline at end of file
+examples/project-exporters/yarn.lock
+
+packages/teleport-project-packer-test/src/config.json
\ No newline at end of file
diff --git a/packages/teleport-plugin-react-base-component/src/constants.ts b/packages/teleport-plugin-react-base-component/src/constants.ts
index 83ed1336..6e75c076 100644
--- a/packages/teleport-plugin-react-base-component/src/constants.ts
+++ b/packages/teleport-plugin-react-base-component/src/constants.ts
@@ -1,13 +1,22 @@
-export const ERROR_LOG_NAME = `react-base-component`
-
 export const REACT_LIBRARY_DEPENDENCY = {
   type: 'library',
   path: 'react',
   version: '16.8.3',
 }
 
+export const USE_STATE_DEPENDENCY = {
+  type: 'library',
+  path: 'react',
+  version: '16.8.3',
+  meta: {
+    namedImport: true,
+  },
+}
+
 export const DEFAULT_COMPONENT_CHUNK_NAME = 'react-component'
 
 export const DEFAULT_EXPORT_CHUNK_NAME = 'export'
 
 export const DEFAULT_IMPORT_CHUNK_NAME = 'import-local'
+
+export const ERROR_LOG_NAME = `react-base-component`
diff --git a/packages/teleport-plugin-react-base-component/src/index.ts b/packages/teleport-plugin-react-base-component/src/index.ts
index bbcf7b93..b96d7533 100644
--- a/packages/teleport-plugin-react-base-component/src/index.ts
+++ b/packages/teleport-plugin-react-base-component/src/index.ts
@@ -1,15 +1,16 @@
-import * as types from '@babel/types'
 import { makeDefaultExport } from '@teleporthq/teleport-shared/lib/utils/ast-js-utils'
-import { createPureComponent, createStateIdentifiers } from './utils'
+import { createPureComponent } from './utils'
 import { generateNodeSyntax } from './node-handlers'
 
 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,
+  USE_STATE_DEPENDENCY,
 } from './constants'
 
 export const createPlugin: ComponentPluginFactory<JSXConfig> = (config) => {
@@ -21,30 +22,29 @@ export const createPlugin: ComponentPluginFactory<JSXConfig> = (config) => {
 
   const reactComponentPlugin: ComponentPlugin = async (structure) => {
     const { uidl, dependencies } = structure
+    const { stateDefinitions = {}, propDefinitions = {} } = uidl
 
     dependencies.React = REACT_LIBRARY_DEPENDENCY
 
-    const stateIdentifiers = uidl.stateDefinitions
-      ? createStateIdentifiers(uidl.stateDefinitions, dependencies)
-      : {}
+    if (Object.keys(stateDefinitions).length) {
+      dependencies.useState = USE_STATE_DEPENDENCY
+    }
 
     // We will keep a flat mapping object from each component identifier (from the UIDL) to its correspoding JSX AST Tag
     // This will help us inject style or classes at a later stage in the pipeline, upon traversing the UIDL
     // The structure will be populated as the AST is being created
     const nodesLookup = {}
     const accumulators = {
-      propDefinitions: uidl.propDefinitions || {},
-      stateIdentifiers,
+      propDefinitions,
+      stateDefinitions,
       nodesLookup,
       dependencies,
     }
-    let pureComponent: types.VariableDeclaration
 
     const jsxTagStructure = generateNodeSyntax(uidl.node, accumulators)
-
-    pureComponent = createPureComponent(
+    const pureComponent = createPureComponent(
       uidl.name,
-      stateIdentifiers,
+      stateDefinitions,
       jsxTagStructure,
       uidl.node.type
     )
diff --git a/packages/teleport-plugin-react-base-component/src/node-handlers.ts b/packages/teleport-plugin-react-base-component/src/node-handlers.ts
index 33dc951a..903f68b3 100644
--- a/packages/teleport-plugin-react-base-component/src/node-handlers.ts
+++ b/packages/teleport-plugin-react-base-component/src/node-handlers.ts
@@ -63,7 +63,7 @@ export const generateNodeSyntax: NodeSyntaxGenerator<
 }
 
 const generateElementNode = (node: UIDLElementNode, accumulators: ReactComponentAccumulators) => {
-  const { dependencies, stateIdentifiers, propDefinitions, nodesLookup } = accumulators
+  const { dependencies, stateDefinitions, propDefinitions, nodesLookup } = accumulators
   const { elementType, children, key, attrs, dependency, events } = node.content
   const elementTag = generateASTDefinitionForJSXTag(elementType)
 
@@ -84,7 +84,7 @@ const generateElementNode = (node: UIDLElementNode, accumulators: ReactComponent
         elementTag,
         eventKey,
         events[eventKey],
-        stateIdentifiers,
+        stateDefinitions,
         propDefinitions
       )
     })
diff --git a/packages/teleport-plugin-react-base-component/src/types.ts b/packages/teleport-plugin-react-base-component/src/types.ts
index 8f2d9df0..cdb6f201 100644
--- a/packages/teleport-plugin-react-base-component/src/types.ts
+++ b/packages/teleport-plugin-react-base-component/src/types.ts
@@ -2,8 +2,8 @@ import * as types from '@babel/types'
 
 import {
   UIDLPropDefinition,
-  StateIdentifier,
   ComponentDependency,
+  UIDLStateDefinition,
 } from '@teleporthq/teleport-types'
 
 export interface JSXConfig {
@@ -14,7 +14,7 @@ export interface JSXConfig {
 
 export interface ReactComponentAccumulators {
   propDefinitions: Record<string, UIDLPropDefinition>
-  stateIdentifiers: Record<string, StateIdentifier>
+  stateDefinitions: Record<string, UIDLStateDefinition>
   nodesLookup: Record<string, types.JSXElement>
   dependencies: Record<string, ComponentDependency>
 }
diff --git a/packages/teleport-plugin-react-base-component/src/utils.ts b/packages/teleport-plugin-react-base-component/src/utils.ts
index 9baaf097..62ca813d 100644
--- a/packages/teleport-plugin-react-base-component/src/utils.ts
+++ b/packages/teleport-plugin-react-base-component/src/utils.ts
@@ -11,10 +11,8 @@ import {
   UIDLPropDefinition,
   UIDLAttributeValue,
   UIDLDynamicReference,
-  ComponentDependency,
   UIDLStateDefinition,
   EventHandlerStatement,
-  StateIdentifier,
   AttributeAssignCodeMod,
   ConditionalIdentifier,
   UIDLConditionalExpression,
@@ -29,41 +27,13 @@ import {
   ContentType,
 } from './types'
 
-export const createStateIdentifiers = (
-  stateDefinitions: Record<string, UIDLStateDefinition>,
-  dependencies: Record<string, ComponentDependency>
-) => {
-  dependencies.useState = {
-    type: 'library',
-    path: 'react',
-    version: '16.8.3',
-    meta: {
-      namedImport: true,
-    },
-  }
-
-  return Object.keys(stateDefinitions).reduce(
-    (acc: Record<string, StateIdentifier>, stateKey: string) => {
-      acc[stateKey] = {
-        key: stateKey,
-        type: stateDefinitions[stateKey].type,
-        default: stateDefinitions[stateKey].defaultValue,
-        setter: 'set' + capitalize(stateKey),
-      }
-
-      return acc
-    },
-    {}
-  )
-}
-
 export const createPureComponent = (
   name: string,
-  stateIdentifiers: Record<string, StateIdentifier>,
+  stateDefinitions: Record<string, UIDLStateDefinition>,
   jsxTagTree: GenerateNodeSyntaxReturnValue,
   nodeType: string,
   t = types
-) => {
+): types.VariableDeclaration => {
   let arrowFunctionBody: any
   switch (nodeType) {
     case 'static':
@@ -72,13 +42,13 @@ export const createPureComponent = (
     case 'dynamic':
     case 'conditional':
       arrowFunctionBody =
-        Object.keys(stateIdentifiers).length === 0
+        Object.keys(stateDefinitions).length === 0
           ? jsxTagTree
-          : createReturnExpressionSyntax(stateIdentifiers, jsxTagTree as types.JSXElement)
+          : createReturnExpressionSyntax(stateDefinitions, jsxTagTree as types.JSXElement)
       break
     default:
       arrowFunctionBody = createReturnExpressionSyntax(
-        stateIdentifiers,
+        stateDefinitions,
         jsxTagTree as types.JSXElement
       )
       break
@@ -98,7 +68,7 @@ export const addEventHandlerToTag = (
   tag: types.JSXElement,
   eventKey: string,
   eventHandlerStatements: EventHandlerStatement[],
-  stateIdentifiers: Record<string, StateIdentifier>,
+  stateDefinitions: Record<string, UIDLStateDefinition>,
   propDefinitions: Record<string, UIDLPropDefinition> = {},
   t = types
 ) => {
@@ -106,7 +76,7 @@ export const addEventHandlerToTag = (
 
   eventHandlerStatements.forEach((eventHandlerAction) => {
     if (eventHandlerAction.type === 'stateChange') {
-      const handler = createStateChangeStatement(eventHandlerAction, stateIdentifiers)
+      const handler = createStateChangeStatement(eventHandlerAction, stateDefinitions)
       if (handler) {
         eventHandlerASTStatements.push(handler)
       }
@@ -194,7 +164,7 @@ export const createConditionIdentifier = (
     case 'state':
       return {
         key: id,
-        type: accumulators.stateIdentifiers[id].type,
+        type: accumulators.stateDefinitions[id].type,
       }
     default:
       throw new Error(
@@ -344,13 +314,14 @@ const convertToUnaryOperator = (operation: string): UnaryOperation => {
 }
 
 const createReturnExpressionSyntax = (
-  stateIdentifiers: Record<string, StateIdentifier>,
+  stateDefinitions: Record<string, UIDLStateDefinition>,
   jsxTagTree: types.JSXElement,
   t = types
 ) => {
   const returnStatement = t.returnStatement(jsxTagTree)
-  const stateHooks = Object.keys(stateIdentifiers).map((stateKey) =>
-    createStateHookAST(stateIdentifiers[stateKey])
+
+  const stateHooks = Object.keys(stateDefinitions).map((stateKey) =>
+    createStateHookAST(stateKey, stateDefinitions[stateKey])
   )
 
   return t.blockStatement([...stateHooks, returnStatement] || [])
@@ -384,7 +355,7 @@ const createPropCallStatement = (
 
 const createStateChangeStatement = (
   eventHandlerStatement: EventHandlerStatement,
-  stateIdentifiers: Record<string, StateIdentifier>,
+  stateDefinitions: Record<string, UIDLStateDefinition>,
   t = types
 ) => {
   if (!eventHandlerStatement.modifies) {
@@ -393,31 +364,30 @@ const createStateChangeStatement = (
   }
 
   const stateKey = eventHandlerStatement.modifies
-  const stateIdentifier = stateIdentifiers[stateKey]
-
-  if (!stateIdentifier) {
-    console.warn(`No state hook was found for "${stateKey}"`)
-    return null
-  }
+  const stateDefinition = stateDefinitions[stateKey]
 
   const stateSetterArgument =
     eventHandlerStatement.newState === '$toggle'
-      ? t.unaryExpression('!', t.identifier(stateIdentifier.key))
-      : convertValueToLiteral(eventHandlerStatement.newState, stateIdentifier.type)
+      ? t.unaryExpression('!', t.identifier(stateKey))
+      : convertValueToLiteral(eventHandlerStatement.newState, stateDefinition.type)
 
   return t.expressionStatement(
-    t.callExpression(t.identifier(stateIdentifier.setter), [stateSetterArgument])
+    t.callExpression(t.identifier(`set${capitalize(stateKey)}`), [stateSetterArgument])
   )
 }
 
 /**
  * Creates an AST line for defining a single state hook
  */
-const createStateHookAST = (stateIdentifier: StateIdentifier, t = types) => {
-  const defaultValueArgument = convertValueToLiteral(stateIdentifier.default, stateIdentifier.type)
+const createStateHookAST = (stateKey: string, stateDefinition: UIDLStateDefinition, t = types) => {
+  const defaultValueArgument = convertValueToLiteral(
+    stateDefinition.defaultValue,
+    stateDefinition.type
+  )
+
   return t.variableDeclaration('const', [
     t.variableDeclarator(
-      t.arrayPattern([t.identifier(stateIdentifier.key), t.identifier(stateIdentifier.setter)]),
+      t.arrayPattern([t.identifier(stateKey), t.identifier(`set${capitalize(stateKey)}`)]),
       t.callExpression(t.identifier('useState'), [defaultValueArgument])
     ),
   ])
diff --git a/packages/teleport-plugin-react-styled-jsx/src/index.ts b/packages/teleport-plugin-react-styled-jsx/src/index.ts
index d6ac9a81..57844483 100644
--- a/packages/teleport-plugin-react-styled-jsx/src/index.ts
+++ b/packages/teleport-plugin-react-styled-jsx/src/index.ts
@@ -7,10 +7,9 @@ import { camelCaseToDashCase } from '@teleporthq/teleport-shared/lib/utils/strin
 import {
   transformDynamicStyles,
   traverseElements,
-  findFirstElementNode,
 } from '@teleporthq/teleport-shared/lib/utils/uidl-utils'
 import { createCSSClassFromStringMap } from '@teleporthq/teleport-shared/lib/utils/jss-utils'
-import { ComponentPluginFactory, ComponentPlugin } from '@teleporthq/teleport-types'
+import { ComponentPluginFactory, ComponentPlugin, UIDLElement } from '@teleporthq/teleport-types'
 
 interface StyledJSXConfig {
   componentChunkName: string
@@ -21,6 +20,7 @@ export const createPlugin: ComponentPluginFactory<StyledJSXConfig> = (config) =>
 
   const reactStyledJSXChunkPlugin: ComponentPlugin = async (structure) => {
     const { uidl, chunks } = structure
+
     const { node } = uidl
 
     const componentChunk = chunks.find((chunk) => chunk.name === componentChunkName)
@@ -59,12 +59,13 @@ export const createPlugin: ComponentPluginFactory<StyledJSXConfig> = (config) =>
     }
 
     const jsxASTNodeReference = generateStyledJSXTag(styleJSXString.join('\n'))
+    const rootJSXNode = jsxNodesLookup[(node.content as UIDLElement).key] // TODO: Check for other types
+
     // We have the ability to insert the tag into the existig JSX structure, or do something else with it.
     // Here we take the JSX <style> tag and we insert it as the last child of the JSX structure
     // inside the React Component
-    const elmRootNode = findFirstElementNode(uidl.node)
-    const rootJSXNode = jsxNodesLookup[elmRootNode.content.key]
     rootJSXNode.children.push(jsxASTNodeReference)
+
     return structure
   }
 
diff --git a/packages/teleport-project-packer-playground/src/index.ts b/packages/teleport-project-packer-playground/src/index.ts
index 2b4fd66f..257e588c 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.setGenerator(projectGenerator)
+    packer.setGeneratorFunction(projectGenerator.generateProject)
     packer.setPublisher(projectPublisher)
 
     const remoteGithubTemplate =
diff --git a/packages/teleport-project-packer/src/errors.ts b/packages/teleport-project-packer/src/errors.ts
index 192e7300..70f9c488 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_PROVIDED = 'No generator provided'
+export const NO_GENERATOR_FUNCTION_PROVIDED = 'No generator function 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 a90a60bd..35c0cb02 100644
--- a/packages/teleport-project-packer/src/index.ts
+++ b/packages/teleport-project-packer/src/index.ts
@@ -1,19 +1,19 @@
 import {
   AssetsDefinition,
   Publisher,
-  ProjectGenerator,
+  GenerateProjectFunction,
   PublisherResponse,
   ProjectUIDL,
   GeneratedFolder,
   RemoteTemplateDefinition,
 } from '@teleporthq/teleport-types'
 import { injectAssetsToProject, fetchTemplate } from './utils'
-import { NO_GENERATOR_PROVIDED, NO_PUBLISHER_PROVIDED } from './errors'
+import { NO_GENERATOR_FUNCTION_PROVIDED, NO_PUBLISHER_PROVIDED } from './errors'
 import { DEFAULT_TEMPLATE } from './constants'
 
 export interface PackerFactoryParams {
   publisher?: Publisher<any, any>
-  generator?: ProjectGenerator
+  generatorFunction?: GenerateProjectFunction
   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
-  setGenerator: (generator: ProjectGenerator) => void
+  setGeneratorFunction: (generatorFunction: GenerateProjectFunction) => void
   setAssets: (assets: AssetsDefinition) => void
   setTemplate: (templateFolder: GeneratedFolder) => void
 }
 
 export const createProjectPacker: PackerFactory = (params: PackerFactoryParams = {}) => {
-  let { assets, generator, publisher, template } = params
+  let { assets, generatorFunction, publisher, template } = params
 
   template = template || DEFAULT_TEMPLATE
 
@@ -39,8 +39,8 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
     publisher = publisherToSet
   }
 
-  const setGenerator = (generatorToSet: ProjectGenerator): void => {
-    generator = generatorToSet
+  const setGeneratorFunction = (functionToSet: GenerateProjectFunction): void => {
+    generatorFunction = functionToSet
   }
 
   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 packGenerator = packParams.generator || generator
-    if (!packGenerator) {
-      return { success: false, payload: NO_GENERATOR_PROVIDED }
+    const packGeneratorFunction = packParams.generatorFunction || generatorFunction
+    if (!packGeneratorFunction) {
+      return { success: false, payload: NO_GENERATOR_FUNCTION_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 packGenerator.generateProject(
+    const { assetsPath, outputFolder } = await packGeneratorFunction(
       definedProjectUIDL,
       templateFolder
     )
@@ -94,7 +94,7 @@ export const createProjectPacker: PackerFactory = (params: PackerFactoryParams =
 
   return {
     setPublisher,
-    setGenerator,
+    setGeneratorFunction,
     setAssets,
     setTemplate,
     loadTemplate,
diff --git a/packages/teleport-shared/src/utils/uidl-utils.ts b/packages/teleport-shared/src/utils/uidl-utils.ts
index 8a8b0a40..dec89f7e 100644
--- a/packages/teleport-shared/src/utils/uidl-utils.ts
+++ b/packages/teleport-shared/src/utils/uidl-utils.ts
@@ -424,18 +424,3 @@ export const transformAttributesAssignmentsToJson = (
 
   return newStyleObject
 }
-
-export const findFirstElementNode = (node: UIDLNode) => {
-  switch (node.type) {
-    case 'element':
-      return node
-    case 'static':
-    case 'dynamic':
-    case 'slot':
-      throw new Error('UIDL does not have any element node')
-    case 'conditional':
-    case 'repeat':
-      const childNode = node.content.node
-      return findFirstElementNode(childNode)
-  }
-}
diff --git a/packages/teleport-types/src/generators.ts b/packages/teleport-types/src/generators.ts
index baaa8eb6..ce40756e 100644
--- a/packages/teleport-types/src/generators.ts
+++ b/packages/teleport-types/src/generators.ts
@@ -69,17 +69,6 @@ export interface GeneratorOptions {
 
 export type CodeGeneratorFunction<T> = (content: T) => string
 
-/**
- * This structure is used for keeping information about a single state key while creating a component
- */
-export interface StateIdentifier {
-  key: string
-  type: string
-  setter: string
-  default: any
-}
-
-// TODO: Use this instead of StateIdentifier (hook setter can be added on a meta object)
 export interface ConditionalIdentifier {
   key: string
   type: string
@@ -175,10 +164,6 @@ export type GenerateProjectFunction = (
   options?: GeneratorOptions
 ) => Promise<ProjectGeneratorOutput>
 
-export interface ProjectGenerator {
-  generateProject?: GenerateProjectFunction
-}
-
 export type GenerateComponentFunction = (
   // TODO rename to ComponentGeneratorOptions
   input: Record<string, unknown>,


Test patch:
diff --git a/packages/teleport-plugin-react-styled-jsx/__tests__/index.ts b/packages/teleport-plugin-react-styled-jsx/__tests__/index.ts
index 3762644e..66108e59 100644
--- a/packages/teleport-plugin-react-styled-jsx/__tests__/index.ts
+++ b/packages/teleport-plugin-react-styled-jsx/__tests__/index.ts
@@ -2,9 +2,6 @@ import {
   component,
   elementNode,
   staticNode,
-  conditionalNode,
-  dynamicNode,
-  definition,
 } from '@teleporthq/teleport-shared/lib/builders/uidl-builders'
 import { ComponentStructure, ChunkDefinition } from '@teleporthq/teleport-types'
 import { createPlugin } from '../src/index'
@@ -82,41 +79,4 @@ describe('plugin-react-styled-jsx', () => {
     expect(styledTag.openingElement.name.name).toBe('style')
     expect(styledTag.children[0].expression.quasis[0].value.raw).toContain('height: 100px')
   })
-
-  it('add <style> tag to first element node if the root is non-element', async () => {
-    const style = {
-      height: staticNode('100px'),
-    }
-    const element = elementNode(
-      'div',
-      {},
-      [dynamicNode('prop', 'title'), staticNode('I am Title')],
-      null,
-      style
-    )
-    element.content.key = 'container'
-    const uidlSample = component(
-      'Component',
-      conditionalNode(dynamicNode('prop', 'title'), element, false),
-      { title: definition('string', 'Hello') },
-      {}
-    )
-
-    const structure: ComponentStructure = {
-      uidl: uidlSample,
-      chunks: [componentChunk],
-      dependencies: {},
-    }
-
-    const { chunks } = await plugin(structure)
-
-    expect(chunks.length).toBe(1)
-    const nodeReference = componentChunk.meta.nodesLookup.container
-    expect(nodeReference.children.length).toBe(1)
-
-    const styledTag = nodeReference.children[0]
-
-    expect(styledTag.openingElement.name.name).toBe('style')
-    expect(styledTag.children[0].expression.quasis[0].value.raw).toContain('height: 100px')
-  })
 })
diff --git a/packages/teleport-project-packer-test/config.example.json b/packages/teleport-project-packer-test/src/config.example.json
similarity index 100%
rename from packages/teleport-project-packer-test/config.example.json
rename to packages/teleport-project-packer-test/src/config.example.json
diff --git a/packages/teleport-project-packer-test/src/index.ts b/packages/teleport-project-packer-test/src/index.ts
index fcb9dbbc..3a1b60a5 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.setGenerator(generators[projectType])
+  projectPacker.setGeneratorFunction(generators[projectType].generateProject)
   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 931f821d..aaac4c72 100644
--- a/packages/teleport-project-packer/__tests__/index.ts
+++ b/packages/teleport-project-packer/__tests__/index.ts
@@ -13,12 +13,10 @@ import {
   ProjectGeneratorOutput,
   GeneratedFolder,
   GeneratedFile,
-  ProjectGenerator,
-  GenerateProjectFunction,
 } from '@teleporthq/teleport-types'
 
 import { createProjectPacker } from '../src'
-import { NO_GENERATOR_PROVIDED, NO_PUBLISHER_PROVIDED } from '../src/errors'
+import { NO_GENERATOR_FUNCTION_PROVIDED, NO_PUBLISHER_PROVIDED } from '../src/errors'
 import { DEFAULT_TEMPLATE } from '../src/constants'
 
 const assetFile = readFileSync(join(__dirname, 'asset.png'))
@@ -40,7 +38,7 @@ describe('teleport generic project packer', () => {
     expect(packer.loadTemplate).toBeDefined()
     expect(packer.pack).toBeDefined()
     expect(packer.setAssets).toBeDefined()
-    expect(packer.setGenerator).toBeDefined()
+    expect(packer.setGeneratorFunction).toBeDefined()
     expect(packer.setPublisher).toBeDefined()
     expect(packer.setTemplate).toBeDefined()
   })
@@ -65,12 +63,12 @@ describe('teleport generic project packer', () => {
       remoteTemplateDefinition: { provider: 'github', username: 'test', repo: 'test' },
     })
     expect(success).toBeFalsy()
-    expect(payload).toBe(NO_GENERATOR_PROVIDED)
+    expect(payload).toBe(NO_GENERATOR_FUNCTION_PROVIDED)
   })
 
   it('should fail to pack if no publisher is provider', async () => {
     const packer = createProjectPacker({
-      generator: dummyGenerator,
+      generatorFunction: dummyGeneratorFunction,
       template: templateDefinition,
     })
 
@@ -83,7 +81,7 @@ describe('teleport generic project packer', () => {
     const publisher = createDummyPublisher()
     const packer = createProjectPacker({
       publisher,
-      generator: dummyGenerator,
+      generatorFunction: dummyGeneratorFunction,
       template: templateDefinition,
       assets: assetsData,
     })
@@ -109,7 +107,7 @@ describe('teleport generic project packer', () => {
     const publisher = createDummyPublisher()
     const packer = createProjectPacker({
       publisher,
-      generator: dummyGenerator,
+      generatorFunction: dummyGeneratorFunction,
       assets: assetsData,
     })
 
@@ -151,7 +149,7 @@ const createDummyPublisher = (): Publisher<ProjectUIDL, string> => {
 }
 
 const dummyGeneratorFunction = async (
-  uidl: Record<string, unknown>,
+  uidl: ProjectUIDL,
   template: GeneratedFolder
 ): Promise<ProjectGeneratorOutput> => {
   const uidlFile: GeneratedFile = {
@@ -171,7 +169,3 @@ const dummyGeneratorFunction = async (
 
   return { assetsPath: 'static', outputFolder: template }
 }
-
-const dummyGenerator = {
-  generateProject: dummyGeneratorFunction,
-}