Skip to content

Commit

Permalink
feat(eslint): no map function in jsx return body (BuilderIO#949)
Browse files Browse the repository at this point in the history
  • Loading branch information
decadef20 authored Jan 3, 2023
1 parent 57bb305 commit 8ce86e6
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const recommendedRules: Record<RulesKeys, string> = {
'@builder.io/mitosis/use-state-var-declarator': 'error',
'@builder.io/mitosis/static-control-flow': 'error',
'@builder.io/mitosis/no-var-name-same-as-prop-name': 'error',
'@builder.io/mitosis/no-map-function-in-jsx-return-body': 'warning',
};

export default {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { RuleTester } from 'eslint';
import rule from '../no-map-function-in-jsx-return-body';

const opts = {
filename: 'component.lite.tsx',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
} as const;

var ruleTester = new RuleTester();

ruleTester.run('no-map-function-in-jsx-return-body', rule, {
valid: [
{
...opts,
code: `
import { useStore, For, onMount } from '@builder.io/mitosis';
export default function MyBasicForComponent() {
const state = useStore({
name: 'Decadef20',
names: ['Steve', 'Decadef20'],
});
onMount(() => {
console.log('onMount code');
});
return (
<div>
<For each={state.names}>
{(person) => (
<>
<input
value={state.name}
onChange={(event) => {
state.name = event.target.value + ' and ' + person;
}}
/>
Hello {person}! I can run in Qwik, Web Component, React, Vue, Solid, or Liquid!
</>
)}
</For>
</div>
);
}
`,
},
],
invalid: [
{
...opts,
code: `
export default function MyComponent() {
return <div> {[].map()} </div>
}
`,
errors: ['No map function in jsx return body. Please use <For /> component instead.'],
},
],
});
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import noVarNameSameAsStateProperty from './no-var-name-same-as-state-property';
import onlyDefaultFunctionAndImports from './only-default-function-and-imports';
import noConditionalLogicInComponentRender from './no-conditional-logic-in-component-render';
import noVarDeclarationOrAssignmentInComponent from './no-var-declaration-or-assignment-in-component';
import noMapFunctionInJsxReturnBody from './no-map-function-in-jsx-return-body';
import { staticControlFlow } from './static-control-flow';

export const rules = {
Expand All @@ -30,4 +31,5 @@ export const rules = {
'only-default-function-and-imports': onlyDefaultFunctionAndImports,
'no-conditional-logic-in-component-render': noConditionalLogicInComponentRender,
'no-var-declaration-or-assignment-in-component': noVarDeclarationOrAssignmentInComponent,
'no-map-function-in-jsx-return-body': noMapFunctionInJsxReturnBody,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Rule } from 'eslint';
import * as types from '@babel/types';
import isMitosisPath from '../helpers/isMitosisPath';

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'no map function in jsx return body',
recommended: true,
},
},

create(context) {
if (!isMitosisPath(context.getFilename())) return {};

return {
JSXExpressionContainer(node) {
if (types.isJSXExpressionContainer(node)) {
if (types.isCallExpression(node.expression)) {
if (
types.isMemberExpression(node.expression.callee) &&
types.isIdentifier(node.expression.callee.property) &&
node.expression.callee.property.name === 'map'
) {
context.report({
node: node as any,
message:
'No map function in jsx return body. Please use <For /> component instead.',
});
}
}
}
},
};
},
};

export default rule;

0 comments on commit 8ce86e6

Please sign in to comment.