diff --git a/package.json b/package.json index 0e9d63abf9..5ce0a0e637 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "@swc/core": "^1.7.14", "@swc/jest": "^0.2.36", "@testing-library/react-hooks": "^8.0.1", + "@types/eslint": "^9.6.1", "@types/fs-extra": "^9.0.13", "@types/jest": "^29.5.12", "@types/lodash": "^4.14.197", diff --git a/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts b/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts new file mode 100644 index 0000000000..91cb4b8564 --- /dev/null +++ b/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import {TSESLint} from '@typescript-eslint/utils'; +import rule from '../no-hardcoded-src'; + +declare const require: any; + +const ruleTester = new TSESLint.RuleTester({ + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, +}); + +ruleTester.run('no-hardcoded-src', rule, { + valid: [ + {code: ``}, + { + code: `import useBaseUrl from '@docusaurus/useBaseUrl';\n`, + }, + {code: `
`}, + {code: ``}, + ], + invalid: [ + { + code: ``, + errors: [{messageId: 'hardcodedSrc'}], + }, + {code: ``, errors: [{messageId: 'hardcodedSrc'}]}, + ], +}); diff --git a/packages/eslint-plugin/src/rules/no-hardcoded-src.ts b/packages/eslint-plugin/src/rules/no-hardcoded-src.ts new file mode 100644 index 0000000000..dc087a37b3 --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-hardcoded-src.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import {createRule} from '../util'; +import type {TSESTree} from '@typescript-eslint/utils'; + +export default createRule({ + name: 'no-hardcoded-src', + meta: { + type: 'problem', + docs: { + description: + 'Enforce using require() or useBaseUrl() for src attributes.', + recommended: 'warn', + }, + schema: [], + messages: { + hardcodedSrc: + 'Do not use a hardcoded string for the src attribute. Use require() or useBaseUrl() for image paths instead.', + }, + }, + defaultOptions: [], + create(context) { + return { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { + if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'img') { + return; + } + + const srcAttribute = node.attributes.find( + (attr): attr is TSESTree.JSXAttribute => + attr.type === 'JSXAttribute' && attr.name.name === 'src', + ); + + if (!srcAttribute) { + return; + } + + if ( + srcAttribute.value?.type === 'Literal' && + typeof srcAttribute.value.value === 'string' && + srcAttribute.value.value.trim().length > 0 + ) { + context.report({ + node: srcAttribute, + messageId: 'hardcodedSrc', + }); + } + }, + }; + }, +}); diff --git a/yarn.lock b/yarn.lock index 23c7994f16..ce4e0e4020 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4243,6 +4243,14 @@ resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2" integrity sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg== +"@types/eslint@^9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + "@types/estree-jsx@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" @@ -4432,7 +4440,7 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==