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) 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..6484c27 100644 --- a/packages/eslint-plugin/lib/rules/memo-react-components.js +++ b/packages/eslint-plugin/lib/rules/memo-react-components.js @@ -24,10 +24,19 @@ export default { }, create: function (context) { const filename = context.filename.replace(context.cwd, '') + const isFileInPath = context.options[0].path.some((pattern) => minimatch(filename, pattern)) + if (!isFileInPath) { + return {} + } - const isMatched = context.options[0].path.some((pattern) => minimatch(filename, pattern)) + let isAlreadyMemoized = false - const globalScope = context.getScope() + const sourceCode = context.sourceCode ?? context.getSourceCode() + + /** + * @type {import('eslint').Scope.Scope | undefined} + */ + let globalScope function importReactMemo(fixer) { let i = 0 @@ -77,18 +86,22 @@ export default { return result } - if (!isMatched) { - 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..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,33 +113,12 @@ 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 */ export const getAllComments = (context) => { - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() return sourceCode.getAllComments() }