From b7c71bb11ae586a6052190c7c3c744d1dce3c238 Mon Sep 17 00:00:00 2001 From: Luke Page Date: Sun, 28 Jul 2019 11:31:13 +0200 Subject: [PATCH] Fix #420 only report Prop errors if Props are found --- src/rules/requireReadonlyReactProps.js | 29 ++++++++++++++----- .../assertions/requireReadonlyReactProps.js | 28 ++++++++---------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/rules/requireReadonlyReactProps.js b/src/rules/requireReadonlyReactProps.js index 2351daae..081f9b8c 100644 --- a/src/rules/requireReadonlyReactProps.js +++ b/src/rules/requireReadonlyReactProps.js @@ -23,12 +23,13 @@ const isReactComponent = (node) => { const create = (context) => { const readOnlyTypes = []; + const foundTypes = []; const reportedFunctionalComponents = []; const isReadOnlyClassProp = (node) => { const id = node.superTypeParameters.params[0].id; - return id && !reReadOnly.test(id.name) && !readOnlyTypes.includes(id.name); + return id && !reReadOnly.test(id.name) && !readOnlyTypes.includes(id.name) && foundTypes.includes(id.name); }; const isReadOnlyObjectType = (node) => { @@ -49,18 +50,31 @@ const create = (context) => { }; const isReadOnlyType = (node) => { - return node.type === 'TypeAlias' && node.right.id && reReadOnly.test(node.right.id.name) || isReadOnlyObjectType(node.right); + return node.right.id && reReadOnly.test(node.right.id.name) || isReadOnlyObjectType(node.right); }; for (const node of context.getSourceCode().ast.body) { + let idName; + let typeNode; + // type Props = $ReadOnly<{}> - if (isReadOnlyType(node) || + if (node.type === 'TypeAlias') { + idName = node.id.name; + typeNode = node; - // export type Props = $ReadOnly<{}> - node.type === 'ExportNamedDeclaration' && + // export type Props = $ReadOnly<{}> + } else if (node.type === 'ExportNamedDeclaration' && node.declaration && - isReadOnlyType(node.declaration)) { - readOnlyTypes.push(node.id ? node.id.name : node.declaration.id.name); + node.declaration.type === 'TypeAlias') { + idName = node.declaration.id.name; + typeNode = node.declaration; + } + + if (idName) { + foundTypes.push(idName); + if (isReadOnlyType(typeNode)) { + readOnlyTypes.push(idName); + } } } @@ -101,6 +115,7 @@ const create = (context) => { if (currentNode.params[0].type === 'Identifier' && (typeAnnotation = currentNode.params[0].typeAnnotation)) { if ((identifier = typeAnnotation.typeAnnotation.id) && + foundTypes.includes(identifier.name) && !readOnlyTypes.includes(identifier.name) && !reReadOnly.test(identifier.name)) { if (reportedFunctionalComponents.includes(identifier)) { diff --git a/tests/rules/assertions/requireReadonlyReactProps.js b/tests/rules/assertions/requireReadonlyReactProps.js index 96b3d732..952c28d4 100644 --- a/tests/rules/assertions/requireReadonlyReactProps.js +++ b/tests/rules/assertions/requireReadonlyReactProps.js @@ -50,14 +50,6 @@ export default { }, ], }, - { - code: 'class Foo extends React.Component { }', - errors: [ - { - message: 'UnknownProps must be $ReadOnly', - }, - ], - }, { code: 'export type Props = {}; class Foo extends Component { }', errors: [ @@ -116,14 +108,6 @@ export default { }, ], }, - { - code: 'function Foo(props: UnknownProps) { return

}', - errors: [ - { - message: 'UnknownProps must be $ReadOnly', - }, - ], - }, { code: 'export type Props = {}; function Foo(props: Props) { return

}', errors: [ @@ -184,6 +168,12 @@ export default { { code: 'class Foo extends Component<{||}> { }', }, + { + code: 'class Foo extends React.Component { }', + }, + { + code: 'import { type Props } from "file"; class Foo extends React.Component { }', + }, // functional components { @@ -204,5 +194,11 @@ export default { { code: 'function Foo(props: {||}) { return

}', }, + { + code: 'function Foo(props: UnknownProps) { return

}', + }, + { + code: 'import { type Props } from "file"; function Foo(props: Props) { return

}', + }, ], };