Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add no-duplicate-store-ids #15

Merged
merged 3 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ To use the all configuration, extend it in your `.eslintrc` file:

| Name                                  | Description | 💼 | ⚠️ | 🚫 |
| :------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------- | :- | :- | :- |
| [no-duplicate-store-ids](docs/rules/no-duplicate-store-ids.md) | Disallow duplicate store ids | ✅ | 🌐 | |
| [no-return-global-properties](docs/rules/no-return-global-properties.md) | Disallows returning globally provided properties from Pinia stores. | ✅ | 🌐 | |
| [prefer-single-store-per-file](docs/rules/prefer-single-store-per-file.md) | Encourages defining each store in a separate file. | | | 🌐 |
| [prefer-use-store-naming-convention](docs/rules/prefer-use-store-naming-convention.md) | Enforces the convention of naming stores with the prefix `use` followed by the store name. | | 🌐 | |
Expand Down
55 changes: 55 additions & 0 deletions docs/rules/no-duplicate-store-ids.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Disallow duplicate store ids (`pinia/no-duplicate-store-ids`)

💼⚠️ This rule is enabled in the ✅ `recommended` config. This rule _warns_ in the 🌐 `all` config.

<!-- end auto-generated rule header -->

## Rule Details

❌ Examples of **incorrect** code for this rule:

```js
// a.js
export const useBarStore = defineStore('bar', () => {
const bar = ref(0)

return { bar }
})

// b.js
export const useAnotherBarStore = defineStore('bar', () => {
const foo = ref(0)

return { foo }
})
```

```js
export const useBarStore = defineStore('bar', () => {
const bar = ref(0)

return { bar }
})

export const useAnotherBarStore = defineStore('bar', () => {
const foo = ref(0)

return { foo }
})
```

✅ Examples of **correct** code for this rule:

```js
export const useBarStore = defineStore('bar', () => {
const bar = ref(0)

return { bar }
})

export const useAnotherCounterStore = defineStore('foo', () => {
const foo = ref(0)

return { foo }
})
```
13 changes: 10 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import noReturnGlobalProperties, {
RULE_NAME as noReturnGlobalPropertiesName
} from './rules/no-return-global-properties'

import noDuplicateStoreIds, {
RULE_NAME as noDuplicateStoreIdsName
} from './rules/no-duplicate-store-ids'

const createConfig = (rules: Record<string, string>) => ({
plugins: ['pinia'],
rules: Object.keys(rules).reduce((acc, ruleName) => {
Expand All @@ -28,20 +32,23 @@ const allRules = {
[requireSetupStorePropsName]: 'warn',
[preferNamingConventionName]: 'warn',
[preferSingleStoreName]: 'off',
[noReturnGlobalPropertiesName]: 'warn'
[noReturnGlobalPropertiesName]: 'warn',
[noDuplicateStoreIdsName]: 'warn'
}

const recommended = {
[requireSetupStorePropsName]: 'error',
[noReturnGlobalPropertiesName]: 'error'
[noReturnGlobalPropertiesName]: 'error',
[noDuplicateStoreIdsName]: 'error'
}

export default {
rules: {
[requireSetupStorePropsName]: requireSetupStoreProps,
[preferNamingConventionName]: preferNamingConvention,
[preferSingleStoreName]: preferSingleStore,
[noReturnGlobalPropertiesName]: noReturnGlobalProperties
[noReturnGlobalPropertiesName]: noReturnGlobalProperties,
[noDuplicateStoreIdsName]: noDuplicateStoreIds
},
configs: {
all: createConfig(allRules),
Expand Down
50 changes: 50 additions & 0 deletions src/rules/no-duplicate-store-ids.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { createEslintRule } from '../utils/rule-creator'
import { AST_NODE_TYPES } from '@typescript-eslint/utils'

export const RULE_NAME = 'no-duplicate-store-ids'
export type MESSAGE_IDS = 'duplicatedStoreIds'
type Options = []

const usingStoreIds = new Set<string>()
lisilinhart marked this conversation as resolved.
Show resolved Hide resolved

export default createEslintRule<Options, MESSAGE_IDS>({
name: RULE_NAME,
meta: {
type: 'problem',
docs: {
description: 'Disallow duplicate store ids.'
},
schema: [],
messages: {
duplicatedStoreIds: 'No duplicated store ids allowed: {{storeId}}'
}
},
defaultOptions: [],
create: (context) => {
lisilinhart marked this conversation as resolved.
Show resolved Hide resolved
return {
CallExpression(node) {
const callee = node.callee
if (callee.type !== 'Identifier' || callee.name !== 'defineStore')
return

const storeId = node.arguments && node.arguments[0]

if (!storeId || storeId.type !== AST_NODE_TYPES.Literal) return

const value = storeId.value as string

if (usingStoreIds.has(value)) {
context.report({
node: storeId,
messageId: 'duplicatedStoreIds',
data: {
storeId: storeId.value
}
})
} else {
usingStoreIds.add(value)
}
}
}
}
})
43 changes: 43 additions & 0 deletions tests/rules/no-duplicate-store-ids.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import rule, { RULE_NAME } from '../../src/rules/no-duplicate-store-ids'
import { ruleTester } from '../rule-tester'

ruleTester.run(RULE_NAME, rule, {
valid: [
{
code: `import { defineStore } from 'pinia'
export const useCounterStore = defineStore()`
},
{
code: `import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
return { count }
})
export const useTodoStore = defineStore('todo', () => {
const todo = ref(0)
return { todo }
})`
}
],
invalid: [
{
code: `import { defineStore } from 'pinia'

const useCounterStore = defineStore('counter', () => {
const count = ref(0)
return { count }
})

const useCounter2Store = defineStore('counter', () => {
})`,
errors: [
{
messageId: 'duplicatedStoreIds'
},
{
messageId: 'duplicatedStoreIds'
}
]
}
]
})