prettier-plugin-sort 1.1.0 → 1.1.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 CHANGED
@@ -56,20 +56,20 @@ Dynamic `import()` calls and import-like text in strings or comments are left un
56
56
 
57
57
  `esmImportGroups` accepts these values:
58
58
 
59
- | Group | Matches |
60
- | ---------- | ------------------------------------------------------------------ |
61
- | `builtin` | Modules beginning with `node:` or `bun:`, plus `bun` |
62
- | `external` | Packages and module paths not matched by any other group |
63
- | `internal` | Path aliases defined by `compilerOptions.paths` in `tsconfig.json` |
64
- | `parent` | Parent-relative paths such as `../utils` |
65
- | `sibling` | Sibling paths such as `./Button` |
66
- | `index` | `.`, `./`, `./index`, and `./index` with an optional extension |
59
+ | Group | Matches |
60
+ | ---------- | ----------------------------------------------------------------------------------------------- |
61
+ | `builtin` | Modules beginning with `node:` or `bun:`, plus `bun` |
62
+ | `external` | Packages and module paths not matched by any other group |
63
+ | `internal` | Path aliases from `compilerOptions.paths` in the TypeScript project containing the current file |
64
+ | `parent` | Parent-relative paths such as `../utils` |
65
+ | `sibling` | Sibling paths such as `./Button` |
66
+ | `index` | `.`, `./`, `./index`, and `./index` with an optional extension |
67
67
 
