eslint-plugin-primer-react 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # eslint-plugin-primer-react
2
2
 
3
+ ## 2.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#47](https://github.com/primer/eslint-plugin-primer-react/pull/47) [`9964e4e`](https://github.com/primer/eslint-plugin-primer-react/commit/9964e4e5415c3bbeab78763b7b4d4e29a0bdbb95) Thanks [@colebemis](https://github.com/colebemis)! - - Update the no-system-props rule to properly check subcomponents for system props
8
+ - Adds valid sucomponent props to the allowlist
9
+
3
10
  ## 2.0.2
4
11
 
5
12
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-primer-react",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "ESLint rules for Primer React",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -20,7 +20,8 @@ ruleTester.run('no-system-props', rule, {
20
20
  `import {ProgressBar} from '@primer/react'; <ProgressBar bg="howdy" />`,
21
21
  `import {Button} from '@primer/react'; <Button {...someExpression()} />`,
22
22
  `import {Button} from '@primer/react'; <Button variant="large" />`,
23
- `import {Button} from '@primer/react'; <Button size="large" />`
23
+ `import {Button} from '@primer/react'; <Button size="large" />`,
24
+ `import {ActionMenu} from '@primer/react'; <ActionMenu.Overlay width="large" />`
24
25
  ],
25
26
  invalid: [
26
27
  {
@@ -166,6 +167,16 @@ ruleTester.run('no-system-props', rule, {
166
167
  data: {propNames: 'width', componentName: 'Foo'}
167
168
  }
168
169
  ]
170
+ },
171
+ {
172
+ code: `import {Button} from '@primer/react'; <Button.Counter width={200} />`,
173
+ output: `import {Button} from '@primer/react'; <Button.Counter sx={{width: 200}} />`,
174
+ errors: [
175
+ {
176
+ messageId: 'noSystemProps',
177
+ data: {propNames: 'width', componentName: 'Button.Counter'}
178
+ }
179
+ ]
169
180
  }
170
181
  ]
171
182
  })
@@ -1,4 +1,5 @@
1
1
  const {isPrimerComponent} = require('../utils/is-primer-component')
2
+ const {getJSXOpeningElementName} = require('../utils/get-jsx-opening-element-name')
2
3
  const {last} = require('lodash')
3
4
 
4
5
  const slotParentToChildMap = {
@@ -84,12 +85,3 @@ module.exports = {
84
85
  }
85
86
  }
86
87
  }
87
-
88
- // Convert JSXOpeningElement name to string
89
- function getJSXOpeningElementName(jsxNode) {
90
- if (jsxNode.name.type === 'JSXIdentifier') {
91
- return jsxNode.name.name
92
- } else if (jsxNode.name.type === 'JSXMemberExpression') {
93
- return `${jsxNode.name.object.name}.${jsxNode.name.property.name}`
94
- }
95
- }
@@ -1,4 +1,5 @@
1
1
  const {isPrimerComponent} = require('../utils/is-primer-component')
2
+ const {getJSXOpeningElementName} = require('../utils/get-jsx-opening-element-name')
2
3
  const {pick} = require('@styled-system/props')
3
4
  const {some, last} = require('lodash')
4
5
 
@@ -12,18 +13,31 @@ const utilityComponents = new Set(['Box', 'Text'])
12
13
 
13
14
  // Components for which we allow a set of prop names
14
15
  const excludedComponentProps = new Map([
16
+ ['ActionMenu.Overlay', new Set(['width', 'height', 'maxHeight', 'position', 'top', 'right', 'bottom', 'left'])],
17
+ ['Autocomplete.Overlay', new Set(['width', 'height', 'maxHeight', 'position', 'top', 'right', 'bottom', 'left'])],
15
18
  ['AnchoredOverlay', new Set(['width', 'height'])],
16
19
  ['Avatar', new Set(['size'])],
17
20
  ['AvatarToken', new Set(['size'])],
18
21
  ['CircleOcticon', new Set(['size'])],
19
22
  ['Dialog', new Set(['width', 'height'])],
20
23
  ['IssueLabelToken', new Set(['size'])],
24
+ ['Overlay', new Set(['width', 'height', 'maxHeight', 'position', 'top', 'right', 'bottom', 'left'])],
21
25
  ['ProgressBar', new Set(['bg'])],
22
26
  ['Spinner', new Set(['size'])],
27
+ ['SplitPageLayout.Header', new Set(['padding'])],
28
+ ['SplitPageLayout.Footer', new Set(['padding'])],
29
+ ['SplitPageLayout.Pane', new Set(['padding', 'position', 'width'])],
30
+ ['SplitPageLayout.Content', new Set(['padding', 'width'])],
23
31
  ['StyledOcticon', new Set(['size'])],
24
32
  ['PointerBox', new Set(['bg'])],
33
+ ['TextInput', new Set(['size'])],
34
+ ['TextInputWithTokens', new Set(['size', 'maxHeight'])],
25
35
  ['Token', new Set(['size'])],
26
36
  ['PageLayout', new Set(['padding'])],
37
+ ['PageLayout.Header', new Set(['padding'])],
38
+ ['PageLayout.Footer', new Set(['padding'])],
39
+ ['PageLayout.Pane', new Set(['padding', 'position', 'width'])],
40
+ ['PageLayout.Content', new Set(['padding', 'width'])],
27
41
  ['ProgressBar', new Set(['bg'])],
28
42
  ['PointerBox', new Set(['bg'])]
29
43
  ])
@@ -65,7 +79,10 @@ module.exports = {
65
79
  return {
66
80
  JSXOpeningElement(jsxNode) {
67
81
  if (!skipImportCheck && !isPrimerComponent(jsxNode.name, context.getScope(jsxNode))) return
68
- if (excludedComponents.has(jsxNode.name.name)) return
82
+
83
+ const componentName = getJSXOpeningElementName(jsxNode)
84
+
85
+ if (excludedComponents.has(componentName)) return
69
86
 
70
87
  // Create an object mapping from prop name to the AST node for that attribute
71
88
  const propsByNameObject = jsxNode.attributes.reduce((object, attribute) => {
@@ -80,8 +97,8 @@ module.exports = {
80
97
  // Create an array of system prop attribute nodes
81
98
  let systemProps = Object.values(pick(propsByNameObject))
82
99
 
83
- const excludedProps = excludedComponentProps.has(jsxNode.name.name)
84
- ? new Set([...alwaysExcludedProps, ...excludedComponentProps.get(jsxNode.name.name)])
100
+ const excludedProps = excludedComponentProps.has(componentName)
101
+ ? new Set([...alwaysExcludedProps, ...excludedComponentProps.get(componentName)])
85
102
  : alwaysExcludedProps
86
103
 
87
104
  // Filter out our exceptional props
@@ -94,7 +111,7 @@ module.exports = {
94
111
  node: jsxNode,
95
112
  messageId: 'noSystemProps',
96
113
  data: {
97
- componentName: jsxNode.name.name,
114
+ componentName,
98
115
  propNames: systemProps.map(a => a.name.name).join(', ')
99
116
  },
100
117
  fix(fixer) {
@@ -0,0 +1,10 @@
1
+ /** Convert JSXOpeningElement name to string */
2
+ function getJSXOpeningElementName(jsxNode) {
3
+ if (jsxNode.name.type === 'JSXIdentifier') {
4
+ return jsxNode.name.name
5
+ } else if (jsxNode.name.type === 'JSXMemberExpression') {
6
+ return `${jsxNode.name.object.name}.${jsxNode.name.property.name}`
7
+ }
8
+ }
9
+
10
+ exports.getJSXOpeningElementName = getJSXOpeningElementName