Skip to content

Commit

Permalink
Merge pull request #24 from storybookjs/fix/meta-as-variable
Browse files Browse the repository at this point in the history
Fix/meta as variable
  • Loading branch information
yannbf authored Nov 9, 2021
2 parents f1badfa + a441f98 commit d00e6e4
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 126 deletions.
8 changes: 1 addition & 7 deletions lib/rules/await-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ import type { CallExpression, Identifier, Node } from '@typescript-eslint/types/

import { createStorybookRule } from '../utils/create-storybook-rule'
import { CategoryId } from '../utils/constants'
import {
isCallExpression,
isMemberExpression,
isIdentifier,
isProgram,
isAwaitExpression,
} from '../utils/ast'
import { isMemberExpression, isIdentifier, isAwaitExpression } from '../utils/ast'

//------------------------------------------------------------------------------
// Rule Definition
Expand Down
22 changes: 11 additions & 11 deletions lib/rules/csf-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* @author Yann Braga
*/

import { ExportDefaultDeclaration, Node } from '@typescript-eslint/types/dist/ast-spec'
import { isObjectExpression } from '../utils/ast'
import { getMetaObjectExpression } from '../utils'
import { CategoryId } from '../utils/constants'
import { createStorybookRule } from '../utils/create-storybook-rule'

