From bd501b54741d87b91525d897dc7f298e4794a831 Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Fri, 16 Apr 2021 23:50:48 +0800 Subject: [PATCH 1/9] implement automatic adding of jsxImportSource pragma definition --- .changeset/sweet-plums-behave.md | 5 ++ .../eslint-plugin/src/rules/jsx-import.js | 59 ++++++++++++++++++- .../test/rules/jsx-import.test.js | 48 +++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 .changeset/sweet-plums-behave.md diff --git a/.changeset/sweet-plums-behave.md b/.changeset/sweet-plums-behave.md new file mode 100644 index 0000000000..0f3780900b --- /dev/null +++ b/.changeset/sweet-plums-behave.md @@ -0,0 +1,5 @@ +--- +'@emotion/eslint-plugin': patch +--- + +implement automatic adding of jsxImportSource pragma definition diff --git a/packages/eslint-plugin/src/rules/jsx-import.js b/packages/eslint-plugin/src/rules/jsx-import.js index 1618e7bb25..b9b19acb92 100644 --- a/packages/eslint-plugin/src/rules/jsx-import.js +++ b/packages/eslint-plugin/src/rules/jsx-import.js @@ -1,4 +1,5 @@ const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/ +const JSX_IMPORT_SOURCE_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/ // TODO: handling this case //
@@ -7,9 +8,65 @@ const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/ export default { meta: { - fixable: 'code' + fixable: 'code', + schema: { + type: 'array', + items: { + oneOf: [ + { + type: 'string' + }, + { + type: 'object', + properties: { + jsxImportSource: { type: 'string' } + }, + required: ['jsxImportSource'], + additionalProperties: false + } + ] + }, + uniqueItems: true, + minItems: 0 + } }, create(context) { + const jsxRuntimeMode = context.options.find( + option => + option === 'jsxImportSource' || (option && option.jsxImportSource) + ) + + if (jsxRuntimeMode) { + return { + JSXAttribute(node) { + if (node.name.name !== 'css') { + return + } + let hasJsxImportSource = false + let sourceCode = context.getSourceCode() + let pragma = sourceCode + .getAllComments() + .find(node => JSX_IMPORT_SOURCE_REGEX.test(node.value)) + hasJsxImportSource = + pragma && pragma.value.match(JSX_IMPORT_SOURCE_REGEX) + if (!hasJsxImportSource) { + context.report({ + node, + message: + 'The css prop can only be used if you set @jsxImportSource pragma', + fix(fixer) { + return fixer.insertTextBefore( + sourceCode.ast.body[0], + `/** @jsxImportSource ${(jsxRuntimeMode || {}) + .jsxImportSource || '@emotion/react'} */\n` + ) + } + }) + } + } + } + } + return { JSXAttribute(node) { if (node.name.name !== 'css') { diff --git a/packages/eslint-plugin/test/rules/jsx-import.test.js b/packages/eslint-plugin/test/rules/jsx-import.test.js index 6e198e56ac..4d13bffc4a 100644 --- a/packages/eslint-plugin/test/rules/jsx-import.test.js +++ b/packages/eslint-plugin/test/rules/jsx-import.test.js @@ -29,6 +29,22 @@ ruleTester.run('emotion jsx', rule, { let ele = ` }, + { + options: ['jsxImportSource'], + code: ` + /** @jsxImportSource @emotion/react */ + + let ele = + ` + }, + { + options: [{ jsxImportSource: '@emotion/react' }], + code: ` + /** @jsxImportSource @emotion/react */ + + let ele = + ` + }, { code: ` @@ -52,6 +68,38 @@ let ele = output: ` // @jsx jsx import { jsx } from '@emotion/react' +let ele = + `.trim() + }, + { + options: ['jsxImportSource'], + code: ` +let ele = + `.trim(), + errors: [ + { + message: + 'The css prop can only be used if you set @jsxImportSource pragma' + } + ], + output: ` +/** @jsxImportSource @emotion/react */ +let ele = + `.trim() + }, + { + options: [{ jsxImportSource: '@iChenLei/react' }], + code: ` +let ele = + `.trim(), + errors: [ + { + message: + 'The css prop can only be used if you set @jsxImportSource pragma' + } + ], + output: ` +/** @jsxImportSource @iChenLei/react */ let ele = `.trim() }, From 7bbc03d8b21e653b68ac70f4ad15748a57eac656 Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Sat, 24 Apr 2021 15:36:50 +0800 Subject: [PATCH 2/9] chore: change the config implemention --- .../eslint-plugin/src/rules/jsx-import.js | 12 +++--- .../test/rules/jsx-import.test.js | 41 +++++++++++++++++-- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/packages/eslint-plugin/src/rules/jsx-import.js b/packages/eslint-plugin/src/rules/jsx-import.js index b9b19acb92..e9fd722b3e 100644 --- a/packages/eslint-plugin/src/rules/jsx-import.js +++ b/packages/eslint-plugin/src/rules/jsx-import.js @@ -19,9 +19,10 @@ export default { { type: 'object', properties: { - jsxImportSource: { type: 'string' } + runtime: { type: 'string' }, + importSource: { type: 'string' } }, - required: ['jsxImportSource'], + required: ['runtime'], additionalProperties: false } ] @@ -32,8 +33,7 @@ export default { }, create(context) { const jsxRuntimeMode = context.options.find( - option => - option === 'jsxImportSource' || (option && option.jsxImportSource) + option => option && option.runtime === 'automatic' ) if (jsxRuntimeMode) { @@ -57,8 +57,8 @@ export default { fix(fixer) { return fixer.insertTextBefore( sourceCode.ast.body[0], - `/** @jsxImportSource ${(jsxRuntimeMode || {}) - .jsxImportSource || '@emotion/react'} */\n` + `/** @jsxImportSource ${(jsxRuntimeMode || {}).importSource || + '@emotion/react'} */\n` ) } }) diff --git a/packages/eslint-plugin/test/rules/jsx-import.test.js b/packages/eslint-plugin/test/rules/jsx-import.test.js index 4d13bffc4a..08f95fc261 100644 --- a/packages/eslint-plugin/test/rules/jsx-import.test.js +++ b/packages/eslint-plugin/test/rules/jsx-import.test.js @@ -30,7 +30,23 @@ ruleTester.run('emotion jsx', rule, { ` }, { - options: ['jsxImportSource'], + options: [{ runtime: 'classic' }], + code: ` + // @jsx jsx + import { jsx } from '@emotion/react' + let ele = + ` + }, + { + options: [{ runtime: 'invalidRuntime' }], + code: ` + // @jsx jsx + import { jsx } from '@emotion/react' + let ele = + ` + }, + { + options: [{ runtime: 'automatic' }], code: ` /** @jsxImportSource @emotion/react */ @@ -38,7 +54,7 @@ ruleTester.run('emotion jsx', rule, { ` }, { - options: [{ jsxImportSource: '@emotion/react' }], + options: [{ runtime: 'automatic', importSource: '@emotion/react' }], code: ` /** @jsxImportSource @emotion/react */ @@ -72,7 +88,7 @@ let ele = `.trim() }, { - options: ['jsxImportSource'], + options: [{ runtime: 'automatic' }], code: ` let ele = `.trim(), @@ -88,7 +104,7 @@ let ele = `.trim() }, { - options: [{ jsxImportSource: '@iChenLei/react' }], + options: [{ runtime: 'automatic', importSource: '@iChenLei/react' }], code: ` let ele = `.trim(), @@ -100,6 +116,23 @@ let ele = ], output: ` /** @jsxImportSource @iChenLei/react */ +let ele = + `.trim() + }, + { + options: [{ runtime: 'classic' }], + code: ` +let ele = + `.trim(), + errors: [ + { + message: + 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + } + ], + output: ` +/** @jsx jsx */ +import { jsx } from '@emotion/react' let ele = `.trim() }, From fb9c777314b7994d55e59c7977cabddf409e058e Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Sat, 8 May 2021 12:10:33 +0800 Subject: [PATCH 3/9] test: add ut for test converage --- packages/eslint-plugin/test/rules/jsx-import.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/eslint-plugin/test/rules/jsx-import.test.js b/packages/eslint-plugin/test/rules/jsx-import.test.js index 08f95fc261..2fc4d6191e 100644 --- a/packages/eslint-plugin/test/rules/jsx-import.test.js +++ b/packages/eslint-plugin/test/rules/jsx-import.test.js @@ -53,6 +53,13 @@ ruleTester.run('emotion jsx', rule, { let ele = ` }, + { + options: [{ runtime: 'automatic' }], + code: ` + // no css prop usage for test coverage + let ele = + ` + }, { options: [{ runtime: 'automatic', importSource: '@emotion/react' }], code: ` From 57a92cc64338f5c86dc6c6a5a86dad4fcb875d58 Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Sat, 8 May 2021 12:57:42 +0800 Subject: [PATCH 4/9] test: add jsx attr for test coverage --- packages/eslint-plugin/test/rules/jsx-import.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/test/rules/jsx-import.test.js b/packages/eslint-plugin/test/rules/jsx-import.test.js index 2fc4d6191e..3e7f32b119 100644 --- a/packages/eslint-plugin/test/rules/jsx-import.test.js +++ b/packages/eslint-plugin/test/rules/jsx-import.test.js @@ -57,7 +57,7 @@ ruleTester.run('emotion jsx', rule, { options: [{ runtime: 'automatic' }], code: ` // no css prop usage for test coverage - let ele = + let ele = ` }, { From 4bdbacdf98f97867f4c01db77ecaf7970121cabc Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Wed, 30 Jun 2021 14:13:47 +0800 Subject: [PATCH 5/9] fix: run eslint --fix --- packages/eslint-plugin/src/rules/import-from-emotion.js | 9 +++++---- packages/eslint-plugin/src/rules/pkg-renaming.js | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/import-from-emotion.js b/packages/eslint-plugin/src/rules/import-from-emotion.js index 7889e3ca5b..71bd0251b8 100644 --- a/packages/eslint-plugin/src/rules/import-from-emotion.js +++ b/packages/eslint-plugin/src/rules/import-from-emotion.js @@ -24,10 +24,11 @@ export default { node.specifiers[0].local.name } from '@emotion/styled';\nimport { ${node.specifiers .filter(x => x.type === 'ImportSpecifier') - .map(x => - x.local.name === x.imported.name - ? x.local.name - : `${x.imported.name} as ${x.local.name}` + .map( + x => + x.local.name === x.imported.name + ? x.local.name + : `${x.imported.name} as ${x.local.name}` ) .join(', ')} } from 'emotion';` ) diff --git a/packages/eslint-plugin/src/rules/pkg-renaming.js b/packages/eslint-plugin/src/rules/pkg-renaming.js index 2e6dbfaf85..b7f614cb7e 100644 --- a/packages/eslint-plugin/src/rules/pkg-renaming.js +++ b/packages/eslint-plugin/src/rules/pkg-renaming.js @@ -42,7 +42,9 @@ export default { : '@emotion/react/macro' context.report({ node: node.source, - message: `The default export of "${node.source.value}" in Emotion 10 has been moved to a named export, \`css\`, from "${replacement}" in Emotion 11, please import it from "${replacement}"`, + message: `The default export of "${ + node.source.value + }" in Emotion 10 has been moved to a named export, \`css\`, from "${replacement}" in Emotion 11, please import it from "${replacement}"`, fix: fixer => fixer.replaceText( node, From dd991385f67d05fc7360fdd6c80b8b68e70677b8 Mon Sep 17 00:00:00 2001 From: iChenLei <2470828450@qq.com> Date: Wed, 30 Jun 2021 15:05:18 +0800 Subject: [PATCH 6/9] fix: eslint --- packages/eslint-plugin/src/rules/import-from-emotion.js | 9 ++++----- packages/eslint-plugin/src/rules/jsx-import.js | 5 +++-- packages/eslint-plugin/src/rules/pkg-renaming.js | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/eslint-plugin/src/rules/import-from-emotion.js b/packages/eslint-plugin/src/rules/import-from-emotion.js index 71bd0251b8..7889e3ca5b 100644 --- a/packages/eslint-plugin/src/rules/import-from-emotion.js +++ b/packages/eslint-plugin/src/rules/import-from-emotion.js @@ -24,11 +24,10 @@ export default { node.specifiers[0].local.name } from '@emotion/styled';\nimport { ${node.specifiers .filter(x => x.type === 'ImportSpecifier') - .map( - x => - x.local.name === x.imported.name - ? x.local.name - : `${x.imported.name} as ${x.local.name}` + .map(x => + x.local.name === x.imported.name + ? x.local.name + : `${x.imported.name} as ${x.local.name}` ) .join(', ')} } from 'emotion';` ) diff --git a/packages/eslint-plugin/src/rules/jsx-import.js b/packages/eslint-plugin/src/rules/jsx-import.js index e9fd722b3e..406a160d84 100644 --- a/packages/eslint-plugin/src/rules/jsx-import.js +++ b/packages/eslint-plugin/src/rules/jsx-import.js @@ -57,8 +57,9 @@ export default { fix(fixer) { return fixer.insertTextBefore( sourceCode.ast.body[0], - `/** @jsxImportSource ${(jsxRuntimeMode || {}).importSource || - '@emotion/react'} */\n` + `/** @jsxImportSource ${ + (jsxRuntimeMode || {}).importSource || '@emotion/react' + } */\n` ) } }) diff --git a/packages/eslint-plugin/src/rules/pkg-renaming.js b/packages/eslint-plugin/src/rules/pkg-renaming.js index b7f614cb7e..2e6dbfaf85 100644 --- a/packages/eslint-plugin/src/rules/pkg-renaming.js +++ b/packages/eslint-plugin/src/rules/pkg-renaming.js @@ -42,9 +42,7 @@ export default { : '@emotion/react/macro' context.report({ node: node.source, - message: `The default export of "${ - node.source.value - }" in Emotion 10 has been moved to a named export, \`css\`, from "${replacement}" in Emotion 11, please import it from "${replacement}"`, + message: `The default export of "${node.source.value}" in Emotion 10 has been moved to a named export, \`css\`, from "${replacement}" in Emotion 11, please import it from "${replacement}"`, fix: fixer => fixer.replaceText( node, From be486b54c0c4b107089f9a862a5c463929dcc88d Mon Sep 17 00:00:00 2001 From: Lei Chen