-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
exports-last #632
Merged
+210
−0
Merged
exports-last #632
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
84fd4f2
Add rule exports-last
k15a 76f1b84
Add documentation for exports-last
k15a 0de28bd
Remove CommonJS exports
k15a 0611e21
Refactor exports-last rule
k15a 531d04d
Add ES6 only hint to the docs
k15a baa585d
Add more tests for exports-last
k15a 8c0e7d6
Refactor exports-last
k15a 8d4e25e
Fix Changelog
k15a 1ba1c3a
removing changelog note, will re-add
benmosher File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# exports-last | ||
|
||
This rule enforces that all exports are declared at the bottom of the file. This rule will report any export declarations that comes before any non-export statements. | ||
|
||
|
||
## This will be reported | ||
|
||
```JS | ||
|
||
const bool = true | ||
|
||
export default bool | ||
|
||
const str = 'foo' | ||
|
||
``` | ||
|
||
```JS | ||
|
||
export const bool = true | ||
|
||
const str = 'foo' | ||
|
||
``` | ||
|
||
## This will not be reported | ||
|
||
```JS | ||
const arr = ['bar'] | ||
|
||
export const bool = true | ||
|
||
export default bool | ||
|
||
export function func() { | ||
console.log('Hello World 🌍') | ||
} | ||
|
||
export const str = 'foo' | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you don't mind exports being sprinkled throughout a file, you may not want to enable this rule. | ||
|
||
#### ES6 exports only | ||
|
||
The exports-last rule is currently only working on ES6 exports. You may not want to enable this rule if you're using CommonJS exports. | ||
|
||
If you need CommonJS support feel free to open an issue or create a PR. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
function isNonExportStatement({ type }) { | ||
return type !== 'ExportDefaultDeclaration' && | ||
type !== 'ExportNamedDeclaration' && | ||
type !== 'ExportAllDeclaration' | ||
} | ||
|
||
module.exports = { | ||
create: function (context) { | ||
return { | ||
Program: function ({ body }) { | ||
const lastNonExportStatementIndex = body.reduce(function findLastIndex(acc, item, index) { | ||
if (isNonExportStatement(item)) { | ||
return index | ||
} | ||
return acc | ||
}, -1) | ||
|
||
if (lastNonExportStatementIndex !== -1) { | ||
body.slice(0, lastNonExportStatementIndex).forEach(function checkNonExport(node) { | ||
if (!isNonExportStatement(node)) { | ||
context.report({ | ||
node, | ||
message: 'Export statements should appear at the end of the file', | ||
}) | ||
} | ||
}) | ||
} | ||
}, | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { test } from '../utils' | ||
|
||
import { RuleTester } from 'eslint' | ||
import rule from 'rules/exports-last' | ||
|
||
const ruleTester = new RuleTester() | ||
|
||
const error = type => ({ | ||
ruleId: 'exports-last', | ||
message: 'Export statements should appear at the end of the file', | ||
type | ||
}); | ||
|
||
ruleTester.run('exports-last', rule, { | ||
valid: [ | ||
// Empty file | ||
test({ | ||
code: '// comment', | ||
}), | ||
test({ | ||
// No exports | ||
code: ` | ||
const foo = 'bar' | ||
const bar = 'baz' | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
const foo = 'bar' | ||
export {foo} | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
const foo = 'bar' | ||
export default foo | ||
`, | ||
}), | ||
// Only exports | ||
test({ | ||
code: ` | ||
export default foo | ||
export const bar = true | ||
`, | ||
}), | ||
test({ | ||
code: ` | ||
const foo = 'bar' | ||
export default foo | ||
export const bar = true | ||
`, | ||
}), | ||
// Multiline export | ||
test({ | ||
code: ` | ||
const foo = 'bar' | ||
export default function foo () { | ||
const very = 'multiline' | ||
} | ||
export const bar = true | ||
`, | ||
}), | ||
// Many exports | ||
test({ | ||
code: ` | ||
const foo = 'bar' | ||
export default foo | ||
export const so = 'many' | ||
export const exports = ':)' | ||
export const i = 'cant' | ||
export const even = 'count' | ||
export const how = 'many' | ||
`, | ||
}), | ||
// Export all | ||
test({ | ||
code: ` | ||
export * from './foo' | ||
`, | ||
}), | ||
], | ||
invalid: [ | ||
// Default export before variable declaration | ||
test({ | ||
code: ` | ||
export default 'bar' | ||
const bar = true | ||
`, | ||
errors: [error('ExportDefaultDeclaration')], | ||
}), | ||
// Named export before variable declaration | ||
test({ | ||
code: ` | ||
export const foo = 'bar' | ||
const bar = true | ||
`, | ||
errors: [error('ExportNamedDeclaration')], | ||
}), | ||
// Export all before variable declaration | ||
test({ | ||
code: ` | ||
export * from './foo' | ||
const bar = true | ||
`, | ||
errors: [error('ExportAllDeclaration')], | ||
}), | ||
// Many exports arround variable declaration | ||
test({ | ||
code: ` | ||
export default 'such foo many bar' | ||
export const so = 'many' | ||
const foo = 'bar' | ||
export const exports = ':)' | ||
export const i = 'cant' | ||
export const even = 'count' | ||
export const how = 'many' | ||
`, | ||
errors: [ | ||
error('ExportDefaultDeclaration'), | ||
error('ExportNamedDeclaration'), | ||
], | ||
}), | ||
], | ||
}) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to indicate that this is only for the export statements using the
export
keyword, and not for CommonJSmodule.exports/exports