Expand Down Expand Up @@ -40,19 +43,16 @@ export = createStorybookRule({
//----------------------------------------------------------------------

return {
ExportDefaultDeclaration: function (node: any) {
// Typescript 'TSAsExpression' has properties under declaration.expression
const metaProperties =
node.declaration.properties ||
(node.declaration.expression && node.declaration.expression.properties)

if (!metaProperties) {
return
ExportDefaultDeclaration(node: ExportDefaultDeclaration) {
const meta = getMetaObjectExpression(node, context)
if (!meta) {
return null
}

const component = metaProperties.find((prop: any) => prop.key.name === 'component')

if (!component) {
const componentProperty = meta.properties.find(
(property: any) => property.key.name === 'component'
)
if (!componentProperty) {
context.report({
node,
messageId: 'missingComponentProperty',
Expand Down
26 changes: 15 additions & 11 deletions lib/rules/hierarchy-separator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* @author Yann Braga
*/

import { getMetaObjectExpression } from '../utils'
import { isLiteral } from '../utils/ast'
import { CategoryId } from '../utils/constants'
import { createStorybookRule } from '../utils/create-storybook-rule'

Expand Down Expand Up @@ -31,22 +33,19 @@ export = createStorybookRule({
create: function (context: any) {
return {
ExportDefaultDeclaration: function (node: any) {
// Typescript 'TSAsExpression' has properties under declaration.expression
const metaProperties =
node.declaration.properties ||
(node.declaration.expression && node.declaration.expression.properties)

if (!metaProperties) {
return
const meta = getMetaObjectExpression(node, context)
if (!meta) {
return null
}

const titleNode = metaProperties.find((prop: any) => prop.key.name === 'title')
const titleNode = meta.properties.find((prop: any) => prop.key.name === 'title')

// @ts-expect-error ts-migrate(2367) FIXME: This condition will always return 'false' since th... Remove this comment to see the full error message
if (!titleNode || !titleNode.value.type === 'Literal') {
//@ts-ignore
if (!titleNode || !isLiteral(titleNode.value)) {
return
}

//@ts-ignore
const metaTitle = titleNode.value.raw || ''

if (metaTitle.includes('|') || metaTitle.includes('.')) {
Expand All @@ -56,13 +55,18 @@ export = createStorybookRule({
data: { metaTitle },
// In case we want this to be auto fixed by --fix
fix: function (fixer: any) {
return fixer.replaceTextRange(titleNode.value.range, metaTitle.replace(/\||\./g, '/'))
return fixer.replaceTextRange(
//@ts-ignore
titleNode.value.range,
metaTitle.replace(/\||\./g, '/')
)
},
suggest: [
{
messageId: 'useCorrectSeparators',
fix: function (fixer: any) {
return fixer.replaceTextRange(
//@ts-ignore
titleNode.value.range,
metaTitle.replace(/\||\./g, '/')
)
Expand Down
13 changes: 5 additions & 8 deletions lib/rules/meta-inline-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* @author Yann Braga
*/

import { getMetaObjectExpression } from '../utils'
import { CategoryId } from '../utils/constants'
import { createStorybookRule } from '../utils/create-storybook-rule'

Expand Down Expand Up @@ -62,19 +63,15 @@ export = createStorybookRule({

return {
ExportDefaultDeclaration(node: any) {
// Typescript 'TSAsExpression' has properties under declaration.expression
const metaProperties =
node.declaration.properties ||
(node.declaration.expression && node.declaration.expression.properties)

if (!metaProperties) {
return
const meta = getMetaObjectExpression(node, context)
if (!meta) {
return null
}

const ruleProperties = ['title', 'args']
let dynamicProperties: any = []

const metaNodes = metaProperties.filter((prop: any) =>
const metaNodes = meta.properties.filter((prop: any) =>
//@ts-ignore
ruleProperties.includes(prop.key.name)
)
Expand Down
13 changes: 5 additions & 8 deletions lib/rules/no-title-property-in-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* @author Yann Braga
*/

import { getMetaObjectExpression } from '../utils'
import { CategoryId } from '../utils/constants'
import { createStorybookRule } from '../utils/create-storybook-rule'

Expand Down Expand Up @@ -31,16 +32,12 @@ export = createStorybookRule({
create: function (context: any) {
return {
ExportDefaultDeclaration: function (node: any) {
// Typescript 'TSAsExpression' has properties under declaration.expression
const metaProperties =
node.declaration.properties ||
(node.declaration.expression && node.declaration.expression.properties)

if (!metaProperties) {
return
const meta = getMetaObjectExpression(node, context)
if (!meta) {
return null
}

const titleNode = metaProperties.find((prop: any) => prop.key.name === 'title')
const titleNode = meta.properties.find((prop: any) => prop.key.name === 'title')

if (titleNode) {
context.report({
Expand Down
1 change: 1 addition & 0 deletions lib/utils/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export const isProperty = isNodeOfType(AST_NODE_TYPES.Property)
export const isReturnStatement = isNodeOfType(AST_NODE_TYPES.ReturnStatement)
export const isFunctionExpression = isNodeOfType(AST_NODE_TYPES.FunctionExpression)
export const isProgram = isNodeOfType(AST_NODE_TYPES.Program)
export const isTSAsExpression = isNodeOfType(AST_NODE_TYPES.TSAsExpression)
20 changes: 20 additions & 0 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
import { ExportDefaultDeclaration, Node } from '@typescript-eslint/types/dist/ast-spec'
import { findVariable } from '@typescript-eslint/experimental-utils/dist/ast-utils'
import { isIdentifier, isObjectExpression, isTSAsExpression, isVariableDeclarator } from './ast'

export const docsUrl = (ruleName: any) =>
`https://github.com/storybookjs/eslint-plugin-storybook/blob/main/docs/rules/${ruleName}.md`

export const isPlayFunction = (node: any) => {
const propertyName = node.left && node.left.property && node.left.property.name
return propertyName === 'play'
}

export const getMetaObjectExpression = (node: ExportDefaultDeclaration, context: any) => {
let meta = node.declaration
if (isIdentifier(meta)) {
const variable = findVariable(context.getScope(), meta.name)
const decl = variable && variable.defs.find((def) => isVariableDeclarator(def.node))
if (decl && isVariableDeclarator(decl.node)) {
meta = decl.node.init
}
}
if (isTSAsExpression(meta)) {
meta = meta.expression
}

return isObjectExpression(meta) ? meta : null
}
25 changes: 12 additions & 13 deletions tests/lib/rules/csf-component.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,17 @@ ruleTester.run('csf-component', rule, {
},
],
},
// @TODO: Support this use case - meta as constant
// {
// code: `
// const meta = { title: 'Button' } as Meta<typeof Button>
// export default meta
// `,
// errors: [
// {
// messageId: 'missingComponentProperty',
// type: AST_NODE_TYPES.ExportDefaultDeclaration,
// },
// ],
// },
{
code: `
const meta = { title: 'Button' } as Meta<typeof Button>
export default meta
`,
errors: [
{
messageId: 'missingComponentProperty',
type: AST_NODE_TYPES.ExportDefaultDeclaration,
},
],
},
],
})
52 changes: 26 additions & 26 deletions tests/lib/rules/hierarchy-separator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//------------------------------------------------------------------------------

import { AST_NODE_TYPES } from '@typescript-eslint/types'
import dedent from 'ts-dedent'

import rule from '../../../lib/rules/hierarchy-separator'
import ruleTester from '../../utils/rule-tester'
Expand Down Expand Up @@ -55,31 +56,30 @@ ruleTester.run('hierarchy-separator', rule, {
},
],
},
// @TODO: Support this use case - meta as constant
// {
// code: dedent`
// const meta = { title: 'Examples.Components.Button' }
// export default meta
// `,
// output: dedent`
// const meta = { title: 'Examples/Components/Button' }
// export default meta
// `,
// errors: [
// {
// type: AST_NODE_TYPES.ExportDefaultDeclaration,
// messageId: 'deprecatedHierarchySeparator',
// suggestions: [
// {
// messageId: 'useCorrectSeparators',
// output: dedent`
// const meta = { title: 'Examples/Components/Button' }
// export default meta
// `,
// },
// ],
// },
// ],
// },
{
code: dedent`
const meta = { title: 'Examples.Components.Button' }
export default meta
`,
output: dedent`
const meta = { title: 'Examples/Components/Button' }
export default meta
`,
errors: [
{
type: AST_NODE_TYPES.ExportDefaultDeclaration,
messageId: 'deprecatedHierarchySeparator',
suggestions: [
{
messageId: 'useCorrectSeparators',
output: dedent`
const meta = { title: 'Examples/Components/Button' }
export default meta
`,
},
],
},
],
},
],
})
40 changes: 20 additions & 20 deletions tests/lib/rules/meta-inline-properties.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//------------------------------------------------------------------------------

import { AST_NODE_TYPES } from '@typescript-eslint/types'
import dedent from 'ts-dedent'

import rule from '../../../lib/rules/meta-inline-properties'
import ruleTester from '../../utils/rule-tester'
Expand Down Expand Up @@ -109,27 +110,26 @@ ruleTester.run('meta-inline-properties', rule, {
},
],
},
// @TODO: Support this use case - meta as constant
// {
// code: `
// const title = 'a'
{
code: dedent`
const title = 'a'
// const meta: ComponentMeta<typeof Badge> = {
// title,
// component: Badge,
// }
const meta: ComponentMeta<typeof Badge> = {
title,
component: Badge,
}
// export default meta
// `,
// errors: [
// {
// messageId: 'metaShouldHaveInlineProperties',
// data: {
// property: 'title',
// },
// type: AST_NODE_TYPES.Property,
// },
// ],
// },
export default meta
`,
errors: [
{
messageId: 'metaShouldHaveInlineProperties',
data: {
property: 'title',
},
type: AST_NODE_TYPES.Property,
},
],
},
],
})
Loading

0 comments on commit d00e6e4

Please sign in to comment.