Skip to content

Commit

Permalink
[New] order: Add support for TypeScript's "import equals"-expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
manuth authored and ljharb committed May 29, 2020
1 parent 2e72af5 commit 62b554b
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 22 deletions.
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
}

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

0 comments on commit 62b554b

Please sign in to comment.