Repository: vuejs/eslint-plugin-vue
Pull request #115 (2017-07-29 22:03:26)

Add documentation for some internal function


Patch:
diff --git a/docs/rules/require-prop-types.md b/docs/rules/require-prop-types.md
new file mode 100644
index 00000000..4c0c0c46
--- /dev/null
+++ b/docs/rules/require-prop-types.md
@@ -0,0 +1,42 @@
+# Prop definitions should be detailed (require-prop-types)
+
+In committed code, prop definitions should always be as detailed as possible, specifying at least type(s).
+
+## :book: Rule Details
+
+This rule enforces that a `props` statement contains type definition.
+
+:-1: Examples of **incorrect** code for this rule:
+
+```js
+export default {
+  props: ['status']
+}
+```
+
+:+1: Examples of **correct** code for this rule:
+
+```js
+export default {
+  props: {
+    status: String
+  }
+}
+```
+
+```js
+export default {
+  props: {
+    status: {
+      type: String,
+      required: true,
+      validate: function (value) {
+        return ['syncing', 'synced', 'version-conflict', 'error'].indexOf(value) !== -1
+      }
+    }
+  }
+}
+```
+## :wrench: Options
+
+Nothing.
diff --git a/lib/rules/html-end-tags.js b/lib/rules/html-end-tags.js
index 852d7925..4238cca1 100644
--- a/lib/rules/html-end-tags.js
+++ b/lib/rules/html-end-tags.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for html-end-tags.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/html-no-self-closing.js b/lib/rules/html-no-self-closing.js
index daf10d11..6378686e 100644
--- a/lib/rules/html-no-self-closing.js
+++ b/lib/rules/html-no-self-closing.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for html-no-self-closing.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/html-quotes.js b/lib/rules/html-quotes.js
index dd66dcad..2dd4ec45 100644
--- a/lib/rules/html-quotes.js
+++ b/lib/rules/html-quotes.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for html-quotes.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const sourceCode = context.getSourceCode()
diff --git a/lib/rules/name-property-casing.js b/lib/rules/name-property-casing.js
index c4136d85..89744d4b 100644
--- a/lib/rules/name-property-casing.js
+++ b/lib/rules/name-property-casing.js
@@ -21,11 +21,11 @@ function create (context) {
 
   return utils.executeOnVue(context, (obj) => {
     const node = obj.properties
-      .filter(item => (
+      .find(item => (
         item.type === 'Property' &&
         item.key.name === 'name' &&
         item.value.type === 'Literal'
-      ))[0]
+      ))
 
     if (!node) return
 
diff --git a/lib/rules/no-confusing-v-for-v-if.js b/lib/rules/no-confusing-v-for-v-if.js
index e202a9a1..d6963224 100644
--- a/lib/rules/no-confusing-v-for-v-if.js
+++ b/lib/rules/no-confusing-v-for-v-if.js
@@ -34,7 +34,7 @@ function isUsingIterationVar (vIf) {
  * Creates AST event handlers for no-confusing-v-for-v-if.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-duplicate-attributes.js b/lib/rules/no-duplicate-attributes.js
index 99afe50e..65a566fb 100644
--- a/lib/rules/no-duplicate-attributes.js
+++ b/lib/rules/no-duplicate-attributes.js
@@ -34,7 +34,7 @@ function getName (attribute) {
  * Creates AST event handlers for no-duplicate-attributes.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const names = new Set()
diff --git a/lib/rules/no-invalid-template-root.js b/lib/rules/no-invalid-template-root.js
index c759a420..78d55ece 100644
--- a/lib/rules/no-invalid-template-root.js
+++ b/lib/rules/no-invalid-template-root.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-template-root.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const sourceCode = context.getSourceCode()
diff --git a/lib/rules/no-invalid-v-bind.js b/lib/rules/no-invalid-v-bind.js
index dd8da2dd..cd9ddc60 100644
--- a/lib/rules/no-invalid-v-bind.js
+++ b/lib/rules/no-invalid-v-bind.js
@@ -21,7 +21,7 @@ const VALID_MODIFIERS = new Set(['prop', 'camel', 'sync'])
  * Creates AST event handlers for no-invalid-v-bind.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-cloak.js b/lib/rules/no-invalid-v-cloak.js
index 33d3e684..55757d12 100644
--- a/lib/rules/no-invalid-v-cloak.js
+++ b/lib/rules/no-invalid-v-cloak.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-cloak.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-else-if.js b/lib/rules/no-invalid-v-else-if.js
index 1f985d24..e9f00745 100644
--- a/lib/rules/no-invalid-v-else-if.js
+++ b/lib/rules/no-invalid-v-else-if.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-else-if.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-else.js b/lib/rules/no-invalid-v-else.js
index 1141f4db..58eb6e76 100644
--- a/lib/rules/no-invalid-v-else.js
+++ b/lib/rules/no-invalid-v-else.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-else.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-for.js b/lib/rules/no-invalid-v-for.js
index cd18f146..aced1b81 100644
--- a/lib/rules/no-invalid-v-for.js
+++ b/lib/rules/no-invalid-v-for.js
@@ -74,7 +74,7 @@ function checkKey (context, vFor, element) {
  * Creates AST event handlers for no-invalid-v-for.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const sourceCode = context.getSourceCode()
diff --git a/lib/rules/no-invalid-v-html.js b/lib/rules/no-invalid-v-html.js
index 8bacfdab..8d179da0 100644
--- a/lib/rules/no-invalid-v-html.js
+++ b/lib/rules/no-invalid-v-html.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-html.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-if.js b/lib/rules/no-invalid-v-if.js
index a4695af1..e77b15c4 100644
--- a/lib/rules/no-invalid-v-if.js
+++ b/lib/rules/no-invalid-v-if.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-if.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-model.js b/lib/rules/no-invalid-v-model.js
index aa0e543c..59deadf5 100644
--- a/lib/rules/no-invalid-v-model.js
+++ b/lib/rules/no-invalid-v-model.js
@@ -77,7 +77,7 @@ function getVariable (name, leafNode) {
  * Creates AST event handlers for no-invalid-v-model.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-on.js b/lib/rules/no-invalid-v-on.js
index a271d45f..142d849a 100644
--- a/lib/rules/no-invalid-v-on.js
+++ b/lib/rules/no-invalid-v-on.js
@@ -28,7 +28,7 @@ const VERB_MODIFIERS = new Set([
  * Creates AST event handlers for no-invalid-v-on.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-once.js b/lib/rules/no-invalid-v-once.js
index bfd94acf..36f73afb 100644
--- a/lib/rules/no-invalid-v-once.js
+++ b/lib/rules/no-invalid-v-once.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-once.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-pre.js b/lib/rules/no-invalid-v-pre.js
index 34b2cebf..07f2e401 100644
--- a/lib/rules/no-invalid-v-pre.js
+++ b/lib/rules/no-invalid-v-pre.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-pre.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-show.js b/lib/rules/no-invalid-v-show.js
index f3ef4c86..f2812f16 100644
--- a/lib/rules/no-invalid-v-show.js
+++ b/lib/rules/no-invalid-v-show.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-show.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-invalid-v-text.js b/lib/rules/no-invalid-v-text.js
index 2fe71564..6284f90a 100644
--- a/lib/rules/no-invalid-v-text.js
+++ b/lib/rules/no-invalid-v-text.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-invalid-v-text.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-parsing-error.js b/lib/rules/no-parsing-error.js
index 98665232..94a3b1af 100644
--- a/lib/rules/no-parsing-error.js
+++ b/lib/rules/no-parsing-error.js
@@ -54,7 +54,7 @@ const DEFAULT_OPTIONS = Object.freeze(Object.assign(Object.create(null), {
  * Creates AST event handlers for no-parsing-error.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const options = Object.assign({}, DEFAULT_OPTIONS, context.options[0] || {})
diff --git a/lib/rules/no-template-key.js b/lib/rules/no-template-key.js
index 1c844430..b9677e46 100644
--- a/lib/rules/no-template-key.js
+++ b/lib/rules/no-template-key.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-template-key.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/no-textarea-mustache.js b/lib/rules/no-textarea-mustache.js
index d89ec7a4..fd637a8f 100644
--- a/lib/rules/no-textarea-mustache.js
+++ b/lib/rules/no-textarea-mustache.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for no-textarea-mustache.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/require-component-is.js b/lib/rules/require-component-is.js
index 977c1951..e72587fe 100644
--- a/lib/rules/require-component-is.js
+++ b/lib/rules/require-component-is.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for require-component-is.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/require-prop-types.js b/lib/rules/require-prop-types.js
new file mode 100644
index 00000000..d8291cf8
--- /dev/null
+++ b/lib/rules/require-prop-types.js
@@ -0,0 +1,94 @@
+/**
+ * @fileoverview Prop definitions should be detailed
+ * @author Armano
+ */
+'use strict'
+
+const utils = require('../utils')
+
+function create (context) {
+  // ----------------------------------------------------------------------
+  // Helpers
+  // ----------------------------------------------------------------------
+
+  function objectHasType (node) {
+    const typeProperty = node.properties
+      .find(p =>
+        utils.getStaticPropertyName(p.key) === 'type' &&
+        (
+          p.value.type !== 'ArrayExpression' ||
+          p.value.elements.length > 0
+        )
+      )
+    return Boolean(typeProperty)
+  }
+
+  function checkProperties (items) {
+    for (const cp of items) {
+      if (cp.type !== 'Property') {
+        return
+      }
+      let hasType = true
+      if (cp.value.type === 'ObjectExpression') { // foo: {
+        hasType = objectHasType(cp.value)
+      } else if (cp.value.type === 'ArrayExpression') { // foo: [
+        hasType = cp.value.elements.length > 0
+      } else if (cp.value.type === 'FunctionExpression' || cp.value.type === 'ArrowFunctionExpression') {
+        hasType = false
+      }
+      if (!hasType) {
+        context.report({
+          node: cp,
+          message: 'Prop "{{name}}" should define at least it\'s type.',
+          data: {
+            name: cp.key.name
+          }
+        })
+      }
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  // Public
+  // ----------------------------------------------------------------------
+
+  return utils.executeOnVue(context, (obj) => {
+    const node = obj.properties
+      .find(p =>
+        p.type === 'Property' &&
+        p.key.type === 'Identifier' &&
+        p.key.name === 'props'
+      )
+
+    if (!node) return
+
+    if (node.value.type === 'ObjectExpression') {
+      checkProperties(node.value.properties)
+    } else {
+      context.report({
+        node,
+        message: 'Props should at least define their types.'
+      })
+    }
+  })
+}
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+  meta: {
+    docs: {
+      description: 'Prop definitions should be detailed',
+      category: 'Best Practices',
+      recommended: false
+    },
+    fixable: null,  // or "code" or "whitespace"
+    schema: [
+      // fill in your schema
+    ]
+  },
+
+  create
+}
diff --git a/lib/rules/require-v-for-key.js b/lib/rules/require-v-for-key.js
index 7033555e..5125fc5d 100644
--- a/lib/rules/require-v-for-key.js
+++ b/lib/rules/require-v-for-key.js
@@ -40,7 +40,7 @@ function checkKey (context, element) {
  * Creates AST event handlers for require-v-for-key.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   utils.registerTemplateBodyVisitor(context, {
diff --git a/lib/rules/v-bind-style.js b/lib/rules/v-bind-style.js
index bff958a6..1093171d 100644
--- a/lib/rules/v-bind-style.js
+++ b/lib/rules/v-bind-style.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for v-bind-style.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const shorthand = context.options[0] !== 'longform'
diff --git a/lib/rules/v-on-style.js b/lib/rules/v-on-style.js
index 92a6453a..fead015c 100644
--- a/lib/rules/v-on-style.js
+++ b/lib/rules/v-on-style.js
@@ -19,7 +19,7 @@ const utils = require('../utils')
  * Creates AST event handlers for v-on-style.
  *
  * @param {RuleContext} context - The rule context.
- * @returns {object} AST event handlers.
+ * @returns {Object} AST event handlers.
  */
 function create (context) {
   const shorthand = context.options[0] !== 'longform'
diff --git a/lib/utils/casing.js b/lib/utils/casing.js
index 15fd415a..4069216f 100644
--- a/lib/utils/casing.js
+++ b/lib/utils/casing.js
@@ -2,6 +2,11 @@ const assert = require('assert')
 
 const invalidChars = /[^a-zA-Z0-9:]+/g
 
+/**
+ * Convert text to kebab-case
+ * @param {string} str Text to be converted
+ * @return {string}
+ */
 function kebabCase (str) {
   return str
     .replace(/([a-z])([A-Z])/g, match => match[0] + '-' + match[1])
@@ -9,6 +14,11 @@ function kebabCase (str) {
     .toLowerCase()
 }
 
+/**
+ * Convert text to camelCase
+ * @param {string} str Text to be converted
+ * @return {string} Converted string
+ */
 function camelCase (str) {
   return str
     .replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => (
@@ -17,6 +27,11 @@ function camelCase (str) {
     .replace(invalidChars, '')
 }
 
+/**
+ * Convert text to PascalCase
+ * @param {string} str Text to be converted
+ * @return {string} Converted string
+ */
 function pascalCase (str) {
   return str
     .replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => letter.toUpperCase())
@@ -36,6 +51,11 @@ module.exports = {
     'PascalCase'
   ],
 
+  /**
+   * Return case converter
+   * @param {string} name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
+   * @return {kebabCase|camelCase|pascalCase}
+   */
   getConverter (name) {
     assert(typeof name === 'string')
 
diff --git a/lib/utils/index.js b/lib/utils/index.js
index 35c8e5b9..ccf3b915 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -25,8 +25,7 @@ module.exports = {
    * this generates a warning.
    *
    * @param {RuleContext} context The rule context to use parser services.
-   * @param {object} visitor The visitor.
-   * @returns {void}
+   * @param {Object} visitor The visitor.
    */
   registerTemplateBodyVisitor (context, visitor) {
     if (context.parserServices.registerTemplateBodyVisitor == null) {
@@ -175,11 +174,11 @@ module.exports = {
         )
   },
 
-    /**
-     * Check whether the previous sibling element has `if` or `else-if` directive.
-     * @param {ASTNode} node The element node to check.
-     * @returns {boolean} `true` if the previous sibling element has `if` or `else-if` directive.
-     */
+  /**
+   * Check whether the previous sibling element has `if` or `else-if` directive.
+   * @param {ASTNode} node The element node to check.
+   * @returns {boolean} `true` if the previous sibling element has `if` or `else-if` directive.
+   */
   prevElementHasIf (node) {
     assert(node && node.type === 'VElement')
 
@@ -193,11 +192,11 @@ module.exports = {
     )
   },
 
-    /**
-     * Check whether the given node is a custom component or not.
-     * @param {ASTNode} node The start tag node to check.
-     * @returns {boolean} `true` if the node is a custom component.
-     */
+  /**
+   * Check whether the given node is a custom component or not.
+   * @param {ASTNode} node The start tag node to check.
+   * @returns {boolean} `true` if the node is a custom component.
+   */
   isCustomComponent (node) {
     assert(node && node.type === 'VElement')
 
@@ -271,6 +270,48 @@ module.exports = {
     return members.reverse()
   },
 
+  /**
+   * Gets the property name of a given node.
+   * @param {ASTNode} node - The node to get.
+   * @return {string|null} The property name if static. Otherwise, null.
+   */
+  getStaticPropertyName (node) {
+    let prop
+    switch (node && node.type) {
+      case 'Property':
+      case 'MethodDefinition':
+        prop = node.key
+        break
+      case 'MemberExpression':
+        prop = node.property
+        break
+      case 'Literal':
+      case 'TemplateLiteral':
+      case 'Identifier':
+        prop = node
+        break
+      // no default
+    }
+
+    switch (prop && prop.type) {
+      case 'Literal':
+        return String(prop.value)
+      case 'TemplateLiteral':
+        if (prop.expressions.length === 0 && prop.quasis.length === 1) {
+          return prop.quasis[0].value.cooked
+        }
+        break
+      case 'Identifier':
+        if (!node.computed) {
+          return prop.name
+        }
+        break
+      // no default
+    }
+
+    return null
+  },
+
   /**
    * Get all computed properties by looking at all component's properties
    * @param {ObjectExpression} Object with component definition
@@ -278,11 +319,11 @@ module.exports = {
    */
   getComputedProperties (componentObject) {
     const computedPropertiesNode = componentObject.properties
-      .filter(p =>
+      .find(p =>
         p.key.type === 'Identifier' &&
         p.key.name === 'computed' &&
         p.value.type === 'ObjectExpression'
-      )[0]
+      )
 
     if (!computedPropertiesNode) { return [] }
 
@@ -362,6 +403,11 @@ module.exports = {
       node.arguments[0].type === 'ObjectExpression'
   },
 
+  /**
+   * Check if current file is a Vue instance or component and call callback
+   * @param {RuleContext} context The ESLint rule context object.
+   * @param {Function} cb Callback function
+   */
   executeOnVue (context, cb) {
     return Object.assign(
       this.executeOnVueComponent(context, cb),
@@ -369,6 +415,11 @@ module.exports = {
     )
   },
 
+  /**
+   * Check if current file is a Vue instance (new Vue) and call callback
+   * @param {RuleContext} context The ESLint rule context object.
+   * @param {Function} cb Callback function
+   */
   executeOnVueInstance (context, cb) {
     const _this = this
 
@@ -381,6 +432,11 @@ module.exports = {
     }
   },
 
+  /**
+   * Check if current file is a Vue component and call callback
+   * @param {RuleContext} context The ESLint rule context object.
+   * @param {Function} cb Callback function
+   */
   executeOnVueComponent (context, cb) {
     const filePath = context.getFilename()
     const _this = this


Test patch:
diff --git a/tests/lib/rules/name-property-casing.js b/tests/lib/rules/name-property-casing.js
index 07df1508..88ede6d6 100644
--- a/tests/lib/rules/name-property-casing.js
+++ b/tests/lib/rules/name-property-casing.js
@@ -15,6 +15,11 @@ const RuleTester = require('eslint').RuleTester
 // Tests
 // ------------------------------------------------------------------------------
 
+const parserOptions = {
+  ecmaVersion: 6,
+  sourceType: 'module'
+}
+
 const ruleTester = new RuleTester()
 ruleTester.run('name-property-casing', rule, {
 
@@ -26,7 +31,7 @@ ruleTester.run('name-property-casing', rule, {
         }
       `,
       options: ['camelCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+      parserOptions
     },
     {
       filename: 'test.vue',
@@ -36,7 +41,7 @@ ruleTester.run('name-property-casing', rule, {
         }
       `,
       options: ['camelCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+      parserOptions
     },
     {
       filename: 'test.vue',
@@ -46,7 +51,7 @@ ruleTester.run('name-property-casing', rule, {
         }
       `,
       options: ['PascalCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+      parserOptions
     },
     {
       filename: 'test.vue',
@@ -56,7 +61,7 @@ ruleTester.run('name-property-casing', rule, {
         }
       `,
       options: ['kebab-case'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+      parserOptions
     }
   ],
 
@@ -68,8 +73,13 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo-bar'
         }
       `,
+      output: `
+        export default {
+          name: 'fooBar'
+        }
+      `,
       options: ['camelCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      parserOptions,
       errors: [{
         message: 'Property name "foo-bar" is not camelCase.',
         type: 'Literal',
@@ -83,8 +93,12 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo  bar'
         }
       `,
-      options: ['PascalCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      output: `
+        export default {
+          name: 'FooBar'
+        }
+      `,
+      parserOptions,
       errors: [{
         message: 'Property name "foo  bar" is not PascalCase.',
         type: 'Literal',
@@ -98,8 +112,13 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo!bar'
         }
       `,
+      output: `
+        export default {
+          name: 'fooBar'
+        }
+      `,
       options: ['camelCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      parserOptions,
       errors: [{
         message: 'Property name "foo!bar" is not camelCase.',
         type: 'Literal',
@@ -113,6 +132,11 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo!bar'
         })
       `,
+      output: `
+        new Vue({
+          name: 'fooBar'
+        })
+      `,
       options: ['camelCase'],
       parserOptions: { ecmaVersion: 6 },
       errors: [{
@@ -128,8 +152,13 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo_bar'
         }
       `,
+      output: `
+        export default {
+          name: 'foobar'
+        }
+      `,
       options: ['camelCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      parserOptions,
       errors: [{
         message: 'Property name "foo_bar" is not camelCase.',
         type: 'Literal',
@@ -143,8 +172,13 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo_bar'
         }
       `,
+      output: `
+        export default {
+          name: 'Foobar'
+        }
+      `,
       options: ['PascalCase'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      parserOptions,
       errors: [{
         message: 'Property name "foo_bar" is not PascalCase.',
         type: 'Literal',
@@ -158,8 +192,13 @@ ruleTester.run('name-property-casing', rule, {
           name: 'foo_bar'
         }
       `,
+      output: `
+        export default {
+          name: 'foo-bar'
+        }
+      `,
       options: ['kebab-case'],
-      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      parserOptions,
       errors: [{
         message: 'Property name "foo_bar" is not kebab-case.',
         type: 'Literal',
diff --git a/tests/lib/rules/require-prop-types.js b/tests/lib/rules/require-prop-types.js
new file mode 100644
index 00000000..835d2552
--- /dev/null
+++ b/tests/lib/rules/require-prop-types.js
@@ -0,0 +1,150 @@
+/**
+ * @fileoverview Prop definitions should be detailed
+ * @author Armano
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const rule = require('../../../lib/rules/require-prop-types')
+
+const RuleTester = require('eslint').RuleTester
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+var ruleTester = new RuleTester()
+ruleTester.run('require-prop-types', rule, {
+
+  valid: [
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            ...test(),
+            foo: String
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true }}
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo: [String, Number]
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo: {
+              type: String
+            }
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo: {
+              ['type']: String
+            }
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' }
+    }
+  ],
+
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: ['foo']
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      errors: [{
+        message: 'Props should at least define their types.',
+        line: 3
+      }]
+    },
+    {
+      filename: 'test.js',
+      code: `
+        new Vue({
+          props: ['foo']
+        })
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      errors: [{
+        message: 'Props should at least define their types.',
+        line: 3
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo: {
+            }
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      errors: [{
+        message: 'Prop "foo" should define at least it\'s type.',
+        line: 4
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo: {
+              type: []
+            }
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      errors: [{
+        message: 'Prop "foo" should define at least it\'s type.',
+        line: 4
+      }]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+        export default {
+          props: {
+            foo() {}
+          }
+        }
+      `,
+      parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+      errors: [{
+        message: 'Prop "foo" should define at least it\'s type.',
+        line: 4
+      }]
+    }
+  ]
+})
diff --git a/tests/lib/utils/index.js b/tests/lib/utils/index.js
index 13293fb3..2189f896 100644
--- a/tests/lib/utils/index.js
+++ b/tests/lib/utils/index.js
@@ -121,3 +121,48 @@ describe('getComputedProperties', () => {
     assert.ok(computedProperties[0].value)
   })
 })
+
+describe('getStaticPropertyName', () => {
+  let node
+
+  const parse = function (code) {
+    return babelEslint.parse(code).body[0].declarations[0].init
+  }
+
+  it('should parse property expression with identifier', () => {
+    node = parse(`const test = { computed: { } }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0])
+    assert.ok(parsed === 'computed')
+  })
+  it('should parse property expression with literal', () => {
+    node = parse(`const test = { ['computed'] () {} }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0])
+    assert.ok(parsed === 'computed')
+  })
+  it('should parse property expression with template literal', () => {
+    node = parse(`const test = { [\`computed\`] () {} }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0])
+    assert.ok(parsed === 'computed')
+  })
+  it('should parse identifier', () => {
+    node = parse(`const test = { computed: { } }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0].key)
+    assert.ok(parsed === 'computed')
+  })
+  it('should parse literal', () => {
+    node = parse(`const test = { ['computed'] () {} }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0].key)
+    assert.ok(parsed === 'computed')
+  })
+  it('should parse template literal', () => {
+    node = parse(`const test = { [\`computed\`] () {} }`)
+
+    const parsed = utils.getStaticPropertyName(node.properties[0].key)
+    assert.ok(parsed === 'computed')
+  })
+})