Skip to content

Commit

Permalink
rewrite force-types-on-object-props
Browse files Browse the repository at this point in the history
  • Loading branch information
przemyslawjanpietrzak committed Feb 28, 2023
1 parent 75fc825 commit 9161964
Show file tree
Hide file tree
Showing 2 changed files with 379 additions and 158 deletions.
174 changes: 109 additions & 65 deletions lib/rules/force-types-on-object-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
*/
'use strict'

const utils = require('../utils')
/**
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------
Expand All @@ -29,6 +34,97 @@ const isLooksLike = (a, b) =>
: isLooksLike(aVal, bVal)
})

/**
* @param {ComponentProp} property
* @param {RuleContext} context
*/
const checkProperty = (property, context) => {
if (!property.value) {
return
}

if (
isLooksLike(property.value, { type: 'Identifier', name: 'Object' }) &&
property.node.value.type !== 'TSAsExpression'
) {
context.report({
node: property.node,
message: 'Expected type annotation on object prop.'
})
}

if (
property.type === 'object' &&
property.value.type === 'ObjectExpression' &&
property.node.value.type === 'ObjectExpression'
) {
const typePropert = property.node.value.properties.find(
(prop) =>
prop.type === 'Property' &&
prop.key.type === 'Identifier' &&
prop.key.name === 'type'
)
if (
typePropert &&
typePropert.type === 'Property' &&
isLooksLike(typePropert.value, { type: 'Identifier', name: 'Object' })
) {
context.report({
node: property.node,
message: 'Expected type annotation on object prop.'
})
}
}

if (property.node.value.type === 'ObjectExpression') {
for (const prop of property.node.value.properties) {
if (prop.type !== 'Property') {
continue
}
if (prop.key.type !== 'Identifier' || prop.key.name !== 'type') {
continue
}
if (prop.value.type !== 'TSAsExpression') {
continue
}

const { typeAnnotation } = prop.value
if (
['TSAnyKeyword', 'TSUnknownKeyword'].includes(typeAnnotation.type) ||
!typeAnnotation.typeName ||
!['Prop', 'PropType'].includes(typeAnnotation.typeName.name)
) {
context.report({
node: property.node,
message: 'Expected type annotation on object prop.'
})
}
}
}

if (property.node.value.type === 'TSAsExpression') {
const { typeAnnotation } = property.node.value
if (typeAnnotation.type === 'TSFunctionType') {
return
}
if (
[
'TSAnyKeyword',
'TSTypeLiteral',
'TSUnknownKeyword',
'TSObjectKeyword'
].includes(typeAnnotation.type) ||
!typeAnnotation.typeName ||
!['Prop', 'PropType'].includes(typeAnnotation.typeName.name)
) {
context.report({
node: property.node,
message: 'Expected type annotation on object prop.'
})
}
}
}

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
Expand All @@ -47,73 +143,21 @@ module.exports = {
},
/** @param {RuleContext} context */
create(context) {
return {
/** @param {ExportDefaultDeclaration} node */
ExportDefaultDeclaration(node) {
if (node.declaration.type !== 'ObjectExpression') {
return
}
if (!Array.isArray(node.declaration.properties)) {
return
return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(_node, props) {
for (const prop of props) {
checkProperty(prop, context)
}
}
}),
utils.executeOnVue(context, (obj) => {
const props = utils.getComponentPropsFromOptions(obj)

const property = node.declaration.properties.find(
(property) =>
property.type === 'Property' &&
isLooksLike(property.key, { type: 'Identifier', name: 'props' }) &&
property.value.type === 'ObjectExpression'
)

if (
!property ||
property.type === 'SpreadElement' ||
!('properties' in property.value)
) {
return
}
const properties = property.value.properties
.filter(
(prop) =>
prop.type === 'Property' && prop.value.type === 'ObjectExpression'
)
.map((prop) =>
prop.value.properties.find((propValueProperty) =>
isLooksLike(propValueProperty.key, {
type: 'Identifier',
name: 'type'
})
)
)
for (const prop of properties) {
if (!prop) {
continue
}
if (isLooksLike(prop.value, { type: 'Identifier', name: 'Object' })) {
context.report({
node: prop,
message: 'Expected type annotation on object prop.'
})
}
if (prop.value.type === 'TSAsExpression') {
const { typeAnnotation } = prop.value
if (
[
'TSAnyKeyword',
'TSTypeLiteral',
'TSUnknownKeyword',
'TSObjectKeyword'
].includes(typeAnnotation.type) ||
!typeAnnotation.typeName ||
!['Prop', 'PropType'].includes(typeAnnotation.typeName.name)
) {
context.report({
node: prop,
message: 'Expected type annotation on object prop.'
})
}
}
for (const prop of props) {
checkProperty(prop, context)
}
}
}
})
)
}
}

0 comments on commit 9161964

Please sign in to comment.