Skip to content

Commit

Permalink
prepare force types on object implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
przemyslawjanpietrzak committed Sep 19, 2022
1 parent 49d0f30 commit 8acfba0
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/rules/force-types-on-object-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Nothing.

## When Not To Use It

When you're not using TypeScript in the project.
When you're not using TypeScript in the project****.

## Further Reading

Expand Down
95 changes: 71 additions & 24 deletions lib/rules/force-types-on-object-props.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,92 @@
/**
* @author *****your name*****
* @author Przemysław Jan Beigert
* See LICENSE file in root directory for full license.
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const utils = require('../utils')

// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------

// ...
/**
* Check if all keys and values from second object are resent in first object
*
* @param {{ [key: string]: any }} a object to
* @param {{ [key: string]: any }} b The string to escape.
* @returns {boolean} Returns the escaped string.
*/
const isLooksLike = (a, b) => {
return (
a &&
b &&
Object.keys(b).every(bKey => {
const bVal = b[bKey];
const aVal = a[bKey];
if (typeof bVal === 'function') {
return bVal(aVal);
}
return bVal == null || /^[sbn]/.test(typeof bVal) ? bVal === aVal : isLooksLike(aVal, bVal);
})
)
}

// ------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
//------------------------------------------------------------------------------

module.exports = {
meta: {
type: 'problem',
docs: {
description: '',
categories: undefined,
url: ''
description: 'Force user to add type declaration to object props',
category: 'type safe',
recommended: false,
},
fixable: null,
schema: [],
messages: {
// ...
}
},
/** @param {RuleContext} context */
/** @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.defineTemplateBodyVisitor(context, {
// ...
})
}
}
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;
}

property.value.properties
.filter(prop => prop.type === 'Property' && prop.value.type === 'ObjectExpression')
.map(prop => prop.value.properties.find(propValueProperty => {
return isLooksLike(propValueProperty.key, { type: 'Identifier', name: 'type' })
}))
.forEach(prop => {
if (!prop) {
return;
}
if (isLooksLike(prop.value, { type: 'Identifier', name: 'Object' })) {
context.report({ node: prop, message: 'Object props has to be typed' })
}
if (prop.value.type === 'TSAsExpression') {
const { typeAnnotation } = prop.value;
if (
['TSAnyKeyword', 'TSTypeLiteral', 'TSUnknownKeyword', 'TSObjectKeyword'].includes(typeAnnotation.type)
|| !typeAnnotation.typeName
|| typeAnnotation.typeName.name !== 'Prop'
) {
context.report({ node: prop, message: 'Object props should be typed like this: "type: Object as Prop<T>"'})
}
}
})
},
};
},
};
84 changes: 57 additions & 27 deletions tests/lib/rules/force-types-on-object-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,70 @@
const RuleTester = require('eslint').RuleTester
const rule = require('../../../lib/rules/force-types-on-object-props')

const tester = new RuleTester({
const template = prop => `
<template></template>
<script>
export default {
}
</script>
`;

const ruleTester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module'
}
parserOptions: { ecmaVersion: 2015 }
})

tester.run('force-types-on-object-props', rule, {
ruleTester.run('force-types-on-object-props', rule, {
valid: [
{
filename: 'test.vue',
code: `
<template>
</template>
`
},
`
<script lang="ts">
export default {
}
</script>
`,
`
<script lang="ts">
export default {
props: {}
}
</script>
`,
template('type: Object as Prop<{}>'),
template('type: String'),
template('type: Number'),
template('type: Boolean'),
template('type: [String, Number, Boolean]'),
],
invalid: [
{
filename: 'test.vue',
code: `
<template>
</template>
`,
errors: [
{
message: '...',
line: 'line',
column: 'col'
},
]
code: template('type: Object'),
errors: [{
message: 'Object props has to be typed',
}]
},
{
code: template('type: Object as any'),
errors: [{
message: 'Object props should be typed like this: "type: Object as Prop<T>"',
}]
},
{
code: template('type: Object as {}'),
errors: [{
message: 'Object props should be typed like this: "type: Object as Prop<T>"',
}]
},
{
code: template('type: Object as unknown'),
errors: [{
message: 'Object props should be typed like this: "type: Object as Prop<T>"',
}]
},
{
code: template('type: Object as string'),
errors: [{
message: 'Object props should be typed like this: "type: Object as Prop<T>"',
}]
}
]
})

0 comments on commit 8acfba0

Please sign in to comment.