Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@


---
### 5.3.0
#### Breaking Changes
- **BREAKING:** Removed `importOrderBuiltinModulesToTop` option in favor of using `<BUILTIN_MODULES>` placeholder in `importOrder` array [#381](https://github.com/trivago/prettier-plugin-sort-imports/pull/381). This provides more flexibility to control where builtin modules are positioned.
- **Migration:** Replace `importOrderBuiltinModulesToTop: true` with adding `<BUILTIN_MODULES>` to your `importOrder` array.
- Before: `{ importOrderBuiltinModulesToTop: true, importOrder: ['^[./]'] }`
- After: `{ importOrder: ['<BUILTIN_MODULES>', '<THIRD_PARTY_MODULES>', '^[./]'] }`

#### New features
- Add `<BUILTIN_MODULES>` special word to control Node.js builtin module positioning [#71](https://github.com/trivago/prettier-plugin-sort-imports/issues/71) - Support for both traditional (`fs`, `path`) and `node:` prefixed (`node:fs`, `node:path`) builtin modules

### 5.2.2
- Update packages and pin babel/types [#343](https://github.com/trivago/prettier-plugin-sort-imports/pull/343) by [@byara](https://github.com/byara)

Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ To move the third party imports at desired place, you can use `<THIRD_PARTY_MODU
"importOrder": ["^@core/(.*)$", "<THIRD_PARTY_MODULES>", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
```

You can also use `<BUILTIN_MODULES>` to control the position of Node.js builtin modules (like `fs`, `path`, `http`, and their `node:` prefixed variants):

```
"importOrder": ["<BUILTIN_MODULES>", "<THIRD_PARTY_MODULES>", "^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
```

When `<BUILTIN_MODULES>` is included in your `importOrder`, Node.js builtin modules will be sorted to that position. If not included, builtin modules are treated as regular third-party imports.

#### `importOrderSeparation`

**type**: `boolean`
Expand Down Expand Up @@ -245,6 +253,7 @@ import b from 'b'
import c from 'c'
```


### Ignoring import ordering

In some cases it's desired to ignore import ordering, specifically if you require to instantiate a common service or polyfill in your application logic before all the other imports. The plugin supports the `// sort-imports-ignore` comment, which will exclude the file from ordering the imports.
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export const chunkSideOtherNode = 'other-node';
*/
export const THIRD_PARTY_MODULES_SPECIAL_WORD = '<THIRD_PARTY_MODULES>';

export const BUILTIN_MODULES_SPECIAL_WORD = '<BUILTIN_MODULES>';

export const THIRD_PARTY_TYPES_SPECIAL_WORD = '<THIRD_PARTY_TS_TYPES>';
export const TYPES_SPECIAL_WORD = '<TS_TYPES>';
export const SEPARATOR_SPECIAL_WORD = '<SEPARATOR>';
Expand Down
46 changes: 46 additions & 0 deletions src/utils/__tests__/is-builtin-module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest';

import { isBuiltinModule } from '../is-builtin-module.js';

describe('isBuiltinModule', () => {
it('should correctly identify traditional builtin modules', () => {
expect(isBuiltinModule('fs')).toBe(true);
expect(isBuiltinModule('path')).toBe(true);
expect(isBuiltinModule('http')).toBe(true);
expect(isBuiltinModule('crypto')).toBe(true);
expect(isBuiltinModule('util')).toBe(true);
expect(isBuiltinModule('os')).toBe(true);
expect(isBuiltinModule('events')).toBe(true);
});

it('should correctly identify node: prefixed builtin modules', () => {
expect(isBuiltinModule('node:fs')).toBe(true);
expect(isBuiltinModule('node:path')).toBe(true);
expect(isBuiltinModule('node:http')).toBe(true);
expect(isBuiltinModule('node:crypto')).toBe(true);
expect(isBuiltinModule('node:util')).toBe(true);
expect(isBuiltinModule('node:os')).toBe(true);
expect(isBuiltinModule('node:events')).toBe(true);
});

it('should return false for non-builtin modules', () => {
expect(isBuiltinModule('express')).toBe(false);
expect(isBuiltinModule('lodash')).toBe(false);
expect(isBuiltinModule('react')).toBe(false);
expect(isBuiltinModule('@types/node')).toBe(false);
expect(isBuiltinModule('./my-module')).toBe(false);
expect(isBuiltinModule('../other-module')).toBe(false);
});

it('should return false for invalid node: prefixes', () => {
expect(isBuiltinModule('node:express')).toBe(false);
expect(isBuiltinModule('node:lodash')).toBe(false);
expect(isBuiltinModule('node:nonexistent')).toBe(false);
});

it('should handle edge cases', () => {
expect(isBuiltinModule('')).toBe(false);
expect(isBuiltinModule('node:')).toBe(false);
expect(isBuiltinModule('node')).toBe(false);
});
});
12 changes: 12 additions & 0 deletions src/utils/get-import-nodes-matched-group.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ImportDeclaration } from '@babel/types';

import {
BUILTIN_MODULES_SPECIAL_WORD,
THIRD_PARTY_MODULES_SPECIAL_WORD,
THIRD_PARTY_TYPES_SPECIAL_WORD,
TYPES_SPECIAL_WORD,
} from '../constants.js';
import { isBuiltinModule } from './is-builtin-module.js';

/**
* Get the regexp group to keep the import nodes.
Expand All @@ -15,6 +17,16 @@ export const getImportNodesMatchedGroup = (
node: ImportDeclaration,
importOrder: string[],
) => {
const moduleName = node.source.value;

// Check if this is a builtin module and <BUILTIN_MODULES> is in the importOrder
if (
importOrder.includes(BUILTIN_MODULES_SPECIAL_WORD) &&
isBuiltinModule(moduleName)
) {
return BUILTIN_MODULES_SPECIAL_WORD;
}

const groupWithRegExp = importOrder.map((group) => ({
group,
regExp: group.startsWith(TYPES_SPECIAL_WORD)
Expand Down
12 changes: 6 additions & 6 deletions src/utils/get-sorted-nodes-by-import-order.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { clone } from 'lodash-es';

import {
BUILTIN_MODULES_SPECIAL_WORD,
SEPARATOR_SPECIAL_WORD,
THIRD_PARTY_MODULES_SPECIAL_WORD,
newLineNode,
Expand Down Expand Up @@ -43,15 +44,14 @@ export const getSortedNodesByImportOrder: GetSortedNodes = (nodes, options) => {
{},
);

const importOrderWithOutThirdPartyPlaceholder = importOrder.filter(
(group) => group !== THIRD_PARTY_MODULES_SPECIAL_WORD,
const importOrderWithOutSpecialWords = importOrder.filter(
(group) =>
group !== THIRD_PARTY_MODULES_SPECIAL_WORD &&
group !== BUILTIN_MODULES_SPECIAL_WORD,
);

for (const node of originalNodes) {
const matchedGroup = getImportNodesMatchedGroup(
node,
importOrderWithOutThirdPartyPlaceholder,
);
const matchedGroup = getImportNodesMatchedGroup(node, importOrder);
importOrderGroups[matchedGroup].push(node);
}

Expand Down
20 changes: 20 additions & 0 deletions src/utils/is-builtin-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { builtinModules } from 'module';

/**
* Check if a module name is a Node.js builtin module.
* This includes both the traditional names (e.g., 'fs') and the
* new node: prefixed names (e.g., 'node:fs').
*
* @param moduleName The module name to check
* @returns True if the module is a Node.js builtin module
*/
export const isBuiltinModule = (moduleName: string): boolean => {
// Handle node: prefixed modules
if (moduleName.startsWith('node:')) {
const withoutPrefix = moduleName.slice(5);
return builtinModules.includes(withoutPrefix);
}

// Handle traditional module names
return builtinModules.includes(moduleName);
};
2 changes: 1 addition & 1 deletion test-setup/run_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function run_spec(dirname, parsers, options) {
).toMatchSnapshot(filename);
} catch (e) {
throw new Error(
`Problem occurred in ${path} file: ${error.name}`,
`Problem occurred in ${path} file: ${e.name}`,
);
}
});
Expand Down
28 changes: 28 additions & 0 deletions tests/BuiltinModules/__snapshots__/ppsi.spec.mjs.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`builtin-modules.ts - typescript-verify > builtin-modules.ts 1`] = `
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import fs from "fs";
import http from "http";
import crypto from "node:crypto";
import { readFile } from "node:fs";
import { join } from "node:path";
import path from "path";
import util from "util";
import express from "express";
import lodash from "lodash";
import { anotherFunction } from "../other-module";
import { myFunction } from "./my-module";

`;
12 changes: 12 additions & 0 deletions tests/BuiltinModules/builtin-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';
4 changes: 4 additions & 0 deletions tests/BuiltinModules/ppsi.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
run_spec(__dirname, ['typescript'], {
importOrder: ['<BUILTIN_MODULES>', '<THIRD_PARTY_MODULES>', '^[./]'],
importOrderParserPlugins: ['typescript']
});
28 changes: 28 additions & 0 deletions tests/BuiltinModulesDisabled/__snapshots__/ppsi.spec.mjs.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`builtin-modules.ts - typescript-verify > builtin-modules.ts 1`] = `
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import express from "express";
import fs from "fs";
import http from "http";
import lodash from "lodash";
import crypto from "node:crypto";
import { readFile } from "node:fs";
import { join } from "node:path";
import path from "path";
import util from "util";
import { anotherFunction } from "../other-module";
import { myFunction } from "./my-module";

`;
12 changes: 12 additions & 0 deletions tests/BuiltinModulesDisabled/builtin-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';
4 changes: 4 additions & 0 deletions tests/BuiltinModulesDisabled/ppsi.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
run_spec(__dirname, ['typescript'], {
importOrder: ['^[./]'],
importOrderParserPlugins: ['typescript']
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`builtin-modules.ts - typescript-verify > builtin-modules.ts 1`] = `
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import fs from "fs";
import http from "http";
import crypto from "node:crypto";
import { readFile } from "node:fs";
import { join } from "node:path";
import path from "path";
import util from "util";
import express from "express";
import lodash from "lodash";
import { anotherFunction } from "../other-module";
import { myFunction } from "./my-module";

`;
12 changes: 12 additions & 0 deletions tests/BuiltinModulesWithCustomOrder/builtin-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from 'express';
import lodash from 'lodash';
import fs from 'fs';
import path from 'path';
import http from 'http';
import { readFile } from 'node:fs';
import { join } from 'node:path';
import crypto from 'node:crypto';
import util from 'util';

import { myFunction } from './my-module';
import { anotherFunction } from '../other-module';
4 changes: 4 additions & 0 deletions tests/BuiltinModulesWithCustomOrder/ppsi.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
run_spec(__dirname, ['typescript'], {
importOrder: ['<BUILTIN_MODULES>', '<THIRD_PARTY_MODULES>', '^[./]'],
importOrderParserPlugins: ['typescript']
});
4 changes: 1 addition & 3 deletions tests/Ember/__snapshots__/ppsi.spec.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ import sameLevelRelativePath from "./sameLevelRelativePath";
// I am top level comment in this file.

interface FooSignature {
Args: {
bar: string;
};
Args: { bar: string };
}

const what = <template>Used as an expression</template>;
Expand Down
4 changes: 0 additions & 4 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@ used to order imports within each match group.
* If you need to keep side effect imports in the same place but sort all other imports around them,
* set this option to false.
*
* ```
* "importOrderImportAttributesKeyword": 'with',
* ```
*
* @default true
*/
importOrderSideEffects?: boolean;
Expand Down
Loading