Skip to content

Commit

Permalink
Merge pull request #2 from ronparkdev/feature/unique
Browse files Browse the repository at this point in the history
Feature/unique
  • Loading branch information
ronparkdev authored May 29, 2024
2 parents 2250c22 + 50290a6 commit 620a94f
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Here’s a suggested ESLint configuration that:
'annotation/format-date': 'error',
'annotation/sort-keys': 'error',
'annotation/sort': 'error',
'annotation/unique': 'error',
}
}
```
Expand All @@ -41,6 +42,7 @@ Here’s a suggested ESLint configuration that:
| [`format-date`](https://github.com/ronparkdev/eslint-plugin-annotation/blob/master/documents/format-date.md) | Ensure dates in strings match the specified `@format-date` annotation ||
| [`sort-keys`](https://github.com/ronparkdev/eslint-plugin-annotation/blob/master/documents/sort-keys.md) | Sort interface properties or object keys if has `@sort-keys` annotation | ✔️ |
| [`sort`](https://github.com/ronparkdev/eslint-plugin-annotation/blob/master/documents/sort.md) | Sort array values if has `@sort` annotation | ✔️ |
| [`unique`](https://github.com/ronparkdev/eslint-plugin-annotation/blob/master/documents/unique.md) | Ensure array values are unique if annotated with `@unique` | ✔️ |

# License
BSD License
Expand Down
35 changes: 35 additions & 0 deletions documents/unique.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# eslint-plugin-annotation/unique
Ensure array values are unique if annotated with `@unique`

## Annotation options
* `@unique` : Ensure all values in the array are unique

### Lint Success Case
```javascript
// @unique
const ids = [1, 2, 3, 4, 5];

// @unique
const names = ["Alice", "Bob", "Charlie"];
```

### Lint Failure Case
```javascript
// @unique
const ids = [1, 2, 2, 4, 5];

// @unique
const names = ["Alice", "Bob", "Alice"];
```

### My best case to use this rule that :
If you frequently work with arrays that require unique values, using this rule can help enforce uniqueness across your codebase.

```javascript
// @unique
const userIds = [101, 102, 103, 104];

// @unique
const userNames = ["John", "Doe", "Jane", "Smith"];
```
Ensuring all values in the array are unique can help avoid issues with duplicate entries in your application.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "eslint-plugin-annotation",
"version": "1.1.2",
"version": "1.1.5",
"description": "Lint rules to validate and auto-correct annotation-based policies",
"main": "dist/index.js",
"scripts": {
"publish": "npm run clean && npm run build && npm publish",
"prepublishOnly": "npm run clean && npm run build",
"build": "tsc -p tsconfig.build.json",
"clean": "rm -rf dist",
"format": "prettier --write src/**/*.ts",
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import formatDate from './rules/format-date'
import sort from './rules/sort'
import sortKeys from './rules/sort-keys'
import unique from './rules/unique'

// Import all rules in lib/rules
module.exports.rules = {
'format-date': formatDate,
sort: sort,
'sort-keys': sortKeys,
unique: unique,
}
56 changes: 56 additions & 0 deletions src/rules/unique.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createRule } from '../utils/createRule'
import { ConfigUtils } from '../utils/config'

type Options = []

export const DUPLICATE_VALUES_MESSAGE_ID = 'duplicateValues'

type MessageIds = typeof DUPLICATE_VALUES_MESSAGE_ID

export default createRule<Options, MessageIds>({
name: 'unique',
meta: {
docs: {
description: 'Ensure array values are unique if annotated with @unique',
recommended: 'error',
suggestion: false,
},
fixable: 'code',
type: 'problem',
schema: [],
messages: {
[DUPLICATE_VALUES_MESSAGE_ID]: 'Array contains duplicate values.',
},
},
defaultOptions: [],
create(context) {
const sourceCode = context.getSourceCode()

return {
ArrayExpression(node) {
const commentExpectedEndLine = node.loc.start.line - 1
const config = ConfigUtils.getConfig(sourceCode, '@unique', commentExpectedEndLine)

if (!config) {
return
}

const elements = node.elements
const uniqueElements = Array.from(
new Set(elements.map((element) => (element === null ? '' : sourceCode.getText(element)))),
)

if (elements.length !== uniqueElements.length) {
context.report({
node,
messageId: DUPLICATE_VALUES_MESSAGE_ID,
fix(fixer) {
const fixedArray = uniqueElements.join(', ')
return fixer.replaceText(node, `[${fixedArray}]`)
},
})
}
},
}
},
})
90 changes: 90 additions & 0 deletions tests/unique.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import path from 'path'

import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'

const { RuleTester } = ESLintUtils

import rule from '../src/rules/unique'

const getFilename = (filePath: string): string => path.resolve('./tests', filePath)

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
ecmaVersion: 2015,
project: getFilename('tsconfig.json'),
sourceType: 'module',
},
})

ruleTester.run('unique', rule, {
valid: [
{
code: `
// @unique
const ids = [1, 2, 3, 4, 5];
`,
filename: getFilename('main.ts'),
},
{
code: `
// @unique
const names = ["Alice", "Bob", "Charlie"];
`,
filename: getFilename('main.ts'),
},
{
code: `
// @unique
const mixed = [1, "2", null, true, false];
`,
filename: getFilename('main.ts'),
},
{
code: `
// @unique
const sparseArray = [1, 2, , 3];
`,
filename: getFilename('main.ts'),
},
],
invalid: [
{
code: `
// @unique
const ids = [1, 2, 2, 4, 5];
`,
errors: [{ messageId: 'duplicateValues', type: AST_NODE_TYPES.ArrayExpression }],
output: `
// @unique
const ids = [1, 2, 4, 5];
`,
filename: getFilename('main.ts'),
},
{
code: `
// @unique
const names = ["Alice", "Bob", "Alice"];
`,
errors: [{ messageId: 'duplicateValues', type: AST_NODE_TYPES.ArrayExpression }],
output: `
// @unique
const names = ["Alice", "Bob"];
`,
filename: getFilename('main.ts'),
},
{
code: `
// @unique
const sparseArray = [1, 2, , 1];
`,
errors: [{ messageId: 'duplicateValues', type: AST_NODE_TYPES.ArrayExpression }],
output: `
// @unique
const sparseArray = [1, 2, ];
`,
filename: getFilename('main.ts'),
},
],
})

0 comments on commit 620a94f

Please sign in to comment.