Skip to content

Commit 9a5320b

Browse files
prepare force types on object implementation
1 parent 49d0f30 commit 9a5320b

File tree

3 files changed

+165
-47
lines changed

3 files changed

+165
-47
lines changed

docs/rules/force-types-on-object-props.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Nothing.
8181

8282
## When Not To Use It
8383

84-
When you're not using TypeScript in the project.
84+
When you're not using TypeScript in the project****.
8585

8686
## Further Reading
8787

+96-22
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,119 @@
11
/**
2-
* @author *****your name*****
2+
* @author Przemysław Jan Beigert
33
* See LICENSE file in root directory for full license.
44
*/
55
'use strict'
66

7-
// ------------------------------------------------------------------------------
8-
// Requirements
9-
// ------------------------------------------------------------------------------
10-
11-
const utils = require('../utils')
12-
137
// ------------------------------------------------------------------------------
148
// Helpers
159
// ------------------------------------------------------------------------------
1610

17-
// ...
11+
/**
12+
* Check if all keys and values from second object are resent in first object
13+
*
14+
* @param {{ [key: string]: any }} a object to
15+
* @param {{ [key: string]: any }} b The string to escape.
16+
* @returns {boolean} Returns the escaped string.
17+
*/
18+
const isLooksLike = (a, b) =>
19+
a &&
20+
b &&
21+
Object.keys(b).every((bKey) => {
22+
const bVal = b[bKey]
23+
const aVal = a[bKey]
24+
if (typeof bVal === 'function') {
25+
return bVal(aVal)
26+
}
27+
return bVal == null || /^[bns]/.test(typeof bVal)
28+
? bVal === aVal
29+
: isLooksLike(aVal, bVal)
30+
})
1831

19-
// ------------------------------------------------------------------------------
32+
//------------------------------------------------------------------------------
2033
// Rule Definition
21-
// ------------------------------------------------------------------------------
34+
//------------------------------------------------------------------------------
2235

2336
module.exports = {
2437
meta: {
25-
type: 'problem',
38+
type: 'suggestion',
2639
docs: {
27-
description: '',
28-
categories: undefined,
29-
url: ''
40+
description: 'enforce user to add type declaration to object props',
41+
categories: ['type safe'],
42+
recommended: false,
43+
url: 'https://eslint.vuejs.org/rules/force-types-on-object-props.html'
3044
},
3145
fixable: null,
32-
schema: [],
33-
messages: {
34-
// ...
35-
}
46+
schema: []
3647
},
3748
/** @param {RuleContext} context */
3849
create(context) {
39-
// ...
50+
return {
51+
/** @param {ExportDefaultDeclaration} node */
52+
ExportDefaultDeclaration(node) {
53+
if (node.declaration.type !== 'ObjectExpression') {
54+
return
55+
}
56+
if (!Array.isArray(node.declaration.properties)) {
57+
return
58+
}
59+
60+
const property = node.declaration.properties.find(
61+
(property) =>
62+
property.type === 'Property' &&
63+
isLooksLike(property.key, { type: 'Identifier', name: 'props' }) &&
64+
property.value.type === 'ObjectExpression'
65+
)
4066

41-
return utils.defineTemplateBodyVisitor(context, {
42-
// ...
43-
})
67+
if (
68+
!property ||
69+
property.type === 'SpreadElement' ||
70+
!('properties' in property.value)
71+
) {
72+
return
73+
}
74+
const properties = property.value.properties
75+
.filter(
76+
(prop) =>
77+
prop.type === 'Property' && prop.value.type === 'ObjectExpression'
78+
)
79+
.map((prop) =>
80+
prop.value.properties.find((propValueProperty) =>
81+
isLooksLike(propValueProperty.key, {
82+
type: 'Identifier',
83+
name: 'type'
84+
})
85+
)
86+
)
87+
for (const prop of properties) {
88+
if (!prop) {
89+
break
90+
}
91+
if (isLooksLike(prop.value, { type: 'Identifier', name: 'Object' })) {
92+
context.report({
93+
node: prop,
94+
message: 'Object props has to contains type.'
95+
})
96+
}
97+
if (prop.value.type === 'TSAsExpression') {
98+
const { typeAnnotation } = prop.value
99+
if (
100+
[
101+
'TSAnyKeyword',
102+
'TSTypeLiteral',
103+
'TSUnknownKeyword',
104+
'TSObjectKeyword'
105+
].includes(typeAnnotation.type) ||
106+
!typeAnnotation.typeName ||
107+
typeAnnotation.typeName.name !== 'Prop'
108+
) {
109+
context.report({
110+
node: prop,
111+
message: 'Object props has to contains type.'
112+
})
113+
}
114+
}
115+
}
116+
}
117+
}
44118
}
45119
}

tests/lib/rules/force-types-on-object-props.js

+68-24
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,83 @@
77
const RuleTester = require('eslint').RuleTester
88
const rule = require('../../../lib/rules/force-types-on-object-props')
99

10-
const tester = new RuleTester({
10+
const template = (prop) => `
11+
<template></template>
12+
<script>
13+
export default {
14+
}
15+
</script>
16+
`
17+
18+
const ruleTester = new RuleTester({
1119
parser: require.resolve('vue-eslint-parser'),
12-
parserOptions: {
13-
ecmaVersion: 2020,
14-
sourceType: 'module'
15-
}
20+
parserOptions: { ecmaVersion: 2015 }
1621
})
1722

18-
tester.run('force-types-on-object-props', rule, {
23+
ruleTester.run('force-types-on-object-props', rule, {
1924
valid: [
20-
{
21-
filename: 'test.vue',
22-
code: `
23-
<template>
24-
25-
</template>
26-
`
27-
},
25+
`
26+
<script lang="ts">
27+
export default {
28+
}
29+
</script>
30+
`,
31+
`
32+
<script lang="ts">
33+
export default {
34+
props: {}
35+
}
36+
</script>
37+
`,
38+
template('type: Object as Prop<{}>'),
39+
template('type: String'),
40+
template('type: Number'),
41+
template('type: Boolean'),
42+
template('type: [String, Number, Boolean]')
2843
],
2944
invalid: [
3045
{
31-
filename: 'test.vue',
32-
code: `
33-
<template>
34-
35-
</template>
36-
`,
46+
code: template('type: Object'),
47+
errors: [
48+
{
49+
message: 'Object props has to be typed'
50+
}
51+
]
52+
},
53+
{
54+
code: template('type: Object as any'),
55+
errors: [
56+
{
57+
message:
58+
'Object props should be typed like this: "type: Object as Prop<T>"'
59+
}
60+
]
61+
},
62+
{
63+
code: template('type: Object as {}'),
64+
errors: [
65+
{
66+
message:
67+
'Object props should be typed like this: "type: Object as Prop<T>"'
68+
}
69+
]
70+
},
71+
{
72+
code: template('type: Object as unknown'),
73+
errors: [
74+
{
75+
message:
76+
'Object props should be typed like this: "type: Object as Prop<T>"'
77+
}
78+
]
79+
},
80+
{
81+
code: template('type: Object as string'),
3782
errors: [
3883
{
39-
message: '...',
40-
line: 'line',
41-
column: 'col'
42-
},
84+
message:
85+
'Object props should be typed like this: "type: Object as Prop<T>"'
86+
}
4387
]
4488
}
4589
]

0 commit comments

Comments
 (0)