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 ================================================ ![Tests](https://github.com/infctr/eslint-plugin-typescript-sort-keys/workflows/Tests/badge.svg?branch=master) # 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 **Key**: :heavy_check_mark: = recommended, :wrench: = fixable | 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: | ================================================ 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 ", "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] 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 = { type: 'suggestion', docs: { description: 'require interface keys to be sorted', recommended: 'warn', }, messages: errorMessages, fixable: 'code', schema, } /** * Create the rule. */ export const rule = createRule({ 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] 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 = { 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({ 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) { 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, currentNode: TSType, replaceNode: TSType, ) => [currentNode, replaceNode].reduce((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( context: UtilRuleContext, 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 // "docs.url" will be set automatically. export type RuleMetaData = { readonly docs: RuleMetaDataDocs } & Omit, 'docs'> export type RuleResult = { readonly context: UtilRuleContext readonly descriptors: readonly ReportDescriptor[] } type Mutable = { -readonly [P in keyof T]: T[P] } /** * Create a rule. */ export function createRule(data: { readonly name: string readonly meta: RuleMetaData readonly defaultOptions: Options readonly create: ( context: UtilRuleContext, optionsWithDefault: Mutable, ) => RuleListener }): RuleModule { 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 = ( value: readonly [string, T][], ): Record => { return value.reduce>((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} 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({...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 = 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} 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({...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 = 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} 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({...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 = 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 = { /** * The set of options this test case should pass for. */ readonly optionsSet: readonly (Options | [])[] } export type ValidTestCase = Omit< ESLintRuleTester.ValidTestCase, 'options' > & OptionsSet export type InvalidTestCase = Omit< ESLintRuleTester.InvalidTestCase, 'options' > & OptionsSet /** * Convert our test cases into ones eslint test runner is expecting. */ export function processInvalidTestCase( testCases: readonly InvalidTestCase[], ): 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[], ): 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[] = [ /** * 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 { [nkey: number]: T; [skey: string]: T; $: T; A: T; _: T; a: T; }`, optionsSet: [[SortingOrder.Ascending]], }, { code: `interface U { a: T; _: T; A: T; $: T; [skey: string]: T; [nkey: number]: T; }`, optionsSet: [[SortingOrder.Descending]], }, ] const invalid: readonly InvalidTestCase[] = [ /** * 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 { A: T; [skey: string]: T; _: T; }', output: 'interface U { [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; [skey: string]: T; A: T; }', output: 'interface U { _: 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[] = [ /** * 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[] = [ /** * 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"] }