eslint-plugin-code-style 1.0.16 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/index.js +191 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -789,11 +789,11 @@ import { Button } from " @mui/material ";
|
|
|
789
789
|
|
|
790
790
|
### `index-export-style`
|
|
791
791
|
|
|
792
|
-
Enforce consistent export style in index files. Choose between shorthand re-exports or import-then-export pattern.
|
|
792
|
+
Enforce consistent export style in index files. Choose between shorthand re-exports or import-then-export pattern. Also enforces no empty lines between exports/imports.
|
|
793
793
|
|
|
794
794
|
**Style: "shorthand" (default)**
|
|
795
795
|
```javascript
|
|
796
|
-
// Good - shorthand re-exports
|
|
796
|
+
// Good - shorthand re-exports (no empty lines between them)
|
|
797
797
|
export { Button } from "./button";
|
|
798
798
|
export { Input, Select } from "./form";
|
|
799
799
|
export { StyledCard, StyledCardWithActions } from "./card";
|
|
@@ -801,7 +801,7 @@ export { StyledCard, StyledCardWithActions } from "./card";
|
|
|
801
801
|
|
|
802
802
|
**Style: "import-export"**
|
|
803
803
|
```javascript
|
|
804
|
-
// Good -
|
|
804
|
+
// Good - imports grouped, single export statement at bottom
|
|
805
805
|
import { Button } from "./button";
|
|
806
806
|
import { Input, Select } from "./form";
|
|
807
807
|
import { StyledCard, StyledCardWithActions } from "./card";
|
|
@@ -815,12 +815,23 @@ export {
|
|
|
815
815
|
};
|
|
816
816
|
```
|
|
817
817
|
|
|
818
|
-
**Bad
|
|
818
|
+
**Bad Examples**
|
|
819
819
|
```javascript
|
|
820
|
-
// Bad -
|
|
820
|
+
// Bad - mixing styles
|
|
821
821
|
export { Button } from "./button";
|
|
822
822
|
import { Input } from "./input";
|
|
823
823
|
export { Input };
|
|
824
|
+
|
|
825
|
+
// Bad - empty lines between shorthand exports
|
|
826
|
+
export { Button } from "./button";
|
|
827
|
+
|
|
828
|
+
export { Input } from "./input";
|
|
829
|
+
|
|
830
|
+
// Bad - multiple standalone exports (should be one)
|
|
831
|
+
import { Button } from "./button";
|
|
832
|
+
import { Input } from "./input";
|
|
833
|
+
export { Button };
|
|
834
|
+
export { Input };
|
|
824
835
|
```
|
|
825
836
|
|
|
826
837
|
**Customization Options:**
|
package/index.js
CHANGED
|
@@ -3398,23 +3398,42 @@ const moduleIndexExports = {
|
|
|
3398
3398
|
*
|
|
3399
3399
|
* Options:
|
|
3400
3400
|
* - style: "shorthand" (default) | "import-export"
|
|
3401
|
-
* - "shorthand": export { a } from "./file";
|
|
3402
|
-
* - "import-export": import { a } from "./file"; export { a };
|
|
3401
|
+
* - "shorthand": export { a } from "./file"; (no empty lines between exports)
|
|
3402
|
+
* - "import-export": import { a } from "./file"; export { a }; (single export statement)
|
|
3403
3403
|
*
|
|
3404
3404
|
* ✓ Good (style: "shorthand" - default):
|
|
3405
3405
|
* export { Button } from "./button";
|
|
3406
3406
|
* export { Input, Select } from "./form";
|
|
3407
|
+
* export { Modal } from "./modal";
|
|
3407
3408
|
*
|
|
3408
3409
|
* ✓ Good (style: "import-export"):
|
|
3409
3410
|
* import { Button } from "./button";
|
|
3410
3411
|
* import { Input, Select } from "./form";
|
|
3411
|
-
*
|
|
3412
|
+
* import { Modal } from "./modal";
|
|
3413
|
+
*
|
|
3414
|
+
* export {
|
|
3415
|
+
* Button,
|
|
3416
|
+
* Input,
|
|
3417
|
+
* Modal,
|
|
3418
|
+
* Select,
|
|
3419
|
+
* };
|
|
3412
3420
|
*
|
|
3413
3421
|
* ✗ Bad (mixing styles):
|
|
3414
3422
|
* export { Button } from "./button";
|
|
3415
3423
|
* import { Input } from "./input";
|
|
3416
3424
|
* export { Input };
|
|
3417
3425
|
*
|
|
3426
|
+
* ✗ Bad (empty lines between shorthand exports):
|
|
3427
|
+
* export { Button } from "./button";
|
|
3428
|
+
*
|
|
3429
|
+
* export { Input } from "./input";
|
|
3430
|
+
*
|
|
3431
|
+
* ✗ Bad (multiple standalone exports):
|
|
3432
|
+
* import { Button } from "./button";
|
|
3433
|
+
* import { Input } from "./input";
|
|
3434
|
+
* export { Button };
|
|
3435
|
+
* export { Input };
|
|
3436
|
+
*
|
|
3418
3437
|
* Configuration Example:
|
|
3419
3438
|
* "code-style/index-export-style": ["error", { style: "shorthand" }]
|
|
3420
3439
|
* "code-style/index-export-style": ["error", { style: "import-export" }]
|
|
@@ -3484,24 +3503,28 @@ const indexExportStyle = {
|
|
|
3484
3503
|
|
|
3485
3504
|
if (preferredStyle === "shorthand") {
|
|
3486
3505
|
// Check if using import-then-export pattern when shorthand is preferred
|
|
3487
|
-
standaloneExports.
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3506
|
+
if (standaloneExports.length > 0 && imports.length > 0) {
|
|
3507
|
+
// Collect all specifiers to convert
|
|
3508
|
+
const allSpecifiersToConvert = [];
|
|
3509
|
+
|
|
3510
|
+
standaloneExports.forEach((exportStmt) => {
|
|
3511
|
+
exportStmt.specifiers.forEach((spec) => {
|
|
3512
|
+
const exportedName = spec.local ? spec.local.name : spec.exported.name;
|
|
3513
|
+
const importInfo = importSourceMap.get(exportedName);
|
|
3514
|
+
|
|
3515
|
+
if (importInfo) {
|
|
3516
|
+
allSpecifiersToConvert.push({
|
|
3517
|
+
exportStmt,
|
|
3518
|
+
exportedName,
|
|
3519
|
+
importInfo,
|
|
3520
|
+
localName: spec.local ? spec.local.name : exportedName,
|
|
3521
|
+
spec,
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
});
|
|
3502
3525
|
});
|
|
3503
3526
|
|
|
3504
|
-
if (
|
|
3527
|
+
if (allSpecifiersToConvert.length > 0) {
|
|
3505
3528
|
context.report({
|
|
3506
3529
|
fix(fixer) {
|
|
3507
3530
|
const fixes = [];
|
|
@@ -3509,7 +3532,7 @@ const indexExportStyle = {
|
|
|
3509
3532
|
// Group specifiers by source
|
|
3510
3533
|
const bySource = new Map();
|
|
3511
3534
|
|
|
3512
|
-
|
|
3535
|
+
allSpecifiersToConvert.forEach(({ exportedName, importInfo, localName }) => {
|
|
3513
3536
|
const source = importInfo.source;
|
|
3514
3537
|
|
|
3515
3538
|
if (!bySource.has(source)) {
|
|
@@ -3523,80 +3546,184 @@ const indexExportStyle = {
|
|
|
3523
3546
|
}
|
|
3524
3547
|
});
|
|
3525
3548
|
|
|
3526
|
-
// Create shorthand exports
|
|
3549
|
+
// Create shorthand exports (no empty lines between them)
|
|
3527
3550
|
const newExports = [];
|
|
3528
3551
|
|
|
3529
3552
|
bySource.forEach((specifiers, source) => {
|
|
3530
3553
|
newExports.push(`export { ${specifiers.join(", ")} } from "${source}";`);
|
|
3531
3554
|
});
|
|
3532
3555
|
|
|
3533
|
-
// Remove
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
const importsToRemove = new Set();
|
|
3556
|
+
// Remove all standalone exports
|
|
3557
|
+
standaloneExports.forEach((exportStmt) => {
|
|
3558
|
+
fixes.push(fixer.remove(exportStmt));
|
|
3559
|
+
});
|
|
3538
3560
|
|
|
3539
|
-
|
|
3540
|
-
|
|
3561
|
+
// Remove all imports
|
|
3562
|
+
imports.forEach((importStmt) => {
|
|
3563
|
+
fixes.push(fixer.remove(importStmt));
|
|
3541
3564
|
});
|
|
3542
3565
|
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
const allSpecifiersConverted = importStmt.specifiers.every((spec) => {
|
|
3546
|
-
const name = spec.local ? spec.local.name : spec.imported.name;
|
|
3566
|
+
// Insert new shorthand exports at the beginning
|
|
3567
|
+
const firstStatement = node.body[0];
|
|
3547
3568
|
|
|
3548
|
-
|
|
3549
|
-
|
|
3569
|
+
if (firstStatement) {
|
|
3570
|
+
fixes.push(fixer.insertTextBefore(firstStatement, newExports.join("\n") + "\n"));
|
|
3571
|
+
}
|
|
3550
3572
|
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3573
|
+
return fixes;
|
|
3574
|
+
},
|
|
3575
|
+
message: `Use shorthand export style: export { ... } from "source" instead of import then export.`,
|
|
3576
|
+
node,
|
|
3577
|
+
});
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3555
3580
|
|
|
3556
|
-
|
|
3557
|
-
|
|
3581
|
+
// Check for empty lines between shorthand exports
|
|
3582
|
+
for (let i = 0; i < shorthandExports.length - 1; i += 1) {
|
|
3583
|
+
const currentExport = shorthandExports[i];
|
|
3584
|
+
const nextExport = shorthandExports[i + 1];
|
|
3585
|
+
const currentEndLine = currentExport.loc.end.line;
|
|
3586
|
+
const nextStartLine = nextExport.loc.start.line;
|
|
3558
3587
|
|
|
3559
|
-
|
|
3588
|
+
if (nextStartLine - currentEndLine > 1) {
|
|
3589
|
+
context.report({
|
|
3590
|
+
fix(fixer) {
|
|
3591
|
+
const textBetween = sourceCode.getText().slice(
|
|
3592
|
+
currentExport.range[1],
|
|
3593
|
+
nextExport.range[0],
|
|
3594
|
+
);
|
|
3595
|
+
|
|
3596
|
+
// Replace multiple newlines with single newline
|
|
3597
|
+
return fixer.replaceTextRange(
|
|
3598
|
+
[currentExport.range[1], nextExport.range[0]],
|
|
3599
|
+
"\n",
|
|
3600
|
+
);
|
|
3560
3601
|
},
|
|
3561
|
-
message:
|
|
3562
|
-
node:
|
|
3602
|
+
message: "No empty lines between shorthand exports in index files.",
|
|
3603
|
+
node: nextExport,
|
|
3563
3604
|
});
|
|
3564
3605
|
}
|
|
3565
|
-
}
|
|
3606
|
+
}
|
|
3566
3607
|
} else if (preferredStyle === "import-export") {
|
|
3567
3608
|
// Check if using shorthand when import-export is preferred
|
|
3568
|
-
shorthandExports.
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3609
|
+
if (shorthandExports.length > 0) {
|
|
3610
|
+
// Convert all shorthand exports to import-then-export with single export statement
|
|
3611
|
+
context.report({
|
|
3612
|
+
fix(fixer) {
|
|
3613
|
+
const fixes = [];
|
|
3614
|
+
const allImports = [];
|
|
3615
|
+
const allExportNames = [];
|
|
3616
|
+
|
|
3617
|
+
shorthandExports.forEach((exportStmt) => {
|
|
3618
|
+
const source = exportStmt.source.value;
|
|
3619
|
+
const importSpecifiers = [];
|
|
3577
3620
|
|
|
3578
|
-
|
|
3621
|
+
exportStmt.specifiers.forEach((spec) => {
|
|
3622
|
+
const imported = spec.local ? spec.local.name : spec.exported.name;
|
|
3623
|
+
const exported = spec.exported.name;
|
|
3624
|
+
|
|
3625
|
+
importSpecifiers.push(imported);
|
|
3626
|
+
allExportNames.push(exported);
|
|
3627
|
+
});
|
|
3628
|
+
|
|
3629
|
+
allImports.push(`import { ${importSpecifiers.join(", ")} } from "${source}";`);
|
|
3630
|
+
|
|
3631
|
+
// Remove the shorthand export
|
|
3632
|
+
fixes.push(fixer.remove(exportStmt));
|
|
3633
|
+
});
|
|
3634
|
+
|
|
3635
|
+
// Sort export names alphabetically
|
|
3636
|
+
allExportNames.sort((a, b) => a.localeCompare(b));
|
|
3637
|
+
|
|
3638
|
+
// Create single export statement with proper formatting
|
|
3639
|
+
let exportStatement;
|
|
3640
|
+
|
|
3641
|
+
if (allExportNames.length <= 3) {
|
|
3642
|
+
exportStatement = `export { ${allExportNames.join(", ")} };`;
|
|
3643
|
+
} else {
|
|
3644
|
+
exportStatement = `export {\n ${allExportNames.join(",\n ")},\n};`;
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
// Insert imports and export at the beginning
|
|
3648
|
+
const firstStatement = node.body[0];
|
|
3649
|
+
|
|
3650
|
+
if (firstStatement) {
|
|
3651
|
+
const newContent = allImports.join("\n") + "\n\n" + exportStatement + "\n";
|
|
3652
|
+
|
|
3653
|
+
fixes.push(fixer.insertTextBefore(firstStatement, newContent));
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
return fixes;
|
|
3657
|
+
},
|
|
3658
|
+
message: `Use import-then-export style with a single export statement.`,
|
|
3659
|
+
node,
|
|
3579
3660
|
});
|
|
3661
|
+
}
|
|
3580
3662
|
|
|
3663
|
+
// Check for multiple standalone exports - should be combined into one
|
|
3664
|
+
if (standaloneExports.length > 1) {
|
|
3581
3665
|
context.report({
|
|
3582
3666
|
fix(fixer) {
|
|
3583
|
-
const
|
|
3584
|
-
|
|
3667
|
+
const fixes = [];
|
|
3668
|
+
const allExportNames = [];
|
|
3669
|
+
|
|
3670
|
+
standaloneExports.forEach((exportStmt) => {
|
|
3671
|
+
exportStmt.specifiers.forEach((spec) => {
|
|
3672
|
+
const exported = spec.exported.name;
|
|
3673
|
+
|
|
3674
|
+
allExportNames.push(exported);
|
|
3675
|
+
});
|
|
3585
3676
|
|
|
3586
|
-
|
|
3677
|
+
// Remove all but the last export
|
|
3678
|
+
fixes.push(fixer.remove(exportStmt));
|
|
3587
3679
|
});
|
|
3588
3680
|
|
|
3589
|
-
|
|
3681
|
+
// Sort export names alphabetically
|
|
3682
|
+
allExportNames.sort((a, b) => a.localeCompare(b));
|
|
3683
|
+
|
|
3684
|
+
// Create single export statement
|
|
3685
|
+
let exportStatement;
|
|
3686
|
+
|
|
3687
|
+
if (allExportNames.length <= 3) {
|
|
3688
|
+
exportStatement = `export { ${allExportNames.join(", ")} };`;
|
|
3689
|
+
} else {
|
|
3690
|
+
exportStatement = `export {\n ${allExportNames.join(",\n ")},\n};`;
|
|
3691
|
+
}
|
|
3692
|
+
|
|
3693
|
+
// Find last import to insert after
|
|
3694
|
+
const lastImport = imports[imports.length - 1];
|
|
3590
3695
|
|
|
3591
|
-
|
|
3592
|
-
|
|
3696
|
+
if (lastImport) {
|
|
3697
|
+
fixes.push(fixer.insertTextAfter(lastImport, "\n\n" + exportStatement));
|
|
3698
|
+
}
|
|
3593
3699
|
|
|
3594
|
-
return
|
|
3700
|
+
return fixes;
|
|
3595
3701
|
},
|
|
3596
|
-
message: `
|
|
3597
|
-
node
|
|
3702
|
+
message: `Combine multiple export statements into a single export statement.`,
|
|
3703
|
+
node,
|
|
3598
3704
|
});
|
|
3599
|
-
}
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
// Check for empty lines between imports
|
|
3708
|
+
for (let i = 0; i < imports.length - 1; i += 1) {
|
|
3709
|
+
const currentImport = imports[i];
|
|
3710
|
+
const nextImport = imports[i + 1];
|
|
3711
|
+
const currentEndLine = currentImport.loc.end.line;
|
|
3712
|
+
const nextStartLine = nextImport.loc.start.line;
|
|
3713
|
+
|
|
3714
|
+
if (nextStartLine - currentEndLine > 1) {
|
|
3715
|
+
context.report({
|
|
3716
|
+
fix(fixer) {
|
|
3717
|
+
return fixer.replaceTextRange(
|
|
3718
|
+
[currentImport.range[1], nextImport.range[0]],
|
|
3719
|
+
"\n",
|
|
3720
|
+
);
|
|
3721
|
+
},
|
|
3722
|
+
message: "No empty lines between imports in index files.",
|
|
3723
|
+
node: nextImport,
|
|
3724
|
+
});
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3600
3727
|
}
|
|
3601
3728
|
},
|
|
3602
3729
|
};
|
package/package.json
CHANGED