Skip to content

Commit b62a116

Browse files
authored
Add skipImportCheck option
1 parent 6145ba3 commit b62a116

File tree

2 files changed

+26
-35
lines changed

2 files changed

+26
-35
lines changed

src/rules/__tests__/no-unnecessary-components.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,13 @@ ruleTester.run('unnecessary-components', rule, {
131131
errors: [{messageId}],
132132
filename,
133133
},
134+
{
135+
name: `Non-PRC ${component} when \`skipImportCheck\` is enabled`,
136+
code: `${brandImport}${jsx(`<${component}>Hello World</${component}>`)}`,
137+
output: `${brandImport}${jsx(`<${replacement}>Hello World</${replacement}>`)}`,
138+
filename,
139+
errors: [{messageId}],
140+
options: [{skipImportCheck: true}],
141+
},
134142
]),
135143
})

src/rules/no-unnecessary-components.js

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const {ESLintUtils} = require('@typescript-eslint/utils')
44
const {IndexKind} = require('typescript')
55
const {pick: pickStyledSystemProps} = require('@styled-system/props')
6+
const {isPrimerComponent} = require('../utils/is-primer-component')
67

78
/** @typedef {import('@typescript-eslint/types').TSESTree.JSXAttribute} JSXAttribute */
89

@@ -36,23 +37,24 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
3637
[components.Text.messageId]: components.Text.message,
3738
},
3839
type: 'problem',
39-
schema: [],
40+
schema: [
41+
{
42+
type: 'object',
43+
properties: {
44+
skipImportCheck: {
45+
type: 'boolean',
46+
},
47+
},
48+
additionalProperties: false,
49+
},
50+
],
4051
fixable: 'code',
4152
},
42-
defaultOptions: [],
53+
defaultOptions: [{skipImportCheck: false}],
4354
create(context) {
44-
/**
45-
* Cache components that we've verified are imported from @primer/react in this file, to save a bit of time
46-
* @type {Map<string, boolean>}
47-
*/
48-
const validatedComponents = new Map()
49-
5055
return {
51-
JSXElement(node) {
52-
const {
53-
openingElement: {name, attributes},
54-
closingElement,
55-
} = node
56+
JSXElement({openingElement, closingElement}) {
57+
const {name, attributes} = openingElement
5658

5759
// Ensure this is one of the components we are looking for. Note this doesn't account for import aliases; this
5860
// is intentional to avoid having to do the scope tree traversal for every component of every name, which would
@@ -62,28 +64,9 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
6264

6365
// Only continue if the variable declaration is an import from @primer/react. Otherwise it could, for example,
6466
// be an import from @primer/brand, which would be valid without sx.
65-
let isImportedFromPrimer = validatedComponents.get(name.name)
66-
if (isImportedFromPrimer === undefined) {
67-
// Find the variable declaration for this component
68-
let variable
69-
/** @type {import('@typescript-eslint/utils/ts-eslint').Scope.Scope | undefined} */
70-
let scope = context.sourceCode.getScope(name)
71-
while (scope && !variable) {
72-
variable = scope.variables.find(v => v.name === name.name)
73-
scope = scope.upper ?? undefined
74-
}
75-
76-
isImportedFromPrimer =
77-
variable?.defs.some(
78-
def =>
79-
def.type === 'ImportBinding' &&
80-
def.parent.type === 'ImportDeclaration' &&
81-
def.parent.source.value === '@primer/react',
82-
) ?? false
83-
84-
validatedComponents.set(name.name, isImportedFromPrimer)
85-
}
86-
if (!isImportedFromPrimer) return
67+
const skipImportCheck = context.options[0]?.skipImportCheck
68+
const isPrimer = skipImportCheck || isPrimerComponent(name, context.sourceCode.getScope(openingElement))
69+
if (!isPrimer) return
8770

8871
// Validate the attributes and ensure an `sx` prop is present or spreaded in
8972
/** @type {typeof attributes[number] | undefined | null} */

0 commit comments

Comments
 (0)