Skip to content

Commit

Permalink
additional 'no-uninstalled-addons' support
Browse files Browse the repository at this point in the history
  • Loading branch information
hjoelh committed Aug 9, 2023
1 parent 611b70e commit 783542f
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 15 deletions.
53 changes: 38 additions & 15 deletions lib/rules/no-uninstalled-addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
isLiteral,
isVariableDeclarator,
isVariableDeclaration,
isTSSatisfiesExpression,
} from '../utils/ast'
import { TSESTree } from '@typescript-eslint/utils'

Expand Down Expand Up @@ -228,33 +229,55 @@ export = createStorybookRule({
}
}

function findAddonsPropAndReport(node: TSESTree.ObjectExpression) {
const addonsProp = node.properties.find(
(prop): prop is TSESTree.Property =>
isProperty(prop) && isIdentifier(prop.key) && prop.key.name === 'addons'
)

if (addonsProp?.value && isArrayExpression(addonsProp.value)) {
reportUninstalledAddons(addonsProp.value)
}
}

//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------

return {
AssignmentExpression: function (node) {
if (isObjectExpression(node.right)) {
const addonsProp = node.right.properties.find(
(prop): prop is TSESTree.Property =>
isProperty(prop) && isIdentifier(prop.key) && prop.key.name === 'addons'
)

if (addonsProp && addonsProp.value && isArrayExpression(addonsProp.value)) {
reportUninstalledAddons(addonsProp.value)
}
findAddonsPropAndReport(node.right)
}
},
ExportDefaultDeclaration: function (node) {
if (isIdentifier(node.declaration)) {
const variable = context
.getScope()
.variables.find((v) =>
node.declaration.type === 'Identifier' ? v.name === node.declaration.name : false
)

if (
variable &&
variable.defs[0] &&
isVariableDeclarator(variable.defs[0].node) &&
isObjectExpression(variable.defs[0].node.init)
) {
const objectNode = variable.defs[0].node.init
findAddonsPropAndReport(objectNode)
}
}

if (isObjectExpression(node.declaration)) {
const addonsProp = node.declaration.properties.find(
(prop): prop is TSESTree.Property =>
isProperty(prop) && isIdentifier(prop.key) && prop.key.name === 'addons'
)
findAddonsPropAndReport(node.declaration)
}

if (addonsProp && addonsProp.value && isArrayExpression(addonsProp.value)) {
reportUninstalledAddons(addonsProp.value)
}
if (
isTSSatisfiesExpression(node.declaration) &&
isObjectExpression(node.declaration.expression)
) {
findAddonsPropAndReport(node.declaration.expression)
}
},
ExportNamedDeclaration: function (node) {
Expand Down
84 changes: 84 additions & 0 deletions tests/lib/rules/no-uninstalled-addons.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ ruleTester.run('no-uninstalled-addons', rule, {
"@storybook/preset-create-react-app"
]
}
`,
`
export default {
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/preset-create-react-app"
]
} satisfies StorybookConfig
`,
`
const config: StorybookConfig = {
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/preset-create-react-app"
]
}
export default config
`,
`
export const addons = [
Expand Down Expand Up @@ -291,6 +312,69 @@ ruleTester.run('no-uninstalled-addons', rule, {
},
],
},
{
code: `
export default {
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"addon-withut-the-prefix",
"@storybook/addon-esentials",
]
} satisfies StorybookConfig
`,
errors: [
{
messageId: 'addonIsNotInstalled', // comes from the rule file
type: AST_NODE_TYPES.Literal,
data: {
addonName: 'addon-withut-the-prefix',
packageJsonPath: `eslint-plugin-storybook${sep}`,
},
},
{
messageId: 'addonIsNotInstalled', // comes from the rule file
type: AST_NODE_TYPES.Literal,
data: {
addonName: '@storybook/addon-esentials',
packageJsonPath: `eslint-plugin-storybook${sep}`,
},
},
],
},
{
code: `
const config: StorybookConfig = {
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"addon-withut-the-prefix",
"@storybook/addon-esentials",
]
}
export default config
`,
errors: [
{
messageId: 'addonIsNotInstalled', // comes from the rule file
type: AST_NODE_TYPES.Literal,
data: {
addonName: 'addon-withut-the-prefix',
packageJsonPath: `eslint-plugin-storybook${sep}`,
},
},
{
messageId: 'addonIsNotInstalled', // comes from the rule file
type: AST_NODE_TYPES.Literal,
data: {
addonName: '@storybook/addon-esentials',
packageJsonPath: `eslint-plugin-storybook${sep}`,
},
},
],
},
{
code: `
export const addons = [
Expand Down

0 comments on commit 783542f

Please sign in to comment.