prettier-plugin-sort 1.0.0 → 1.0.1
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 +2 -0
- package/README.zh.md +2 -0
- package/dist/index.js +60 -49
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -136,6 +136,8 @@ Set `esmImportSeparation` to `false` to remove blank lines between groups and ab
|
|
|
136
136
|
|
|
137
137
|
`separate` is the default. Type-only default and namespace imports keep their original form.
|
|
138
138
|
|
|
139
|
+
`import type { T }` and `import { type T }` have different runtime behavior under [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html). The plugin converts between them only when the same module also has a value import. Otherwise, it preserves the original form to avoid changing module loading behavior.
|
|
140
|
+
|
|
139
141
|
### Merging and sorting boundaries
|
|
140
142
|
|
|
141
143
|
With `esmImportMerge` enabled, imports from the same module are merged when it is safe to do so.
|
package/README.zh.md
CHANGED
|
@@ -136,6 +136,8 @@ import App from './App';
|
|
|
136
136
|
|
|
137
137
|
默认值为 `separate`。包含默认导入或命名空间导入的仅类型 `import` 会保留原有形式。
|
|
138
138
|
|
|
139
|
+
`import type { T }` 和 `import { type T }` 在 [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html) 下具有不同的运行时行为。仅当同一模块同时存在值导入时,插件才会在两种写法之间转换。否则保留原写法,避免改变模块的加载行为。
|
|
140
|
+
|
|
139
141
|
### 合并与排序边界
|
|
140
142
|
|
|
141
143
|
启用 `esmImportMerge` 后,来自同一模块的 `import` 会在安全的情况下合并。
|
package/dist/index.js
CHANGED
|
@@ -77,7 +77,7 @@ var options = {
|
|
|
77
77
|
type: "choice",
|
|
78
78
|
default: DEFAULT_SORT_OPTIONS.esmImportTypeStyle,
|
|
79
79
|
category: "ES Module Imports",
|
|
80
|
-
description: "Format named type imports as separate declarations or inline specifiers.",
|
|
80
|
+
description: "Format named type imports as separate declarations or inline specifiers without changing runtime module requests.",
|
|
81
81
|
choices: [
|
|
82
82
|
{
|
|
83
83
|
value: "separate",
|
|
@@ -119,6 +119,7 @@ var options = {
|
|
|
119
119
|
|
|
120
120
|
// src/sort-package.ts
|
|
121
121
|
import findMinimumSemanticVersion from "semver/ranges/min-version.js";
|
|
122
|
+
import getValidSemanticVersionRange from "semver/ranges/valid.js";
|
|
122
123
|
|
|
123
124
|
// src/parser-ast.ts
|
|
124
125
|
function getAstNodeTextRange(node) {
|
|
@@ -911,11 +912,38 @@ function getDependencyName(dependencyIdentifier) {
|
|
|
911
912
|
const versionSeparatorIndex = dependencyIdentifier.indexOf("@", dependencyIdentifier.startsWith("@") ? 1 : 0);
|
|
912
913
|
return versionSeparatorIndex < 0 ? dependencyIdentifier : dependencyIdentifier.slice(0, versionSeparatorIndex);
|
|
913
914
|
}
|
|
915
|
+
function getPackageVersionSeparatorIndex(packageSelector) {
|
|
916
|
+
return packageSelector.indexOf("@", packageSelector.startsWith("@") ? 1 : 0);
|
|
917
|
+
}
|
|
918
|
+
function isCompletePackageSelector(packageSelector) {
|
|
919
|
+
const versionSeparatorIndex = getPackageVersionSeparatorIndex(packageSelector);
|
|
920
|
+
if (versionSeparatorIndex < 0) {
|
|
921
|
+
return packageSelector !== "";
|
|
922
|
+
}
|
|
923
|
+
const name = packageSelector.slice(0, versionSeparatorIndex);
|
|
924
|
+
const versionRange = packageSelector.slice(versionSeparatorIndex + 1);
|
|
925
|
+
return name !== "" && versionRange.trim() !== "" && !versionRange.trimEnd().endsWith("||") && getValidSemanticVersionRange(versionRange) !== null;
|
|
926
|
+
}
|
|
927
|
+
function findPnpmDependencySeparator(packageSelector) {
|
|
928
|
+
for (let separatorIndex = packageSelector.indexOf(">");separatorIndex >= 0; separatorIndex = packageSelector.indexOf(">", separatorIndex + 1)) {
|
|
929
|
+
const isSemverComparator = packageSelector[separatorIndex - 1]?.trim() === "";
|
|
930
|
+
if (isSemverComparator) {
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
const parentSelector = packageSelector.slice(0, separatorIndex);
|
|
934
|
+
const dependencySelector = packageSelector.slice(separatorIndex + 1);
|
|
935
|
+
if (dependencySelector.trim() !== "" && isCompletePackageSelector(parentSelector)) {
|
|
936
|
+
return separatorIndex;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return -1;
|
|
940
|
+
}
|
|
914
941
|
function parsePackageSelector(packageSelector) {
|
|
915
|
-
const
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
942
|
+
const dependencySeparatorIndex = findPnpmDependencySeparator(packageSelector);
|
|
943
|
+
const nameAndVersion = dependencySeparatorIndex < 0 ? packageSelector : packageSelector.slice(0, dependencySeparatorIndex);
|
|
944
|
+
const versionSeparatorIndex = getPackageVersionSeparatorIndex(nameAndVersion);
|
|
945
|
+
if (versionSeparatorIndex < 0) {
|
|
946
|
+
return { name: nameAndVersion, versionRange: null };
|
|
919
947
|
}
|
|
920
948
|
return {
|
|
921
949
|
name: nameAndVersion.slice(0, versionSeparatorIndex),
|
|
@@ -1532,19 +1560,6 @@ function getLocalBindingNames(importDeclaration) {
|
|
|
1532
1560
|
}
|
|
1533
1561
|
return localBindingNames;
|
|
1534
1562
|
}
|
|
1535
|
-
function normalizeNamedTypeOnlyImport(importDeclaration) {
|
|
1536
|
-
if (!importDeclaration.isTypeOnly || !importDeclaration.namedSpecifiers || importDeclaration.defaultBinding || importDeclaration.namespaceBinding || importDeclaration.verbatimDeclaration !== null) {
|
|
1537
|
-
return importDeclaration;
|
|
1538
|
-
}
|
|
1539
|
-
return {
|
|
1540
|
-
...importDeclaration,
|
|
1541
|
-
isTypeOnly: false,
|
|
1542
|
-
namedSpecifiers: importDeclaration.namedSpecifiers.map((importSpecifier) => ({
|
|
1543
|
-
...importSpecifier,
|
|
1544
|
-
isTypeOnly: true
|
|
1545
|
-
}))
|
|
1546
|
-
};
|
|
1547
|
-
}
|
|
1548
1563
|
function getImportRequestKey(importDeclaration) {
|
|
1549
1564
|
return `${importDeclaration.moduleSpecifier}\x00${importDeclaration.importAttributes ?? ""}`;
|
|
1550
1565
|
}
|
|
@@ -1564,9 +1579,10 @@ function isImportDeclarationMergeSafe(targetImportDeclaration, candidateImportDe
|
|
|
1564
1579
|
}
|
|
1565
1580
|
function mergeImportDeclarations(targetImportDeclaration, candidateImportDeclaration) {
|
|
1566
1581
|
let namedSpecifiers = null;
|
|
1582
|
+
const isTypeOnly = targetImportDeclaration.isTypeOnly && candidateImportDeclaration.isTypeOnly;
|
|
1567
1583
|
const mergedNamedSpecifiers = [
|
|
1568
|
-
...targetImportDeclaration
|
|
1569
|
-
...candidateImportDeclaration
|
|
1584
|
+
...getNamedSpecifiersForMerge(targetImportDeclaration, isTypeOnly),
|
|
1585
|
+
...getNamedSpecifiersForMerge(candidateImportDeclaration, isTypeOnly)
|
|
1570
1586
|
];
|
|
1571
1587
|
if (mergedNamedSpecifiers.length > 0) {
|
|
1572
1588
|
namedSpecifiers = mergedNamedSpecifiers;
|
|
@@ -1574,7 +1590,7 @@ function mergeImportDeclarations(targetImportDeclaration, candidateImportDeclara
|
|
|
1574
1590
|
return {
|
|
1575
1591
|
moduleSpecifier: targetImportDeclaration.moduleSpecifier,
|
|
1576
1592
|
moduleSpecifierText: targetImportDeclaration.moduleSpecifierText,
|
|
1577
|
-
isTypeOnly
|
|
1593
|
+
isTypeOnly,
|
|
1578
1594
|
isSideEffectOnly: false,
|
|
1579
1595
|
defaultBinding: targetImportDeclaration.defaultBinding ?? candidateImportDeclaration.defaultBinding,
|
|
1580
1596
|
namespaceBinding: targetImportDeclaration.namespaceBinding ?? candidateImportDeclaration.namespaceBinding,
|
|
@@ -1586,6 +1602,12 @@ function mergeImportDeclarations(targetImportDeclaration, candidateImportDeclara
|
|
|
1586
1602
|
isMergeBoundary: false
|
|
1587
1603
|
};
|
|
1588
1604
|
}
|
|
1605
|
+
function getNamedSpecifiersForMerge(importDeclaration, isMergedTypeOnly) {
|
|
1606
|
+
return (importDeclaration.namedSpecifiers ?? []).map((importSpecifier) => ({
|
|
1607
|
+
...importSpecifier,
|
|
1608
|
+
isTypeOnly: !isMergedTypeOnly && (importDeclaration.isTypeOnly || importSpecifier.isTypeOnly)
|
|
1609
|
+
}));
|
|
1610
|
+
}
|
|
1589
1611
|
function mergeCompatibleImports(importDeclarations) {
|
|
1590
1612
|
const bindingCountsByImportDeclaration = new Map;
|
|
1591
1613
|
const currentBindingCountsByRequest = new Map;
|
|
@@ -1613,10 +1635,9 @@ function mergeCompatibleImports(importDeclarations) {
|
|
|
1613
1635
|
bindingCountsByImportDeclaration.set(importDeclaration, bindingCounts);
|
|
1614
1636
|
}
|
|
1615
1637
|
const mergedImportDeclarations = [];
|
|
1616
|
-
for (const
|
|
1617
|
-
const importDeclaration = normalizeNamedTypeOnlyImport(originalImportDeclaration);
|
|
1638
|
+
for (const importDeclaration of importDeclarations) {
|
|
1618
1639
|
const importRequestKey = getImportRequestKey(importDeclaration);
|
|
1619
|
-
const bindingCounts = bindingCountsByImportDeclaration.get(
|
|
1640
|
+
const bindingCounts = bindingCountsByImportDeclaration.get(importDeclaration) ?? {
|
|
1620
1641
|
defaultBindingCount: 0,
|
|
1621
1642
|
namespaceBindingCount: 0
|
|
1622
1643
|
};
|
|
@@ -1638,18 +1659,19 @@ function applyTypeImportStyle(importDeclaration, typeImportStyle) {
|
|
|
1638
1659
|
return [importDeclaration];
|
|
1639
1660
|
}
|
|
1640
1661
|
const namedSpecifiers = importDeclaration.namedSpecifiers;
|
|
1662
|
+
if (importDeclaration.isTypeOnly) {
|
|
1663
|
+
return [
|
|
1664
|
+
{
|
|
1665
|
+
...importDeclaration,
|
|
1666
|
+
namedSpecifiers: sortNamedImportSpecifiers(namedSpecifiers)
|
|
1667
|
+
}
|
|
1668
|
+
];
|
|
1669
|
+
}
|
|
1641
1670
|
if (typeImportStyle === "separate") {
|
|
1642
|
-
if (importDeclaration.isTypeOnly) {
|
|
1643
|
-
return [
|
|
1644
|
-
{
|
|
1645
|
-
...importDeclaration,
|
|
1646
|
-
namedSpecifiers: sortNamedImportSpecifiers(namedSpecifiers)
|
|
1647
|
-
}
|
|
1648
|
-
];
|
|
1649
|
-
}
|
|
1650
1671
|
const typeSpecifiers2 = namedSpecifiers.filter((importSpecifier) => importSpecifier.isTypeOnly);
|
|
1651
1672
|
const valueSpecifiers2 = namedSpecifiers.filter((importSpecifier) => !importSpecifier.isTypeOnly);
|
|
1652
|
-
|
|
1673
|
+
const hasValueBinding = valueSpecifiers2.length > 0 || importDeclaration.defaultBinding !== null || importDeclaration.namespaceBinding !== null;
|
|
1674
|
+
if (typeSpecifiers2.length > 0 && (!hasValueBinding || importDeclaration.importAttributes !== null || importDeclaration.leadingCommentsText.trim() !== "" || importDeclaration.trailingCommentsText !== "")) {
|
|
1653
1675
|
return [
|
|
1654
1676
|
{
|
|
1655
1677
|
...importDeclaration,
|
|
@@ -1687,32 +1709,21 @@ function applyTypeImportStyle(importDeclaration, typeImportStyle) {
|
|
|
1687
1709
|
}
|
|
1688
1710
|
return styledImportDeclarations;
|
|
1689
1711
|
}
|
|
1690
|
-
let inlineImportDeclaration = { ...importDeclaration, namedSpecifiers };
|
|
1691
|
-
if (importDeclaration.isTypeOnly) {
|
|
1692
|
-
inlineImportDeclaration = {
|
|
1693
|
-
...importDeclaration,
|
|
1694
|
-
isTypeOnly: false,
|
|
1695
|
-
namedSpecifiers: namedSpecifiers.map((importSpecifier) => ({
|
|
1696
|
-
...importSpecifier,
|
|
1697
|
-
isTypeOnly: true
|
|
1698
|
-
}))
|
|
1699
|
-
};
|
|
1700
|
-
}
|
|
1701
1712
|
if (typeImportStyle === "mixed") {
|
|
1702
1713
|
return [
|
|
1703
1714
|
{
|
|
1704
|
-
...
|
|
1705
|
-
namedSpecifiers: sortNamedImportSpecifiers(
|
|
1715
|
+
...importDeclaration,
|
|
1716
|
+
namedSpecifiers: sortNamedImportSpecifiers(namedSpecifiers)
|
|
1706
1717
|
}
|
|
1707
1718
|
];
|
|
1708
1719
|
}
|
|
1709
|
-
const typeSpecifiers = sortNamedImportSpecifiers(
|
|
1710
|
-
const valueSpecifiers = sortNamedImportSpecifiers(
|
|
1720
|
+
const typeSpecifiers = sortNamedImportSpecifiers(namedSpecifiers.filter((importSpecifier) => importSpecifier.isTypeOnly));
|
|
1721
|
+
const valueSpecifiers = sortNamedImportSpecifiers(namedSpecifiers.filter((importSpecifier) => !importSpecifier.isTypeOnly));
|
|
1711
1722
|
let orderedSpecifiers = [...valueSpecifiers, ...typeSpecifiers];
|
|
1712
1723
|
if (typeImportStyle === "inline-first") {
|
|
1713
1724
|
orderedSpecifiers = [...typeSpecifiers, ...valueSpecifiers];
|
|
1714
1725
|
}
|
|
1715
|
-
return [{ ...
|
|
1726
|
+
return [{ ...importDeclaration, namedSpecifiers: orderedSpecifiers }];
|
|
1716
1727
|
}
|
|
1717
1728
|
function getImportBindingShapeRank(importDeclaration) {
|
|
1718
1729
|
if (importDeclaration.defaultBinding !== null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prettier-plugin-sort",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A Prettier plugin for sorting ES module imports, export specifiers, and package.json keys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"imports",
|
|
@@ -29,18 +29,17 @@
|
|
|
29
29
|
"default": "./dist/index.js"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
-
"main": "./dist/index.js",
|
|
33
|
-
"types": "./dist/index.d.ts",
|
|
34
32
|
"files": [
|
|
35
33
|
"dist"
|
|
36
34
|
],
|
|
37
35
|
"scripts": {
|
|
38
36
|
"build": "bun run scripts/build.ts",
|
|
39
|
-
"format": "prettier **/*.{json,ts,
|
|
40
|
-
"
|
|
41
|
-
"lint
|
|
37
|
+
"format": "prettier \"**/*.{json,md,ts,yaml,yml}\" --write --experimental-cli",
|
|
38
|
+
"format:check": "prettier \"**/*.{json,md,ts,yaml,yml}\" --check --experimental-cli",
|
|
39
|
+
"lint": "eslint --cache",
|
|
40
|
+
"lint:fix": "eslint --fix --cache",
|
|
42
41
|
"prepare": "husky",
|
|
43
|
-
"test": "bun test
|
|
42
|
+
"test": "bun test",
|
|
44
43
|
"typecheck": "tsc --noEmit"
|
|
45
44
|
},
|
|
46
45
|
"dependencies": {
|