Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[New] order: Add support for TypeScript's "import equals"-expressions #1785

Merged
merged 1 commit into from May 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
### Added
- [`import/default`]: support default export in TSExportAssignment ([#1528], thanks [@joaovieira])
- [`no-cycle`]: add `ignoreExternal` option ([#1681], thanks [@sveyret])
- [`order`]: Add support for TypeScript's "import equals"-expressions ([#1785], thanks [@manuth])

### Fixed
- [`group-exports`]: Flow type export awareness ([#1702], thanks [@ernestostifano])
Expand Down Expand Up @@ -678,6 +679,7 @@ for info on changes for earlier releases.
[`memo-parser`]: ./memo-parser/README.md

[#1788]: https://github.com/benmosher/eslint-plugin-import/pull/1788
[#1785]: https://github.com/benmosher/eslint-plugin-import/pull/1785
[#1770]: https://github.com/benmosher/eslint-plugin-import/pull/1770
[#1726]: https://github.com/benmosher/eslint-plugin-import/pull/1726
[#1724]: https://github.com/benmosher/eslint-plugin-import/pull/1724
Expand Down Expand Up @@ -1162,3 +1164,4 @@ for info on changes for earlier releases.
[@atos1990]: https://github.com/atos1990
[@Hypnosphi]: https://github.com/Hypnosphi
[@nickofthyme]: https://github.com/nickofthyme
[@manuth]: https://github.com/manuth
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -25,8 +25,8 @@
"watch": "npm run tests-only -- -- --watch",
"pretest": "linklocal",
"posttest": "eslint .",
"mocha": "nyc -s mocha",
"tests-only": "cross-env BABEL_ENV=test npm run mocha tests/src",
"mocha": "cross-env BABEL_ENV=test nyc -s mocha",
"tests-only": "npm run mocha tests/src",
"test": "npm run tests-only",
"test-compiled": "npm run prepublish && BABEL_ENV=testCompiled mocha --compilers js:babel-register tests/src",
"test-all": "npm test && for resolver in ./resolvers/*; do cd $resolver && npm test && cd ../..; done",
Expand Down
55 changes: 35 additions & 20 deletions src/rules/order.js
Expand Up @@ -157,8 +157,12 @@ function isPlainImportModule(node) {
return node.type === 'ImportDeclaration' && node.specifiers != null && node.specifiers.length > 0
}

function isPlainImportEquals(node) {
return node.type === 'TSImportEqualsDeclaration' && node.moduleReference.expression
}

function canCrossNodeWhileReorder(node) {
return isPlainRequireModule(node) || isPlainImportModule(node)
return isPlainRequireModule(node) || isPlainImportModule(node) || isPlainImportEquals(node)
}

function canReorderItems(firstNode, secondNode) {
Expand Down Expand Up @@ -243,28 +247,22 @@ function makeOutOfOrderReport(context, imported) {
reportOutOfOrder(context, imported, outOfOrder, 'before')
}

function importsSorterAsc(importA, importB) {
if (importA < importB) {
return -1
}

if (importA > importB) {
return 1
}
function getSorter(ascending) {
let multiplier = (ascending ? 1 : -1)

return 0
}
return function importsSorter(importA, importB) {
let result

function importsSorterDesc(importA, importB) {
if (importA < importB) {
return 1
}
if ((importA < importB) || importB === null) {
result = -1
} else if ((importA > importB) || importA === null) {
result = 1
} else {
result = 0
}

if (importA > importB) {
return -1
return result * multiplier
}

return 0
}
ljharb marked this conversation as resolved.
Show resolved Hide resolved

function mutateRanksToAlphabetize(imported, alphabetizeOptions) {
Expand All @@ -278,7 +276,7 @@ function mutateRanksToAlphabetize(imported, alphabetizeOptions) {

const groupRanks = Object.keys(groupedByRanks)

const sorterFn = alphabetizeOptions.order === 'asc' ? importsSorterAsc : importsSorterDesc
const sorterFn = getSorter(alphabetizeOptions.order === 'asc')
const comparator = alphabetizeOptions.caseInsensitive ? (a, b) => sorterFn(String(a).toLowerCase(), String(b).toLowerCase()) : (a, b) => sorterFn(a, b)
// sort imports locally within their group
groupRanks.forEach(function(groupRank) {
Expand Down Expand Up @@ -609,6 +607,23 @@ module.exports = {
)
}
},
TSImportEqualsDeclaration: function handleImports(node) {
let name
if (node.moduleReference.type === 'TSExternalModuleReference') {
name = node.moduleReference.expression.value
} else {
name = null
}
registerNode(
context,
node,
name,
'import',
ranks,
imported,
pathGroupsExcludedImportTypes
)
},
CallExpression: function handleRequires(node) {
if (level !== 0 || !isStaticRequire(node) || !isInVariableDeclarator(node.parent)) {
return
Expand Down
58 changes: 58 additions & 0 deletions tests/src/rules/order.js
Expand Up @@ -167,6 +167,22 @@ ruleTester.run('order', rule, {
var index = require('./');
`,
}),
// Export equals expressions should be on top alongside with ordinary import-statements.
...getTSParsers().map(parser => (
test({
code: `
import async, {foo1} from 'async';
import relParent2, {foo2} from '../foo/bar';
import sibling, {foo3} from './foo';
var fs = require('fs');
var util = require("util");
var relParent1 = require('../foo');
var relParent3 = require('../');
var index = require('./');
`,
parser,
})
)),
// Adding unknown import types (e.g. using a resolver alias via babel) to the groups.
test({
code: `
Expand Down Expand Up @@ -1142,6 +1158,24 @@ ruleTester.run('order', rule, {
message: '`fs` import should occur after import of `../foo/bar`',
}],
}),
...getTSParsers().map(parser => (
test({
code: `
var fs = require('fs');
import async, {foo1} from 'async';
import bar = require("../foo/bar");
`,
output: `
import async, {foo1} from 'async';
import bar = require("../foo/bar");
var fs = require('fs');
`,
parser,
errors: [{
message: '`fs` import should occur after import of `../foo/bar`',
}],
})
)),
// Default order using import with custom import alias
test({
code: `
Expand Down Expand Up @@ -1913,6 +1947,30 @@ ruleTester.run('order', rule, {
message: '`Bar` import should occur before import of `bar`',
}],
}),
...getTSParsers().map(parser => (
test({
code: `
import sync = require('sync');
import async, {foo1} from 'async';

import index from './';
`,
output: `
import async, {foo1} from 'async';
import sync = require('sync');

import index from './';
`,
options: [{
groups: ['external', 'index'],
alphabetize: {order: 'asc'},
}],
parser,
errors: [{
message: '`async` import should occur before import of `sync`',
}],
})
)),
// Option alphabetize: {order: 'desc'}
test({
code: `
Expand Down