68
68
  Modern Node.js code should reference built-ins explicitly with [`node:` URLs](https://nodejs.org/api/esm.html#node-imports). The plugin also classifies only `node:`-prefixed modules as `builtin`. Module specifiers without the prefix, such as `fs` and `path`, belong to `external`.
69
69
 
70
70
  The table also shows the default order. Duplicate entries are removed automatically, and omitted default groups are appended in their default order.
71
71
 
72
- The plugin searches upward from the current file for the nearest `tsconfig.json` and identifies `internal` imports from the resolved `compilerOptions.paths`. Inherited `paths` are supported. Non-relative paths not declared in `paths` remain `external`. The catch-all pattern `*` is ignored because it cannot distinguish project modules from third-party packages.
72
+ The plugin searches upward from the current file for the nearest `tsconfig.json`, then uses `files`, `include`, and `exclude` to select the TypeScript project containing the file, following `references` when necessary. Each project is resolved through `extends` before matching the file and reading `compilerOptions.paths`. Only `paths` from the selected project are used to classify `internal`; `paths` from other referenced projects are not merged. Non-relative paths not declared there remain `external`. The catch-all pattern `*` is ignored because it cannot distinguish project modules from third-party packages.
73
73
 
74
74
  With `esmImportSeparation` set to `false`, blank lines are removed both between groups and around side-effect imports.
75
75
 
package/README.zh.md CHANGED
@@ -56,20 +56,20 @@ npm i -D prettier prettier-plugin-sort
56
56
 
57
57
  `esmImportGroups` 支持以下分组:
58
58
 
59
- | 分组 | 匹配范围 |
60
- | ---------- | --------------------------------------------------------- |
61
- | `builtin` | 以 `node:`、`bun:` 开头的模块,以及 `bun` |
62
- | `external` | 第三方包,以及没有匹配其他分组的模块路径 |
63
- | `internal` | `tsconfig.json` `compilerOptions.paths` 定义的路径别名 |
64
- | `parent` | `../utils` 这类指向上级目录的相对路径 |
65
- | `sibling` | `./Button` 这类指向同级目录的相对路径 |
66
- | `index` | `.`、`./`、`./index` 及带扩展名的 `./index` |
59
+ | 分组 | 匹配范围 |
60
+ | ---------- | --------------------------------------------------------------------------- |
61
+ | `builtin` | 以 `node:`、`bun:` 开头的模块,以及 `bun` |
62
+ | `external` | 第三方包,以及没有匹配其他分组的模块路径 |
63
+ | `internal` | 当前文件所属 TypeScript project 的 `compilerOptions.paths` 中定义的路径别名 |
64
+ | `parent` | `../utils` 这类指向上级目录的相对路径 |
65
+ | `sibling` | `./Button` 这类指向同级目录的相对路径 |
66
+ | `index` | `.`、`./`、`./index` 及带扩展名的 `./index` |
67
67
 
68
68
  现代 Node.js 代码应使用 [`node:` URL](https://nodejs.org/api/esm.html#node-imports) 显式引用内置模块。本插件也只把带 `node:` 前缀的内置模块归入 `builtin`。`fs`、`path` 等未带前缀的模块归入 `external`。
69
69
 
70
70
  默认顺序就是表中的顺序。配置数组会自动去重,遗漏的默认分组则按默认顺序补到末尾。
71
71
 
72
- 插件会从当前文件所在目录向上查找最近的 `tsconfig.json`,并根据解析后的 `compilerOptions.paths` 识别 `internal`。继承配置中的 `paths` 同样有效。没有在 `paths` 中声明的非相对路径仍归入 `external`。`*` 无法区分项目代码和第三方包,因此不会用于判断 `internal`。
72
+ 插件会从当前文件所在目录向上查找最近的 `tsconfig.json`,根据 `files`、`include` 和 `exclude` 选择包含当前文件的 TypeScript project,并在需要时沿 `references` 查找。每个 project 都会先解析 `extends`,再匹配文件并读取 `compilerOptions.paths`。识别 `internal` 时只使用当前文件所属 project 的 `paths`,不会合并其他 referenced project 的 `paths`。没有在该 `paths` 中声明的非相对路径仍归入 `external`。`*` 无法区分项目代码和第三方包,因此不会用于判断 `internal`。
73
73
 
74
74
  将 `esmImportSeparation` 设为 `false` 后,分组之间和副作用 `import` 上下两侧都不再留空行。
75
75
 
package/dist/index.js CHANGED
@@ -2307,14 +2307,92 @@ function buildImportSortingEdits(sourceText, programStatements, sortedComments,
2307
2307
  }
2308
2308
 
2309
2309
  // src/sort-typescript.ts
2310
+ var SCRIPT_FILE_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
2310
2311
  async function getTsconfigPathPatterns(filePath) {
2311
2312
  if (!filePath) {
2312
2313
  return [];
2313
2314
  }
2314
2315
  try {
2315
- const { getTsconfig } = await import("get-tsconfig");
2316
- const paths = getTsconfig(filePath)?.config.compilerOptions?.paths;
2317
- return paths ? Object.keys(paths) : [];
2316
+ let isFileIncluded = function(project) {
2317
+ try {
2318
+ if (createFilesMatcher(project, isFileSystemCaseSensitive)(absoluteFilePath)) {
2319
+ return true;
2320
+ }
2321
+ const fileExtension = extname(absoluteFilePath);
2322
+ if (!fileExtension || SCRIPT_FILE_EXTENSION_PATTERN.test(fileExtension)) {
2323
+ return false;
2324
+ }
2325
+ const virtualExtension = ".ts";
2326
+ const normalizedFileExtension = isFileSystemCaseSensitive ? fileExtension : fileExtension.toLowerCase();
2327
+ const addVirtualExtension = (patterns) => patterns?.map((pattern) => {
2328
+ const normalizedPattern = isFileSystemCaseSensitive ? pattern : pattern.toLowerCase();
2329
+ return normalizedPattern.endsWith(normalizedFileExtension) ? `${pattern}${virtualExtension}` : pattern;
2330
+ });
2331
+ const virtualConfig = {
2332
+ ...project.config,
2333
+ files: addVirtualExtension(project.config.files),
2334
+ include: addVirtualExtension(project.config.include),
2335
+ exclude: addVirtualExtension(project.config.exclude)
2336
+ };
2337
+ return Boolean(createFilesMatcher({ path: project.path, config: virtualConfig }, isFileSystemCaseSensitive)(`${absoluteFilePath}${virtualExtension}`));
2338
+ } catch {
2339
+ return false;
2340
+ }
2341
+ }, findProjectForFile = function(project) {
2342
+ if (visitedConfigPaths.has(project.path)) {
2343
+ return;
2344
+ }
2345
+ visitedConfigPaths.add(project.path);
2346
+ if (isFileIncluded(project)) {
2347
+ return project;
2348
+ }
2349
+ for (const reference of project.config.references ?? []) {
2350
+ if (typeof reference.path !== "string") {
2351
+ continue;
2352
+ }
2353
+ let referencedProject;
2354
+ try {
2355
+ const referencePath = resolve(dirname(project.path), reference.path);
2356
+ const configPath = extname(referencePath).toLowerCase() === ".json" ? referencePath : join(referencePath, "tsconfig.json");
2357
+ referencedProject = {
2358
+ path: configPath,
2359
+ config: parseTsconfig(configPath, cache)
2360
+ };
2361
+ } catch {
2362
+ continue;
2363
+ }
2364
+ const selectedProject = findProjectForFile(referencedProject);
2365
+ if (selectedProject) {
2366
+ return selectedProject;
2367
+ }
2368
+ }
2369
+ return;
2370
+ };
2371
+ const { createFilesMatcher, getTsconfig, parseTsconfig } = await import("get-tsconfig");
2372
+ const { dirname, extname, join, resolve } = await import("node:path");
2373
+ const cache = new Map;
2374
+ const absoluteFilePath = resolve(filePath);
2375
+ const isFileSystemCaseSensitive = !["darwin", "win32"].includes(process.platform);
2376
+ const nearestProject = getTsconfig(absoluteFilePath, "tsconfig.json", cache);
2377
+ if (!nearestProject) {
2378
+ return [];
2379
+ }
2380
+ const visitedConfigPaths = new Set;
2381
+ let currentProject = nearestProject;
2382
+ while (currentProject) {
2383
+ const selectedProject = findProjectForFile(currentProject);
2384
+ if (selectedProject) {
2385
+ const paths = selectedProject.config.compilerOptions?.paths;
2386
+ return paths ? Object.keys(paths) : [];
2387
+ }
2388
+ const configDirectory = dirname(currentProject.path);
2389
+ const parentDirectory = dirname(configDirectory);
2390
+ if (parentDirectory === configDirectory) {
2391
+ break;
2392
+ }
2393
+ currentProject = getTsconfig(parentDirectory, "tsconfig.json", cache);
2394
+ }
2395
+ return [];
2318
2396
  } catch {
2319
2397
  return [];
2320
2398
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prettier-plugin-sort",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "A Prettier plugin for sorting ES module imports, export specifiers, and fields in package.json and tsconfig.json.",
5
5
  "keywords": [
6
6
  "imports",