diff --git a/eslint-plugin-expensify/onyx-props-must-have-default.js b/eslint-plugin-expensify/onyx-props-must-have-default.js
deleted file mode 100644
index fc66af6..0000000
--- a/eslint-plugin-expensify/onyx-props-must-have-default.js
+++ /dev/null
@@ -1,249 +0,0 @@
-const _ = require('underscore');
-const lodashGet = require('lodash/get');
-const {parse} = require('babel-eslint');
-const path = require('path');
-const fs = require('fs');
-const {
- PROP_TYPE_REQUIRED_FALSE, PROP_TYPE_NOT_DECLARED, PROP_DEEFAULT_NOT_DECLARED, HAVE_PROP_TYPES, HAVE_DEFAULT_PROPS, ONYX_ONE_PARAM, MUST_USE_VARIABLE_FOR_ASSIGNMENT,
-} = require('./CONST').MESSAGE;
-
-module.exports = {
- create(context) {
- // Report any issues
- function makeReport(node, message, data = null) {
- context.report({
- node,
- message,
- data: {
- key: data,
- },
- });
- }
-
- // Check if a list of properties has a property using spread (...) operator
- function hasSpreadOperator(node) {
- return _.find(
- node.init.properties,
- n => (lodashGet(n, 'type') === 'ExperimentalSpreadProperty' || lodashGet(n, 'type') === 'SpreadElement'),
- );
- }
-
- // Get the list of properties from an external file
- function getExternalProperties(sourceFile, variableNode, type) {
- const importedVariableValue = sourceFile;
-
- // Need to append .js since file extension is not used in imports
- const importedFile = `${path.resolve(path.dirname(context.getFilename()), importedVariableValue)}.js`;
- let importedValue;
- try {
- const raw = fs.readFileSync(importedFile);
- const ast = parse(raw.toString(), {sourceType: 'module'});
- if (type === 'ImportSpecifier') {
- // If the import is of type - import {prop} from "./props"
- const variableName = variableNode.defs[0].node.imported.name;
- importedValue = _.find(
- ast.body,
- n => lodashGet(n, 'type') === 'VariableDeclaration'
- && lodashGet(n, 'declarations[0].id.name') === variableName,
- ).declarations[0].init.properties;
- } else if (type === 'ImportDefaultSpecifier') {
- // If the import is of type - import prop from "./props"
- importedValue = _.find(
- ast.body,
- n => lodashGet(n, 'type') === 'ExportDefaultDeclaration',
- ).declaration.properties;
- }
- } catch (err) {
- // If there are any issues parsing the code to AST.
- // Can be ignored, it's impossible for the parsing to fail as long as the component code is correct
- // console.log(err);
- }
- return importedValue;
- }
-
- // Get the variable node from the list of variable nodes
- function getVariableNode(variables, name) {
- return _.find(
- variables,
- v => lodashGet(v, 'name') === name,
- );
- }
-
- // Get the node of the prop type declaration based on name
- // For example: Component.propTypes = propTypes
- function getPropsDeclaration(body, name) {
- return _.find(
- body,
- n => lodashGet(n, 'type') === 'ExpressionStatement'
- && lodashGet(n, 'expression.left.property.name') === name,
- );
- }
-
- // For each property making use of spread operator, get the properties from the variable
- function getProperties(scope, propertiesVar) {
- const resolvedProps = [];
- _.each(
- _.filter(
- propertiesVar,
- n => (lodashGet(n, 'type') === 'ExperimentalSpreadProperty' || lodashGet(n, 'type') === 'SpreadElement'),
- ),
- (prop) => {
- const variables = scope.variables;
- let variableNode = getVariableNode(variables, prop.argument.name);
- if (!variableNode) {
- // Required in case of HOCs like withPolicy, since they might have the prop types
- // declared outside the function, which is not in function scope
- variableNode = getVariableNode(scope.upper.variables, prop.argument.name);
- }
-
- if (variableNode.defs[0].type === 'ImportBinding') {
- // If the spread operator variable is imported
- const externalProps = getExternalProperties(variableNode.defs[0].node.parent.source.value, variableNode, variableNode.defs[0].node.type);
- resolvedProps.push(...externalProps);
- } else {
- // If the spread operator variable is in same file
- const internalProps = variableNode.defs[0].node.init.properties;
- resolvedProps.push(...internalProps);
- }
- },
- );
- return resolvedProps;
- }
-
- // Get the final list of properties
- function getPropsValue(scope, propsVar) {
- const variables = scope.variables;
- let props = getVariableNode(variables, propsVar);
- if (!props) {
- // Required in case of HOCs like withPolicy, since they might have the prop types
- // declared outside the function, which is not in function scope
- props = getVariableNode(scope.upper.variables, propsVar);
- }
-
- if (!propsVar || !props || !lodashGet(props, 'defs[0]')) {
- return undefined;
- }
-
- // Need to check for existence of init since it is not present if the assignment is to an imported variable
- let propsProperties;
- if (props.defs[0].node.type === 'VariableDeclarator') {
- // If the variable is an assignment
- if (props.defs[0].node.init.type === 'ObjectExpression') {
- // let defaultProps = {....}
- propsProperties = props.defs[0].node.init && props.defs[0].node.init.properties;
- } else if (props.defs[0].node.init.type === 'Identifier') {
- // let defaultProps = importedDefaultProps;
- return getPropsValue(scope, props.defs[0].node.init.name);
- }
-
- if (props.defs[0].type === 'ImportBinding') {
- propsProperties = getExternalProperties(props.defs[0].node.parent.source.value, props, props.defs[0].node.type);
- } else if (hasSpreadOperator(props.defs[0].node)) {
- const resolvedProps = getProperties(scope, propsProperties);
- propsProperties = propsProperties.concat(resolvedProps);
- }
- } else if (props.defs[0].node.type === 'ImportSpecifier') {
- // If the variable is a direct import
- propsProperties = getExternalProperties(props.defs[0].node.parent.source.value, props, props.defs[0].node.type);
- }
-
- return propsProperties;
- }
-
- // Report and exit if direct assignment
- // For example, Component.propType = {prop1: type1}
- function isDirectAssignment(node, declaration, key) {
- if (lodashGet(declaration, 'expression.right.type') === 'ObjectExpression') {
- makeReport(node, MUST_USE_VARIABLE_FOR_ASSIGNMENT, key);
- return true;
- }
- return false;
- }
-
- return {
- CallExpression(node) {
- const name = lodashGet(node, 'callee.name');
- if (!name) {
- return;
- }
-
- if (name !== 'withOnyx') {
- return;
- }
-
- if (node.arguments.length === 0) {
- context.report({
- node,
- message: ONYX_ONE_PARAM,
- });
- }
-
- // Get all the tree ancestors
- const ancestors = context.getAncestors();
-
- // Check the component is an HOC that wraps a component
- const wrappedComponent = _.find(
- ancestors,
- n => lodashGet(n, 'type') === 'ExportDefaultDeclaration'
- && lodashGet(n, 'declaration.params[0].name') === 'WrappedComponent',
- );
-
- let propTypesDeclaration;
- let defaultPropTypesDeclaration;
-
- if (wrappedComponent) {
- propTypesDeclaration = getPropsDeclaration(wrappedComponent.declaration.body.body, 'propTypes');
- defaultPropTypesDeclaration = getPropsDeclaration(wrappedComponent.declaration.body.body, 'defaultProps');
- } else {
- propTypesDeclaration = getPropsDeclaration(ancestors[0].body, 'propTypes');
- defaultPropTypesDeclaration = getPropsDeclaration(ancestors[0].body, 'defaultProps');
- }
-
- if (isDirectAssignment(node, propTypesDeclaration, 'propTypes') || isDirectAssignment(node, defaultPropTypesDeclaration, 'defaultProps')) {
- return;
- }
-
- const scope = context.getScope();
-
- // Get the assigned variable name
- const propTypesVar = lodashGet(propTypesDeclaration, 'expression.right.name');
- const defaultPropsVar = lodashGet(defaultPropTypesDeclaration, 'expression.right.name');
-
- // Get the list of properties
- const propTypesProperties = getPropsValue(scope, propTypesVar);
- const defaultPropsProperties = getPropsValue(scope, defaultPropsVar);
-
- if (!propTypesProperties) {
- makeReport(node, HAVE_PROP_TYPES);
- return;
- } if (!defaultPropsProperties) {
- makeReport(node, HAVE_DEFAULT_PROPS);
- return;
- }
-
- // Get the list of properties of withOnyx
- const onyxProperties = lodashGet(node, 'arguments[0].properties');
-
- _.each(onyxProperties, (property) => {
- const onyxKeyName = lodashGet(property, 'key.name');
- const declaredPropType = _.find(propTypesProperties, p => p.type === 'Property' && lodashGet(p, 'key.name') === onyxKeyName);
- const defaultPropType = _.find(defaultPropsProperties, p => p.type === 'Property' && lodashGet(p, 'key.name') === onyxKeyName);
-
- if (declaredPropType) {
- if (lodashGet(declaredPropType, 'value.type') === 'MemberExpression') {
- if (lodashGet(declaredPropType, 'value.property.name') === 'isRequired') {
- makeReport(node, PROP_TYPE_REQUIRED_FALSE, onyxKeyName);
- }
- }
- } else {
- makeReport(node, PROP_TYPE_NOT_DECLARED, onyxKeyName);
- }
-
- if (!defaultPropType) {
- makeReport(node, PROP_DEEFAULT_NOT_DECLARED, onyxKeyName);
- }
- });
- },
- };
- },
-};
diff --git a/eslint-plugin-expensify/tests/onyx-props-must-have-default.test.js b/eslint-plugin-expensify/tests/onyx-props-must-have-default.test.js
deleted file mode 100644
index 28f707b..0000000
--- a/eslint-plugin-expensify/tests/onyx-props-must-have-default.test.js
+++ /dev/null
@@ -1,321 +0,0 @@
-const RuleTester = require('eslint').RuleTester;
-const rule = require('../onyx-props-must-have-default');
-
-const {
- PROP_TYPE_REQUIRED_FALSE, PROP_TYPE_NOT_DECLARED, PROP_DEEFAULT_NOT_DECLARED, HAVE_PROP_TYPES, HAVE_DEFAULT_PROPS, ONYX_ONE_PARAM, MUST_USE_VARIABLE_FOR_ASSIGNMENT,
-} = require('../CONST');
-
-const ruleTester = new RuleTester({
- parserOptions: {
- ecmaVersion: 2018,
- sourceType: 'module',
- ecmaFeatures: {
- // To support use of < in HOC
- jsx: true,
-
- // To support use of ... operator
- experimentalObjectRestSpread: true,
- },
- },
-});
-
-ruleTester.run('onyx-props-must-have-default', rule, {
- invalid: [
- // onyxProp has isRequired
- {
- code: `
- const defaultProps = {
- propKey: false,
- };
-
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);
- `,
- errors: [{
- HAVE_PROP_TYPES,
- }],
- },
- {
- code: `
- const propTypes = {
- propKey: PropTypes.bool,
- };
-
- Component.propTypes = propTypes;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);
- `,
- errors: [{
- HAVE_DEFAULT_PROPS,
- }],
- },
- {
- code: `
- const propTypes = {
- propKey: PropTypes.bool.isRequired,
- };
-
- const defaultProps = {
- propKey: false,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);
- `,
- errors: [{
- PROP_TYPE_REQUIRED_FALSE,
- }],
- },
- {
- code: `
- const propTypes = {
- randomProp: PropTypes.bool,
- };
-
- const defaultProps = {
- randomProp: false,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);
- `,
- errors: [
- {
- PROP_TYPE_NOT_DECLARED,
- },
- {
- PROP_DEEFAULT_NOT_DECLARED,
- },
- ],
- },
- {
- code: `
- const propTypes = {
- propKey: PropTypes.bool,
- };
-
- const defaultProps = {
- propKey: false,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx()(Component);
- `,
- errors: [{
- ONYX_ONE_PARAM,
- }],
- },
- {
- code: `
- Component.propTypes = {
- propKey: PropTypes.bool,
- };
- Component.defaultProps = {
- propKey: false,
- };
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);
- `,
- errors: [{
- MUST_USE_VARIABLE_FOR_ASSIGNMENT,
- }],
- },
- ],
- valid: [
- {
- code: `
- const propTypes = {
- propKey: PropTypes.bool,
- };
-
- const defaultProps = {
- propKey: false,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);`,
- },
- {
- code: `
- const propTypes = {
- propKey: PropTypes.bool,
- };
-
- const defaultProps = {
- propKey: false,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default compose(
- withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- }),
- )(Component);`,
- },
- {
- code: `
- import {samplePropTypes, sampleDefaultProps} from "./sample-props";
-
- Component.propTypes = samplePropTypes;
- Component.defaultProps = sampleDefaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);`,
- },
- {
- code: `
- import {samplePropTypes, sampleDefaultProps} from "./sample-props";
-
- const propTypes = samplePropTypes;
- const defaultProps = sampleDefaultProps;
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);`,
- },
- {
- code: `
- import {samplePropTypes, sampleDefaultProps} from "./sample-props";
-
- const propTypes = {
- ...samplePropTypes,
- };
-
- const defaultProps = {
- ...sampleDefaultProps,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);`,
- },
- {
- code: `
- import * as sampleProps from "./sample-props";
-
- const propTypes = {
- propKey: sampleProps.samplePropTypes,
- };
-
- const defaultProps = {
- propKey: sampleProps.sampleDefaultProps,
- };
-
- Component.propTypes = propTypes;
- Component.defaultProps = defaultProps;
- export default withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- },
- })(Component);`,
- },
- {
- code: `
- export default function (WrappedComponent) {
- const propTypes = {
- propKey: PropTypes.bool
- };
-
- const defaultProps = {
- propKey: false,
- };
-
- const WithHOC = (props) => {
- const extraProp = props.randomProp;
-
- return (
-
- );
- };
-
- WithHOC.propTypes = propTypes;
- WithHoc.defaultProps = defaultProps;
-
- return withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- }
- })
- }`,
- },
- {
- code: `
- const hocPropTypes = {
- propKey: PropTypes.bool,
- };
-
- const hocDefaultProps = {
- propKey: false,
- }
- export default function (WrappedComponent) {
- const propTypes = {
- ...hocPropTypes
- };
-
- const defaultProps = {
- ...hocDefaultProps,
- };
-
- const WithHOC = (props) => {
- const extraProp = props.randomProp;
-
- return (
-
- );
- };
-
- WithHOC.propTypes = propTypes;
- WithHoc.defaultProps = defaultProps;
-
- return withOnyx({
- propKey: {
- key: ONYXKEYS.key,
- }
- })
- }`,
- },
- ],
-});
diff --git a/rules/expensify.js b/rules/expensify.js
index d8d389a..aa6b742 100644
--- a/rules/expensify.js
+++ b/rules/expensify.js
@@ -15,7 +15,6 @@ module.exports = {
'rulesdir/no-call-actions-from-actions': 'error',
'rulesdir/no-api-side-effects-method': 'error',
'rulesdir/prefer-localization': 'error',
- 'rulesdir/onyx-props-must-have-default': 'error',
'rulesdir/avoid-anonymous-functions': 'error',
'no-restricted-imports': ['error', {
paths: [{