From a04e7a5914264c404cd6fbf3c6b64d05583efff9 Mon Sep 17 00:00:00 2001 From: Frederic Barthelemy Date: Tue, 16 May 2023 12:29:51 -0700 Subject: [PATCH] Feature: Add `` Special Word - This allows users to specify a gap between built-ins and third-party in a slightly less wonky way. - This also allows users to move the built-ins around relative to other imports. --- src/constants.ts | 11 ++++--- src/index.ts | 7 ++-- src/utils/get-comment-registry.ts | 1 - src/utils/get-sorted-nodes-by-import-order.ts | 17 +++------- src/utils/normalize-import-order-options.ts | 33 +++++++++++++++++++ .../__snapshots__/ppsi.spec.ts.snap | 20 +++++++++++ ...exercise-custom-builtin-modules-spacing.ts | 6 ++++ .../ppsi.spec.ts | 5 +++ .../__snapshots__/ppsi.spec.ts.snap | 3 ++ .../ppsi.spec.ts | 2 +- .../relative-import-with-builtin-substring.ts | 1 + 11 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 src/utils/normalize-import-order-options.ts create mode 100644 tests/ImportOrderBuiltinModulesToCustom/__snapshots__/ppsi.spec.ts.snap create mode 100644 tests/ImportOrderBuiltinModulesToCustom/exercise-custom-builtin-modules-spacing.ts create mode 100644 tests/ImportOrderBuiltinModulesToCustom/ppsi.spec.ts diff --git a/src/constants.ts b/src/constants.ts index 2276c1c..e044e8f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -23,11 +23,14 @@ export const mergeableImportFlavors = [ importFlavorType, ] as const; -/* - * Used to mark the position between RegExps, - * where the not matched imports should be placed +export const BUILTIN_MODULES_REGEX_STR = `^(?:node:)?(?:${builtinModules.join( + '|', +)})$`; + +export const BUILTIN_MODULES_SPECIAL_WORD = ''; +/** + * Used to mark not otherwise matched imports should be placed */ -export const BUILTIN_MODULES = `^(?:node:)?(?:${builtinModules.join('|')})$`; export const THIRD_PARTY_MODULES_SPECIAL_WORD = ''; export const TYPES_SPECIAL_WORD = ''; diff --git a/src/index.ts b/src/index.ts index 2e7fd0f..b05cd89 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,10 @@ import { parsers as flowParsers } from 'prettier/parser-flow'; import { parsers as htmlParsers } from 'prettier/parser-html'; import { parsers as typescriptParsers } from 'prettier/parser-typescript'; -import { THIRD_PARTY_MODULES_SPECIAL_WORD } from './constants'; +import { + BUILTIN_MODULES_SPECIAL_WORD, + THIRD_PARTY_MODULES_SPECIAL_WORD, +} from './constants'; import { defaultPreprocessor } from './preprocessors/default'; import { vuePreprocessor } from './preprocessors/vue'; import type { PrettierOptions } from './types'; @@ -29,7 +32,7 @@ export const options: Record< default: [ { value: [ - // node.js built-ins are always first + BUILTIN_MODULES_SPECIAL_WORD, THIRD_PARTY_MODULES_SPECIAL_WORD, // Everything not matching relative imports '^[.]', // relative imports ], diff --git a/src/utils/get-comment-registry.ts b/src/utils/get-comment-registry.ts index 55cd6c9..0e30faf 100644 --- a/src/utils/get-comment-registry.ts +++ b/src/utils/get-comment-registry.ts @@ -4,7 +4,6 @@ import { type ImportDeclaration, } from '@babel/types'; -import { newLineNode } from '../constants'; import { ImportOrLine, ImportRelated, SomeSpecifier } from '../types'; const SpecifierTypes = [ diff --git a/src/utils/get-sorted-nodes-by-import-order.ts b/src/utils/get-sorted-nodes-by-import-order.ts index a42df96..9e3c92d 100644 --- a/src/utils/get-sorted-nodes-by-import-order.ts +++ b/src/utils/get-sorted-nodes-by-import-order.ts @@ -1,12 +1,9 @@ -import { - BUILTIN_MODULES, - newLineNode, - THIRD_PARTY_MODULES_SPECIAL_WORD, -} from '../constants'; +import { newLineNode, THIRD_PARTY_MODULES_SPECIAL_WORD } from '../constants'; import type { GetSortedNodes, ImportGroups, ImportOrLine } from '../types'; import { getImportNodesMatchedGroup } from './get-import-nodes-matched-group'; import { getSortedImportSpecifiers } from './get-sorted-import-specifiers'; import { getSortedNodesGroup } from './get-sorted-nodes-group'; +import { normalizeImportOrderOption } from './normalize-import-order-options'; /** * This function returns the given nodes, sorted in the order as indicated by @@ -19,17 +16,11 @@ export const getSortedNodesByImportOrder: GetSortedNodes = ( originalNodes, options, ) => { - let { importOrder } = options; + // This normalization is safe even if the option is already correct. + const importOrder = normalizeImportOrderOption(options.importOrder); const finalNodes: ImportOrLine[] = []; - if (!importOrder.includes(THIRD_PARTY_MODULES_SPECIAL_WORD)) { - importOrder = [THIRD_PARTY_MODULES_SPECIAL_WORD, ...importOrder]; - } - - // Opinionated decision: builtin modules should always be first - importOrder = [BUILTIN_MODULES, ...importOrder]; - const importOrderGroups = importOrder.reduce( (groups, regexp) => // Don't create a new group for explicit import separators diff --git a/src/utils/normalize-import-order-options.ts b/src/utils/normalize-import-order-options.ts new file mode 100644 index 0000000..7192001 --- /dev/null +++ b/src/utils/normalize-import-order-options.ts @@ -0,0 +1,33 @@ +import { + BUILTIN_MODULES_REGEX_STR, + BUILTIN_MODULES_SPECIAL_WORD, + THIRD_PARTY_MODULES_SPECIAL_WORD, +} from '../constants'; +import { PrettierOptions } from '../types'; + +export function normalizeImportOrderOption( + importOrder: PrettierOptions['importOrder'], +) { + // THIRD_PARTY_MODULES_SPECIAL_WORD is magic because "everything not matched by other groups goes here" + // So it must always be present. + if (!importOrder.includes(THIRD_PARTY_MODULES_SPECIAL_WORD)) { + importOrder = [THIRD_PARTY_MODULES_SPECIAL_WORD, ...importOrder]; + } + + // Opinionated Decision: NodeJS Builtin modules should always be separate from third party modules + // Users may want to add their own separators around them or insert other modules above them though + if ( + !( + importOrder.includes(BUILTIN_MODULES_SPECIAL_WORD) || + importOrder.includes(BUILTIN_MODULES_REGEX_STR) + ) + ) { + importOrder = [BUILTIN_MODULES_SPECIAL_WORD, ...importOrder]; + } + + importOrder = importOrder.map((g) => + g === BUILTIN_MODULES_SPECIAL_WORD ? BUILTIN_MODULES_REGEX_STR : g, + ); + + return importOrder; +} diff --git a/tests/ImportOrderBuiltinModulesToCustom/__snapshots__/ppsi.spec.ts.snap b/tests/ImportOrderBuiltinModulesToCustom/__snapshots__/ppsi.spec.ts.snap new file mode 100644 index 0000000..67912d9 --- /dev/null +++ b/tests/ImportOrderBuiltinModulesToCustom/__snapshots__/ppsi.spec.ts.snap @@ -0,0 +1,20 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`exercise-custom-builtin-modules-spacing.ts - typescript-verify > exercise-custom-builtin-modules-spacing.ts 1`] = ` +// Top-of-file-comment +import path from "path" +import b from 'b'; +import foo from './foo'; +import thirdParty from 'third-party'; +import fs from "node:fs" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Top-of-file-comment +import b from "b"; +import thirdParty from "third-party"; + +import fs from "node:fs"; +import path from "path"; + +import foo from "./foo"; + +`; diff --git a/tests/ImportOrderBuiltinModulesToCustom/exercise-custom-builtin-modules-spacing.ts b/tests/ImportOrderBuiltinModulesToCustom/exercise-custom-builtin-modules-spacing.ts new file mode 100644 index 0000000..285a25c --- /dev/null +++ b/tests/ImportOrderBuiltinModulesToCustom/exercise-custom-builtin-modules-spacing.ts @@ -0,0 +1,6 @@ +// Top-of-file-comment +import path from "path" +import b from 'b'; +import foo from './foo'; +import thirdParty from 'third-party'; +import fs from "node:fs" diff --git a/tests/ImportOrderBuiltinModulesToCustom/ppsi.spec.ts b/tests/ImportOrderBuiltinModulesToCustom/ppsi.spec.ts new file mode 100644 index 0000000..861f38b --- /dev/null +++ b/tests/ImportOrderBuiltinModulesToCustom/ppsi.spec.ts @@ -0,0 +1,5 @@ +import {run_spec} from '../../test-setup/run_spec'; + +run_spec(__dirname, ['typescript'], { + importOrder: ['','','','','^[./]'], +}); diff --git a/tests/ImportOrderBuiltinModulesToTop/__snapshots__/ppsi.spec.ts.snap b/tests/ImportOrderBuiltinModulesToTop/__snapshots__/ppsi.spec.ts.snap index 25831a7..bf3d971 100644 --- a/tests/ImportOrderBuiltinModulesToTop/__snapshots__/ppsi.spec.ts.snap +++ b/tests/ImportOrderBuiltinModulesToTop/__snapshots__/ppsi.spec.ts.snap @@ -3,7 +3,10 @@ exports[`relative-import-with-builtin-substring.ts - typescript-verify > relative-import-with-builtin-substring.ts 1`] = ` import foo from './constants/foo'; import thirdParty from 'third-party'; +import fs from "fs" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import fs from "fs"; + import thirdParty from "third-party"; import foo from "./constants/foo"; diff --git a/tests/ImportOrderBuiltinModulesToTop/ppsi.spec.ts b/tests/ImportOrderBuiltinModulesToTop/ppsi.spec.ts index e79bf42..0e53719 100644 --- a/tests/ImportOrderBuiltinModulesToTop/ppsi.spec.ts +++ b/tests/ImportOrderBuiltinModulesToTop/ppsi.spec.ts @@ -1,5 +1,5 @@ import {run_spec} from '../../test-setup/run_spec'; run_spec(__dirname, ['typescript'], { - importOrder: ['^[./]'], + importOrder: ['','','^[./]'], }); diff --git a/tests/ImportOrderBuiltinModulesToTop/relative-import-with-builtin-substring.ts b/tests/ImportOrderBuiltinModulesToTop/relative-import-with-builtin-substring.ts index ece2e14..67e9859 100644 --- a/tests/ImportOrderBuiltinModulesToTop/relative-import-with-builtin-substring.ts +++ b/tests/ImportOrderBuiltinModulesToTop/relative-import-with-builtin-substring.ts @@ -1,2 +1,3 @@ import foo from './constants/foo'; import thirdParty from 'third-party'; +import fs from "fs"