Add sortImportExportSpecifiers lint rule
MODIFY
packages/@romejs/diagnostics/categories.ts
packages/@romejs/diagnostics/categories.ts
@@ -31,6 +31,7 @@ export type DiagnosticCategory =
| 'lint/inconsiderateLanguage'
| 'lint/noArguments'
| 'lint/noAsyncPromiseExecutor'
+ | 'lint/noCatchAssign'
| 'lint/noCompareNegZero'
| 'lint/noCondAssign'
| 'lint/noDebugger'
@@ -52,12 +53,12 @@ export type DiagnosticCategory =
| 'lint/noShorthandArrayType'
| 'lint/noTemplateCurlyInString'
| 'lint/noUnsafeFinally'
- | 'lint/noCatchAssign'
| 'lint/noVar'
| 'lint/pendingFixes'
| 'lint/preferFunctionDeclarations'
| 'lint/preferTemplate'
| 'lint/singleVarDeclarator'
+ | 'lint/sortImportExportSpecifiers'
| 'lint/sparseArray'
| 'lint/undeclaredVariables'
| 'lint/unsafeNegation'

MODIFY
packages/@romejs/diagnostics/descriptions.ts
packages/@romejs/diagnostics/descriptions.ts
@@ -591,6 +591,16 @@ export const descriptions = createMessages(
],
};
},
+
+ SORT_EXPORT_SPECIFIERS: {
+ category: 'lint/sortImportExportSpecifiers',
+ message: `Specifiers of the export declaration should be sorted alphabetically.`,
+ },
+
+ SORT_IMPORT_SPECIFIERS: {
+ category: 'lint/sortImportExportSpecifiers',
+ message: `Specifiers of the import declaration should be sorted alphabetically.`,
+ },
},
PROJECT_MANAGER: {

MODIFY
packages/@romejs/js-compiler/transforms/lint/index.ts
packages/@romejs/js-compiler/transforms/lint/index.ts
@@ -16,6 +16,7 @@ import getterReturn from './getterReturn';
import inconsiderateLanguage from './inconsiderateLanguage';
import noArguments from './noArguments';
import noAsyncPromiseExecutor from './noAsyncPromiseExecutor';
+import noCatchAssign from './noCatchAssign';
import noCompareNegZero from './noCompareNegZero';
import noCondAssign from './noCondAssign';
import noDebugger from './noDebugger';
@@ -37,11 +38,11 @@ import noShadowRestrictedNames from './noShadowRestrictedNames';
import noShorthandArrayType from './noShorthandArrayType';
import noTemplateCurlyInString from './noTemplateCurlyInString';
import noUnsafeFinally from './noUnsafeFinally';
-import noCatchAssign from './noCatchAssign';
import noVar from './noVar';
import preferFunctionDeclarations from './preferFunctionDeclarations';
import preferTemplate from './preferTemplate';
import singleVarDeclarator from './singleVarDeclarator';
+import sortImportExportSpecifiers from './sortImportExportSpecifiers';
import sparseArray from './sparseArray';
import undeclaredVariables from './undeclaredVariables';
import unsafeNegation from './unsafeNegation';
@@ -50,15 +51,16 @@ import unusedVariables from './unusedVariables';
// Add transforms in alphabetical order.
export const lintTransforms = [
camelCase,
- defaultExportSameBasename,
- duplicateImportSource,
caseSingleStatement,
+ defaultExportSameBasename,
doubleEquals,
+ duplicateImportSource,
emptyBlocks,
getterReturn,
inconsiderateLanguage,
noArguments,
noAsyncPromiseExecutor,
+ noCatchAssign,
noCompareNegZero,
noCondAssign,
noDebugger,
@@ -80,11 +82,11 @@ export const lintTransforms = [
noShorthandArrayType,
noTemplateCurlyInString,
noUnsafeFinally,
- noCatchAssign,
noVar,
preferFunctionDeclarations,
preferTemplate,
singleVarDeclarator,
+ sortImportExportSpecifiers,
sparseArray,
undeclaredVariables,
unsafeNegation,

ADD
packages/@romejs/js-compiler/transforms/lint/sortImportExportSpecifiers.ts
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import {Path, TransformExitResult} from '@romejs/js-compiler';
+import {
+ ExportExternalSpecifier,
+ ExportLocalSpecifier,
+ ImportSpecifier,
+} from '@romejs/js-ast';
+import {descriptions} from '@romejs/diagnostics';
+import {naturalCompare} from '@romejs/string-utils';
+import {removeLoc} from '@romejs/js-ast-utils';
+
+function compareImportSpecifiers(a: ImportSpecifier, b: ImportSpecifier): number {
+ const order = naturalCompare(a.local.name.name, b.local.name.name, false);
+ if (order === 0) {
+ return naturalCompare(a.imported.name, b.imported.name, false);
+ } else {
+ return order;
+ }
+}
+
+function compareExportSpecifiers<
+ T extends ExportExternalSpecifier | ExportLocalSpecifier
+>(a: T, b: T): number {
+ const order = naturalCompare(a.local.name, b.local.name, false);
+ if (order === 0) {
+ return naturalCompare(a.exported.name, b.exported.name, false);
+ } else {
+ return order;
+ }
+}
+
+function shouldReorder<T>(a: Array<T>, b: Array<T>) {
+ for (let i = 0; i < a.length && i < b.length; i++) {
+ if (a[i] !== b[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+export default {
+ name: 'sortImportExportSpecifiers',
+ enter(path: Path): TransformExitResult {
+ const {context, node} = path;
+
+ if (node.type === 'ImportDeclaration') {
+ if (node.namedSpecifiers.length > 1) {
+ const specifiers = node.namedSpecifiers;
+ const sortedSpecifiers = specifiers.slice().sort(compareImportSpecifiers);
+ if (shouldReorder(specifiers, sortedSpecifiers)) {
+ return context.addFixableDiagnostic({
+ old: node,
+ fixed: removeLoc({...node, namedSpecifiers: sortedSpecifiers}),
+ }, descriptions.LINT.SORT_IMPORT_SPECIFIERS);
+ }
+ }
+ } else if (node.type === 'ExportExternalDeclaration') {
+ if (node.namedSpecifiers.length > 1) {
+ const specifiers = node.namedSpecifiers;
+ const sortedSpecifiers = specifiers.slice().sort(compareExportSpecifiers);
+ if (shouldReorder(specifiers, sortedSpecifiers)) {
+ return context.addFixableDiagnostic({
+ old: node,
+ fixed: removeLoc({...node, namedSpecifiers: sortedSpecifiers}),
+ }, descriptions.LINT.SORT_EXPORT_SPECIFIERS);
+ }
+ }
+ } else if (node.type === 'ExportLocalDeclaration') {
+ if (node.specifiers !== undefined && node.specifiers.length > 1) {
+ const specifiers = node.specifiers;
+ const sortedSpecifiers = specifiers.slice().sort(compareExportSpecifiers);
+ if (shouldReorder(specifiers, sortedSpecifiers)) {
+ return context.addFixableDiagnostic({
+ old: node,
+ fixed: removeLoc({...node, specifiers: sortedSpecifiers}),
+ }, descriptions.LINT.SORT_EXPORT_SPECIFIERS);
+ }
+ }
+ }
+
+ return node;
+ },
+};

Add sortImportExportSpecifiers lint rule