From 08fb5cea0ff56d1625677dd58f52d11536914ad6 Mon Sep 17 00:00:00 2001 From: Yongho Lee Date: Fri, 14 Feb 2025 13:56:21 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[#78]=20=F0=9F=91=BD=EF=B8=8F=20support=20e?= =?UTF-8?q?slint=209?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ohjaeyeop --- .../lib/rules/import-server-only.js | 3 +- .../lib/rules/memo-react-components.js | 31 ++++++++--- .../lib/rules/optimize-svg-components.js | 24 +++++---- .../eslint-plugin/lib/rules/svg-unique-id.js | 53 ++++++++++--------- packages/eslint-plugin/lib/utils/astParser.js | 2 +- 5 files changed, 69 insertions(+), 44 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/import-server-only.js b/packages/eslint-plugin/lib/rules/import-server-only.js index a1181eb..2631b5a 100644 --- a/packages/eslint-plugin/lib/rules/import-server-only.js +++ b/packages/eslint-plugin/lib/rules/import-server-only.js @@ -46,7 +46,8 @@ export default { (statement) => statement.type === 'ImportDeclaration' && statement.source.value === 'server-only', ) - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() + if (!hasServerOnlyImport) { context.report({ node, diff --git a/packages/eslint-plugin/lib/rules/memo-react-components.js b/packages/eslint-plugin/lib/rules/memo-react-components.js index c99b087..7bae368 100644 --- a/packages/eslint-plugin/lib/rules/memo-react-components.js +++ b/packages/eslint-plugin/lib/rules/memo-react-components.js @@ -24,10 +24,15 @@ export default { }, create: function (context) { const filename = context.filename.replace(context.cwd, '') - const isMatched = context.options[0].path.some((pattern) => minimatch(filename, pattern)) + let isAlreadyMemoized = false + + const sourceCode = context.sourceCode ?? context.getSourceCode() - const globalScope = context.getScope() + /** + * @type {import('eslint').Scope.Scope | undefined} + */ + let globalScope function importReactMemo(fixer) { let i = 0 @@ -81,14 +86,22 @@ export default { return {} } - const exportDefaultDeclaration = getExportDefaultDeclaration(globalScope.block).declaration - if (exportDefaultDeclaration.type === 'CallExpression' && exportDefaultDeclaration.callee.name === 'memo') { - return {} - } - return { + Program: function (node) { + globalScope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope() + + const exportDefaultDeclaration = getExportDefaultDeclaration(globalScope.block).declaration + if ( + exportDefaultDeclaration.type === 'CallExpression' && + exportDefaultDeclaration.callee.name === 'memo' + ) { + isAlreadyMemoized = true + } + }, // const res = function getAssets({width, height, color}) ... 에 대응 FunctionExpression: function (node) { + if (isAlreadyMemoized) return + const hasJSXBody = node.body.body.some( (item) => item.type === 'ReturnStatement' && item.argument.type === 'JSXElement', ) @@ -114,6 +127,8 @@ export default { }, // function getAssets({width, height, color}) ... 에 대응 FunctionDeclaration: function (node) { + if (isAlreadyMemoized) return + // JSX를 리턴하는 함수인지 체크 const hasJSXBody = node.body.body.some( (item) => item.type === 'ReturnStatement' && item.argument.type === 'JSXElement', @@ -159,6 +174,8 @@ export default { }, // const getAssets = ({width, height, color}) => ... 에 대응 VariableDeclaration: function (node) { + if (isAlreadyMemoized) return + if (node.declarations.length === 1) { const nodeDeclaration = node.declarations[0] diff --git a/packages/eslint-plugin/lib/rules/optimize-svg-components.js b/packages/eslint-plugin/lib/rules/optimize-svg-components.js index cd52fdc..8360ca3 100644 --- a/packages/eslint-plugin/lib/rules/optimize-svg-components.js +++ b/packages/eslint-plugin/lib/rules/optimize-svg-components.js @@ -14,10 +14,10 @@ import { /** * * @param {import('eslint').Rule.RuleContext} context + * @param {import('eslint').Scope.Scope} globalScope * @returns {boolean} */ -const svgValidator = (context) => { - const globalScope = context.getScope() +const svgValidator = (context, globalScope) => { const importDeclarations = getImportDeclarations(globalScope.block) const hasClassNames = findSpecificImportDeclaration(importDeclarations, { @@ -141,16 +141,22 @@ export default { return {} } - const globalScope = context.getScope() - const sourceCode = context.getSourceCode() - const canOptimize = svgValidator(context) + const sourceCode = context.sourceCode ?? context.getSourceCode() - if (!canOptimize) { - return {} - } + /** + * @type {import('eslint').Scope.Scope | undefined} + */ + let globalScope + let canOptimize return { - onCodePathEnd: function (codePath, code) { + Program: function (node) { + globalScope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope() + canOptimize = svgValidator(context, globalScope) + }, + onCodePathEnd: function (_, code) { + if (!canOptimize) return + try { // 변수타입, 함수타입 모두 GET const node = getTargetNode(code) diff --git a/packages/eslint-plugin/lib/rules/svg-unique-id.js b/packages/eslint-plugin/lib/rules/svg-unique-id.js index 5bdde55..e0b6a71 100644 --- a/packages/eslint-plugin/lib/rules/svg-unique-id.js +++ b/packages/eslint-plugin/lib/rules/svg-unique-id.js @@ -42,7 +42,6 @@ function insertCustomImport({fixer, scope}) { } /** - * * @param {ReturnType} props */ function getIdProps(props) { @@ -72,13 +71,18 @@ function insertIdProps(props, globalScope, fixer) { return [] } +/** + * @param {JSXElement|undefined} node + */ +function isSvgElement(node) { + return node && node.openingElement.name.type === 'JSXIdentifier' && node.openingElement.name.name === 'svg' +} /** * @type {import('eslint').Rule.RuleModule} */ export default { meta: { type: 'suggestion', - docs: { description: 'set a unique id to svg component', recommended: true, @@ -86,14 +90,13 @@ export default { fixable: 'code', schema: [ { - properties: [ - { - paths: { - type: 'array', - items: [{type: 'string'}], - }, + type: 'object', + properties: { + paths: { + type: 'array', + items: {type: 'string'}, }, - ], + }, }, ], }, @@ -115,26 +118,24 @@ export default { return {} } - const globalScope = context.getScope() - - const svgElement = getJSXReturnStatement(globalScope) - - if ( - !svgElement || - svgElement.openingElement.name.type !== 'JSXIdentifier' || - svgElement.openingElement.name.name !== 'svg' - ) { - return {} - } - - const props = extractComponentProps(globalScope.block) - - const idPropsValue = getIdProps(props) - - const propsDefinition = idPropsValue ? ` id={${idPropsValue}}` : '' + /** + * @type {import('eslint').Scope.Scope | undefined} + */ + let globalScope + const sourceCode = context.sourceCode ?? context.getSourceCode() return { + Program: function (node) { + globalScope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope() + }, onCodePathEnd: function (_, code) { + const svgElement = getJSXReturnStatement(globalScope) + if (!isSvgElement(svgElement)) return + + const props = extractComponentProps(globalScope.block) + const idPropsValue = getIdProps(props) + const propsDefinition = idPropsValue ? ` id={${idPropsValue}}` : '' + try { context.report({ node: code, diff --git a/packages/eslint-plugin/lib/utils/astParser.js b/packages/eslint-plugin/lib/utils/astParser.js index c8f15fd..77058de 100644 --- a/packages/eslint-plugin/lib/utils/astParser.js +++ b/packages/eslint-plugin/lib/utils/astParser.js @@ -139,7 +139,7 @@ export const getCommentsBeforeImportDeclaration = (context, {name, from}) => { * @param {import('eslint').Rule.RuleContext} context */ export const getAllComments = (context) => { - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() return sourceCode.getAllComments() } From 375d84a67b54cbbf1f439d061e3cfd27d864244d Mon Sep 17 00:00:00 2001 From: Yongho Lee Date: Fri, 14 Feb 2025 13:58:32 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[#78]=20=E2=99=BB=EF=B8=8F=20add=20early=20?= =?UTF-8?q?return=20for=20unmatched=20file=20paths?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eslint-plugin/lib/rules/memo-react-components.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/memo-react-components.js b/packages/eslint-plugin/lib/rules/memo-react-components.js index 7bae368..6484c27 100644 --- a/packages/eslint-plugin/lib/rules/memo-react-components.js +++ b/packages/eslint-plugin/lib/rules/memo-react-components.js @@ -24,7 +24,11 @@ export default { }, create: function (context) { const filename = context.filename.replace(context.cwd, '') - const isMatched = context.options[0].path.some((pattern) => minimatch(filename, pattern)) + const isFileInPath = context.options[0].path.some((pattern) => minimatch(filename, pattern)) + if (!isFileInPath) { + return {} + } + let isAlreadyMemoized = false const sourceCode = context.sourceCode ?? context.getSourceCode() @@ -82,10 +86,6 @@ export default { return result } - if (!isMatched) { - return {} - } - return { Program: function (node) { globalScope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope() From 8e77d52afc4f28e0615970cfbc068fd3d90cc72f Mon Sep 17 00:00:00 2001 From: Yongho Lee Date: Fri, 14 Feb 2025 14:14:19 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[#78]=20=E2=9A=B0=EF=B8=8F=20remove=20dead?= =?UTF-8?q?=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/eslint-plugin/lib/utils/astParser.js | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/eslint-plugin/lib/utils/astParser.js b/packages/eslint-plugin/lib/utils/astParser.js index 77058de..a363f95 100644 --- a/packages/eslint-plugin/lib/utils/astParser.js +++ b/packages/eslint-plugin/lib/utils/astParser.js @@ -1,4 +1,4 @@ -import {getReactComponentDeclaration, getImportDeclarations} from '@naverpay/ast-parser' +import {getReactComponentDeclaration} from '@naverpay/ast-parser' export const ReactComponentDeclarationType = { VariableDeclaration: 'VariableDeclaration', @@ -113,27 +113,6 @@ export function hasSpecificReturnStatement(functionDeclaration, returnType) { ) } -/** - * - * @param {import('eslint').Rule.RuleContext} context - */ -export const getCommentsBeforeImportDeclaration = (context, {name, from}) => { - const globalScope = context.getScope() - const importDeclarations = getImportDeclarations(globalScope.block) - const styleImportDeclaration = findSpecificImportDeclaration(importDeclarations, { - name, - from, - }) - - const sourceCode = context.getSourceCode() - - if (styleImportDeclaration) { - return sourceCode.getCommentsBefore(styleImportDeclaration) - } else { - sourceCode.getAllComments() - } -} - /** * * @param {import('eslint').Rule.RuleContext} context From d4022dc291f8b8952dc3c45320f34cfa1e62a89b Mon Sep 17 00:00:00 2001 From: Yongho Lee Date: Fri, 14 Feb 2025 14:44:25 +0900 Subject: [PATCH 4/4] Create wicked-cooks-count.md --- .changeset/wicked-cooks-count.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/wicked-cooks-count.md diff --git a/.changeset/wicked-cooks-count.md b/.changeset/wicked-cooks-count.md new file mode 100644 index 0000000..36a917f --- /dev/null +++ b/.changeset/wicked-cooks-count.md @@ -0,0 +1,7 @@ +--- +"@naverpay/eslint-plugin": patch +--- + +Support eslint 9 for eslint-plugin + +PR: [Support eslint 9 for eslint-plugin](https://github.com/NaverPayDev/code-style/pull/79)