Repository: infctr/eslint-plugin-typescript-sort-keys
Branch: master
Commit: d32e4dada117
Files: 44
Total size: 151.0 KB
Directory structure:
gitextract__n8p3j18/
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│ └── workflows/
│ ├── publish.yml
│ └── tests.yml
├── .gitignore
├── .huskyrc.js
├── .prettierignore
├── .prettierrc.js
├── .yarnrc
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── babel.config.js
├── docs/
│ └── rules/
│ ├── interface.md
│ └── string-enum.md
├── jest.config.js
├── lint-staged.config.js
├── package.json
├── rollup.config.js
├── src/
│ ├── common/
│ │ └── options.ts
│ ├── config/
│ │ └── recommended.ts
│ ├── index.ts
│ ├── rules/
│ │ ├── index.ts
│ │ ├── interface.ts
│ │ └── string-enum.ts
│ └── utils/
│ ├── ast.ts
│ ├── common.ts
│ ├── compare.ts
│ ├── plugin.ts
│ └── rule.ts
├── tests/
│ ├── autofix.spec.ts
│ ├── config.spec.ts
│ ├── fixtures/
│ │ ├── autofix.input.ts
│ │ ├── autofix.output.ts
│ │ └── requiredFirst.output.ts
│ ├── helpers/
│ │ ├── configs.ts
│ │ ├── tsconfig.json
│ │ └── util.ts
│ ├── rules/
│ │ ├── .prettierrc.js
│ │ ├── interface.spec.ts
│ │ └── string-enum.spec.ts
│ └── tsconfig.json
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
quote_type = single
================================================
FILE: .eslintignore
================================================
tests/fixtures/**
dist
lib
build
================================================
FILE: .eslintrc.js
================================================
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin', 'import', 'jest', 'prettier'],
env: {
es6: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:eslint-plugin/all',
'plugin:prettier/recommended',
],
parserOptions: {
ecmaVersion: 10,
sourceType: 'module',
},
rules: {
'no-console': 'warn',
},
overrides: [
{
files: ['*.ts', '*.tsx'],
extends: ['plugin:import/typescript', 'plugin:@typescript-eslint/recommended'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
parserOptions: {
project: ['./tsconfig.json', './tests/tsconfig.json'],
},
overrides: [
{
files: ['tests/**'],
env: {
jest: true,
},
rules: {
'jest/no-disabled-tests': 'warn',
'jest/no-focused-tests': 'error',
'jest/no-alias-methods': 'error',
'jest/no-identical-title': 'error',
'jest/no-jasmine-globals': 'error',
'jest/no-test-prefixes': 'error',
'jest/no-test-return-statement': 'error',
'jest/prefer-to-have-length': 'warn',
'jest/prefer-spy-on': 'error',
'jest/valid-expect': 'error',
'jest/no-test-callback': 'off',
},
},
],
},
],
settings: {
'import/resolver': {
node: {
moduleDirectory: ['node_modules', 'src'],
},
},
},
}
================================================
FILE: .github/workflows/publish.yml
================================================
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
name: Publish
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 18
- run: yarn
- run: yarn verify
publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- run: yarn
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
================================================
FILE: .github/workflows/tests.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Tests
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn verify
env:
CI: true
================================================
FILE: .gitignore
================================================
.DS_Store
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# IDE
.vscode
# Build artifacts
dist
build
lib
================================================
FILE: .huskyrc.js
================================================
module.exports = {
hooks: {
'pre-commit': 'lint-staged',
},
}
================================================
FILE: .prettierignore
================================================
tests/fixtures/**
build
dist
lib
================================================
FILE: .prettierrc.js
================================================
module.exports = {
printWidth: 90,
trailingComma: 'all',
arrowParens: 'avoid',
semi: false,
}
================================================
FILE: .yarnrc
================================================
save-prefix "~"
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.3.0] - 2024-10-05
### Changed
- Update @typescript-eslint/parser to >=6
## [3.2.0] - 2024-02-26
### Changed
- Update @typescript-eslint/parser to v7
## [3.1.0] - 2023-10-15
### Changed
- Fix esm export paths in config
## [3.0.0] - 2023-08-30
### Changed
- [BREAKING] Minimal required node.js version is v16
- [BREAKING] Update @typescript-eslint/parser to v6 🎉
## [2.3.0] - 2023-03-17
### Changed
- Bump deps to fix security vulnerabilities
## [2.2.0] - 2023-03-17
### Changed
- Bump peer dependencies
## [2.1.0] - 2021-11-23
### Changed
- Bump deps to fix security vulnerabilities
## [2.0.0] - 2021-10-15
### Changed
- [BREAKING] Drop support for node v10
- [BREAKING] Update to eslint v8 🎉
## [1.8.0] - 2021-08-17
### Changed
- Update super old `@typescript-eslint/experimental-utils` dependency
- Update dev dependencies
## [1.7.0] - 2021-06-18
### Changed
- Update dependencies with security issues
- Update dev dependencies
## [1.6.0] - 2021-04-02
### Changed
- Update dependencies with security issues
- Update `package.json` `export` field
## [1.5.0] - 2020-09-22
### Changed
- Use `^` to pin dependencies
## [1.4.0] - 2020-09-22
### Changed
- Support typescript v4 and @typescript-eslint/parser v4 as peer deps
## [1.3.0] - 2020-07-16
### Changed
- Bump @typescript-eslint/parser to v3.5.0
## [1.2.0] - 2020-05-24
### Added
- Explicitly list supported node versions
### Fixed
- Node conditional exports paths
## [1.1.0] - 2020-05-24
### Fixed
- Add explicit dependency of json-schema for @typescript-eslint/experimental-utils
## [1.0.2] - 2020-05-22
### Changed
- Update build artifacts
## [1.0.1] - 2020-05-22
### Fixed
- Fix hanging Publish github action
## [1.0.0] - 2020-05-22
### Changed
- Rewrite to typescript with strong types
- Leverage helpers and types from @typescript-eslint/experimental-utils
- Run autofix tests with ESLint Class rather than spawn a child process for eslint runner
- Heavy refactoring and remove code paths that were never taken
- Update ESLint config
- Update to ESLint v7.0.0
- Update dependencies
### Added
- Follow semver
- Rollup bundler
## [0.10.0] - 2020-05-21
### Added
- Add ESLint 7 to peerDependencies
## [0.9.0] - 2020-05-19
### Added
- New option to `interface` rule: `requiredFirst` - if `true`, enforce optional properties to come after required ones.
## [0.8.0] - 2020-04-02
### Added
- License
### Fixed
- Fix linter crash on accessing node key name
[3.3.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v3.2.0...v3.3.0
[3.2.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v3.1.0...v3.2.0
[3.1.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v3.0.0...v3.1.0
[3.0.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v2.3.0...v3.0.0
[2.3.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v2.2.0...v2.3.0
[2.2.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v2.1.0...v2.2.0
[2.1.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v2.0.0...v2.1.0
[2.0.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.8.0...v2.0.0
[1.8.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.7.0...v1.8.0
[1.7.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.6.0...v1.7.0
[1.6.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.5.0...v1.6.0
[1.5.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.4.0...v1.5.0
[1.4.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.0.2...v1.1.0
[1.0.2]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v0.10.0...v1.0.0
[0.10.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v0.9.0...v0.10.0
[0.9.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v0.8.0...v0.9.0
[0.8.0]: https://github.com/infctr/eslint-plugin-typescript-sort-keys/compare/v0.7.0...v0.8.0
================================================
FILE: LICENSE.md
================================================
Copyright (c) 2019, infctr
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
================================================
FILE: README.md
================================================

# eslint-plugin-typescript-sort-keys
Sort interface and string enum keys
Inspired by and sourced from [eslint/sort-keys]([https://github.com/eslint/eslint/blob/master/docs/rules/sort-keys.md](https://github.com/eslint/eslint/blob/main/docs/src/rules/sort-keys.md))
## Installation
You'll first need to install
- [eslint](http://eslint.org)
- [typescript](http://www.typescriptlang.org/)
- [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser)
```sh
yarn add -D eslint typescript @typescript-eslint/parser
```
Next, install `eslint-plugin-typescript-sort-keys`:
```sh
yarn add -D eslint-plugin-typescript-sort-keys
```
**Note:** If you installed ESLint globally then you must also install `eslint-plugin-typescript-sort-keys` globally.
## Usage
Specify the parser for typescript files in your `.eslintrc` configuration file:
```json
{
"parser": "@typescript-eslint/parser"
}
```
Add `typescript-sort-keys` to the plugins section. You can omit the `eslint-plugin-` prefix:
```json
{
"plugins": ["typescript-sort-keys"]
}
```
Then configure the rules you want to use under the rules section.
```json
{
"rules": {
"typescript-sort-keys/interface": "error",
"typescript-sort-keys/string-enum": "error"
}
}
```
Or enable all rules with defaults
```json
{
"extends": ["plugin:typescript-sort-keys/recommended"]
}
```
## Supported Rules
<!-- begin rule list -->
**Key**: :heavy_check_mark: = recommended, :wrench: = fixable
<!-- prettier-ignore -->
| Name | Description | :heavy_check_mark: | :wrench: |
| ---- | ----------- | ------------------ | -------- |
| [`typescript-sort-keys/interface`](./docs/rules/interface.md) | require interface keys to be sorted | :heavy_check_mark: | :wrench: |
| [`typescript-sort-keys/string-enum`](./docs/rules/string-enum.md) | require string enum members to be sorted | :heavy_check_mark: | :wrench: |
<!-- end rule list -->
================================================
FILE: babel.config.js
================================================
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
}
================================================
FILE: docs/rules/interface.md
================================================
# require interface keys to be sorted (interface)
When declaring multiple properties on an interface, some developers prefer to sort property names alphabetically to be able to find necessary property easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
## Rule Details
This rule checks all property definitions of an interface declaration and verifies that all keys are sorted alphabetically.
Examples of **incorrect** code for this rule:
```ts
/* eslint typescript-sort-keys/interface: "error" */
interface U {
a: T
c: T
b: T
}
interface U {
a: T
c: T
b: T
}
// Case-sensitive by default.
interface U {
a: T
b: T
C: T
}
// Non-natural order by default.
interface U {
1: T
2: T
10: T
}
// Non-required first order by default.
interface U {
b?: T
a: T
c: T
}
interface U {
a: T
['c']: T
b: T
}
```
Examples of **correct** code for this rule:
```ts
/* eslint typescript-sort-keys/interface: "error" */
interface U {
a: T
b: T
c: T
}
interface U {
a: T
b: T
c: T
}
// Case-sensitive by default.
interface U {
C: T
a: T
b: T
}
// Non-natural order by default.
interface U {
1: T
10: T
2: T
}
// Non-required first order by default.
interface U {
a: T
b?: T
c: T
}
// This rule checks computed properties which have a simple name as well.
interface U {
a: T
['b']: T
c: T
}
```
## Options
```json
{
"typescript-sort-keys/interface": [
"error",
"asc",
{ "caseSensitive": true, "natural": false, "requiredFirst": false }
]
}
```
The 1st option is `"asc"` or `"desc"`.
- `"asc"` (default) - enforce properties to be in ascending order.
- `"desc"` - enforce properties to be in descending order.
The 2nd option is an object which has 3 properties.
- `caseSensitive` - if `true`, enforce properties to be in case-sensitive order. Default is `true`.
- `natural` - if `true`, enforce properties to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.
- `requiredFirst` - if `true`, enforce optional properties to come after required ones.
Example for a list:
With `natural` as true, the ordering would be
1
3
6
8
10
With `natural` as false, the ordering would be
1
10
3
6
8
### desc
Examples of **incorrect** code for the `"desc"` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "desc"] */
interface U {
b: T
c: T
a: T
}
interface U {
b: T
c: T
a: T
}
// Case-sensitive by default.
interface U {
C: T
b: T
a: T
}
// Non-required first order by default.
interface U {
a: T
b?: T
c: T
}
// Non-natural order by default.
interface U {
10: T
2: T
1: T
}
```
Examples of **correct** code for the `"desc"` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "desc"] */
interface U {
c: T
b: T
a: T
}
interface U {
c: T
b: T
a: T
}
// Case-sensitive by default.
interface U {
b: T
a: T
C: T
}
// Non-required first order by default.
interface U {
c: T
b?: T
a: T
}
// Non-natural order by default.
interface U {
2: T
10: T
1: T
}
```
### insensitive
Examples of **incorrect** code for the `{ caseSensitive: false }` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { caseSensitive: false }] */
interface U {
a: T
c: T
C: T
b: T
}
interface U {
a: T
C: T
c: T
b: T
}
```
Examples of **correct** code for the `{ caseSensitive: false }` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { caseSensitive: false }] */
interface U {
a: T
b: T
c: T
C: T
}
interface U {
a: T
b: T
C: T
c: T
}
```
### natural
Examples of **incorrect** code for the `{natural: true}` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { natural: true }] */
interface U {
1: T
10: T
2: T
}
```
Examples of **correct** code for the `{natural: true}` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { natural: true }] */
interface U {
1: T
2: T
10: T
}
```
### required
Examples of **incorrect** code for the `{ requiredFirst: true }` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { requiredFirst: true }] */
interface U {
d: T
c?: T
b?: T
a: T
}
```
Examples of **correct** code for the `{ requiredFirst: true }` option:
```ts
/* eslint typescript-sort-keys/interface: ["error", "asc", { requiredFirst: true }] */
interface U {
a: T
d: T
b?: T
c?: T
}
```
## When Not To Use It
If you don't want to notify about properties' order, then it's safe to disable this rule.
================================================
FILE: docs/rules/string-enum.md
================================================
# require string enum members to be sorted (string-enum)
When declaring multiple members on an string enum, some developers prefer to sort enum member names alphabetically to be able to find necessary members easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
## Rule Details
This rule checks all members of a string enum declaration and verifies that all keys are sorted alphabetically.
Examples of **incorrect** code for this rule:
```ts
/* eslint typescript-sort-keys/string-enum: "error" */
enum U {
a = 'T',
c = 'T',
b = 'T',
}
enum U {
a = 'T',
c = 'T',
b = 'T',
}
// Case-sensitive by default.
enum U {
a = 'T',
b = 'T',
C = 'T',
}
enum U {
a = 'T',
'c' = 'T',
b = 'T',
}
```
Examples of **correct** code for this rule:
```ts
/* eslint typescript-sort-keys/string-enum: "error" */
enum U {
a = 'T',
b = 'T',
c = 'T',
}
enum U {
a = 'T',
b = 'T',
c = 'T',
}
// Case-sensitive by default.
enum U {
C = 'T',
a = 'T',
b = 'T',
}
// This rule checks computed properties which have a simple name as well.
enum U {
a = 'T',
'b' = 'T',
c = 'T',
}
```
## Options
```json
{
"typescript-sort-keys/string-enum": ["error", "asc", { "caseSensitive": true }]
}
```
The 1st option is `"asc"` or `"desc"`.
- `"asc"` (default) - enforce enum members to be in ascending order.
- `"desc"` - enforce enum members to be in descending order.
The 2nd option is an object which has 2 properties.
- `caseSensitive` - if `true`, enforce enum members to be in case-sensitive order. Default is `true`.
- `natural` - if `true`, enforce enum members to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.
### desc
Examples of **incorrect** code for the `"desc"` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "desc"] */
enum U {
b = 'T',
c = 'T',
a = 'T',
}
enum U {
b = 'T',
c = 'T',
a = 'T',
}
// Case-sensitive by default.
enum U {
C = 'T',
b = 'T',
a = 'T',
}
```
Examples of **correct** code for the `"desc"` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "desc"] */
enum U {
c = 'T',
b = 'T',
a = 'T',
}
enum U {
c = 'T',
b = 'T',
a = 'T',
}
// Case-sensitive by default.
enum U {
b = 'T',
a = 'T',
C = 'T',
}
```
### insensitive
Examples of **incorrect** code for the `{ caseSensitive: false }` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "asc", { caseSensitive: false }] */
enum U {
a = 'T',
c = 'T',
C = 'T',
b = 'T',
}
enum U {
a = 'T',
C = 'T',
c = 'T',
b = 'T',
}
```
Examples of **correct** code for the `{ caseSensitive: false }` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "asc", { caseSensitive: false }] */
enum U {
a = 'T',
b = 'T',
c = 'T',
C = 'T',
}
enum U {
a = 'T',
b = 'T',
C = 'T',
c = 'T',
}
```
### natural
Examples of **incorrect** code for the `{natural: true}` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "asc", { natural: true }] */
enum U {
a = 'T',
_ = 'T',
A = 'T',
$ = 'T',
}
```
Examples of **correct** code for the `{natural: true}` option:
```ts
/* eslint typescript-sort-keys/string-enum: ["error", "asc", { natural: true }] */
enum U {
a = 'T',
A = 'T',
_ = 'T',
$ = 'T',
}
```
## When Not To Use It
If you don't want to notify about enum members' order, then it's safe to disable this rule.
================================================
FILE: jest.config.js
================================================
module.exports = {
testRegex: 'tests/.*\\.spec\\.(js|ts)$',
moduleDirectories: ['node_modules', 'src'],
}
================================================
FILE: lint-staged.config.js
================================================
module.exports = {
'*.{js,ts}': ['eslint --fix --ext js,jsx,tsx,ts --max-warnings 0 --no-ignore'],
'*.{md,yml,json}': ['prettier --write'],
}
================================================
FILE: package.json
================================================
{
"name": "eslint-plugin-typescript-sort-keys",
"version": "3.3.0",
"description": "Sort interface and string enum keys",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"typescript"
],
"author": "infctr <infctr@gmail.com>",
"main": "./lib/index.cjs.js",
"repository": "git@github.com:infctr/eslint-plugin-typescript-sort-keys.git",
"url": "https://github.com/infctr/eslint-plugin-typescript-sort-keys",
"files": [
"/lib",
"package.json",
"CHANGELOG.md",
"LICENSE.md",
"README.md"
],
"exports": {
".": {
"import": "./lib/index.mjs",
"require": "./lib/index.cjs.js",
"default": "./lib/index.cjs.js"
},
"./package.json": "./package.json"
},
"scripts": {
"prepublishOnly": "yarn compile",
"build": "yarn rimraf lib && yarn compile",
"compile": "yarn rollup -c",
"docs": "eslint-docs",
"docs:check": "eslint-docs check",
"lint": "eslint --ext .js,.ts src/ tests/",
"format": "prettier --write src/**/*.{js,ts} tests/**/*.{js,ts}",
"test": "yarn jest --watch",
"coverage": "yarn test --coverage --watchAll=false",
"coverage-preview": "http-server -o -p 5000 coverage/lcov-report",
"typecheck": "tsc --noEmit --skipLibCheck",
"verify": "yarn typecheck && yarn lint && yarn build && yarn coverage"
},
"dependencies": {
"@typescript-eslint/experimental-utils": "^5.0.0",
"json-schema": "^0.4.0",
"natural-compare-lite": "^1.4.0"
},
"devDependencies": {
"@babel/cli": "~7.14.8",
"@babel/core": "~7.15.0",
"@babel/preset-env": "~7.15.0",
"@babel/preset-typescript": "~7.15.0",
"@infctr/eslint-docs": "~0.4.0",
"@rollup/plugin-commonjs": "~12.0.0",
"@rollup/plugin-json": "~4.0.3",
"@rollup/plugin-node-resolve": "~8.0.0",
"@rollup/plugin-typescript": "~11.1.2",
"@types/babel__core": "~7.1.7",
"@types/babel__preset-env": "~7.9.0",
"@types/eslint": "~7.28.1",
"@types/jest": "~27.0.2",
"@types/natural-compare-lite": "~1.4.0",
"@types/rimraf": "~3.0.1",
"@types/tmp": "~0.2.1",
"@typescript-eslint/eslint-plugin": "~6.4.0",
"@typescript-eslint/parser": "~6.4.0",
"babel-jest": "~26.6.3",
"babel-plugin-module-resolver": "~4.1.0",
"eslint": "~8.0.1",
"eslint-config-prettier": "~9.0.0",
"eslint-plugin-eslint-plugin": "~5.1.1",
"eslint-plugin-import": "~2.28.0",
"eslint-plugin-jest": "~27.2.3",
"eslint-plugin-prettier": "~5.0.0",
"http-server": "~13.0.0",
"husky": "~4.2.5",
"jest": "~29.6.2",
"lint-staged": "~10.5.4",
"prettier": "3.0.1",
"rimraf": "~3.0.2",
"rollup": "~2.10.5",
"tmp": "~0.2.1",
"tsconfig": "~7.0.0",
"typescript": "5.1.6"
},
"peerDependencies": {
"@typescript-eslint/parser": ">=6",
"eslint": "^7 || ^8",
"typescript": "^3 || ^4 || ^5"
},
"engines": {
"node": ">= 16"
},
"license": "ISC"
}
================================================
FILE: rollup.config.js
================================================
import commonjs from '@rollup/plugin-commonjs'
import resolve from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
import json from '@rollup/plugin-json'
import tsconfig from 'tsconfig'
import fs from 'fs'
import assert from 'assert'
const filePath = tsconfig.resolveSync('.')
assert(filePath)
const config = tsconfig.readFileSync(filePath)
const baseUrl = config.compilerOptions.baseUrl
const moduleMappings = fs
.readdirSync(baseUrl, { withFileTypes: true })
.filter(dir => dir.isDirectory())
.map(dir => [dir.name, '/'].join(''))
const external = id =>
!id.startsWith('.') &&
!id.startsWith('/') &&
!id.startsWith('\0') &&
!moduleMappings.some(mapping => id.startsWith(mapping))
export default [
{
input: './src/index.ts',
external,
output: [
{ dir: 'lib', entryFileNames: '[name].cjs.js', format: 'cjs' },
{ dir: 'lib', entryFileNames: '[name].mjs', format: 'es' },
],
plugins: [commonjs(), resolve(), typescript(), json()],
},
]
================================================
FILE: src/common/options.ts
================================================
import { JSONSchema4 } from 'json-schema'
export enum SortingOrder {
Ascending = 'asc',
Descending = 'desc',
}
export const sortingOrderOptionSchema: JSONSchema4 = {
enum: [SortingOrder.Ascending, SortingOrder.Descending],
}
export type SortingOrderOption = SortingOrder
interface CaseSensitiveSortingOption {
readonly caseSensitive: boolean
}
interface NaturalSortingOption {
readonly natural: boolean
}
interface RequiredFirstSortingOption {
readonly requiredFirst: boolean
}
export interface SortingParamsOptions {
readonly caseSensitive: CaseSensitiveSortingOption
readonly natural: NaturalSortingOption
readonly requiredFirst: RequiredFirstSortingOption
}
export enum ErrorMessage {
InterfaceInvalidOrder = `Expected interface keys to be in {{ requiredFirst }}{{ natural }}{{ insensitive }}{{ order }}ending order. '{{ thisName }}' should be before '{{ prevName }}'.`,
StringEnumInvalidOrder = `Expected string enum members to be in {{ natural }}{{ insensitive }}{{ order }}ending order. '{{ thisName }}' should be before '{{ prevName }}'.`,
}
================================================
FILE: src/config/recommended.ts
================================================
export default {
plugins: ['typescript-sort-keys'],
rules: {
'typescript-sort-keys/interface': 'error' as const,
'typescript-sort-keys/string-enum': 'error' as const,
},
}
================================================
FILE: src/index.ts
================================================
import recommended from './config/recommended'
import { rules } from './rules'
const config = {
rules,
configs: {
recommended,
},
}
export default config
================================================
FILE: src/rules/index.ts
================================================
import { name as interfaceName, rule as interfaceRule } from './interface'
import { name as stringEnumName, rule as stringEnumRule } from './string-enum'
export const rules = {
[interfaceName]: interfaceRule,
[stringEnumName]: stringEnumRule,
}
================================================
FILE: src/rules/interface.ts
================================================
import { JSONSchema4 } from 'json-schema'
import { getObjectBody } from 'utils/ast'
import { createReporter } from 'utils/plugin'
import { createRule, RuleMetaData } from 'utils/rule'
import {
sortingOrderOptionSchema,
SortingOrder,
ErrorMessage,
SortingOrderOption,
SortingParamsOptions,
} from 'common/options'
/**
* The name of this rule.
*/
export const name = 'interface' as const
type SortingParams = SortingParamsOptions['caseSensitive'] &
SortingParamsOptions['natural'] &
SortingParamsOptions['requiredFirst']
/**
* The options this rule can take.
*/
export type Options = [SortingOrderOption] | [SortingOrderOption, Partial<SortingParams>]
const sortingParamsOptionSchema: JSONSchema4 = {
type: 'object',
properties: {
caseSensitive: {
type: 'boolean',
},
natural: {
type: 'boolean',
},
requiredFirst: {
type: 'boolean',
},
},
additionalProperties: false,
}
/**
* The schema for the rule options.
*/
const schema: JSONSchema4[] = [sortingOrderOptionSchema, sortingParamsOptionSchema]
/**
* The default options for the rule.
*/
const defaultOptions: Options = [
SortingOrder.Ascending,
{ caseSensitive: true, natural: false, requiredFirst: false },
]
/**
* The possible error messages.
*/
const errorMessages = {
invalidOrder: ErrorMessage.InterfaceInvalidOrder,
} as const
/**
* The meta data for this rule.
*/
const meta: RuleMetaData<keyof typeof errorMessages> = {
type: 'suggestion',
docs: {
description: 'require interface keys to be sorted',
recommended: 'warn',
},
messages: errorMessages,
fixable: 'code',
schema,
}
/**
* Create the rule.
*/
export const rule = createRule<keyof typeof errorMessages, Options>({
name,
meta,
defaultOptions,
create(context) {
const compareNodeListAndReport = createReporter(context, ({ loc }) => ({
loc,
messageId: 'invalidOrder',
}))
return {
TSInterfaceDeclaration(node) {
const body = getObjectBody(node)
return compareNodeListAndReport(body)
},
TSTypeLiteral(node) {
const body = getObjectBody(node)
return compareNodeListAndReport(body)
},
}
},
})
================================================
FILE: src/rules/string-enum.ts
================================================
import { JSONSchema4 } from 'json-schema'
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'
import { getObjectBody } from 'utils/ast'
import { createReporter } from 'utils/plugin'
import { createRule, RuleMetaData } from 'utils/rule'
import {
sortingOrderOptionSchema,
SortingOrder,
ErrorMessage,
SortingOrderOption,
SortingParamsOptions,
} from 'common/options'
/**
* The name of this rule.
*/
export const name = 'string-enum' as const
type SortingParams = SortingParamsOptions['caseSensitive'] &
SortingParamsOptions['natural']
/**
* The options this rule can take.
*/
export type Options = [SortingOrderOption] | [SortingOrderOption, Partial<SortingParams>]
const sortingParamsOptionSchema: JSONSchema4 = {
type: 'object',
properties: {
caseSensitive: {
type: 'boolean',
},
natural: {
type: 'boolean',
},
},
additionalProperties: false,
}
/**
* The schema for the rule options.
*/
const schema: JSONSchema4[] = [sortingOrderOptionSchema, sortingParamsOptionSchema]
/**
* The default options for the rule.
*/
const defaultOptions: Options = [
SortingOrder.Ascending,
{ caseSensitive: true, natural: false },
]
/**
* The possible error messages.
*/
const errorMessages = {
invalidOrder: ErrorMessage.StringEnumInvalidOrder,
} as const
/**
* The meta data for this rule.
*/
const meta: RuleMetaData<keyof typeof errorMessages> = {
type: 'suggestion',
docs: {
description: 'require string enum members to be sorted',
recommended: 'warn',
},
messages: errorMessages,
fixable: 'code',
schema,
}
/**
* Create the rule.
*/
export const rule = createRule<keyof typeof errorMessages, Options>({
name,
meta,
defaultOptions,
create(context) {
const compareNodeListAndReport = createReporter(context, ({ loc }) => ({
loc,
messageId: 'invalidOrder',
}))
return {
TSEnumDeclaration(node) {
const body = getObjectBody(node) as TSESTree.TSEnumMember[]
const isStringEnum = body.every(
(member: TSESTree.TSEnumMember) =>
member.initializer &&
member.initializer.type === AST_NODE_TYPES.Literal &&
typeof member.initializer.value === 'string',
)
if (isStringEnum) {
compareNodeListAndReport(body)
}
},
}
},
})
================================================
FILE: src/utils/ast.ts
================================================
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'
import { indexSignature } from './common'
export function getObjectBody(
node:
| TSESTree.TSEnumDeclaration
| TSESTree.TSInterfaceDeclaration
| TSESTree.TSTypeLiteral,
) {
switch (node.type) {
case AST_NODE_TYPES.TSInterfaceDeclaration:
return node.body.body
case AST_NODE_TYPES.TSEnumDeclaration:
case AST_NODE_TYPES.TSTypeLiteral:
return node.members
}
}
function getProperty(node: TSESTree.Node) {
switch (node.type) {
case AST_NODE_TYPES.TSIndexSignature: {
const [identifier] = node.parameters
return {
...identifier,
// Override name for error message readability and weight calculation
name: indexSignature.create(
(identifier as TSESTree.Parameter & { name: string }).name,
),
}
}
case AST_NODE_TYPES.TSPropertySignature:
case AST_NODE_TYPES.TSMethodSignature:
return node.key
case AST_NODE_TYPES.TSEnumMember:
return node.id
default:
return undefined
}
}
/**
* Gets the property name of the given `Property` node.
*
* - If the property's key is an `Identifier` node, this returns the key's name
* whether it's a computed property or not.
* - If the property has a static name, this returns the static name.
* - Otherwise, this returns undefined.
*
* a.b // => "b"
* a["b"] // => "b"
* a['b'] // => "b"
* a[`b`] // => "b"
* a[100] // => "100"
* a[b] // => undefined
* a["a" + "b"] // => undefined
* a[tag`b`] // => undefined
* a[`${b}`] // => undefined
*
* let a = {b: 1} // => "b"
* let a = {["b"]: 1} // => "b"
* let a = {['b']: 1} // => "b"
* let a = {[`b`]: 1} // => "b"
* let a = {[100]: 1} // => "100"
* let a = {[b]: 1} // => undefined
* let a = {["a" + "b"]: 1} // => undefined
* let a = {[tag`b`]: 1} // => undefined
* let a = {[`${b}`]: 1} // => undefined
*/
export function getPropertyName(node: TSESTree.TypeElement | TSESTree.TSEnumMember) {
const property = getProperty(node)
if (!property) {
return undefined
}
switch (property.type) {
case AST_NODE_TYPES.Literal:
return String(property.value)
case AST_NODE_TYPES.Identifier:
return property.name
default:
return undefined
}
}
export function getPropertyIsOptional(
node: TSESTree.TypeElement | TSESTree.TSEnumMember,
) {
switch (node.type) {
case AST_NODE_TYPES.TSMethodSignature:
case AST_NODE_TYPES.TSPropertySignature:
return Boolean(node.optional)
}
return false
}
================================================
FILE: src/utils/common.ts
================================================
const nameToIndexSignature = (x: string) => `[index: ${x}]`
const indexSignatureRegexp = new RegExp(
`^${nameToIndexSignature('.+')}`.replace('[', '\\[').replace(']', '\\]'),
)
export const indexSignature = {
create: nameToIndexSignature,
regex: indexSignatureRegexp,
}
================================================
FILE: src/utils/compare.ts
================================================
import naturalCompare from 'natural-compare-lite'
import { indexSignature } from './common'
function charCompare(a: string, b: string) {
if (a < b) {
return -1
}
if (b < a) {
return 1
}
return 0
}
function getWeight(value: string) {
switch (true) {
// Custom name for index signature used here
case indexSignature.regex.test(value):
return 100
default:
return 0
}
}
function weightedCompare(
a: string,
b: string,
compareFn: (a: string, b: string) => number,
) {
return compareFn(a, b) - getWeight(a) + getWeight(b)
}
const ascending = (a: string, b: string) => {
return weightedCompare(a, b, charCompare)
}
const ascendingInsensitive = (a: string, b: string) => {
return weightedCompare(a.toLowerCase(), b.toLowerCase(), charCompare)
}
const ascendingNatural = (a: string, b: string) => {
return weightedCompare(a, b, naturalCompare)
}
const ascendingInsensitiveNatural = (a: string, b: string) => {
return weightedCompare(a.toLowerCase(), b.toLowerCase(), naturalCompare)
}
/**
* Functions which check that the given 2 names are in specific order.
*/
export const compareFn =
(isAscending: boolean, isInsensitive: boolean, isNatural: boolean) =>
(...args: [string?, string?]) => {
if (args.filter(Boolean).length !== 2) {
return 0
}
const input = (isAscending ? args : args.reverse()) as [string, string]
if (isInsensitive && isNatural) {
return ascendingInsensitiveNatural(...input)
}
if (!isInsensitive && isNatural) {
return ascendingNatural(...input)
}
if (isInsensitive && !isNatural) {
return ascendingInsensitive(...input)
}
return ascending(...input)
}
================================================
FILE: src/utils/plugin.ts
================================================
import { TSESTree, AST_TOKEN_TYPES } from '@typescript-eslint/experimental-utils'
import {
RuleContext as UtilRuleContext,
RuleFixer,
RuleFix,
SourceCode,
} from '@typescript-eslint/experimental-utils/dist/ts-eslint'
import assert from 'assert'
import { SortingOrder } from 'common/options'
import { Options as InterfaceRuleOptions } from 'rules/interface'
import { Options as StringEnumRuleOptions } from 'rules/string-enum'
import { getPropertyName, getPropertyIsOptional } from './ast'
import { compareFn } from './compare'
type RuleOptions = InterfaceRuleOptions & StringEnumRuleOptions
type TSType = TSESTree.TypeElement | TSESTree.TSEnumMember
function createNodeSwapper(context: UtilRuleContext<string, RuleOptions>) {
const sourceCode = context.getSourceCode() as SourceCode & {
lineStartIndices: number[]
}
/**
* Returns the indent range of a node if it's the first on its line.
* Otherwise, returns a range starting immediately after the previous sibling.
*/
function getIndentRange(node: TSESTree.Node | TSESTree.Comment): TSESTree.Range {
const prevSibling = sourceCode.getTokenBefore(node)
const end = node.range[0]
const start =
prevSibling && prevSibling.loc.start.line === node.loc.start.line
? prevSibling.range[1] + 1
: node.range[0] - node.loc.start.column
return [start, end]
}
function getRangeWithIndent(node: TSESTree.Comment) {
return [getIndentRange(node)[0], node.range[1]]
}
/**
* Returns the range for the entire line, including EOL, if node is the only
* token on its lines. Otherwise, returns the node range.
*/
function getLineRange(node: TSESTree.Comment): TSESTree.Range {
const [start] = getRangeWithIndent(node)
const index = sourceCode.lineStartIndices.findIndex(n => start === n)
if (index < 0) {
// Node is not at the beginning of the line
return node.range
}
const lines = 1 + node.loc.end.line - node.loc.start.line
return [
sourceCode.lineStartIndices[index],
sourceCode.lineStartIndices[index + lines],
]
}
function getIndentText(node: TSESTree.Node) {
return sourceCode.text.slice(...getIndentRange(node))
}
function getNodePunctuator(node: TSESTree.Node) {
const punctuator = sourceCode.getTokenAfter(node, {
filter: n => n.type === AST_TOKEN_TYPES.Punctuator && n.value !== ':',
includeComments: false,
})
// Check the punctuator value outside of filter because we
// want to stop traversal on any terminating punctuator
return punctuator && /^[,;]$/.test(punctuator.value) ? punctuator : undefined
}
return (
fixer: RuleFixer,
nodePositions: Map<TSType, { initial: number; final: number }>,
currentNode: TSType,
replaceNode: TSType,
) =>
[currentNode, replaceNode].reduce<RuleFix[]>((acc, node) => {
const otherNode = node === currentNode ? replaceNode : currentNode
const comments = sourceCode.getCommentsBefore(node)
const nextSibling = sourceCode.getTokenAfter(node)
const isLastReplacingLast =
nodePositions.get(node)?.final === nodePositions.size - 1 &&
nodePositions.get(node)?.final === nodePositions.get(otherNode)?.initial
let text = [
comments.length ? getIndentText(node) : '',
sourceCode.getText(node),
].join('')
// If nextSibling is the node punctuator, remove it
if (nextSibling === getNodePunctuator(node)) {
acc.push(fixer.remove(nextSibling))
}
if (!/[,;]$/.test(text)) {
// Add a punctuator if the node doesn't already have one
text += ','
}
if (isLastReplacingLast) {
// If we're moving the last node to its final destination, we can remove the punctuator
text = text.replace(/,$/, '')
}
if (comments.length) {
// Insert leading comments above the other node
acc.push(
fixer.insertTextBefore(
otherNode,
comments
.map(comment => sourceCode.getText(comment as any))
.concat('')
.join('\n'),
),
)
}
acc.push(
// Insert the node before the other node
fixer.insertTextBefore(otherNode, text),
// Remove the original instance of node
fixer.remove(node),
// Remove the original instances of node comments
...comments.map(n => fixer.removeRange(getLineRange(n))),
)
return acc
}, [])
}
export function createReporter<MessageIds extends string>(
context: UtilRuleContext<MessageIds, RuleOptions>,
createReportObject: (node: TSESTree.Node) => {
readonly loc: TSESTree.SourceLocation
readonly messageId: MessageIds
},
) {
// Parse options.
const order = context.options[0] || SortingOrder.Ascending
const options = context.options[1]
const isAscending = order === SortingOrder.Ascending
const isInsensitive = (options && options.caseSensitive) === false
const isNatural = Boolean(options && options.natural)
const isRequiredFirst = (options && options.requiredFirst) === true
const compare = compareFn(isAscending, isInsensitive, isNatural)
const swapNodes = createNodeSwapper(context)
return (body: TSType[]) => {
const sortedBody = isRequiredFirst
? [
...body
.slice(0)
.filter(node => !getPropertyIsOptional(node))
.sort((a, b) => compare(getPropertyName(a), getPropertyName(b))),
...body
.slice(0)
.filter(node => getPropertyIsOptional(node))
.sort((a, b) => compare(getPropertyName(a), getPropertyName(b))),
]
: body.slice(0).sort((a, b) => compare(getPropertyName(a), getPropertyName(b)))
const nodePositions = new Map(
body.map(n => [n, { initial: body.indexOf(n), final: sortedBody.indexOf(n) }]),
)
for (let i = 1; i < body.length; i += 1) {
const prevNode = body[i - 1]
const currentNode = body[i]
const prevNodeName = getPropertyName(prevNode)
const currentNodeName = getPropertyName(currentNode)
if (
(!isRequiredFirst && compare(prevNodeName, currentNodeName) > 0) ||
(isRequiredFirst &&
getPropertyIsOptional(prevNode) === getPropertyIsOptional(currentNode) &&
compare(prevNodeName, currentNodeName) > 0) ||
(isRequiredFirst &&
getPropertyIsOptional(prevNode) !== getPropertyIsOptional(currentNode) &&
getPropertyIsOptional(prevNode))
) {
const targetPosition = sortedBody.indexOf(currentNode)
const replaceNode = body[targetPosition]
const { loc, messageId } = createReportObject(currentNode)
// Sanity check
assert(loc, 'createReportObject return value must include a node location')
assert(
messageId,
'createReportObject return value must include a problem message',
)
context.report({
loc,
messageId,
node: currentNode,
data: {
thisName: currentNodeName,
prevName: prevNodeName,
order,
insensitive: isInsensitive ? 'insensitive ' : '',
natural: isNatural ? 'natural ' : '',
requiredFirst: isRequiredFirst ? 'required first ' : '',
},
fix: fixer => {
if (currentNode !== replaceNode) {
return swapNodes(fixer, nodePositions, currentNode, replaceNode)
}
return null
},
})
}
}
}
}
================================================
FILE: src/utils/rule.ts
================================================
import { ESLintUtils } from '@typescript-eslint/experimental-utils'
import {
ReportDescriptor,
RuleContext as UtilRuleContext,
RuleListener,
RuleMetaData as UtilRuleMetaData,
RuleMetaDataDocs as UtilRuleMetaDataDocs,
RuleModule,
} from '@typescript-eslint/experimental-utils/dist/ts-eslint'
export type BaseOptions = readonly unknown[]
// "url" will be set automatically.
export type RuleMetaDataDocs = Omit<UtilRuleMetaDataDocs, 'url'>
// "docs.url" will be set automatically.
export type RuleMetaData<MessageIds extends string> = {
readonly docs: RuleMetaDataDocs
} & Omit<UtilRuleMetaData<MessageIds>, 'docs'>
export type RuleResult<MessageIds extends string, Options extends BaseOptions> = {
readonly context: UtilRuleContext<MessageIds, Options>
readonly descriptors: readonly ReportDescriptor<MessageIds>[]
}
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
/**
* Create a rule.
*/
export function createRule<MessageIds extends string, Options extends BaseOptions>(data: {
readonly name: string
readonly meta: RuleMetaData<MessageIds>
readonly defaultOptions: Options
readonly create: (
context: UtilRuleContext<MessageIds, Options>,
optionsWithDefault: Mutable<Options>,
) => RuleListener
}): RuleModule<MessageIds, Options, RuleListener> {
return ESLintUtils.RuleCreator(
name =>
`https://github.com/infctr/eslint-plugin-typescript-sort-keys/blob/master/docs/rules/${name}.md`,
)(data)
}
================================================
FILE: tests/autofix.spec.ts
================================================
import path from 'path'
import fs from 'fs'
import tmp from 'tmp'
import { ESLint, Linter } from 'eslint'
import plugin from '../src'
import recommended from 'config/recommended'
import { SortingOrder } from 'common/options'
import { typescript } from './helpers/configs'
describe('autofix', () => {
beforeEach(() => {
tmp.setGracefulCleanup()
})
it.each([
[recommended, 'autofix.output.ts'],
[
{
plugins: recommended.plugins,
rules: {
...recommended.rules,
'typescript-sort-keys/interface': [
'error' as const,
SortingOrder.Ascending,
{ caseSensitive: true, natural: true, requiredFirst: true },
] as Linter.RuleEntry,
},
},
'requiredFirst.output.ts',
],
])(
'should autofix and properly format comments and indent level',
async (config, fileName) => {
const { name: tmpDir } = tmp.dirSync({
prefix: 'typescript-sort-keys-',
unsafeCleanup: true,
})
const testFilePath = path.join(tmpDir, 'autofix.ts')
const input = fs.readFileSync('tests/fixtures/autofix.input.ts', 'utf8')
const expected = fs.readFileSync(`tests/fixtures/${fileName}`, 'utf8')
fs.writeFileSync(testFilePath, input)
const eslint = new ESLint({
overrideConfig: {
...config,
parser: typescript.parser,
parserOptions: { sourceType: 'module' },
},
plugins: {
'typescript-sort-keys': plugin,
},
useEslintrc: false,
fix: true,
})
const results = await eslint.lintFiles(testFilePath)
const result = results[0]
expect(result.messages).toHaveLength(0)
expect(result.errorCount).toBe(0)
expect(result.warningCount).toBe(0)
expect(result.fixableErrorCount).toBe(0)
expect(result.fixableWarningCount).toBe(0)
await ESLint.outputFixes(results)
const output = fs.readFileSync(testFilePath, 'utf8')
expect(output).toStrictEqual(expected)
},
)
})
================================================
FILE: tests/config.spec.ts
================================================
import { readdirSync } from 'fs'
import plugin from '../src'
describe('recommended config', () => {
const RULE_NAME_PREFIX = 'typescript-sort-keys/'
const {
rules,
configs: {
recommended: { rules: configRules },
},
} = plugin
const entriesToObject = <T = unknown>(
value: readonly [string, T][],
): Record<string, T> => {
return value.reduce<Record<string, T>>((memo, [k, v]) => {
memo[k] = v
return memo
}, {})
}
const ruleConfigs = Object.entries(rules)
.filter(([, rule]) => rule.meta.docs && rule.meta.docs.recommended !== false)
.map<[string, string]>(([name, rule]) => [
`${RULE_NAME_PREFIX}${name}`,
rule.meta.docs && rule.meta.docs.recommended ? 'error' : 'off',
])
it('contains all recommended rules', () => {
expect(entriesToObject(ruleConfigs)).toEqual(configRules)
})
})
describe('plugin', () => {
const ruleFiles: readonly string[] = readdirSync('./src/rules').filter(
file => file !== 'index.ts' && file.endsWith('.ts'),
)
const configFiles: readonly string[] = readdirSync('./src/config').filter(
file => file !== 'index.ts' && file.endsWith('.ts'),
)
it('should have all the rules', () => {
expect(plugin).toHaveProperty('rules')
expect(Object.keys(plugin.rules)).toHaveLength(ruleFiles.length)
})
it('should have all the configs', () => {
expect(plugin).toHaveProperty('configs')
expect(Object.keys(plugin.configs)).toHaveLength(configFiles.length)
})
})
================================================
FILE: tests/fixtures/autofix.input.ts
================================================
// So typescript treats this as a module
export {};
class GraphQLExtension<T> {_: T}
interface GraphQLResponse {}
namespace Koa {
export interface Context {}
}
const inlineArrow: (props: {foo: boolean; baz?: boolean; bar: boolean}) => null = ({...props}) => null;
const inlineArrow2: (props: {foo: boolean; bar?: boolean; baz: boolean}) => null = ({...props}) => null;
const inlineWeird: (props: {foo?: boolean;baz: boolean,
bar: boolean}) => null = ({...props}) => null;
function inlineGeneric<T extends { foo: boolean; baz?: boolean; bar: boolean}>({...props}: T | {foo: boolean; bar: boolean; baz?: boolean}) {
return null
}
enum InlineEnum {e="T", c="T", d="T", b="T", a="T"}
enum InlineEnum2 {Foo = 'FOO',Baz = 'BAZ', Bar = 'BAR' }
enum InlineEnum3 {b_="T", c="T", C="T"}
enum WeirdEnum {
Foo = 'FOO',Baz = 'BAZ', Bar = 'BAR',}
interface InlineInterface {e: "T"; c?:"T"; d:"T"; b:"T"; a?:"T"}
class Class extends GraphQLExtension<{
graphqlResponse: GraphQLResponse;
context?: Koa.Context;
}> {
public method(o: {
graphqlResponse: GraphQLResponse;
context?: Koa.Context;
}): void | { graphqlResponse?: GraphQLResponse; context?: Koa.Context } {
//
}
}
interface Interface {
/**
* %foo
*/
foo: boolean;
/* %baz */
baz?: boolean;
// %bar
bar: boolean;
}
type Type1<TKey extends string> = Partial<{
// %foo
foo?: boolean;
/* %baz */ baz: boolean;
/**
* %bar
*/
bar: boolean;
}> & {/* %foo */
foo?: boolean;
// %baz
baz: boolean;
/**
* %bar
*/
bar: boolean;
} & {
[K in keyof TKey]: boolean;
};
enum StringEnum {
/* %foo */
Foo = 'FOO',
// %baz
Baz = 'BAZ',
/**
* %bar
*/
Bar = 'BAR',
}
type Type2 = {/* %foo */
foo?: boolean;
// %baz
baz: boolean;
/**
* %bar
*/
bar: boolean;
}
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
new (hour: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
interface Methods {
/**
* %foo
*/
quux(): any;
qux?();
quuz?(): any;
foo: boolean;
/* %baz */
baz: boolean;
// %bar
bar(): boolean;
['grault']?(): void;
['corge']?(): void;
['garply']();
}
================================================
FILE: tests/fixtures/autofix.output.ts
================================================
// So typescript treats this as a module
export {};
class GraphQLExtension<T> {_: T}
interface GraphQLResponse {}
namespace Koa {
export interface Context {}
}
const inlineArrow: (props: {bar: boolean, baz?: boolean; foo: boolean;}) => null = ({...props}) => null;
const inlineArrow2: (props: {bar?: boolean; baz: boolean, foo: boolean;}) => null = ({...props}) => null;
const inlineWeird: (props: {bar: boolean,baz: boolean,
foo?: boolean;}) => null = ({...props}) => null;
function inlineGeneric<T extends { bar: boolean, baz?: boolean; foo: boolean;}>({...props}: T | {bar: boolean; baz?: boolean, foo: boolean;}) {
return null
}
enum InlineEnum {a="T", b="T", c="T", d="T", e="T"}
enum InlineEnum2 {Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO' }
enum InlineEnum3 {C="T", b_="T", c="T"}
enum WeirdEnum {
Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO'}
interface InlineInterface {a?:"T", b:"T"; c?:"T"; d:"T"; e: "T";}
class Class extends GraphQLExtension<{
context?: Koa.Context;
graphqlResponse: GraphQLResponse;
}> {
public method(o: {
context?: Koa.Context;
graphqlResponse: GraphQLResponse;
}): void | { context?: Koa.Context, graphqlResponse?: GraphQLResponse; } {
//
}
}
interface Interface {
// %bar
bar: boolean;
/* %baz */
baz?: boolean;
/**
* %foo
*/
foo: boolean;
}
type Type1<TKey extends string> = Partial<{
/**
* %bar
*/
bar: boolean;
/* %baz */ baz: boolean;
// %foo
foo?: boolean;
}> & {
/**
* %bar
*/
bar: boolean;
// %baz
baz: boolean;
/* %foo */
foo?: boolean;
} & {
[K in keyof TKey]: boolean;
};
enum StringEnum {
/**
* %bar
*/
Bar = 'BAR',
// %baz
Baz = 'BAZ',
/* %foo */
Foo = 'FOO'
}
type Type2 = {
/**
* %bar
*/
bar: boolean;
// %baz
baz: boolean;
/* %foo */
foo?: boolean;
}
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
new (hour: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
interface Methods {
// %bar
bar(): boolean;
/* %baz */
baz: boolean;
['corge']?(): void;
foo: boolean;
['garply']();
['grault']?(): void;
/**
* %foo
*/
quux(): any;
quuz?(): any;
qux?();
}
================================================
FILE: tests/fixtures/requiredFirst.output.ts
================================================
// So typescript treats this as a module
export {};
class GraphQLExtension<T> {_: T}
interface GraphQLResponse {}
namespace Koa {
export interface Context {}
}
const inlineArrow: (props: {bar: boolean, foo: boolean; baz?: boolean;}) => null = ({...props}) => null;
const inlineArrow2: (props: {baz: boolean, foo: boolean; bar?: boolean;}) => null = ({...props}) => null;
const inlineWeird: (props: {bar: boolean,baz: boolean,
foo?: boolean;}) => null = ({...props}) => null;
function inlineGeneric<T extends { bar: boolean, foo: boolean; baz?: boolean;}>({...props}: T | {bar: boolean; foo: boolean; baz?: boolean}) {
return null
}
enum InlineEnum {a="T", b="T", c="T", d="T", e="T"}
enum InlineEnum2 {Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO' }
enum InlineEnum3 {C="T", b_="T", c="T"}
enum WeirdEnum {
Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO'}
interface InlineInterface {b:"T"; d:"T"; e: "T"; a?:"T", c?:"T";}
class Class extends GraphQLExtension<{
graphqlResponse: GraphQLResponse;
context?: Koa.Context;
}> {
public method(o: {
graphqlResponse: GraphQLResponse;
context?: Koa.Context;
}): void | { context?: Koa.Context, graphqlResponse?: GraphQLResponse; } {
//
}
}
interface Interface {
// %bar
bar: boolean;
/**
* %foo
*/
foo: boolean;
/* %baz */
baz?: boolean;
}
type Type1<TKey extends string> = Partial<{
/**
* %bar
*/
bar: boolean;
/* %baz */ baz: boolean;
// %foo
foo?: boolean;
}> & {
/**
* %bar
*/
bar: boolean;
// %baz
baz: boolean;
/* %foo */
foo?: boolean;
} & {
[K in keyof TKey]: boolean;
};
enum StringEnum {
/**
* %bar
*/
Bar = 'BAR',
// %baz
Baz = 'BAZ',
/* %foo */
Foo = 'FOO'
}
type Type2 = {
/**
* %bar
*/
bar: boolean;
// %baz
baz: boolean;
/* %foo */
foo?: boolean;
}
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
new (hour: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
interface Methods {
// %bar
bar(): boolean;
/* %baz */
baz: boolean;
foo: boolean;
['garply']();
/**
* %foo
*/
quux(): any;
['corge']?(): void;
['grault']?(): void;
quuz?(): any;
qux?();
}
================================================
FILE: tests/helpers/configs.ts
================================================
import { Linter } from 'eslint'
import * as path from 'path'
export const filename = path.join(__dirname, 'file.ts')
export const typescript: Linter.Config = {
parser: require.resolve('@typescript-eslint/parser'),
parserOptions: {
sourceType: 'module',
project: path.join(__dirname, './tsconfig.json'),
},
}
================================================
FILE: tests/helpers/tsconfig.json
================================================
{
"compilerOptions": {
"lib": ["es2017"],
"module": "commonjs",
"moduleResolution": "node",
"skipLibCheck": true,
"target": "es2017"
},
"files": ["file.ts"]
}
================================================
FILE: tests/helpers/util.ts
================================================
import { RuleTester as ESLintRuleTester } from 'eslint'
import { filename } from './configs'
type OptionsSet<Options extends any[]> = {
/**
* The set of options this test case should pass for.
*/
readonly optionsSet: readonly (Options | [])[]
}
export type ValidTestCase<Options extends any[]> = Omit<
ESLintRuleTester.ValidTestCase,
'options'
> &
OptionsSet<Options>
export type InvalidTestCase<Options extends any[]> = Omit<
ESLintRuleTester.InvalidTestCase,
'options'
> &
OptionsSet<Options>
/**
* Convert our test cases into ones eslint test runner is expecting.
*/
export function processInvalidTestCase(
testCases: readonly InvalidTestCase<any>[],
): ESLintRuleTester.InvalidTestCase[] {
return testCases.flatMap(testCase =>
testCase.optionsSet.map(options => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { optionsSet, ...eslintTestCase } = testCase
return { filename, ...eslintTestCase, options }
}),
)
}
/**
* Convert our test cases into ones eslint test runner is expecting.
*/
export function processValidTestCase(
testCases: readonly ValidTestCase<any>[],
): ESLintRuleTester.ValidTestCase[] {
return processInvalidTestCase(testCases as any)
}
================================================
FILE: tests/rules/.prettierrc.js
================================================
module.exports = {
printWidth: 100,
trailingComma: 'all',
arrowParens: 'avoid',
semi: false,
}
================================================
FILE: tests/rules/interface.spec.ts
================================================
import { Rule, RuleTester } from 'eslint'
import { rule, name, Options } from 'rules/interface'
import { SortingOrder } from 'common/options'
import { typescript } from '../helpers/configs'
import {
InvalidTestCase,
processInvalidTestCase,
processValidTestCase,
ValidTestCase,
} from '../helpers/util'
const valid: readonly ValidTestCase<Options>[] = [
/**
* default, asc, caseSensitive
*/
{
code: 'interface U {_:T; a:T; b:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; b:T; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; b:T; b_:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {C:T; b_:T; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {$:T; A:T; _:T; a:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {1:T; '11':T; 2:T; A:T;}",
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {'#':T; 'Z':T; À:T; è:T;}",
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* computed
*/
{
code: 'interface U {a:T; ["ab"]:T; b:T; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* nested
*/
{
code: 'interface U {a:T; b:{x:T; y:T;}; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; b:{x:T; y:T; z:{i:T; j:T;};}; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'type U = {a:T; b:{x:T; y:T;}; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'type U = {a:T; b:{x:T; y:T; z:{i:T; j:T;};}; c:T;}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* asc, insensitive
*/
{
code: 'interface U {_:T; a:T; b:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {a:T; b:T; c:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {a:T; b:T; b_:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {b_:T; C:T; c:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "interface U {1:T; '11':T; 2:T; A:T;}",
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "interface U {'#':T; 'Z':T; À:T; è:T;}",
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
/**
* asc, natural, insensitive
*/
{
code: 'interface U {_:T; a:T; b:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {a:T; b:T; c:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {a:T; b:T; b_:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; C:T; c:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {1:T; 2:T; '11':T; A:T;}",
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {'#':T; 'Z':T; À:T; è:T;}",
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
/**
* asc, natural, insensitive, required
*/
{
code: 'interface U {_:T; b:T; a?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {a:T; c:T; b?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b:T; b_:T; a?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {C:T; c:T; b_?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {c:T; C:T; b_?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {$:T; _:T; A?:T; a?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {1:T; '11':T; A:T; 2?:T;}",
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {'Z':T; À:T; è:T; '#'?:T;}",
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
/**
* asc, required
*/
{
code: 'interface U {_:T; b:T; a?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: 'interface U {a:T; c:T; b?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: 'interface U {b:T; b_:T; a?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: 'interface U {C:T; c:T; b_?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: 'interface U {1:T; 11:T; 9:T; 111?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: 'interface U {$:T; _:T; A?:T; a?:T;}',
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: "interface U {10:T; '11':T; 1?:T; 12?:T; 2?:T;}",
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
{
code: "interface U {'Z':T; À:T; è:T; '#'?:T;}",
optionsSet: [[SortingOrder.Ascending, { requiredFirst: true }]],
},
/**
* asc, natural, insensitive, not-required
*/
{
code: 'interface U {_:T; a?:T; b:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; b?:T; c:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {a?:T; b:T; b_:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_?:T; C:T; c:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_?:T; c:T; C:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {$:T; _:T; A?:T; a?:T;}',
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {1:T; 2?:T; '11':T; A:T;}",
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {'#'?:T; 'Z':T; À:T; è:T;}",
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
/**
* desc
*/
{
code: 'interface U {b:T; a:T; _:T;}',
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: 'interface U {c:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: 'interface U {b_:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: 'interface U {c:T; b_:T; C:T;}',
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: 'interface U {a:T; _:T; A:T; $:T;}',
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: "interface U {A:T; 2:T; '11':T; 1:T;}",
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#':T;}",
optionsSet: [
[SortingOrder.Descending],
[SortingOrder.Descending, { caseSensitive: true }],
[SortingOrder.Descending, { natural: false }],
[SortingOrder.Descending, { caseSensitive: true, natural: false }],
],
},
/**
* desc, insensitive
*/
{
code: 'interface U {b:T; a:T; _:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: 'interface U {c:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: 'interface U {b_:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: 'interface U {c:T; C:T; b_:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: 'interface U {C:T; c:T; b_:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: 'interface U {a:T; A:T; _:T; $:T;}',
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: "interface U {A:T; 2:T; '11':T; 1:T;}",
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#':T;}",
optionsSet: [
[SortingOrder.Descending, { caseSensitive: false }],
[SortingOrder.Descending, { caseSensitive: false, natural: false }],
],
},
/**
* desc, natural
*/
{
code: 'interface U {b:T; a:T; _:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: 'interface U {c:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: 'interface U {b_:T; b:T; a:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: 'interface U {c:T; b_:T; C:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: 'interface U {a:T; A:T; _:T; $:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: "interface U {A:T; '11':T; 2:T; 1:T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#':T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true }],
[SortingOrder.Descending, { natural: true, caseSensitive: true }],
],
},
/**
* desc, natural, insensitive
*/
{
code: 'interface U {b:T; a:T; _:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {c:T; b:T; a:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; b:T; a:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {c:T; C:T; b_:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {C:T; c:T; b_:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {a:T; A:T; _:T; $:T;}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {A:T; '11':T; 2:T; 1:T;}",
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#':T;}",
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
/**
* desc, natural, insensitive, required
*/
{
code: 'interface U {b:T; _:T; a?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {c:T; a:T; b?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b_:T; b:T; a?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {c:T; C:T; b_?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {C:T; c:T; b_?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {_:T; $:T; a?:T; A?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U { A:T; '11':T; 1:T; 2?:T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {è:T; 'Z':T; À?:T; '#'?:T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
/**
* desc, required
*/
{
code: 'interface U {b:T; _:T; a?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: 'interface U {c:T; a:T; b?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: 'interface U {b_:T; b:T; a?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: 'interface U {c:T; C:T; b_?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: 'interface U {9:T; 11:T; 1:T; 111?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: 'interface U {_:T; $:T; a?:T; A?:T;}',
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: "interface U {'11':T; 10:T; 2?:T; 12?:T; 1?:T;}",
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#'?:T;}",
optionsSet: [[SortingOrder.Descending, { requiredFirst: true }]],
},
/**
* desc, natural, insensitive, not-required
*/
{
code: 'interface U {b:T; a?:T; _:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {c:T; b?:T; a:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_:T; b:T; a?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {c:T; C:T; b_?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {C:T; c:T; b_?:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {a?:T; A?:T; _:T; $:T;}',
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {A:T; '11':T; 2?:T; 1:T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {è:T; À:T; 'Z':T; '#'?:T;}",
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
/**
* index signatures
*/
{
code: `interface U<T> { [nkey: number]: T; [skey: string]: T; $: T; A: T; _: T; a: T; }`,
optionsSet: [[SortingOrder.Ascending]],
},
{
code: `interface U<T> { a: T; _: T; A: T; $: T; [skey: string]: T; [nkey: number]: T; }`,
optionsSet: [[SortingOrder.Descending]],
},
]
const invalid: readonly InvalidTestCase<Options>[] = [
/**
* default (asc)
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {_:T; a:T; b:T;}',
errors: ["Expected interface keys to be in ascending order. '_' should be before 'a'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {a:T; b:T; c:T;}',
errors: ["Expected interface keys to be in ascending order. 'b' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {a:T; b_:T; b:T;}',
errors: ["Expected interface keys to be in ascending order. 'a' should be before 'b_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {C:T; c:T; b_:T;}',
errors: ["Expected interface keys to be in ascending order. 'C' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {$:T; A:T; _:T; a:T;}',
errors: ["Expected interface keys to be in ascending order. 'A' should be before '_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {1:T; '11':T; A:T; 2:T;}",
errors: ["Expected interface keys to be in ascending order. '11' should be before 'A'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {'#':T; 'Z':T; À:T; è:T;}",
errors: ["Expected interface keys to be in ascending order. 'Z' should be before 'À'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* methods
*/
{
code: "interface U {1:T; 2:T; A():T; '11':T;}",
output: "interface U {1:T; '11':T; A():T; 2:T;}",
errors: ["Expected interface keys to be in ascending order. '11' should be before 'A'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {'#'():T; À():T; 'Z':T; è:T;}",
output: "interface U {'#'():T; 'Z':T; À():T; è:T;}",
errors: ["Expected interface keys to be in ascending order. 'Z' should be before 'À'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* not ignore simple computed properties.
*/
{
code: 'interface U {a:T; b:T; ["a"]:T; c:T;}',
output: 'interface U {a:T; ["a"]:T; b:T; c:T;}',
errors: ["Expected interface keys to be in ascending order. 'a' should be before 'b'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* nested
*/
{
code: 'interface U {a:T; c:{y:T; x:T;}, b:T;}',
output: 'interface U {a:T; b:T; c:{y:T; x:T;}}',
errors: [
"Expected interface keys to be in ascending order. 'x' should be before 'y'.",
"Expected interface keys to be in ascending order. 'b' should be before 'c'.",
],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'type U = {a:T; c:{y:T; x:T;}, b:T;}',
output: 'type U = {a:T; b:T; c:{y:T; x:T;}}',
errors: [
"Expected interface keys to be in ascending order. 'x' should be before 'y'.",
"Expected interface keys to be in ascending order. 'b' should be before 'c'.",
],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
/**
* asc
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {_:T; a:T; b:T;}',
errors: ["Expected interface keys to be in ascending order. '_' should be before 'a'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {a:T; b:T; c:T;}',
errors: ["Expected interface keys to be in ascending order. 'b' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {a:T; b_:T; b:T;}',
errors: ["Expected interface keys to be in ascending order. 'a' should be before 'b_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {C:T; c:T; b_:T;}',
errors: ["Expected interface keys to be in ascending order. 'C' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {$:T; A:T; _:T; a:T;}',
errors: ["Expected interface keys to be in ascending order. 'A' should be before '_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {1:T; '11':T; A:T; 2:T;}",
errors: ["Expected interface keys to be in ascending order. '11' should be before 'A'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false, requiredFirst: false }],
],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {'#':T; 'Z':T; À:T; è:T;}",
errors: ["Expected interface keys to be in ascending order. 'Z' should be before 'À'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* asc, insensitive
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {_:T; a:T; b:T;}',
errors: [
"Expected interface keys to be in insensitive ascending order. '_' should be before 'a'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {a:T; b:T; c:T;}',
errors: [
"Expected interface keys to be in insensitive ascending order. 'b' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {a:T; b_:T; b:T;}',
errors: [
"Expected interface keys to be in insensitive ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'interface U {$:T; A:T; _:T; a:T;}',
output: 'interface U {$:T; _:T; A:T; a:T;}',
errors: [
"Expected interface keys to be in insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {1:T; '11':T; A:T; 2:T;}",
errors: [
"Expected interface keys to be in insensitive ascending order. '11' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {'#':T; 'Z':T; À:T; è:T;}",
errors: [
"Expected interface keys to be in insensitive ascending order. 'Z' should be before 'À'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
/**
* asc, natural
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {_:T; a:T; b:T;}',
errors: ["Expected interface keys to be in natural ascending order. '_' should be before 'a'."],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {a:T; b:T; c:T;}',
errors: ["Expected interface keys to be in natural ascending order. 'b' should be before 'c'."],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {a:T; b_:T; b:T;}',
errors: [
"Expected interface keys to be in natural ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {C:T; c:T; b_:T;}',
errors: ["Expected interface keys to be in natural ascending order. 'C' should be before 'c'."],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'interface U {$:T; A:T; _:T; a:T;}',
output: 'interface U {$:T; _:T; A:T; a:T;}',
errors: ["Expected interface keys to be in natural ascending order. '_' should be before 'A'."],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {1:T; 2:T; '11':T; A:T;}",
errors: [
"Expected interface keys to be in natural ascending order. '11' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {'#':T; 'Z':T; À:T; è:T;}",
errors: ["Expected interface keys to be in natural ascending order. 'Z' should be before 'À'."],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
/**
* asc, natural, insensitive
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {_:T; a:T; b:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. '_' should be before 'a'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {a:T; b:T; c:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'b' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {a:T; b_:T; b:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {$:T; A:T; _:T; a:T;}',
output: 'interface U {$:T; _:T; A:T; a:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {1:T; '11':T; 2:T; A:T;}",
output: "interface U {1:T; 2:T; '11':T; A:T;}",
errors: [
"Expected interface keys to be in natural insensitive ascending order. '2' should be before '11'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {'#':T; 'Z':T; À:T; è:T;}",
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'Z' should be before 'À'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
/**
* asc, natural, insensitive, required
*/
{
code: 'interface U {_:T; a?:T; b:T;}',
output: 'interface U {_:T; b:T; a?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'b' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {a:T; b?:T; c:T;}',
output: 'interface U {a:T; c:T; b?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'c' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b:T; a?:T; b_:T;}',
output: 'interface U {b:T; b_:T; a?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'b_' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {C:T; b_?:T; c:T;}',
output: 'interface U {C:T; c:T; b_?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'c' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {C:T; b_?:T; c:T;}',
output: 'interface U {C:T; c:T; b_?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'c' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {$:T; A?:T; _:T; a?:T;}',
output: 'interface U {$:T; _:T; A?:T; a?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {1:T; '11':T; 2?:T; A:T;}",
output: "interface U {1:T; '11':T; A:T; 2?:T;}",
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'A' should be before '2'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {'Z':T; À:T; '#'?:T; è:T;}",
output: "interface U {'Z':T; À:T; è:T; '#'?:T;}",
errors: [
"Expected interface keys to be in required first natural insensitive ascending order. 'è' should be before '#'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
/**
* asc, natural, insensitive, not-required
*/
{
code: 'interface U {_:T; b:T; a?:T;}',
output: 'interface U {_:T; a?:T; b:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'a' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b?:T; a:T; c:T;}',
output: 'interface U {a:T; b?:T; c:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'a' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b:T; a?:T; b_:T;}',
output: 'interface U {a?:T; b:T; b_:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'a' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {C:T; c:T; b_?:T;}',
output: 'interface U {b_?:T; c:T; C:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'b_' should be before 'c'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {C:T; b_?:T; c:T;}',
output: 'interface U {b_?:T; C:T; c:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. 'b_' should be before 'C'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {$:T; A?:T; _:T; a?:T;}',
output: 'interface U {$:T; _:T; A?:T; a?:T;}',
errors: [
"Expected interface keys to be in natural insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {1:T; '11':T; 2?:T; A:T;}",
output: "interface U {1:T; 2?:T; '11':T; A:T;}",
errors: [
"Expected interface keys to be in natural insensitive ascending order. '2' should be before '11'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {'Z':T; À:T; '#'?:T; è:T;}",
output: "interface U {'#'?:T; À:T; 'Z':T; è:T;}",
errors: [
"Expected interface keys to be in natural insensitive ascending order. '#' should be before 'À'.",
],
optionsSet: [
[SortingOrder.Ascending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
/**
* desc
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {b:T; _:T; a:T;}',
errors: ["Expected interface keys to be in descending order. 'b' should be before '_'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {c:T; a:T; b:T;}',
errors: ["Expected interface keys to be in descending order. 'c' should be before 'a'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {b_:T; b:T; a:T;}',
errors: ["Expected interface keys to be in descending order. 'b' should be before 'a'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {c:T; b_:T; C:T;}',
errors: ["Expected interface keys to be in descending order. 'c' should be before 'b_'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {a:T; _:T; A:T; $:T;}',
errors: [
"Expected interface keys to be in descending order. '_' should be before '$'.",
"Expected interface keys to be in descending order. 'a' should be before 'A'.",
],
optionsSet: [[SortingOrder.Descending]],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {A:T; 2:T; 1:T; '11':T;}",
errors: [
"Expected interface keys to be in descending order. '2' should be before '1'.",
"Expected interface keys to be in descending order. 'A' should be before '2'.",
],
optionsSet: [[SortingOrder.Descending]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {è:T; À:T; 'Z':T; '#':T;}",
errors: [
"Expected interface keys to be in descending order. 'À' should be before '#'.",
"Expected interface keys to be in descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending]],
},
/**
* desc, insensitive
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {b:T; _:T; a:T;}',
errors: [
"Expected interface keys to be in insensitive descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {c:T; a:T; b:T;}',
errors: [
"Expected interface keys to be in insensitive descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {b_:T; b:T; a:T;}',
errors: [
"Expected interface keys to be in insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {c:T; b_:T; C:T;}',
errors: [
"Expected interface keys to be in insensitive descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {A:T; _:T; $:T; a:T;}',
errors: [
"Expected interface keys to be in insensitive descending order. '_' should be before '$'.",
"Expected interface keys to be in insensitive descending order. 'A' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {A:T; 2:T; 1:T; '11':T;}",
errors: [
"Expected interface keys to be in insensitive descending order. '2' should be before '1'.",
"Expected interface keys to be in insensitive descending order. 'A' should be before '2'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {è:T; À:T; 'Z':T; '#':T;}",
errors: [
"Expected interface keys to be in insensitive descending order. 'À' should be before '#'.",
"Expected interface keys to be in insensitive descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
/**
* desc, natural
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {b:T; _:T; a:T;}',
errors: [
"Expected interface keys to be in natural descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {c:T; a:T; b:T;}',
errors: [
"Expected interface keys to be in natural descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {b_:T; b:T; a:T;}',
errors: [
"Expected interface keys to be in natural descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {c:T; b_:T; C:T;}',
errors: [
"Expected interface keys to be in natural descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {a:T; _:T; A:T; $:T;}',
errors: [
"Expected interface keys to be in natural descending order. '_' should be before '$'.",
"Expected interface keys to be in natural descending order. 'A' should be before '_'.",
"Expected interface keys to be in natural descending order. 'a' should be before 'A'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: "interface U {1:T; 2:T; A:T; '11':T;}",
output: "interface U {A:T; 2:T; 1:T; '11':T;}",
errors: [
"Expected interface keys to be in natural descending order. '2' should be before '1'.",
"Expected interface keys to be in natural descending order. 'A' should be before '2'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {è:T; À:T; 'Z':T; '#':T;}",
errors: [
"Expected interface keys to be in natural descending order. 'À' should be before '#'.",
"Expected interface keys to be in natural descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
/**
* desc, natural, insensitive
*/
{
code: 'interface U {a:T; _:T; b:T;}',
output: 'interface U {b:T; _:T; a:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {a:T; c:T; b:T;}',
output: 'interface U {c:T; a:T; b:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; a:T; b:T;}',
output: 'interface U {b_:T; b:T; a:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {b_:T; c:T; C:T;}',
output: 'interface U {c:T; b_:T; C:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'interface U {$:T; _:T; A:T; a:T;}',
output: 'interface U {A:T; _:T; $:T; a:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. '_' should be before '$'.",
"Expected interface keys to be in natural insensitive descending order. 'A' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {1:T; 2:T; '11':T; A:T;}",
output: "interface U {A:T; 2:T; '11':T; 1:T;}",
errors: [
"Expected interface keys to be in natural insensitive descending order. '2' should be before '1'.",
"Expected interface keys to be in natural insensitive descending order. '11' should be before '2'.",
"Expected interface keys to be in natural insensitive descending order. 'A' should be before '11'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "interface U {'#':T; À:T; 'Z':T; è:T;}",
output: "interface U {è:T; À:T; 'Z':T; '#':T;}",
errors: [
"Expected interface keys to be in natural insensitive descending order. 'À' should be before '#'.",
"Expected interface keys to be in natural insensitive descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
/**
* desc, natural, insensitive, required
*/
{
code: 'interface U {_:T; a?:T; b:T;}',
output: 'interface U {b:T; a?:T; _:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b:T; a?:T; _:T;}',
output: 'interface U {b:T; _:T; a?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. '_' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b:T; b_:T; a?:T;}',
output: 'interface U {b_:T; b:T; a?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'b_' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {c:T; b_?:T; C:T;}',
output: 'interface U {c:T; C:T; b_?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'C' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {b_?:T; C:T; c:T;}',
output: 'interface U {C:T; b_?:T; c:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'C' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: 'interface U {_:T; a?:T; $:T; A?:T;}',
output: 'interface U {_:T; $:T; a?:T; A?:T;}',
errors: [
"Expected interface keys to be in required first natural insensitive descending order. '$' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {2?:T; A:T; 1:T; '11':T;}",
output: "interface U {A:T; 2?:T; 1:T; '11':T;}",
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'A' should be before '2'.",
"Expected interface keys to be in required first natural insensitive descending order. '11' should be before '1'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {è:T; 'Z':T; '#'?:T; À?:T;}",
output: "interface U {è:T; 'Z':T; À?:T; '#'?:T;}",
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'À' should be before '#'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
{
code: "interface U {À?:T; 'Z':T; '#'?:T; è:T;}",
output: "interface U {è:T; 'Z':T; '#'?:T; À?:T;}",
errors: [
"Expected interface keys to be in required first natural insensitive descending order. 'Z' should be before 'À'.",
"Expected interface keys to be in required first natural insensitive descending order. 'è' should be before '#'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: true }],
],
},
/**
* desc, natural, insensitive, not-required
*/
{
code: 'interface U {_:T; a?:T; b:T;}',
output: 'interface U {b:T; a?:T; _:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'a' should be before '_'.",
"Expected interface keys to be in natural insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {a?:T; b:T; _:T;}',
output: 'interface U {b:T; a?:T; _:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b:T; b_:T; a?:T;}',
output: 'interface U {b_:T; b:T; a?:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'b_' should be before 'b'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {c:T; b_?:T; C:T;}',
output: 'interface U {c:T; C:T; b_?:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'C' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {b_?:T; C:T; c:T;}',
output: 'interface U {C:T; b_?:T; c:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'C' should be before 'b_'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: 'interface U {_:T; a?:T; $:T; A?:T;}',
output: 'interface U {a?:T; _:T; $:T; A?:T;}',
errors: [
"Expected interface keys to be in natural insensitive descending order. 'a' should be before '_'.",
"Expected interface keys to be in natural insensitive descending order. 'A' should be before '$'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {2?:T; A:T; 1:T; '11':T;}",
output: "interface U {A:T; 2?:T; 1:T; '11':T;}",
errors: [
"Expected interface keys to be in natural insensitive descending order. 'A' should be before '2'.",
"Expected interface keys to be in natural insensitive descending order. '11' should be before '1'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {è:T; 'Z':T; '#'?:T; À?:T;}",
output: "interface U {è:T; À?:T; '#'?:T; 'Z':T;}",
errors: [
"Expected interface keys to be in natural insensitive descending order. 'À' should be before '#'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
{
code: "interface U {À?:T; 'Z':T; '#'?:T; è:T;}",
output: "interface U {è:T; 'Z':T; '#'?:T; À?:T;}",
errors: [
"Expected interface keys to be in natural insensitive descending order. 'è' should be before '#'.",
],
optionsSet: [
[SortingOrder.Descending, { natural: true, caseSensitive: false, requiredFirst: false }],
],
},
/**
* index signatures
*/
{
code: 'interface U<T> { A: T; [skey: string]: T; _: T; }',
output: 'interface U<T> { [skey: string]: T; A: T; _: T; }',
errors: [
"Expected interface keys to be in ascending order. '[index: skey]' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending]],
},
{
code: 'interface U<T> { _: T; [skey: string]: T; A: T; }',
output: 'interface U<T> { _: T; A: T; [skey: string]: T; }',
errors: [
"Expected interface keys to be in descending order. 'A' should be before '[index: skey]'.",
],
optionsSet: [[SortingOrder.Descending]],
},
]
describe('TypeScript', () => {
const ruleTester = new RuleTester(typescript)
ruleTester.run(name, rule as unknown as Rule.RuleModule, {
valid: processValidTestCase(valid),
invalid: processInvalidTestCase(invalid),
})
})
================================================
FILE: tests/rules/string-enum.spec.ts
================================================
import { Rule, RuleTester } from 'eslint'
import { rule, name, Options } from 'rules/string-enum'
import { SortingOrder } from 'common/options'
import { typescript } from '../helpers/configs'
import {
InvalidTestCase,
processInvalidTestCase,
processValidTestCase,
ValidTestCase,
} from '../helpers/util'
const valid: readonly ValidTestCase<Options>[] = [
/**
* ignores
*/
{ code: 'enum U {c, b, a}', optionsSet: [[]] },
{ code: 'enum U {c=a(), b, a}', optionsSet: [[]] },
{ code: 'enum U {c=0, b, a}', optionsSet: [[]] },
{ code: 'enum U {c=3, b, a}', optionsSet: [[]] },
{ code: 'enum U {c=1<<1, b, a}', optionsSet: [[]] },
{ code: 'enum U {c=M|N, b, a}', optionsSet: [[]] },
{ code: 'enum U {c="123".length, b, a}', optionsSet: [[]] },
{ code: 'enum U {c=0, b="b", a}', optionsSet: [[]] },
{ code: 'const enum U {A=1, B=A*2}', optionsSet: [[]] },
/**
* default (asc)
*/
{
code: 'enum U {_="a", a="b", b="c"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="a", b="b", c="c"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="a", b="b", b_="c"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {C="a", b_="b", c="c"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {$="a", A="b", _="c", a="d"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: "enum U {'#'='a', 'Z'='b', À='c', è='d'}",
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {_="T", a="T", b="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="T", b="T", c="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="T", b="T", b_="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {C="T", b_="T", c="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {$="T", A="T", _="T", a="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* computed
*/
{
code: '{a="T", ["aa"]="T", b="T", c="T"}',
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* asc, insensitive
*/
{
code: 'enum U {_="T", a="T", b="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {a="T", b="T", c="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {a="T", b="T", b_="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", C="T", c="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
/**
* asc, natural, insensitive
*/
{
code: 'enum U {_="T", a="T", b="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {a="T", b="T", c="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {a="T", b="T", b_="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", C="T", c="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
/**
* desc
*/
{ code: 'enum U {b="T", a="T", _="T"}', optionsSet: [[SortingOrder.Descending]] },
{ code: 'enum U {c="T", b="T", a="T"}', optionsSet: [[SortingOrder.Descending]] },
{ code: 'enum U {b_="T", b="T", a="T"}', optionsSet: [[SortingOrder.Descending]] },
{ code: 'enum U {c="T", b_="T", C="T"}', optionsSet: [[SortingOrder.Descending]] },
{ code: 'enum U {a="T", _="T", A="T", $="T"}', optionsSet: [[SortingOrder.Descending]] },
{ code: "enum U {è='T', À='T', 'Z'='T', '#'='T'}", optionsSet: [[SortingOrder.Descending]] },
/**
* desc, insensitive
*/
{
code: 'enum U {b="T", a="T", _="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {c="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {c="T", C="T", b_="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {C="T", c="T", b_="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {a="T", A="T", _="T", $="T"}',
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
/**
* desc, natural
*/
{
code: 'enum U {b="T", a="T", _="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {c="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {b_="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {c="T", b_="T", C="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {a="T", A="T", _="T", $="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
/**
* desc, natural, insensitive
*/
{
code: 'enum U {b="T", a="T", _="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {c="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", b="T", a="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {c="T", C="T", b_="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {C="T", c="T", b_="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {a="T", A="T", _="T", $="T"}',
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
]
const invalid: readonly InvalidTestCase<Options>[] = [
/**
* default (asc)
*/
{
code: 'enum U {a="a", _="b", b="c"}',
output: 'enum U {_="b", a="a", b="c"}',
errors: ["Expected string enum members to be in ascending order. '_' should be before 'a'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {a="T", b="T", c="T"}',
errors: ["Expected string enum members to be in ascending order. 'b' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {a="T", b_="T", b="T"}',
errors: ["Expected string enum members to be in ascending order. 'a' should be before 'b_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {C="T", c="T", b_="T",}',
errors: ["Expected string enum members to be in ascending order. 'C' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {$="T", A="T", _="T", a="T"}',
errors: ["Expected string enum members to be in ascending order. 'A' should be before '_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
errors: ["Expected string enum members to be in ascending order. 'Z' should be before 'À'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* not ignore simple computed properties.
*/
{
code: 'enum U {a="T", b="T", ["aa"]="T", c="T"}',
output: 'enum U {a="T", ["aa"]="T", b="T", c="T"}',
errors: ["Expected string enum members to be in ascending order. 'aa' should be before 'b'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* asc
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {_="T", a="T", b="T"}',
errors: ["Expected string enum members to be in ascending order. '_' should be before 'a'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {a="T", b="T", c="T"}',
errors: ["Expected string enum members to be in ascending order. 'b' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {a="T", b_="T", b="T"}',
errors: ["Expected string enum members to be in ascending order. 'a' should be before 'b_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {C="T", c="T", b_="T",}',
errors: ["Expected string enum members to be in ascending order. 'C' should be before 'c'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {$="T", A="T", _="T", a="T"}',
errors: ["Expected string enum members to be in ascending order. 'A' should be before '_'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
errors: ["Expected string enum members to be in ascending order. 'Z' should be before 'À'."],
optionsSet: [
[],
[SortingOrder.Ascending],
[SortingOrder.Ascending, { caseSensitive: true }],
[SortingOrder.Ascending, { natural: false }],
[SortingOrder.Ascending, { caseSensitive: true, natural: false }],
],
},
/**
* asc, insensitive
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {_="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in insensitive ascending order. '_' should be before 'a'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {a="T", b="T", c="T"}',
errors: [
"Expected string enum members to be in insensitive ascending order. 'b' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {a="T", b_="T", b="T"}',
errors: [
"Expected string enum members to be in insensitive ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: 'enum U {$="T", A="T", _="T", a="T"}',
output: 'enum U {$="T", _="T", A="T", a="T"}',
errors: [
"Expected string enum members to be in insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
errors: [
"Expected string enum members to be in insensitive ascending order. 'Z' should be before 'À'.",
],
optionsSet: [[SortingOrder.Ascending, { caseSensitive: false }]],
},
/**
* asc, natural
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {_="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in natural ascending order. '_' should be before 'a'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {a="T", b="T", c="T"}',
errors: [
"Expected string enum members to be in natural ascending order. 'b' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {a="T", b_="T", b="T"}',
errors: [
"Expected string enum members to be in natural ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {C="T", c="T", b_="T",}',
errors: [
"Expected string enum members to be in natural ascending order. 'C' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: 'enum U {$="T", A="T", _="T", a="T"}',
output: 'enum U {$="T", _="T", A="T", a="T"}',
errors: [
"Expected string enum members to be in natural ascending order. '_' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
errors: [
"Expected string enum members to be in natural ascending order. 'Z' should be before 'À'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true }]],
},
/**
* asc, natural, insensitive
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {_="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in natural insensitive ascending order. '_' should be before 'a'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {a="T", b="T", c="T"}',
errors: [
"Expected string enum members to be in natural insensitive ascending order. 'b' should be before 'c'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {a="T", b_="T", b="T"}',
errors: [
"Expected string enum members to be in natural insensitive ascending order. 'a' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {$="T", A="T", _="T", a="T"}',
output: 'enum U {$="T", _="T", A="T", a="T"}',
errors: [
"Expected string enum members to be in natural insensitive ascending order. '_' should be before 'A'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {'#'='T', 'Z'='T', À='T', è='T'}",
errors: [
"Expected string enum members to be in natural insensitive ascending order. 'Z' should be before 'À'.",
],
optionsSet: [[SortingOrder.Ascending, { natural: true, caseSensitive: false }]],
},
/**
* desc
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {b="T", _="T", a="T",}',
errors: ["Expected string enum members to be in descending order. 'b' should be before '_'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {c="T", a="T", b="T"}',
errors: ["Expected string enum members to be in descending order. 'c' should be before 'a'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {b_="T", b="T", a="T"}',
errors: ["Expected string enum members to be in descending order. 'b' should be before 'a'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {c="T", b_="T", C="T"}',
errors: ["Expected string enum members to be in descending order. 'c' should be before 'b_'."],
optionsSet: [[SortingOrder.Descending]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {a="T", _="T", A="T", $="T"}',
errors: [
"Expected string enum members to be in descending order. '_' should be before '$'.",
"Expected string enum members to be in descending order. 'a' should be before 'A'.",
],
optionsSet: [[SortingOrder.Descending]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
errors: [
"Expected string enum members to be in descending order. 'À' should be before '#'.",
"Expected string enum members to be in descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending]],
},
/**
* desc, insensitive
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {b="T", _="T", a="T",}',
errors: [
"Expected string enum members to be in insensitive descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {c="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in insensitive descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {b_="T", b="T", a="T"}',
errors: [
"Expected string enum members to be in insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {c="T", b_="T", C="T"}',
errors: [
"Expected string enum members to be in insensitive descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {A="T", _="T", $="T", a="T"}',
errors: [
"Expected string enum members to be in insensitive descending order. '_' should be before '$'.",
"Expected string enum members to be in insensitive descending order. 'A' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
errors: [
"Expected string enum members to be in insensitive descending order. 'À' should be before '#'.",
"Expected string enum members to be in insensitive descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { caseSensitive: false }]],
},
/**
* desc, natural
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {b="T", _="T", a="T",}',
errors: [
"Expected string enum members to be in natural descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {c="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in natural descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {b_="T", b="T", a="T"}',
errors: [
"Expected string enum members to be in natural descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {c="T", b_="T", C="T"}',
errors: [
"Expected string enum members to be in natural descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {a="T", _="T", A="T", $="T"}',
errors: [
"Expected string enum members to be in natural descending order. '_' should be before '$'.",
"Expected string enum members to be in natural descending order. 'A' should be before '_'.",
"Expected string enum members to be in natural descending order. 'a' should be before 'A'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
errors: [
"Expected string enum members to be in natural descending order. 'À' should be before '#'.",
"Expected string enum members to be in natural descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true }]],
},
/**
* desc, natural, insensitive
*/
{
code: 'enum U {a="T", _="T", b="T"}',
output: 'enum U {b="T", _="T", a="T",}',
errors: [
"Expected string enum members to be in natural insensitive descending order. 'b' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {a="T", c="T", b="T"}',
output: 'enum U {c="T", a="T", b="T"}',
errors: [
"Expected string enum members to be in natural insensitive descending order. 'c' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", a="T", b="T"}',
output: 'enum U {b_="T", b="T", a="T"}',
errors: [
"Expected string enum members to be in natural insensitive descending order. 'b' should be before 'a'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {b_="T", c="T", C="T"}',
output: 'enum U {c="T", b_="T", C="T"}',
errors: [
"Expected string enum members to be in natural insensitive descending order. 'c' should be before 'b_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: 'enum U {$="T", _="T", A="T", a="T"}',
output: 'enum U {A="T", _="T", $="T", a="T"}',
errors: [
"Expected string enum members to be in natural insensitive descending order. '_' should be before '$'.",
"Expected string enum members to be in natural insensitive descending order. 'A' should be before '_'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
{
code: "enum U {'#'='T', À='T', 'Z'='T', è='T'}",
output: "enum U {è='T', À='T', 'Z'='T', '#'='T'}",
errors: [
"Expected string enum members to be in natural insensitive descending order. 'À' should be before '#'.",
"Expected string enum members to be in natural insensitive descending order. 'è' should be before 'Z'.",
],
optionsSet: [[SortingOrder.Descending, { natural: true, caseSensitive: false }]],
},
]
describe('TypeScript', () => {
const ruleTester = new RuleTester(typescript)
ruleTester.run(name, rule as unknown as Rule.RuleModule, {
valid: processValidTestCase(valid),
invalid: processInvalidTestCase(invalid),
})
})
================================================
FILE: tests/tsconfig.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../build",
// Turn off checks to make debugging nicer.
"noFallthroughCasesInSwitch": false,
"noImplicitAny": false,
"noImplicitReturns": false,
"noImplicitThis": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"strictNullChecks": false
},
"include": ["**/*.ts"],
"exclude": ["fixtures"]
}
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"lib": ["ESNext"] /* Specify library files to be included in the compilation. */,
"allowJs": true /* Allow javascript files to be compiled. */,
"checkJs": false /* Report errors in .js files. */,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true /* Generates corresponding '.d.ts' file. */,
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": false /* Generates corresponding '.map' file. */,
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "lib" /* Redirect output structure to the directory. */,
// "rootDir": "src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
/* Module Resolution Options */
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
"baseUrl": "src" /* Base directory to resolve non-absolute module names. */,
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"exclude": ["./node_modules", "tests/fixtures", "dist", "lib"]
}
gitextract__n8p3j18/ ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github/ │ └── workflows/ │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── .huskyrc.js ├── .prettierignore ├── .prettierrc.js ├── .yarnrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── babel.config.js ├── docs/ │ └── rules/ │ ├── interface.md │ └── string-enum.md ├── jest.config.js ├── lint-staged.config.js ├── package.json ├── rollup.config.js ├── src/ │ ├── common/ │ │ └── options.ts │ ├── config/ │ │ └── recommended.ts │ ├── index.ts │ ├── rules/ │ │ ├── index.ts │ │ ├── interface.ts │ │ └── string-enum.ts │ └── utils/ │ ├── ast.ts │ ├── common.ts │ ├── compare.ts │ ├── plugin.ts │ └── rule.ts ├── tests/ │ ├── autofix.spec.ts │ ├── config.spec.ts │ ├── fixtures/ │ │ ├── autofix.input.ts │ │ ├── autofix.output.ts │ │ └── requiredFirst.output.ts │ ├── helpers/ │ │ ├── configs.ts │ │ ├── tsconfig.json │ │ └── util.ts │ ├── rules/ │ │ ├── .prettierrc.js │ │ ├── interface.spec.ts │ │ └── string-enum.spec.ts │ └── tsconfig.json └── tsconfig.json
SYMBOL INDEX (89 symbols across 11 files)
FILE: src/common/options.ts
type SortingOrder (line 3) | enum SortingOrder {
type SortingOrderOption (line 12) | type SortingOrderOption = SortingOrder
type CaseSensitiveSortingOption (line 14) | interface CaseSensitiveSortingOption {
type NaturalSortingOption (line 18) | interface NaturalSortingOption {
type RequiredFirstSortingOption (line 22) | interface RequiredFirstSortingOption {
type SortingParamsOptions (line 26) | interface SortingParamsOptions {
type ErrorMessage (line 32) | enum ErrorMessage {
FILE: src/rules/interface.ts
type SortingParams (line 19) | type SortingParams = SortingParamsOptions['caseSensitive'] &
type Options (line 26) | type Options = [SortingOrderOption] | [SortingOrderOption, Partial<Sorti...
method create (line 86) | create(context) {
FILE: src/rules/string-enum.ts
type SortingParams (line 20) | type SortingParams = SortingParamsOptions['caseSensitive'] &
type Options (line 26) | type Options = [SortingOrderOption] | [SortingOrderOption, Partial<Sorti...
method create (line 83) | create(context) {
FILE: src/utils/ast.ts
function getObjectBody (line 5) | function getObjectBody(
function getProperty (line 20) | function getProperty(node: TSESTree.Node) {
function getPropertyName (line 74) | function getPropertyName(node: TSESTree.TypeElement | TSESTree.TSEnumMem...
function getPropertyIsOptional (line 93) | function getPropertyIsOptional(
FILE: src/utils/compare.ts
function charCompare (line 5) | function charCompare(a: string, b: string) {
function getWeight (line 17) | function getWeight(value: string) {
function weightedCompare (line 27) | function weightedCompare(
FILE: src/utils/plugin.ts
type RuleOptions (line 16) | type RuleOptions = InterfaceRuleOptions & StringEnumRuleOptions
type TSType (line 18) | type TSType = TSESTree.TypeElement | TSESTree.TSEnumMember
function createNodeSwapper (line 20) | function createNodeSwapper(context: UtilRuleContext<string, RuleOptions>) {
function createReporter (line 140) | function createReporter<MessageIds extends string>(
FILE: src/utils/rule.ts
type BaseOptions (line 11) | type BaseOptions = readonly unknown[]
type RuleMetaDataDocs (line 14) | type RuleMetaDataDocs = Omit<UtilRuleMetaDataDocs, 'url'>
type RuleMetaData (line 17) | type RuleMetaData<MessageIds extends string> = {
type RuleResult (line 21) | type RuleResult<MessageIds extends string, Options extends BaseOptions> = {
type Mutable (line 26) | type Mutable<T> = {
function createRule (line 33) | function createRule<MessageIds extends string, Options extends BaseOptio...
FILE: tests/fixtures/autofix.input.ts
class GraphQLExtension (line 4) | class GraphQLExtension<T> {_: T}
type GraphQLResponse (line 6) | interface GraphQLResponse {}
type Context (line 9) | interface Context {}
function inlineGeneric (line 19) | function inlineGeneric<T extends { foo: boolean; baz?: boolean; bar: boo...
type InlineEnum (line 23) | enum InlineEnum {e="T", c="T", d="T", b="T", a="T"}
type InlineEnum2 (line 25) | enum InlineEnum2 {Foo = 'FOO',Baz = 'BAZ', Bar = 'BAR' }
type InlineEnum3 (line 27) | enum InlineEnum3 {b_="T", c="T", C="T"}
type WeirdEnum (line 29) | enum WeirdEnum {
type InlineInterface (line 32) | interface InlineInterface {e: "T"; c?:"T"; d:"T"; b:"T"; a?:"T"}
class Class (line 34) | class Class extends GraphQLExtension<{
method method (line 38) | public method(o: {
type Interface (line 46) | interface Interface {
type Type1 (line 57) | type Type1<TKey extends string> = Partial<{
type StringEnum (line 79) | enum StringEnum {
type Type2 (line 92) | type Type2 = {/* %foo */
type ClockConstructor (line 103) | interface ClockConstructor {
type ClockInterface (line 108) | interface ClockInterface {
type Methods (line 112) | interface Methods {
FILE: tests/fixtures/autofix.output.ts
class GraphQLExtension (line 4) | class GraphQLExtension<T> {_: T}
type GraphQLResponse (line 6) | interface GraphQLResponse {}
type Context (line 9) | interface Context {}
function inlineGeneric (line 19) | function inlineGeneric<T extends { bar: boolean, baz?: boolean; foo: boo...
type InlineEnum (line 23) | enum InlineEnum {a="T", b="T", c="T", d="T", e="T"}
type InlineEnum2 (line 25) | enum InlineEnum2 {Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO' }
type InlineEnum3 (line 27) | enum InlineEnum3 {C="T", b_="T", c="T"}
type WeirdEnum (line 29) | enum WeirdEnum {
type InlineInterface (line 32) | interface InlineInterface {a?:"T", b:"T"; c?:"T"; d:"T"; e: "T";}
class Class (line 34) | class Class extends GraphQLExtension<{
method method (line 38) | public method(o: {
type Interface (line 46) | interface Interface {
type Type1 (line 57) | type Type1<TKey extends string> = Partial<{
type StringEnum (line 80) | enum StringEnum {
type Type2 (line 93) | type Type2 = {
type ClockConstructor (line 105) | interface ClockConstructor {
type ClockInterface (line 110) | interface ClockInterface {
type Methods (line 114) | interface Methods {
FILE: tests/fixtures/requiredFirst.output.ts
class GraphQLExtension (line 4) | class GraphQLExtension<T> {_: T}
type GraphQLResponse (line 6) | interface GraphQLResponse {}
type Context (line 9) | interface Context {}
function inlineGeneric (line 19) | function inlineGeneric<T extends { bar: boolean, foo: boolean; baz?: boo...
type InlineEnum (line 23) | enum InlineEnum {a="T", b="T", c="T", d="T", e="T"}
type InlineEnum2 (line 25) | enum InlineEnum2 {Bar = 'BAR',Baz = 'BAZ', Foo = 'FOO' }
type InlineEnum3 (line 27) | enum InlineEnum3 {C="T", b_="T", c="T"}
type WeirdEnum (line 29) | enum WeirdEnum {
type InlineInterface (line 32) | interface InlineInterface {b:"T"; d:"T"; e: "T"; a?:"T", c?:"T";}
class Class (line 34) | class Class extends GraphQLExtension<{
method method (line 38) | public method(o: {
type Interface (line 46) | interface Interface {
type Type1 (line 57) | type Type1<TKey extends string> = Partial<{
type StringEnum (line 80) | enum StringEnum {
type Type2 (line 93) | type Type2 = {
type ClockConstructor (line 105) | interface ClockConstructor {
type ClockInterface (line 110) | interface ClockInterface {
type Methods (line 114) | interface Methods {
FILE: tests/helpers/util.ts
type OptionsSet (line 4) | type OptionsSet<Options extends any[]> = {
type ValidTestCase (line 11) | type ValidTestCase<Options extends any[]> = Omit<
type InvalidTestCase (line 17) | type InvalidTestCase<Options extends any[]> = Omit<
function processInvalidTestCase (line 26) | function processInvalidTestCase(
function processValidTestCase (line 42) | function processValidTestCase(
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (164K chars).
[
{
"path": ".editorconfig",
"chars": 166,
"preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
},
{
"path": ".eslintignore",
"chars": 33,
"preview": "tests/fixtures/**\ndist\nlib\nbuild\n"
},
{
"path": ".eslintrc.js",
"chars": 1797,
"preview": "module.exports = {\n root: true,\n parser: '@typescript-eslint/parser',\n plugins: ['@typescript-eslint', 'eslint-plugin"
},
{
"path": ".github/workflows/publish.yml",
"chars": 831,
"preview": "# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created\n# For "
},
{
"path": ".github/workflows/tests.yml",
"chars": 731,
"preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
},
{
"path": ".gitignore",
"chars": 1211,
"preview": ".DS_Store\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock"
},
{
"path": ".huskyrc.js",
"chars": 70,
"preview": "module.exports = {\n hooks: {\n 'pre-commit': 'lint-staged',\n },\n}\n"
},
{
"path": ".prettierignore",
"chars": 33,
"preview": "tests/fixtures/**\nbuild\ndist\nlib\n"
},
{
"path": ".prettierrc.js",
"chars": 102,
"preview": "module.exports = {\n printWidth: 90,\n trailingComma: 'all',\n arrowParens: 'avoid',\n semi: false,\n}\n"
},
{
"path": ".yarnrc",
"chars": 16,
"preview": "save-prefix \"~\"\n"
},
{
"path": "CHANGELOG.md",
"chars": 4809,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
},
{
"path": "LICENSE.md",
"chars": 725,
"preview": "Copyright (c) 2019, infctr\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or wit"
},
{
"path": "README.md",
"chars": 2066,
"preview": "\n\n# eslint"
},
{
"path": "babel.config.js",
"chars": 132,
"preview": "module.exports = {\n presets: [\n ['@babel/preset-env', { targets: { node: 'current' } }],\n '@babel/preset-typescri"
},
{
"path": "docs/rules/interface.md",
"chars": 4817,
"preview": "# require interface keys to be sorted (interface)\n\nWhen declaring multiple properties on an interface, some developers p"
},
{
"path": "docs/rules/string-enum.md",
"chars": 3675,
"preview": "# require string enum members to be sorted (string-enum)\n\nWhen declaring multiple members on an string enum, some develo"
},
{
"path": "jest.config.js",
"chars": 110,
"preview": "module.exports = {\n testRegex: 'tests/.*\\\\.spec\\\\.(js|ts)$',\n moduleDirectories: ['node_modules', 'src'],\n}\n"
},
{
"path": "lint-staged.config.js",
"chars": 146,
"preview": "module.exports = {\n '*.{js,ts}': ['eslint --fix --ext js,jsx,tsx,ts --max-warnings 0 --no-ignore'],\n '*.{md,yml,json}'"
},
{
"path": "package.json",
"chars": 2945,
"preview": "{\n \"name\": \"eslint-plugin-typescript-sort-keys\",\n \"version\": \"3.3.0\",\n \"description\": \"Sort interface and string enum"
},
{
"path": "rollup.config.js",
"chars": 1023,
"preview": "import commonjs from '@rollup/plugin-commonjs'\nimport resolve from '@rollup/plugin-node-resolve'\nimport typescript from "
},
{
"path": "src/common/options.ts",
"chars": 1079,
"preview": "import { JSONSchema4 } from 'json-schema'\n\nexport enum SortingOrder {\n Ascending = 'asc',\n Descending = 'desc',\n}\n\nexp"
},
{
"path": "src/config/recommended.ts",
"chars": 186,
"preview": "export default {\n plugins: ['typescript-sort-keys'],\n rules: {\n 'typescript-sort-keys/interface': 'error' as const,"
},
{
"path": "src/index.ts",
"chars": 166,
"preview": "import recommended from './config/recommended'\nimport { rules } from './rules'\n\nconst config = {\n rules,\n configs: {\n "
},
{
"path": "src/rules/index.ts",
"chars": 250,
"preview": "import { name as interfaceName, rule as interfaceRule } from './interface'\nimport { name as stringEnumName, rule as stri"
},
{
"path": "src/rules/interface.ts",
"chars": 2216,
"preview": "import { JSONSchema4 } from 'json-schema'\n\nimport { getObjectBody } from 'utils/ast'\nimport { createReporter } from 'uti"
},
{
"path": "src/rules/string-enum.ts",
"chars": 2373,
"preview": "import { JSONSchema4 } from 'json-schema'\nimport { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-util"
},
{
"path": "src/utils/ast.ts",
"chars": 2767,
"preview": "import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'\n\nimport { indexSignature } from './comm"
},
{
"path": "src/utils/common.ts",
"chars": 277,
"preview": "const nameToIndexSignature = (x: string) => `[index: ${x}]`\nconst indexSignatureRegexp = new RegExp(\n `^${nameToIndexSi"
},
{
"path": "src/utils/compare.ts",
"chars": 1713,
"preview": "import naturalCompare from 'natural-compare-lite'\n\nimport { indexSignature } from './common'\n\nfunction charCompare(a: st"
},
{
"path": "src/utils/plugin.ts",
"chars": 7603,
"preview": "import { TSESTree, AST_TOKEN_TYPES } from '@typescript-eslint/experimental-utils'\nimport {\n RuleContext as UtilRuleCont"
},
{
"path": "src/utils/rule.ts",
"chars": 1460,
"preview": "import { ESLintUtils } from '@typescript-eslint/experimental-utils'\nimport {\n ReportDescriptor,\n RuleContext as UtilRu"
},
{
"path": "tests/autofix.spec.ts",
"chars": 2069,
"preview": "import path from 'path'\nimport fs from 'fs'\nimport tmp from 'tmp'\nimport { ESLint, Linter } from 'eslint'\n\nimport plugin"
},
{
"path": "tests/config.spec.ts",
"chars": 1509,
"preview": "import { readdirSync } from 'fs'\n\nimport plugin from '../src'\n\ndescribe('recommended config', () => {\n const RULE_NAME_"
},
{
"path": "tests/fixtures/autofix.input.ts",
"chars": 2219,
"preview": "// So typescript treats this as a module\nexport {};\n\nclass GraphQLExtension<T> {_: T}\n\ninterface GraphQLResponse {}\n\nnam"
},
{
"path": "tests/fixtures/autofix.output.ts",
"chars": 2230,
"preview": "// So typescript treats this as a module\nexport {};\n\nclass GraphQLExtension<T> {_: T}\n\ninterface GraphQLResponse {}\n\nnam"
},
{
"path": "tests/fixtures/requiredFirst.output.ts",
"chars": 2229,
"preview": "// So typescript treats this as a module\nexport {};\n\nclass GraphQLExtension<T> {_: T}\n\ninterface GraphQLResponse {}\n\nnam"
},
{
"path": "tests/helpers/configs.ts",
"chars": 324,
"preview": "import { Linter } from 'eslint'\nimport * as path from 'path'\n\nexport const filename = path.join(__dirname, 'file.ts')\n\ne"
},
{
"path": "tests/helpers/tsconfig.json",
"chars": 185,
"preview": "{\n \"compilerOptions\": {\n \"lib\": [\"es2017\"],\n \"module\": \"commonjs\",\n \"moduleResolution\": \"node\",\n \"skipLibCh"
},
{
"path": "tests/helpers/util.ts",
"chars": 1248,
"preview": "import { RuleTester as ESLintRuleTester } from 'eslint'\nimport { filename } from './configs'\n\ntype OptionsSet<Options ex"
},
{
"path": "tests/rules/.prettierrc.js",
"chars": 103,
"preview": "module.exports = {\n printWidth: 100,\n trailingComma: 'all',\n arrowParens: 'avoid',\n semi: false,\n}\n"
},
{
"path": "tests/rules/interface.spec.ts",
"chars": 61759,
"preview": "import { Rule, RuleTester } from 'eslint'\n\nimport { rule, name, Options } from 'rules/interface'\nimport { SortingOrder }"
},
{
"path": "tests/rules/string-enum.spec.ts",
"chars": 29145,
"preview": "import { Rule, RuleTester } from 'eslint'\n\nimport { rule, name, Options } from 'rules/string-enum'\nimport { SortingOrder"
},
{
"path": "tests/tsconfig.json",
"chars": 439,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"module\": \"commonjs\",\n \"outDir\": \"../build\",\n // Tur"
},
{
"path": "tsconfig.json",
"chars": 5608,
"preview": "{\n \"compilerOptions\": {\n /* Basic Options */\n // \"incremental\": true, /* Enable incremental com"
}
]
About this extraction
This page contains the full source code of the infctr/eslint-plugin-typescript-sort-keys GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (151.0 KB), approximately 45.6k tokens, and a symbol index with 89 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.