Repository: teleporthq/teleport-code-generators
Pull request #224 (2019-05-16 16:37:01)

Feature/validator extension + bug fix 
This MR tackles both #41 and #215 

codecov[bot]: # [Codecov](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=h1) Report
> Merging [#224](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=desc) into [master](https://codecov.io/gh/teleporthq/teleport-code-generators/commit/061d3129435cee796cf75078354866f6a4b49e3b?src=pr&el=desc) will **increase** coverage by `0.98%`.
> The diff coverage is `84.61%`.

[![Impacted file tree graph](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/graphs/tree.svg?width=650&token=LI2WPEFm1R&height=150&src=pr)](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #224      +/-   ##
==========================================
+ Coverage   44.73%   45.72%   +0.98%     
==========================================
  Files          57       57              
  Lines        1967     1988      +21     
  Branches      226      226              
==========================================
+ Hits          880      909      +29     
+ Misses       1079     1071       -8     
  Partials        8        8
```


| [Impacted Files](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/teleport-component-generator/src/index.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtY29tcG9uZW50LWdlbmVyYXRvci9zcmMvaW5kZXgudHM=) | `44.44% <0%> (-2.62%)` | :arrow_down: |
| [.../teleport-generator-shared/src/utils/uidl-utils.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtZ2VuZXJhdG9yLXNoYXJlZC9zcmMvdXRpbHMvdWlkbC11dGlscy50cw==) | `40.41% <0%> (-0.57%)` | :arrow_down: |
| [...ges/teleport-generator-core/src/validator/index.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtZ2VuZXJhdG9yLWNvcmUvc3JjL3ZhbGlkYXRvci9pbmRleC50cw==) | `100% <100%> (ø)` | :arrow_up: |
| [.../teleport-plugin-react-base-component/src/index.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtcGx1Z2luLXJlYWN0LWJhc2UtY29tcG9uZW50L3NyYy9pbmRleC50cw==) | `0% <0%> (ø)` | :arrow_up: |
| [...leport-generator-shared/src/utils/ast-jsx-utils.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtZ2VuZXJhdG9yLXNoYXJlZC9zcmMvdXRpbHMvYXN0LWpzeC11dGlscy50cw==) | `52.33% <0%> (ø)` | :arrow_up: |
| [.../teleport-plugin-react-base-component/src/utils.ts](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224/diff?src=pr&el=tree#diff-cGFja2FnZXMvdGVsZXBvcnQtcGx1Z2luLXJlYWN0LWJhc2UtY29tcG9uZW50L3NyYy91dGlscy50cw==) | `0% <0%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=footer). Last update [061d312...2757dee](https://codecov.io/gh/teleporthq/teleport-code-generators/pull/224?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/examples/project-exporters/package-lock.json b/examples/project-exporters/package-lock.json
new file mode 100644
index 00000000..83c791b6
--- /dev/null
+++ b/examples/project-exporters/package-lock.json
@@ -0,0 +1,158 @@
+{
+  "name": "project-exporters",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "arg": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
+      "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "diff": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "glob": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+    },
+    "make-error": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
+      "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "rimraf": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.5.12",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz",
+      "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "ts-node": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz",
+      "integrity": "sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A==",
+      "dev": true,
+      "requires": {
+        "arg": "^4.1.0",
+        "diff": "^3.1.0",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.6",
+        "yn": "^3.0.0"
+      }
+    },
+    "typescript": {
+      "version": "3.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
+      "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "yn": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz",
+      "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==",
+      "dev": true
+    }
+  }
+}
diff --git a/packages/teleport-component-generator/src/index.ts b/packages/teleport-component-generator/src/index.ts
index f26841be..194644dd 100644
--- a/packages/teleport-component-generator/src/index.ts
+++ b/packages/teleport-component-generator/src/index.ts
@@ -44,14 +44,19 @@ export const createGenerator = (
     options = {}
   ): Promise<CompiledComponent> => {
     if (!options.skipValidation) {
-      const validationResult = validator.validateComponent(input)
-      if (!validationResult.valid) {
-        throw new Error(validationResult.errorMsg)
+      const schemaValidationResult = validator.validateComponentSchema(input)
+      if (!schemaValidationResult.valid) {
+        throw new Error(schemaValidationResult.errorMsg)
       }
     }
 
     const uidl = Parser.parseComponentJSON(input)
 
+    const contentValidationResult = validator.validateComponentContent(uidl)
+    if (!contentValidationResult.valid) {
+      throw new Error(contentValidationResult.errorMsg)
+    }
+
     const resolvedUIDL = resolver.resolveUIDL(uidl, options)
     const { chunks, externalDependencies } = await assemblyLine.run(resolvedUIDL)
 
diff --git a/packages/teleport-generator-core/src/uidl-schemas/component.json b/packages/teleport-generator-core/src/uidl-schemas/component.json
index 62546134..88e1618a 100644
--- a/packages/teleport-generator-core/src/uidl-schemas/component.json
+++ b/packages/teleport-generator-core/src/uidl-schemas/component.json
@@ -120,6 +120,8 @@
         },
         {
           "type":"object",
+          "additionalProperties": false,
+          "required": ["type", "content"],
           "properties": {
             "type": {
               "type":"string",
@@ -249,6 +251,7 @@
       "required": ["elementType"],
       "additionalProperties": false,
       "properties": {
+        "additionalProperties": false,
         "elementType": {"type": "string"},
         "name": {"type": "string"},
         "key": {"type": "string"},
diff --git a/packages/teleport-generator-core/src/validator/index.ts b/packages/teleport-generator-core/src/validator/index.ts
index f1e79215..7e294f62 100644
--- a/packages/teleport-generator-core/src/validator/index.ts
+++ b/packages/teleport-generator-core/src/validator/index.ts
@@ -2,6 +2,9 @@ import Ajv from 'ajv'
 import componentSchema from '../uidl-schemas/component.json'
 import projectSchema from '../uidl-schemas/project.json'
 
+import { ProjectUIDL, ComponentUIDL } from '@teleporthq/teleport-generator-shared/lib/typings/uidl'
+import * as utils from './utils'
+
 interface ValidationResult {
   valid: boolean
   errorMsg: string
@@ -20,35 +23,69 @@ export default class Validator {
     this.projectValidator = ajv.compile(projectSchema)
   }
 
-  public validateComponent(input: any): ValidationResult {
+  public validateComponentSchema(input: any): ValidationResult {
     const valid = this.componentValidator(input)
+
     if (!valid && this.componentValidator.errors) {
-      return { valid: false, errorMsg: formatErrors(this.componentValidator.errors) }
+      const errors = utils.formatErrors(this.componentValidator.errors)
+      return { valid: false, errorMsg: errors }
     }
 
     return { valid: true, errorMsg: '' }
   }
 
-  public validateProject(input: Record<string, unknown>): ValidationResult {
+  public validateProjectSchema(input: Record<string, unknown>): ValidationResult {
     const valid = this.projectValidator(input)
 
     if (!valid && this.projectValidator.errors) {
-      return { valid: false, errorMsg: formatErrors(this.projectValidator.errors) }
+      return { valid: false, errorMsg: utils.formatErrors(this.projectValidator.errors) }
+    }
+
+    return { valid: true, errorMsg: '' }
+  }
+
+  public validateComponentContent(input: ComponentUIDL): ValidationResult {
+    const errorsInDefinitions = utils.checkDynamicDefinitions(input)
+    const errorsWithLocalVariables = utils.checkForLocalVariables(input)
+
+    utils.checkForDuplicateDefinitions(input)
+    const errors = [...errorsInDefinitions, ...errorsWithLocalVariables]
+
+    if (errors.length > 0) {
+      return {
+        valid: false,
+        errorMsg: `\nUIDL Component Content Validation Error. Please check the following: \n${errors}`,
+      }
     }
 
     return { valid: true, errorMsg: '' }
   }
-}
 
-const formatErrors = (errors: any) => {
-  const listOfErrors = []
-  errors.forEach((error) => {
-    const message =
-      error.keyword === 'type'
-        ? `\n - Path ${error.dataPath}: ${error.message}. Received ${typeof error.data}`
-        : `\n - Path ${error.dataPath}: ${error.message}. ${JSON.stringify(error.params)}`
-    listOfErrors.push(message)
-  })
-
-  return `UIDL Validation error. Please check the following: ${listOfErrors}`
+  public validateProjectContent(input: ProjectUIDL): ValidationResult {
+    const errorsOnRouteNode = utils.checkRouteDefinition(input) || []
+    let allErrors = errorsOnRouteNode
+
+    if (errorsOnRouteNode.length === 0) {
+      const errorsInRootComponent = utils.checkRootComponent(input)
+
+      const errorsWithComponentNaming = utils.checkComponentNaming(input)
+      const errorsWtihComponentExistence = utils.checkComponentExistence(input)
+
+      allErrors = [
+        ...errorsOnRouteNode,
+        ...errorsWtihComponentExistence,
+        ...errorsWithComponentNaming,
+        ...errorsInRootComponent,
+      ]
+    }
+
+    if (allErrors.length > 0) {
+      return {
+        valid: false,
+        errorMsg: `\nUIDL Project Content Validation Error. Please check the following: ${allErrors}`,
+      }
+    }
+
+    return { valid: true, errorMsg: '' }
+  }
 }
diff --git a/packages/teleport-generator-core/src/validator/utils.ts b/packages/teleport-generator-core/src/validator/utils.ts
new file mode 100644
index 00000000..e70f57cd
--- /dev/null
+++ b/packages/teleport-generator-core/src/validator/utils.ts
@@ -0,0 +1,202 @@
+import {
+  traverseNodes,
+  traverseElements,
+} from '@teleporthq/teleport-generator-shared/lib/utils/uidl-utils'
+
+import {
+  ProjectUIDL,
+  UIDLElement,
+  ComponentUIDL,
+} from '@teleporthq/teleport-generator-shared/lib/typings/uidl'
+
+// Prop definitions and state definitions should have different keys
+export const checkForDuplicateDefinitions = (input: ComponentUIDL) => {
+  const props = Object.keys(input.propDefinitions || {})
+  const states = Object.keys(input.stateDefinitions || {})
+
+  props
+    .filter((x) => states.includes(x))
+    .forEach((duplicate) =>
+      console.warn(
+        `\n"${duplicate}" is defined both as a prop and as a state. If you are using VUE Code Generators this can cause bad behavior.`
+      )
+    )
+}
+
+// In "repeat" node:
+// If index is used, "useIndex" must be declared in "meta"
+// If custom local variable is used, it's name must be specified inside "meta" as "iteratorName"
+export const checkForLocalVariables = (input: ComponentUIDL) => {
+  const errors = []
+
+  traverseNodes(input.node, (node) => {
+    if (node.type === 'repeat') {
+      traverseNodes(node, (childNode) => {
+        if (childNode.type === 'dynamic' && childNode.content.referenceType === 'local') {
+          if (
+            childNode.content.id &&
+            node.content.meta.iteratorName &&
+            childNode.content.id !== node.content.meta.iteratorName
+          ) {
+            const errorMsg = `\n"${
+              childNode.content.id
+            }" is used in the "repeat" structure but the iterator name has this value: "${
+              node.content.meta.iteratorName
+            }"`
+            errors.push(errorMsg)
+          }
+          if (childNode.content.id && !node.content.meta.useIndex) {
+            const errorMsg = `\nIndex variable is used but the "useIndex" meta information is false.`
+            errors.push(errorMsg)
+          }
+        }
+      })
+    }
+  })
+  return errors
+}
+
+// All referenced props and states should be previously defined in the
+// "propDefinitions" and "stateDefinitions" sections
+// If props or states are defined and not used, a warning witll be displayed
+export const checkDynamicDefinitions = (input: any) => {
+  const propKeys = Object.keys(input.propDefinitions || {})
+  const stateKeys = Object.keys(input.stateDefinitions || {})
+
+  const usedPropKeys = []
+  const usedstateKeys = []
+  const errors = []
+
+  traverseNodes(input.node, (node) => {
+    if (node.type === 'dynamic' && node.content.referenceType === 'prop') {
+      if (!propKeys.includes(node.content.id)) {
+        const errorMsg = `"${
+          node.content.id
+        }" is used but not defined. Please add it in propDefinitions`
+        errors.push(errorMsg)
+      }
+      usedPropKeys.push(node.content.id)
+    }
+
+    if (node.type === 'dynamic' && node.content.referenceType === 'state') {
+      if (!stateKeys.includes(node.content.id)) {
+        const errorMsg = `\n"${
+          node.content.id
+        }" is used but not defined. Please add it in stateDefinitions`
+        errors.push(errorMsg)
+      }
+      usedstateKeys.push(node.content.id)
+    }
+  })
+
+  propKeys
+    .filter((x) => !usedPropKeys.includes(x))
+    .forEach((diff) =>
+      console.warn(`"${diff}" is defined in propDefinitions but it is not used in the UIDL.`)
+    )
+
+  stateKeys
+    .filter((x) => !usedstateKeys.includes(x))
+    .forEach((diff) =>
+      console.warn(`"${diff}" is defined in stateDefinitions but it is not used in the UIDL.`)
+    )
+
+  return errors
+}
+
+// A projectUIDL must contain "route" key
+export const checkRouteDefinition = (input: ProjectUIDL) => {
+  const errors = []
+
+  const keys = Object.keys(input.root.stateDefinitions || {})
+  if (!keys.includes('route')) {
+    const errorMsg = 'Route is not defined in stateDefinitions'
+    errors.push(errorMsg)
+  }
+  return errors
+}
+
+// All referenced components inside of the projectUIDL should be defined
+// in the component section
+export const checkComponentExistence = (input: ProjectUIDL) => {
+  const errors = []
+  const components = Object.keys(input.components)
+
+  traverseElements(input.root.node, (element) => {
+    if (
+      element.dependency &&
+      element.dependency.type === 'local' &&
+      !components.includes(element.elementType)
+    ) {
+      const errorMsg = `\nThe component "${
+        element.elementType
+      }" is not defined in the UIDL's component section.`
+      errors.push(errorMsg)
+    }
+  })
+  return errors
+}
+
+// All components should have the same key as the value of their name key
+// Example:
+//  "components": {
+//     "OneComponent": {
+//       "name": "OneComponent",
+//    ..
+//      }
+//    }
+export const checkComponentNaming = (input: ProjectUIDL) => {
+  const errors = []
+  const namesUsed = Object.keys(input.components)
+
+  const diffs = namesUsed.filter((name) => input.components[name].name !== name)
+
+  if (diffs.length > 0) {
+    const errorMsg = `\nThe following components have different name than their key: ${diffs}`
+    errors.push(errorMsg)
+  }
+
+  return errors
+}
+
+// The "root" node should contain only elements of type "conditional"
+export const checkRootComponent = (input: ProjectUIDL) => {
+  const errors = []
+  const routeNaming = []
+  const rootNode = input.root.node.content as UIDLElement
+  rootNode.children.forEach((child) => {
+    if (child.type !== 'conditional') {
+      const errorMsg = `\nRoot Node contains elements of type "${
+        child.type
+      }". It should contain only elements of type "conditional"`
+      errors.push(errorMsg)
+    } else {
+      routeNaming.push(child.content.value)
+    }
+  })
+
+  input.root.stateDefinitions.route.values
+    .filter((route) => !routeNaming.includes(route.value))
+    .forEach((route) => {
+      const errorMsg = `\nRoot Node contains routes that don't have corresponding components. Check the "value" for the following routes: ${
+        route.meta.path
+      }.`
+      errors.push(errorMsg)
+    })
+
+  return errors
+}
+
+// The errors should be displayed in a human-readeable way
+export const formatErrors = (errors: any) => {
+  const listOfErrors = []
+  errors.forEach((error) => {
+    const message =
+      error.keyword === 'type'
+        ? `\n - Path ${error.dataPath}: ${error.message}. Received ${typeof error.data}`
+        : `\n - Path ${error.dataPath}: ${error.message}. ${JSON.stringify(error.params)}`
+    listOfErrors.push(message)
+  })
+
+  return `\nUIDL Format Validation Error. Please check the following: ${listOfErrors}`
+}
diff --git a/packages/teleport-generator-shared/src/utils/uidl-utils.ts b/packages/teleport-generator-shared/src/utils/uidl-utils.ts
index 75463008..010ae5d4 100644
--- a/packages/teleport-generator-shared/src/utils/uidl-utils.ts
+++ b/packages/teleport-generator-shared/src/utils/uidl-utils.ts
@@ -100,10 +100,12 @@ export const traverseNodes = (
 
     case 'repeat':
       traverseNodes(node.content.node, fn, node)
+      traverseNodes(node.content.dataSource, fn, node)
       break
 
     case 'conditional':
       traverseNodes(node.content.node, fn, node)
+      traverseNodes(node.content.reference, fn, node)
       break
 
     case 'slot':
diff --git a/packages/teleport-project-generator-react-basic/src/index.ts b/packages/teleport-project-generator-react-basic/src/index.ts
index 71c41ed1..5271b9aa 100644
--- a/packages/teleport-project-generator-react-basic/src/index.ts
+++ b/packages/teleport-project-generator-react-basic/src/index.ts
@@ -46,16 +46,19 @@ const createReactBasicGenerator = (generatorOptions: ProjectGeneratorOptions = {
     template: TemplateDefinition,
     options: ProjectGeneratorOptions = {}
   ) => {
-    // Step 0: Validate project input and transform to UIDL
+    // Step 0: Validate project input and transform to UIDL and validate content of UIDL
     if (!options.skipValidation) {
-      const validationResult = validator.validateProject(input)
-      if (!validationResult.valid) {
-        throw new Error(validationResult.errorMsg)
+      const schemaValidationResult = validator.validateProjectSchema(input)
+      if (!schemaValidationResult.valid) {
+        throw new Error(schemaValidationResult.errorMsg)
       }
     }
 
     const uidl = Parser.parseProjectJSON(input)
-
+    const contentValidationResult = validator.validateProjectContent(uidl)
+    if (!contentValidationResult.valid) {
+      throw new Error(contentValidationResult.errorMsg)
+    }
     // Step 1: Add any custom mappings found in the options
     if (options.customMapping) {
       reactGenerator.addMapping(options.customMapping)
diff --git a/packages/teleport-project-generator-react-next/src/index.ts b/packages/teleport-project-generator-react-next/src/index.ts
index a5173c2f..eac674c1 100644
--- a/packages/teleport-project-generator-react-next/src/index.ts
+++ b/packages/teleport-project-generator-react-next/src/index.ts
@@ -45,13 +45,16 @@ const createReactNextGenerator = (generatorOptions: ProjectGeneratorOptions = {}
   ) => {
     // Step 0: Validate project input
     if (!options.skipValidation) {
-      const validationResult = validator.validateProject(input)
-      if (!validationResult.valid) {
-        throw new Error(validationResult.errorMsg)
+      const schemaValidationResult = validator.validateProjectSchema(input)
+      if (!schemaValidationResult.valid) {
+        throw new Error(schemaValidationResult.errorMsg)
       }
     }
     const uidl = Parser.parseProjectJSON(input)
-
+    const contentValidationResult = validator.validateProjectContent(uidl)
+    if (!contentValidationResult.valid) {
+      throw new Error(contentValidationResult.errorMsg)
+    }
     // Step 1: Add any custom mappings found in the options
     if (options.customMapping) {
       reactGenerator.addMapping(options.customMapping)
@@ -63,7 +66,7 @@ const createReactNextGenerator = (generatorOptions: ProjectGeneratorOptions = {}
     // Step 2: The root html file is customized in next via the _document.js page
     const documentComponentFile = createDocumentFile(uidl)
 
-    // Step 2: The first level conditional nodes are taken as project pages
+    // Step 3: The first level conditional nodes are taken as project pages
     const localDependenciesPrefix = generateLocalDependenciesPrefix(template, {
       defaultComponentsPath: DEFAULT_COMPONENT_FILES_PATH,
       defaultPagesPath: DEFAULT_PAGE_FILES_PATH,
diff --git a/packages/teleport-project-generator-vue-basic/src/index.ts b/packages/teleport-project-generator-vue-basic/src/index.ts
index ec3582db..64d95355 100644
--- a/packages/teleport-project-generator-vue-basic/src/index.ts
+++ b/packages/teleport-project-generator-vue-basic/src/index.ts
@@ -43,13 +43,16 @@ const createVueBasicGenerator = (generatorOptions: ProjectGeneratorOptions = {})
   ) => {
     // Step 0: Validate project input
     if (!options.skipValidation) {
-      const validationResult = validator.validateProject(input)
-      if (!validationResult.valid) {
-        throw new Error(validationResult.errorMsg)
+      const schemaValidationResult = validator.validateProjectSchema(input)
+      if (!schemaValidationResult.valid) {
+        throw new Error(schemaValidationResult.errorMsg)
       }
     }
     const uidl = Parser.parseProjectJSON(input)
-
+    const contentValidationResult = validator.validateProjectContent(uidl)
+    if (!contentValidationResult.valid) {
+      throw new Error(contentValidationResult.errorMsg)
+    }
     // Step 1: Add any custom mappings found in the options
     if (options.customMapping) {
       vueGenerator.addMapping(options.customMapping)
diff --git a/packages/teleport-project-generator-vue-nuxt/src/index.ts b/packages/teleport-project-generator-vue-nuxt/src/index.ts
index bb2ab1ae..d2b57716 100644
--- a/packages/teleport-project-generator-vue-nuxt/src/index.ts
+++ b/packages/teleport-project-generator-vue-nuxt/src/index.ts
@@ -45,13 +45,16 @@ const createVueNuxtGenerator = (generatorOptions: ProjectGeneratorOptions = {})
   ) => {
     // Step 0: Validate project input
     if (!options.skipValidation) {
-      const validationResult = validator.validateProject(input)
-      if (!validationResult.valid) {
-        throw new Error(validationResult.errorMsg)
+      const schemaValidationResult = validator.validateProjectSchema(input)
+      if (!schemaValidationResult.valid) {
+        throw new Error(schemaValidationResult.errorMsg)
       }
     }
     const uidl = Parser.parseProjectJSON(input)
-
+    const contentValidationResult = validator.validateProjectContent(uidl)
+    if (!contentValidationResult.valid) {
+      throw new Error(contentValidationResult.errorMsg)
+    }
     // Step 1: Add any custom mappings found in the options
     if (options.customMapping) {
       vueGenerator.addMapping(options.customMapping)
diff --git a/packages/teleport-project-packer/package.json b/packages/teleport-project-packer/package.json
index 60180b2d..e0606482 100644
--- a/packages/teleport-project-packer/package.json
+++ b/packages/teleport-project-packer/package.json
@@ -18,7 +18,8 @@
     "access": "public"
   },
   "scripts": {
-    "build": "tsc"
+    "build": "tsc",
+    "build:watch": "tsc -w"
   },
   "dependencies": {
     "@teleporthq/teleport-generator-shared": "^0.6.0",
diff --git a/packages/teleport-publisher-disk/package.json b/packages/teleport-publisher-disk/package.json
index 37c6175f..413d5c96 100644
--- a/packages/teleport-publisher-disk/package.json
+++ b/packages/teleport-publisher-disk/package.json
@@ -18,7 +18,8 @@
     "access": "public"
   },
   "scripts": {
-    "build": "tsc"
+    "build": "tsc",
+    "build:watch": "tsc -w"
   },
   "dependencies": {
     "@teleporthq/teleport-generator-shared": "^0.6.0"
diff --git a/packages/teleport-publisher-netlify/package.json b/packages/teleport-publisher-netlify/package.json
index cf02ed64..5bdffd0c 100644
--- a/packages/teleport-publisher-netlify/package.json
+++ b/packages/teleport-publisher-netlify/package.json
@@ -18,7 +18,8 @@
     "access": "public"
   },
   "scripts": {
-    "build": "tsc"
+    "build": "tsc",
+    "build:watch": "tsc -w"
   },
   "dependencies": {
     "@teleporthq/teleport-generator-shared": "^0.6.0",
diff --git a/packages/teleport-publisher-now/package.json b/packages/teleport-publisher-now/package.json
index f581c4c5..07dbc321 100644
--- a/packages/teleport-publisher-now/package.json
+++ b/packages/teleport-publisher-now/package.json
@@ -18,7 +18,8 @@
     "access": "public"
   },
   "scripts": {
-    "build": "tsc"
+    "build": "tsc",
+    "build:watch": "tsc -w"
   },
   "dependencies": {
     "@teleporthq/teleport-generator-shared": "^0.6.0",
diff --git a/packages/teleport-publisher-zip/package.json b/packages/teleport-publisher-zip/package.json
index d21808a3..6556612d 100644
--- a/packages/teleport-publisher-zip/package.json
+++ b/packages/teleport-publisher-zip/package.json
@@ -18,7 +18,8 @@
     "access": "public"
   },
   "scripts": {
-    "build": "tsc"
+    "build": "tsc",
+    "build:watch": "tsc -w"
   },
   "dependencies": {
     "@teleporthq/teleport-generator-shared": "^0.6.0",


Test patch:
diff --git a/packages/teleport-component-generator-react/__tests__/integration/component-with-old-format-attributes.json b/packages/teleport-component-generator-react/__tests__/integration/component-with-old-format-attributes.json
index 7eb4e21b..249d3206 100644
--- a/packages/teleport-component-generator-react/__tests__/integration/component-with-old-format-attributes.json
+++ b/packages/teleport-component-generator-react/__tests__/integration/component-with-old-format-attributes.json
@@ -16,6 +16,7 @@
   "node": {
     "type": "element",
     "content": {
+      "children": ["hello!"],
       "elementType": "container",
       "attrs": {
         "data-test": "$props.test",
diff --git a/packages/teleport-component-generator/__tests__/index.ts b/packages/teleport-component-generator/__tests__/index.ts
index 935bf490..544ad161 100644
--- a/packages/teleport-component-generator/__tests__/index.ts
+++ b/packages/teleport-component-generator/__tests__/index.ts
@@ -1,5 +1,3 @@
-import { GenerateComponentFunction } from '@teleporthq/teleport-generator-shared/lib/typings/generators'
-
 import { createGenerator } from '../src/index'
 import { element } from '@teleporthq/teleport-generator-shared/lib/builders/uidl-builders'
 
diff --git a/packages/teleport-generator-core/__tests__/validator/component-invalid-sample-multiple-errors.json b/packages/teleport-generator-core/__tests__/validator/component-invalid-sample-multiple-errors.json
deleted file mode 100644
index 4a28ecc7..00000000
--- a/packages/teleport-generator-core/__tests__/validator/component-invalid-sample-multiple-errors.json
+++ /dev/null
@@ -1,125 +0,0 @@
-{
-  "name": "New UIDL",
-  "propDefinitions": {
-    "title": {
-      "type": "string",
-      "defaultValue": "Hello"
-    },
-    "items": {
-      "type": "array",
-      "defaultValue": []
-    }
-  },
-  "stateDefinitions": {
-    "isVisible": {
-      "type": "boolean",
-      "defaultValue": true
-    }
-  },
-  "nodes": {
-    "type": "element",
-    "content": {
-      "elementType": "container",
-      "attrs": {
-        "data-static-attr": {
-          "type": "static",
-          "content": "test"
-        },
-        "data-dynamic-attr": {
-          "type": "dynamic",
-          "content": {
-            "referenceType": "prop",
-            "id": "title"
-          }
-        }
-      },
-      "children": [
-        {
-          "type": "element",
-          "content": {
-            "elementType": "text",
-            "children": [
-              {
-                "type": "static",
-                "content": "Hello World!"
-              },
-              {
-                "type": "dynamic",
-                "content": {
-                  "referenceType": "prop",
-                  "id": "title"
-                }
-              }
-            ]
-          }
-        },
-        {
-          "type": "repeat",
-          "content": {
-            "node": {
-              "type": "element",
-              "content": {
-                "elementType": "text",
-                "children": [
-                  {
-                    "type": "dynamic",
-                    "content": {
-                      "referenceType": "local",
-                      "id": "item"
-                    }
-                  },
-                  {
-                    "type": "element",
-                    "content": {
-                      "elementType": "list",
-                      "attrs": {
-                        "items": {
-                          "type": "static",
-                          "content": ["angular", "react", "vue"]
-                        }
-                      }
-                    }
-                  }
-                ]
-              }
-            },
-            "dataSource": {
-              "type": "dynamic",
-              "content": {
-                "referenceType": "prop",
-                "id": "items"
-              }
-            },
-            "meta": {
-              "useIndex": true,
-              "iteratorName": "item"
-            }
-          }
-        },
-        {
-          "type": "conditional",
-          "content": {
-            "reference": {
-              "type": "dynamic",
-              "content": {
-                "referenceType": "state",
-                "id": "isVisible"
-              }
-            },
-            "value": true,
-            "node": {
-              "type": "element",
-              "content": {
-                "elementType": "text",
-                "children": [{
-                  "type": "static",
-                  "content": "Now you see me!"
-                }]
-              }
-            }
-          }
-        }
-      ]
-    }
-  }
-}
\ No newline at end of file
diff --git a/packages/teleport-generator-core/__tests__/validator/component-invalid-sample.json b/packages/teleport-generator-core/__tests__/validator/component-invalid-sample.json
index c8b298a0..63f02d91 100644
--- a/packages/teleport-generator-core/__tests__/validator/component-invalid-sample.json
+++ b/packages/teleport-generator-core/__tests__/validator/component-invalid-sample.json
@@ -8,6 +8,10 @@
     "items": {
       "type": "array",
       "defaultValue": []
+    },
+    "test": {
+      "type": "string",
+      "defaultValues": "test"
     }
   },
   "stateDefinitions": {
@@ -15,6 +19,10 @@
       "type": "boolean",
       "defaultValue": true,
       "test":"test"
+    },
+    "test": {
+      "type": "string",
+      "defaultValues": "test"
     }
   },
   "node": {
@@ -48,7 +56,7 @@
                 "type": "dynamic",
                 "content": {
                   "referenceType": "prop",
-                  "id": "title"
+                  "id": "titles"
                 }
               }
             ]
@@ -92,11 +100,54 @@
               }
             },
             "meta": {
-              "useIndex": true,
+              "useIndex": false,
               "iteratorName": "item"
             }
           }
         },
+        {
+          "type": "repeat",
+          "content": {
+            "node": {
+              "type": "element",
+              "content": {
+                "elementType": "text",
+                "children": [
+                  {
+                    "type": "dynamic",
+                    "content": {
+                      "referenceType": "local",
+                      "id": "item"
+                    }
+                  },
+                  {
+                    "type": "element",
+                    "content": {
+                      "elementType": "list",
+                      "attrs": {
+                        "items": {
+                          "type": "static",
+                          "content": ["angular", "react", "vue"]
+                        }
+                      }
+                    }
+                  }
+                ]
+              }
+            },
+            "dataSource": {
+              "type": "dynamic",
+              "content": {
+                "referenceType": "prop",
+                "id": "items"
+              }
+            },
+            "meta": {
+              "useIndex": true,
+              "iteratorName": "item-test"
+            }
+          }
+        },
         {
           "type": "conditional",
           "content": {
@@ -104,7 +155,7 @@
               "type": "dynamic",
               "content": {
                 "referenceType": "state",
-                "id": "isVisible"
+                "id": "isVisibles"
               }
             },
             "value": true,
diff --git a/packages/teleport-generator-core/__tests__/validator/component-sample.json b/packages/teleport-generator-core/__tests__/validator/component-sample.json
deleted file mode 100644
index a023002b..00000000
--- a/packages/teleport-generator-core/__tests__/validator/component-sample.json
+++ /dev/null
@@ -1,125 +0,0 @@
-{
-  "name": "New UIDL",
-  "propDefinitions": {
-    "title": {
-      "type": "string",
-      "defaultValue": "Hello"
-    },
-    "items": {
-      "type": "array",
-      "defaultValue": []
-    }
-  },
-  "stateDefinitions": {
-    "isVisible": {
-      "type": "boolean",
-      "defaultValue": true
-    }
-  },
-  "node": {
-    "type": "element",
-    "content": {
-      "elementType": "container",
-      "attrs": {
-        "data-static-attr": {
-          "type": "static",
-          "content": "test"
-        },
-        "data-dynamic-attr": {
-          "type": "dynamic",
-          "content": {
-            "referenceType": "prop",
-            "id": "title"
-          }
-        }
-      },
-      "children": [
-        {
-          "type": "element",
-          "content": {
-            "elementType": "text",
-            "children": [
-              {
-                "type": "static",
-                "content": "Hello World!"
-              },
-              {
-                "type": "dynamic",
-                "content": {
-                  "referenceType": "prop",
-                  "id": "title"
-                }
-              }
-            ]
-          }
-        },
-        {
-          "type": "repeat",
-          "content": {
-            "node": {
-              "type": "element",
-              "content": {
-                "elementType": "text",
-                "children": [
-                  {
-                    "type": "dynamic",
-                    "content": {
-                      "referenceType": "local",
-                      "id": "item"
-                    }
-                  },
-                  {
-                    "type": "element",
-                    "content": {
-                      "elementType": "list",
-                      "attrs": {
-                        "items": {
-                          "type": "static",
-                          "content": ["angular", "react", "vue"]
-                        }
-                      }
-                    }
-                  }
-                ]
-              }
-            },
-            "dataSource": {
-              "type": "dynamic",
-              "content": {
-                "referenceType": "prop",
-                "id": "items"
-              }
-            },
-            "meta": {
-              "useIndex": true,
-              "iteratorName": "item"
-            }
-          }
-        },
-        {
-          "type": "conditional",
-          "content": {
-            "reference": {
-              "type": "dynamic",
-              "content": {
-                "referenceType": "state",
-                "id": "isVisible"
-              }
-            },
-            "value": true,
-            "node": {
-              "type": "element",
-              "content": {
-                "elementType": "text",
-                "children": [{
-                  "type": "static",
-                  "content": "Now you see me!"
-                }]
-              }
-            }
-          }
-        }
-      ]
-    }
-  }
-}
\ No newline at end of file
diff --git a/packages/teleport-generator-core/__tests__/validator/index.ts b/packages/teleport-generator-core/__tests__/validator/index.ts
index 88df8d42..79da78cb 100644
--- a/packages/teleport-generator-core/__tests__/validator/index.ts
+++ b/packages/teleport-generator-core/__tests__/validator/index.ts
@@ -1,51 +1,102 @@
 import { Validator } from '../../src'
 
-// @ts-ignore
-import componentUidlSample from './component-sample.json'
 // @ts-ignore
 import invalidComponentUidlSample from './component-invalid-sample.json'
 // @ts-ignore
-import multiErrorsInvalidComponentUidlSample from './component-invalid-sample-multiple-errors.json'
-// @ts-ignore
 import projectUidlSample from './project-sample.json'
 // @ts-ignore
+import oldInvalidProjectUidlSample from './old-project-invalid-sample.json'
+// @ts-ignore
 import invalidProjectUidlSample from './project-invalid-sample.json'
+// @ts-ignore
+import noRouteProjectUidlSample from './project-invalid-sample-no-route.json'
+import {
+  component,
+  definition,
+  repeatNode,
+  dynamicNode,
+  elementNode,
+} from '@teleporthq/teleport-generator-shared/lib/builders/uidl-builders'
+
+const uidl = component(
+  'Repeat Component',
+  elementNode('container', {}, [
+    repeatNode(
+      elementNode('div', {}, [dynamicNode('local', 'item')]),
+      dynamicNode('prop', 'items'),
+      {
+        useIndex: true,
+      }
+    ),
+  ]),
+  { items: definition('array', ['hello', 'world']) },
+  { items: definition('array', ['hello', 'world']) }
+)
 
 describe('Validate UIDL', () => {
-  describe('Component UIDL', () => {
+  describe('Component UIDL Format', () => {
     it('returns object with valid=true and errorMsg="" if uidl is valid', () => {
       const validator = new Validator()
-      const validationResult = validator.validateComponent(componentUidlSample)
+      const validationResult = validator.validateComponentSchema(uidl)
       expect(typeof validationResult).toBe('object')
       expect(validationResult.valid).toEqual(true)
       expect(validationResult.errorMsg).toEqual('')
     })
-    it('returns customized error', () => {
+    it('returns customized errors', () => {
       const validator = new Validator()
-      const validationResult = validator.validateComponent(invalidComponentUidlSample)
+      const validationResult = validator.validateComponentSchema(invalidComponentUidlSample)
       expect(typeof validationResult).toBe('object')
       expect(validationResult.valid).toEqual(false)
       expect(validationResult.errorMsg).toBe(
-        `UIDL Validation error. Please check the following: 
- - Path .stateDefinitions['isVisible']: should NOT have additional properties. {"additionalProperty":"test"}`
+        `\nUIDL Format Validation Error. Please check the following: 
+ - Path .stateDefinitions['isVisible']: should NOT have additional properties. {"additionalProperty":"test"},
+ - Path .stateDefinitions['test']: should have required property 'defaultValue'. {\"missingProperty\":\"defaultValue\"},
+ - Path .stateDefinitions['test']: should NOT have additional properties. {\"additionalProperty\":\"defaultValues\"},
+ - Path .propDefinitions['test']: should NOT have additional properties. {"additionalProperty":"defaultValues"}`
       )
     })
-    it('returns multiple customized errors', () => {
+  })
+
+  describe('Component UIDL Content', () => {
+    it('returns object with valid=true and errorMSG="" if everything is ok', () => {
+      const validator = new Validator()
+      const validationResult = validator.validateComponentContent(uidl)
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(true)
+      expect(validationResult.errorMsg).toEqual('')
+    })
+    it('throws error if prop and state is used but not defined in propDefinitions', () => {
       const validator = new Validator()
-      const validationResult = validator.validateComponent(multiErrorsInvalidComponentUidlSample)
-      const expectedErrorMsg = `UIDL Validation error. Please check the following: 
- - Path : should NOT have additional properties. {\"additionalProperty\":\"nodes\"},
- - Path : should have required property 'node'. {\"missingProperty\":\"node\"}`
+      const validationResult = validator.validateComponentContent(invalidComponentUidlSample)
       expect(typeof validationResult).toBe('object')
       expect(validationResult.valid).toEqual(false)
-      expect(validationResult.errorMsg).toBe(expectedErrorMsg)
+      expect(validationResult.errorMsg).not.toEqual('')
+      expect(validationResult.errorMsg).toBe(
+        `\nUIDL Component Content Validation Error. Please check the following: 
+"titles" is used but not defined. Please add it in propDefinitions,
+"isVisibles" is used but not defined. Please add it in stateDefinitions,
+Index variable is used but the "useIndex" meta information is false.,
+"item" is used in the "repeat" structure but the iterator name has this value: "item-test"`
+      )
+    })
+
+    it('does not throw error if props and states have same keys', () => {
+      const validator = new Validator()
+      const warn = jest.spyOn(global.console, 'warn')
+
+      const validationResult = validator.validateComponentContent(uidl)
+
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(true)
+      expect(validationResult.errorMsg).toEqual('')
+      expect(warn).toHaveBeenCalled()
     })
   })
 
-  describe('Project UIDL', () => {
+  describe('Project UIDL Format', () => {
     it('returns object with valid=true and errorMsg="" if uidl is valid', () => {
       const validator = new Validator()
-      const validationResult = validator.validateProject(projectUidlSample)
+      const validationResult = validator.validateProjectSchema(projectUidlSample)
 
       expect(typeof validationResult).toBe('object')
       expect(validationResult.valid).toEqual(true)
@@ -53,11 +104,23 @@ describe('Validate UIDL', () => {
     })
     it('returns customized error', () => {
       const validator = new Validator()
-      const validationResult = validator.validateProject(invalidProjectUidlSample)
+      const validationResult = validator.validateProjectSchema(invalidProjectUidlSample)
       expect(typeof validationResult).toBe('object')
       expect(validationResult.valid).toEqual(false)
       expect(validationResult.errorMsg).toBe(
-        `UIDL Validation error. Please check the following: 
+        `\nUIDL Format Validation Error. Please check the following: 
+ - Path : should have required property 'name'. {"missingProperty":"name"},
+ - Path .globals.settings: should NOT have additional properties. {"additionalProperty":"key"},
+ - Path .globals.settings.language: should be string. Received number`
+      )
+    })
+    it('supports older UIDL version and returns customized error', () => {
+      const validator = new Validator()
+      const validationResult = validator.validateProjectSchema(oldInvalidProjectUidlSample)
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(false)
+      expect(validationResult.errorMsg).toBe(
+        `\nUIDL Format Validation Error. Please check the following: 
  - Path : should have required property 'name'. {"missingProperty":"name"},
  - Path .globals.settings: should NOT have additional properties. {"additionalProperty":"key"},
  - Path .globals.settings.language: should be string. Received number,
@@ -65,4 +128,39 @@ describe('Validate UIDL', () => {
       )
     })
   })
+
+  describe('Project UIDL Content', () => {
+    it('returns object with valid=true and errorMsg="" if uidl content is valid', () => {
+      const validator = new Validator()
+      const validationResult = validator.validateProjectContent(projectUidlSample)
+
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(true)
+      expect(validationResult.errorMsg).toEqual('')
+    })
+    it('returns customized error if content is not properly defined', () => {
+      const validator = new Validator()
+      const validationResult = validator.validateProjectContent(invalidProjectUidlSample)
+
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(false)
+      expect(validationResult.errorMsg).toEqual(
+        `\nUIDL Project Content Validation Error. Please check the following: 
+The component "Navbars" is not defined in the UIDL's component section.,
+The following components have different name than their key: Navbar,OneComponent,
+Root Node contains elements of type "static". It should contain only elements of type "conditional",
+Root Node contains routes that don't have corresponding components. Check the "value" for the following routes: /about.`
+      )
+    })
+    it('returns error if route is missing from state definitions', () => {
+      const validator = new Validator()
+      const validationResult = validator.validateProjectContent(noRouteProjectUidlSample)
+
+      expect(typeof validationResult).toBe('object')
+      expect(validationResult.valid).toEqual(false)
+      expect(validationResult.errorMsg).toEqual(
+        `\nUIDL Project Content Validation Error. Please check the following: Route is not defined in stateDefinitions`
+      )
+    })
+  })
 })
diff --git a/packages/teleport-generator-core/__tests__/validator/old-project-invalid-sample.json b/packages/teleport-generator-core/__tests__/validator/old-project-invalid-sample.json
new file mode 100644
index 00000000..47901298
--- /dev/null
+++ b/packages/teleport-generator-core/__tests__/validator/old-project-invalid-sample.json
@@ -0,0 +1,318 @@
+{
+  "$schema": "https://raw.githubusercontent.com/teleporthq/teleport-code-generators/master/packages/teleport-generator-core/src/uidl-schemas/project.json",
+  "globals": {
+    "settings": {
+      "language": 1,
+      "title": "teleportHQ",
+      "key": "test"
+    },
+    "meta" : [
+      { "name": "description", "content": "Free Web tutorials" },
+      { "name": "keywords", "content": "prea bun, prea ca la tara" },
+      { "name": "viewport", "content": "width=device-width, initial-scale=1.0" },
+      { "property": "og:title", "content": "Free Web tutorials" },
+      { "property": "og:url", "content": "/playground_assets/asdasd.png" }
+    ],
+    "manifest": {
+      "icons": [
+        {
+          "src": "/playground_assets/icons-192.png",
+          "type": "image/png",
+          "sizes": "192x192"
+        },
+        {
+          "src": "/playground_assets/icons-512.png",
+          "type": "image/png",
+          "sizes": "512x512"
+        }
+      ],
+      "theme_color": "#822CEC",
+      "background_color": "#822CEC"
+    },
+    "assets": [
+      {
+        "type": "style",
+        "path": "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css",
+        "meta": {
+          "target": "body"
+        }
+      }, 
+      {
+        "type": "scripts",
+        "path": "https://www.googletagmanager.com/gtm.js",
+        "meta": {
+          "defer": true
+        }
+      },
+      {
+        "type": "script",
+        "content": "console.log(\"inline script\")",
+        "meta": {
+          "target": "body"
+        }
+      },
+      {
+        "type": "font",
+        "path": "https://fonts.googleapis.com/css?family=Roboto"
+      },
+      {
+        "type": "style",
+        "content": "body{font-family: 'Roboto', sans-serif;}"
+      },
+      {
+        "type": "icon",
+        "path": "/playground_assets/favicon-32x32.png",
+        "meta": {
+          "type": "image/png",
+          "sizes": "32x32"
+        }
+      }
+    ],
+    "variables": {
+      "primaryColor": "#822CEC",
+      "secondaryColor": "#414141",
+      "spacing": "10px"
+    }
+  },
+  "root": {
+    "name": "App",
+    "stateDefinitions": {
+      "route": {
+        "type": "string",
+        "defaultValue": "index",
+        "values": [
+          {
+            "value": "index",
+            "meta": {
+              "path": "/",
+              "componentName": "Home"
+            }
+          },
+          {
+            "value": "about",
+            "meta": {
+              "path": "/about",
+              "componentName": "About"
+            }
+          },
+          {
+            "value": "contact-us",
+            "meta": {
+              "path": "/here-we-are",
+              "componentName": "Us"
+            }
+          }
+        ]
+      }
+    },
+    "node": {
+      "type": "element",
+      "content": {
+        "elementType": "Router",
+        "children": [
+          {
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "children": [
+                    {
+                      "type": "static",
+                      "content": "Page 1"
+                    }
+                  ]
+                }
+              },
+              "value": "index",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          },
+          {
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "children": [
+                    {
+                      "type": "static",
+                      "content": "Page 2"
+                    }
+                  ]
+                }
+              },
+              "value": "about",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          },{
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "children": [
+                    {
+                      "type": "static",
+                      "content": "Page 3"
+                    }
+                  ]
+                }
+              },
+              "value": "contact-us",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "OneComponent": {
+      "name": "OneComponent",
+      "propDefinitions": {
+        "title": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "items": {
+          "type": "array",
+          "defaultValue": []
+        }
+      },
+      "stateDefinitions": {
+        "isVisible": {
+          "type": "boolean",
+          "defaultValue": true
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "attrs": {
+            "data-static-attr": {
+              "type": "static",
+              "content": "test"
+            },
+            "data-dynamic-attr": {
+              "type": "dynamic",
+              "content": {
+                "referenceType": "prop",
+                "id": "title"
+              }
+            }
+          },
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "text",
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Hello World!"
+                  },
+                  {
+                    "type": "dynamic",
+                    "content": {
+                      "referenceType": "prop",
+                      "id": "title"
+                    }
+                  }
+                ]
+              }
+            },
+            {
+              "type": "repeat",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [
+                      {
+                        "type": "dynamic",
+                        "content": {
+                          "referenceType": "local",
+                          "id": "item"
+                        }
+                      },
+                      {
+                        "type": "element",
+                        "content": {
+                          "elementType": "list",
+                          "attrs": {
+                            "items": {
+                              "type": "static",
+                              "content": ["angular", "react", "vue"]
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "dataSource": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "prop",
+                    "id": "items"
+                  }
+                },
+                "meta": {
+                  "useIndex": true,
+                  "iteratorName": "item"
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "state",
+                    "id": "isVisible"
+                  }
+                },
+                "value": true,
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [{
+                      "type": "static",
+                      "content": "Now you see me!"
+                    }]
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/packages/teleport-generator-core/__tests__/validator/project-invalid-sample-no-route.json b/packages/teleport-generator-core/__tests__/validator/project-invalid-sample-no-route.json
new file mode 100644
index 00000000..3c969c4e
--- /dev/null
+++ b/packages/teleport-generator-core/__tests__/validator/project-invalid-sample-no-route.json
@@ -0,0 +1,663 @@
+{
+  "$schema": "https://raw.githubusercontent.com/teleporthq/teleport-code-generators/master/packages/teleport-generator-core/src/uidl-schemas/project.json",
+  "name": "myVueProject",
+  "globals": {
+    "settings": {
+      "language": "en",
+      "title": "UIDL v0.6 Project"
+    },
+    "assets": [],
+    "meta": []
+  },
+  "root": {
+    "name": "App",
+    "stateDefinitions": {
+      "routes": {
+        "type": "string",
+        "defaultValue": "index",
+        "values": [
+          {
+            "value": "index",
+            "meta": {
+              "path": "/",
+              "componentName": "Home"
+            }
+          },
+          {
+            "value": "abouts",
+            "meta": {
+              "path": "/about",
+              "componentName": "About"
+            }
+          },
+          {
+            "value": "contact-us",
+            "meta": {
+              "path": "/here-we-are",
+              "componentName": "Us"
+            }
+          }
+        ]
+      }
+    },
+    "node": {
+      "type": "element",
+      "content": {
+        "elementType": "Router",
+        "children": [
+          {
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "style": {
+                    "border": "1px solid green",
+                    "padding": {
+                      "type": "static",
+                      "content": "10px"
+                    }
+                  },
+                  "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
+                    {
+                      "type": "static",
+                      "content": "Page 1"
+                    }
+                  ]
+                }
+              },
+              "value": "index",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          },
+          {
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
+                  "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
+                    {
+                      "type": "static",
+                      "content": "Page 2"
+                    }
+                  ]
+                }
+              },
+              "value": "about",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          },{
+            "type": "conditional",
+            "content": {
+              "node": {
+                "type": "element",
+                "content": {
+                  "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
+                  "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
+                    {
+                      "type": "static",
+                      "content": "Page 3"
+                    },
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "OneComponent",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "value": "contact-us",
+              "reference": {
+                "type": "dynamic",
+                "content": {
+                  "referenceType": "state",
+                  "id": "route"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "Navbar": {
+      "name": "Navbar",
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "group",
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Home"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/about"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/here-we-are"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Contact"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
+    "OneComponent": {
+      "name": "New UIDL",
+      "propDefinitions": {
+        "title": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "items": {
+          "type": "array",
+          "defaultValue": []
+        }
+      },
+      "stateDefinitions": {
+        "isVisible": {
+          "type": "boolean",
+          "defaultValue": true
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "attrs": {
+            "data-static-attr": {
+              "type": "static",
+              "content": "test"
+            },
+            "data-dynamic-attr": {
+              "type": "dynamic",
+              "content": {
+                "referenceType": "prop",
+                "id": "title"
+              }
+            }
+          },
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "text",
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Hello World!"
+                  },
+                  {
+                    "type": "dynamic",
+                    "content": {
+                      "referenceType": "prop",
+                      "id": "title"
+                    }
+                  }
+                ]
+              }
+            },
+            {
+              "type": "repeat",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [
+                      {
+                        "type": "dynamic",
+                        "content": {
+                          "referenceType": "local",
+                          "id": "item"
+                        }
+                      },
+                      {
+                        "type": "element",
+                        "content": {
+                          "elementType": "list",
+                          "attrs": {
+                            "items": {
+                              "type": "static",
+                              "content": ["angular", "react", "vue"]
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "dataSource": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "prop",
+                    "id": "items"
+                  }
+                },
+                "meta": {
+                  "useIndex": true,
+                  "iteratorName": "item"
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "prop",
+                    "id": "title"
+                  }
+                },
+                "value": "matching",
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [{
+                      "type": "static",
+                      "content": "Now you see me!"
+                    }]
+                  }
+                }
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "video",
+                "attrs": {
+                  "autoPlay": {
+                    "type": "static",
+                    "content": true
+                  }
+                },
+                "children": [{
+                  "type": "element",
+                  "content": {
+                    "elementType": "source",
+                    "attrs": {
+                      "type": {
+                        "type": "static",
+                        "content": "video/mp4"
+                      },
+                      "url": {
+                        "type": "static",
+                        "content": "https://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"
+                      }
+                    }
+                  }
+                }]
+              }
+            },
+            {
+              "type": "slot",
+              "content": {}
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": {
+                    "type": "static",
+                    "content": "about"
+                  }
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About Page"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
+    "ExpandableArea": {
+      "name": "ExpandableArea",
+      "propDefinitions": {
+        "title": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "text": {
+          "type": "string",
+          "defaultValue": "Is it me you're looking for?"
+        }
+      },
+      "stateDefinitions": {
+        "isExpanded": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "style": {
+            "border": {
+              "type": "static",
+              "content": "1px solid green"
+            },
+            "margin": {
+              "type": "static",
+              "content": "10px"
+            }
+          },
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "text",
+                "children": [{
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "prop",
+                    "id": "title"
+                  }
+                }]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "button",
+                "children": [{
+                  "type": "conditional",
+                  "content": {
+                    "node": {
+                      "type": "static",
+                      "content": "Hide me"
+                    },
+                    "value": true,
+                    "reference": {
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "state",
+                        "id": "isExpanded"
+                      }
+                    }
+                  }
+                },{
+                  "type": "conditional",
+                  "content": {
+                    "node": {
+                      "type": "static",
+                      "content": "Show me"
+                    },
+                    "value": false,
+                    "reference": {
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "state",
+                        "id": "isExpanded"
+                      }
+                    }
+                  }
+                }],
+                "events": {
+                  "click": [
+                    {
+                      "type": "stateChange",
+                      "modifies": "isExpanded",
+                      "newState": "$toggle"
+                    }
+                  ]
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [{
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "prop",
+                        "id": "text"
+                      }
+                    }]
+                  }
+                },
+                "value": true,
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "state",
+                    "id": "isExpanded"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    },
+    "Modal": {
+      "name": "Modal",
+      "stateDefinitions": {
+        "isOpen": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "group",
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "button",
+                "name": "openmodal",
+                "children": [{
+                  "type": "static",
+                  "content": "Show Popup"
+                }],
+                "events": {
+                  "click": [{
+                    "type": "stateChange",
+                    "modifies": "isOpen",
+                    "newState": true
+                  }]
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "ModalWindow",
+                    "name": "window",
+                    "dependency": {
+                      "type": "local"
+                    },
+                    "events": {
+                      "onClose": [{
+                        "type": "stateChange",
+                        "modifies": "isOpen",
+                        "newState": false
+                      }]
+                    }
+                  }
+                },
+                "value": true,
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "state",
+                    "id": "isOpen"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    },
+    "ModalWindow": {
+      "name": "ModalWindow",
+      "propDefinitions": {
+        "message": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "onClose": {
+          "type": "func",
+          "defaultValue": "() => {}"
+        }
+      },
+      "stateDefinitions": {
+        "fakeState": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "children": [{
+            "type": "dynamic",
+            "content": {
+              "referenceType": "prop",
+              "id": "message"
+            }
+          },{
+            "type": "element",
+            "content": {
+              "elementType": "button",
+              "name": "close",
+              "children": [{
+                "type": "static",
+                "content": "Close me"
+              }],
+              "events": {
+                "click": [{
+                  "type": "propCall",
+                  "calls": "onClose"
+                },{
+                  "type": "stateChange",
+                  "modifies": "fakeState",
+                  "newState": false
+                }]
+              }
+            }
+          }]
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/packages/teleport-generator-core/__tests__/validator/project-invalid-sample.json b/packages/teleport-generator-core/__tests__/validator/project-invalid-sample.json
index 47901298..0dc3c20a 100644
--- a/packages/teleport-generator-core/__tests__/validator/project-invalid-sample.json
+++ b/packages/teleport-generator-core/__tests__/validator/project-invalid-sample.json
@@ -2,77 +2,12 @@
   "$schema": "https://raw.githubusercontent.com/teleporthq/teleport-code-generators/master/packages/teleport-generator-core/src/uidl-schemas/project.json",
   "globals": {
     "settings": {
-      "language": 1,
-      "title": "teleportHQ",
-      "key": "test"
+      "language": 2,
+      "key": "test",
+      "title": "UIDL v0.6 Project"
     },
-    "meta" : [
-      { "name": "description", "content": "Free Web tutorials" },
-      { "name": "keywords", "content": "prea bun, prea ca la tara" },
-      { "name": "viewport", "content": "width=device-width, initial-scale=1.0" },
-      { "property": "og:title", "content": "Free Web tutorials" },
-      { "property": "og:url", "content": "/playground_assets/asdasd.png" }
-    ],
-    "manifest": {
-      "icons": [
-        {
-          "src": "/playground_assets/icons-192.png",
-          "type": "image/png",
-          "sizes": "192x192"
-        },
-        {
-          "src": "/playground_assets/icons-512.png",
-          "type": "image/png",
-          "sizes": "512x512"
-        }
-      ],
-      "theme_color": "#822CEC",
-      "background_color": "#822CEC"
-    },
-    "assets": [
-      {
-        "type": "style",
-        "path": "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css",
-        "meta": {
-          "target": "body"
-        }
-      }, 
-      {
-        "type": "scripts",
-        "path": "https://www.googletagmanager.com/gtm.js",
-        "meta": {
-          "defer": true
-        }
-      },
-      {
-        "type": "script",
-        "content": "console.log(\"inline script\")",
-        "meta": {
-          "target": "body"
-        }
-      },
-      {
-        "type": "font",
-        "path": "https://fonts.googleapis.com/css?family=Roboto"
-      },
-      {
-        "type": "style",
-        "content": "body{font-family: 'Roboto', sans-serif;}"
-      },
-      {
-        "type": "icon",
-        "path": "/playground_assets/favicon-32x32.png",
-        "meta": {
-          "type": "image/png",
-          "sizes": "32x32"
-        }
-      }
-    ],
-    "variables": {
-      "primaryColor": "#822CEC",
-      "secondaryColor": "#414141",
-      "spacing": "10px"
-    }
+    "assets": [],
+    "meta": []
   },
   "root": {
     "name": "App",
@@ -89,7 +24,7 @@
             }
           },
           {
-            "value": "about",
+            "value": "abouts",
             "meta": {
               "path": "/about",
               "componentName": "About"
@@ -110,6 +45,10 @@
       "content": {
         "elementType": "Router",
         "children": [
+          {
+            "type": "static",
+            "content": "Hello World!"
+          },
           {
             "type": "conditional",
             "content": {
@@ -117,7 +56,23 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": "1px solid green",
+                    "padding": {
+                      "type": "static",
+                      "content": "10px"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 1"
@@ -142,7 +97,26 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbars",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 2"
@@ -166,10 +140,38 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 3"
+                    },
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "OneComponent",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
                     }
                   ]
                 }
@@ -189,8 +191,64 @@
     }
   },
   "components": {
+    "Navbar": {
+      "name": "Navbars",
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "group",
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Home"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/about"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/here-we-are"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Contact"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
     "OneComponent": {
-      "name": "OneComponent",
+      "name": "New UIDL",
       "propDefinitions": {
         "title": {
           "type": "string",
@@ -293,11 +351,11 @@
                 "reference": {
                   "type": "dynamic",
                   "content": {
-                    "referenceType": "state",
-                    "id": "isVisible"
+                    "referenceType": "prop",
+                    "id": "title"
                   }
                 },
-                "value": true,
+                "value": "matching",
                 "node": {
                   "type": "element",
                   "content": {
@@ -309,10 +367,301 @@
                   }
                 }
               }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "video",
+                "attrs": {
+                  "autoPlay": {
+                    "type": "static",
+                    "content": true
+                  }
+                },
+                "children": [{
+                  "type": "element",
+                  "content": {
+                    "elementType": "source",
+                    "attrs": {
+                      "type": {
+                        "type": "static",
+                        "content": "video/mp4"
+                      },
+                      "url": {
+                        "type": "static",
+                        "content": "https://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"
+                      }
+                    }
+                  }
+                }]
+              }
+            },
+            {
+              "type": "slot",
+              "content": {}
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": {
+                    "type": "static",
+                    "content": "about"
+                  }
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About Page"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
+    "ExpandableArea": {
+      "name": "ExpandableArea",
+      "propDefinitions": {
+        "title": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "text": {
+          "type": "string",
+          "defaultValue": "Is it me you're looking for?"
+        }
+      },
+      "stateDefinitions": {
+        "isExpanded": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "style": {
+            "border": {
+              "type": "static",
+              "content": "1px solid green"
+            },
+            "margin": {
+              "type": "static",
+              "content": "10px"
+            }
+          },
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "text",
+                "children": [{
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "prop",
+                    "id": "title"
+                  }
+                }]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "button",
+                "children": [{
+                  "type": "conditional",
+                  "content": {
+                    "node": {
+                      "type": "static",
+                      "content": "Hide me"
+                    },
+                    "value": true,
+                    "reference": {
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "state",
+                        "id": "isExpanded"
+                      }
+                    }
+                  }
+                },{
+                  "type": "conditional",
+                  "content": {
+                    "node": {
+                      "type": "static",
+                      "content": "Show me"
+                    },
+                    "value": false,
+                    "reference": {
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "state",
+                        "id": "isExpanded"
+                      }
+                    }
+                  }
+                }],
+                "events": {
+                  "click": [
+                    {
+                      "type": "stateChange",
+                      "modifies": "isExpanded",
+                      "newState": "$toggle"
+                    }
+                  ]
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "text",
+                    "children": [{
+                      "type": "dynamic",
+                      "content": {
+                        "referenceType": "prop",
+                        "id": "text"
+                      }
+                    }]
+                  }
+                },
+                "value": true,
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "state",
+                    "id": "isExpanded"
+                  }
+                }
+              }
             }
           ]
         }
       }
+    },
+    "Modal": {
+      "name": "Modal",
+      "stateDefinitions": {
+        "isOpen": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "group",
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "button",
+                "name": "openmodal",
+                "children": [{
+                  "type": "static",
+                  "content": "Show Popup"
+                }],
+                "events": {
+                  "click": [{
+                    "type": "stateChange",
+                    "modifies": "isOpen",
+                    "newState": true
+                  }]
+                }
+              }
+            },
+            {
+              "type": "conditional",
+              "content": {
+                "node": {
+                  "type": "element",
+                  "content": {
+                    "elementType": "ModalWindow",
+                    "name": "window",
+                    "dependency": {
+                      "type": "local"
+                    },
+                    "events": {
+                      "onClose": [{
+                        "type": "stateChange",
+                        "modifies": "isOpen",
+                        "newState": false
+                      }]
+                    }
+                  }
+                },
+                "value": true,
+                "reference": {
+                  "type": "dynamic",
+                  "content": {
+                    "referenceType": "state",
+                    "id": "isOpen"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    },
+    "ModalWindow": {
+      "name": "ModalWindow",
+      "propDefinitions": {
+        "message": {
+          "type": "string",
+          "defaultValue": "Hello"
+        },
+        "onClose": {
+          "type": "func",
+          "defaultValue": "() => {}"
+        }
+      },
+      "stateDefinitions": {
+        "fakeState": {
+          "type": "boolean",
+          "defaultValue": false
+        }
+      },
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "container",
+          "children": [{
+            "type": "dynamic",
+            "content": {
+              "referenceType": "prop",
+              "id": "message"
+            }
+          },{
+            "type": "element",
+            "content": {
+              "elementType": "button",
+              "name": "close",
+              "children": [{
+                "type": "static",
+                "content": "Close me"
+              }],
+              "events": {
+                "click": [{
+                  "type": "propCall",
+                  "calls": "onClose"
+                },{
+                  "type": "stateChange",
+                  "modifies": "fakeState",
+                  "newState": false
+                }]
+              }
+            }
+          }]
+        }
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/packages/teleport-generator-core/__tests__/validator/project-sample.json b/packages/teleport-generator-core/__tests__/validator/project-sample.json
index 2c093447..e7e587e4 100644
--- a/packages/teleport-generator-core/__tests__/validator/project-sample.json
+++ b/packages/teleport-generator-core/__tests__/validator/project-sample.json
@@ -4,75 +4,10 @@
   "globals": {
     "settings": {
       "language": "en",
-      "title": "teleportHQ"
+      "title": "UIDL v0.6 Project"
     },
-    "meta" : [
-      { "name": "description", "content": "Free Web tutorials" },
-      { "name": "keywords", "content": "prea bun, prea ca la tara" },
-      { "name": "viewport", "content": "width=device-width, initial-scale=1.0" },
-      { "property": "og:title", "content": "Free Web tutorials" },
-      { "property": "og:url", "content": "/playground_assets/asdasd.png" }
-    ],
-    "manifest": {
-      "icons": [
-        {
-          "src": "/playground_assets/icons-192.png",
-          "type": "image/png",
-          "sizes": "192x192"
-        },
-        {
-          "src": "/playground_assets/icons-512.png",
-          "type": "image/png",
-          "sizes": "512x512"
-        }
-      ],
-      "theme_color": "#822CEC",
-      "background_color": "#822CEC"
-    },
-    "assets": [
-      {
-        "type": "style",
-        "path": "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css",
-        "meta": {
-          "target": "body"
-        }
-      }, 
-      {
-        "type": "script",
-        "path": "https://www.googletagmanager.com/gtm.js",
-        "meta": {
-          "defer": true
-        }
-      },
-      {
-        "type": "script",
-        "content": "console.log(\"inline script\")",
-        "meta": {
-          "target": "body"
-        }
-      },
-      {
-        "type": "font",
-        "path": "https://fonts.googleapis.com/css?family=Roboto"
-      },
-      {
-        "type": "style",
-        "content": "body{font-family: 'Roboto', sans-serif;}"
-      },
-      {
-        "type": "icon",
-        "path": "/playground_assets/favicon-32x32.png",
-        "meta": {
-          "type": "image/png",
-          "sizes": "32x32"
-        }
-      }
-    ],
-    "variables": {
-      "primaryColor": "#822CEC",
-      "secondaryColor": "#414141",
-      "spacing": "10px"
-    }
+    "assets": [],
+    "meta": []
   },
   "root": {
     "name": "App",
@@ -117,7 +52,23 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": "1px solid green",
+                    "padding": {
+                      "type": "static",
+                      "content": "10px"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 1"
@@ -142,7 +93,26 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 2"
@@ -166,10 +136,38 @@
                 "type": "element",
                 "content": {
                   "elementType": "container",
+                  "style": {
+                    "border": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    },
+                    "padding": {
+                      "type": "static",
+                      "content": "1px solid black"
+                    }
+                  },
                   "children": [
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "Navbar",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
+                    },
                     {
                       "type": "static",
                       "content": "Page 3"
+                    },
+                    {
+                      "type": "element",
+                      "content": {
+                        "elementType": "OneComponent",
+                        "dependency": {
+                          "type": "local"
+                        }
+                      }
                     }
                   ]
                 }
@@ -189,6 +187,62 @@
     }
   },
   "components": {
+    "Navbar": {
+      "name": "Navbar",
+      "node": {
+        "type": "element",
+        "content": {
+          "elementType": "group",
+          "children": [
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Home"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/about"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": "/here-we-are"
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "Contact"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
     "OneComponent": {
       "name": "OneComponent",
       "propDefinitions": {
@@ -293,11 +347,11 @@
                 "reference": {
                   "type": "dynamic",
                   "content": {
-                    "referenceType": "state",
-                    "id": "isVisible"
+                    "referenceType": "prop",
+                    "id": "title"
                   }
                 },
-                "value": true,
+                "value": "matching",
                 "node": {
                   "type": "element",
                   "content": {
@@ -309,6 +363,56 @@
                   }
                 }
               }
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "video",
+                "attrs": {
+                  "autoPlay": {
+                    "type": "static",
+                    "content": true
+                  }
+                },
+                "children": [{
+                  "type": "element",
+                  "content": {
+                    "elementType": "source",
+                    "attrs": {
+                      "type": {
+                        "type": "static",
+                        "content": "video/mp4"
+                      },
+                      "url": {
+                        "type": "static",
+                        "content": "https://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"
+                      }
+                    }
+                  }
+                }]
+              }
+            },
+            {
+              "type": "slot",
+              "content": {}
+            },
+            {
+              "type": "element",
+              "content": {
+                "elementType": "navlink",
+                "attrs": {
+                  "transitionTo": {
+                    "type": "static",
+                    "content": "about"
+                  }
+                },
+                "children": [
+                  {
+                    "type": "static",
+                    "content": "About Page"
+                  }
+                ]
+              }
             }
           ]
         }
@@ -336,6 +440,16 @@
         "type": "element",
         "content": {
           "elementType": "container",
+          "style": {
+            "border": {
+              "type": "static",
+              "content": "1px solid green"
+            },
+            "margin": {
+              "type": "static",
+              "content": "10px"
+            }
+          },
           "children": [
             {
               "type": "element",