Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@trivago/prettier-plugin-sort-imports

Package Overview
Dependencies
Maintainers
4
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@trivago/prettier-plugin-sort-imports - npm Package Compare versions

Comparing version 3.0.0-0 to 3.0.0-1

lib/src/utils/get-import-nodes-matched-group.js

7

lib/src/constants.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.newLineNode = exports.newLineCharacters = exports.jsx = exports.typescript = exports.flow = void 0;
exports.newLineNode = exports.THIRD_PARTY_MODULES_SPECIAL_WORD = exports.newLineCharacters = exports.jsx = exports.typescript = exports.flow = void 0;
var types_1 = require("@babel/types");

@@ -9,3 +9,8 @@ exports.flow = 'flow';

exports.newLineCharacters = '\n\n';
/*
* Used to mark the position between RegExps,
* where the not matched imports should be placed
*/
exports.THIRD_PARTY_MODULES_SPECIAL_WORD = '<THIRD_PARTY_MODULES>';
var PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE = 'PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE';
exports.newLineNode = types_1.expressionStatement(types_1.stringLiteral(PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE));

15

lib/src/index.js

@@ -24,3 +24,3 @@ "use strict";

default: [{ value: [] }],
description: 'Provide a list of plugins for special syntax',
description: 'Deprecated! Please use `importOrderParserPlugins` to provide a list of parser plugins for special syntax.',
},

@@ -40,2 +40,9 @@ importOrder: {

},
importOrderParserPlugins: {
type: 'path',
category: 'Global',
array: true,
default: [{ value: [] }],
description: 'Provide a list of plugins for special syntax',
},
importOrderSeparation: {

@@ -45,9 +52,9 @@ type: 'boolean',

default: false,
description: 'Should imports be separated by new line ?',
description: 'Should imports be separated by new line?',
},
sortModules: {
importOrderSortSpecifiers: {
type: 'boolean',
category: 'Global',
default: false,
description: 'Should modules be sorted ?',
description: 'Should specifiers be sorted?',
},

@@ -54,0 +61,0 @@ };

"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -17,12 +12,16 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

var get_sorted_nodes_1 = require("./utils/get-sorted-nodes");
var get_parser_plugins_1 = require("./utils/get-parser-plugins");
var get_experimental_parser_plugins_1 = require("./utils/get-experimental-parser-plugins");
var lodash_1 = require("lodash");
function preprocessor(code, options) {
var _a = options.experimentalBabelParserPluginsList, experimentalBabelParserPluginsList = _a === void 0 ? [] : _a, importOrder = options.importOrder, importOrderCaseInsensitive = options.importOrderCaseInsensitive, importOrderSeparation = options.importOrderSeparation, prettierParser = options.parser, sortModules = options.sortModules;
var plugins = get_parser_plugins_1.getParserPlugins(prettierParser);
var parsedExperimentalBabelParserPluginsList = get_experimental_parser_plugins_1.getExperimentalParserPlugins(experimentalBabelParserPluginsList);
var _a = options.experimentalBabelParserPluginsList, experimentalBabelParserPluginsList = _a === void 0 ? [] : _a, // Deprecated in favor of importOrderParserPlugins
_b = options.importOrderParserPlugins, // Deprecated in favor of importOrderParserPlugins
importOrderParserPlugins = _b === void 0 ? [] : _b, importOrder = options.importOrder, importOrderCaseInsensitive = options.importOrderCaseInsensitive, importOrderSeparation = options.importOrderSeparation, importOrderSortSpecifiers = options.importOrderSortSpecifiers;
var parserPlugins = lodash_1.isEmpty(importOrderParserPlugins)
? experimentalBabelParserPluginsList
: importOrderParserPlugins;
var parsedParserPlugins = get_experimental_parser_plugins_1.getExperimentalParserPlugins(parserPlugins);
var importNodes = [];
var parserOptions = {
sourceType: 'module',
plugins: __spreadArray(__spreadArray([], plugins), parsedExperimentalBabelParserPluginsList),
plugins: parsedParserPlugins,
};

@@ -48,3 +47,3 @@ var ast = parser_1.parse(code, parserOptions);

importOrderSeparation: importOrderSeparation,
sortModules: sortModules,
importOrderSortSpecifiers: importOrderSortSpecifiers,
});

@@ -51,0 +50,0 @@ return get_code_from_ast_1.getCodeFromAst(allImports, code, interpreter);

@@ -39,3 +39,3 @@ "use strict";

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -42,0 +42,0 @@ };

@@ -45,3 +45,3 @@ "use strict";

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -48,0 +48,0 @@ var formatted = get_code_from_ast_1.getCodeFromAst(sortedNodes, code, null);

@@ -8,15 +8,25 @@ "use strict";

test('it should return flow and decorators', function () {
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins(['flow', 'decorators'])).toEqual(['flow', 'decorators']);
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins(['flow', 'decorators'])).toEqual([
'flow',
'decorators',
]);
});
test('it should return decorators with parsed options', function () {
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins(["[\"decorators\", { \"decoratorsBeforeExport\": true }]"]))
.toEqual([['decorators', { decoratorsBeforeExport: true }]]);
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins([
'["decorators", { "decoratorsBeforeExport": true }]',
])).toEqual([['decorators', { decoratorsBeforeExport: true }]]);
});
test('it should return decorators with parsed options', function () {
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins(['flow', "[\"decorators\", { \"decoratorsBeforeExport\": true }]"]))
.toEqual(['flow', ['decorators', { decoratorsBeforeExport: true }]]);
expect(get_experimental_parser_plugins_1.getExperimentalParserPlugins([
'flow',
'["decorators", { "decoratorsBeforeExport": true }]',
])).toEqual(['flow', ['decorators', { decoratorsBeforeExport: true }]]);
});
test('it should throw an Error for invalid JSON', function () {
expect(function () { return get_experimental_parser_plugins_1.getExperimentalParserPlugins(['flow', "[\"decorators\", { decoratorsBeforeExport: true }]"]); })
.toThrowError("Invalid JSON in experimentalBabelParserPluginsList: ");
expect(function () {
return get_experimental_parser_plugins_1.getExperimentalParserPlugins([
'flow',
'["decorators", { decoratorsBeforeExport: true }]',
]);
}).toThrowError('Invalid JSON in importOrderParserPlugins: ');
});

@@ -59,3 +59,3 @@ "use strict";

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -98,3 +98,3 @@ expect(sorted).toMatchSnapshot();

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -137,3 +137,3 @@ expect(sorted).toMatchSnapshot();

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -176,3 +176,3 @@ expect(sorted).toMatchSnapshot();

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -209,3 +209,3 @@ expect(sorted).toMatchSnapshot();

});
test('it returns all sorted nodes with sort order and sorted modules', function () {
test('it returns all sorted import nodes with sorted import specifiers', function () {
var result = getImportNodes(code);

@@ -216,3 +216,3 @@ var sorted = get_sorted_nodes_1.getSortedNodes(result, {

importOrderSeparation: false,
sortModules: true,
importOrderSortSpecifiers: true,
});

@@ -249,3 +249,3 @@ expect(sorted).toMatchSnapshot();

});
test('it returns all sorted nodes with sort order case-insensitive and sorted modules', function () {
test('it returns all sorted import nodes with sorted import specifiers with case-insensitive ', function () {
var result = getImportNodes(code);

@@ -256,3 +256,3 @@ var sorted = get_sorted_nodes_1.getSortedNodes(result, {

importOrderSeparation: false,
sortModules: true,
importOrderSortSpecifiers: true,
});

@@ -289,1 +289,23 @@ expect(sorted).toMatchSnapshot();

});
test('it returns all sorted nodes with custom third party modules', function () {
var result = getImportNodes(code);
var sorted = get_sorted_nodes_1.getSortedNodes(result, {
importOrder: ['^a$', '<THIRD_PARTY_MODULES>', '^t$', '^k$'],
importOrderSeparation: false,
importOrderCaseInsensitive: true,
importOrderSortSpecifiers: false,
});
expect(sorted).toMatchSnapshot();
expect(getSortedNodesNames(sorted)).toEqual([
'a',
'Ba',
'BY',
'c',
'g',
'Xa',
'XY',
'z',
't',
'k',
]);
});

@@ -51,3 +51,3 @@ "use strict";

importOrderSeparation: false,
sortModules: false,
importOrderSortSpecifiers: false,
});

@@ -54,0 +54,0 @@ var allCommentsFromImports = get_all_comments_from_nodes_1.getAllCommentsFromNodes(sortedNodes);

@@ -6,10 +6,10 @@ "use strict";

* Returns a list of babel parser plugin names
* @param experimentalBabelParserPluginsList array of experimental babel parser plugins
* @param importOrderParserPlugins array of experimental babel parser plugins
* @returns list of parser plugins to be passed to babel parser
*/
var getExperimentalParserPlugins = function (experimentalBabelParserPluginsList) {
return experimentalBabelParserPluginsList.map(function (pluginNameOrJson) {
var getExperimentalParserPlugins = function (importOrderParserPlugins) {
return importOrderParserPlugins.map(function (pluginNameOrJson) {
// ParserPlugin can be either a string or and array of [name: string, options: object]
// in prettier options the array will be sent in a JSON string
var isParserPluginWithOptions = pluginNameOrJson.startsWith("[");
var isParserPluginWithOptions = pluginNameOrJson.startsWith('[');
var plugin;

@@ -21,3 +21,4 @@ if (isParserPluginWithOptions) {

catch (e) {
throw Error("Invalid JSON in experimentalBabelParserPluginsList: " + pluginNameOrJson);
throw Error('Invalid JSON in importOrderParserPlugins: ' +
pluginNameOrJson);
}

@@ -24,0 +25,0 @@ }

"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {

@@ -17,18 +28,6 @@ for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)

var types_1 = require("@babel/types");
var is_similar_text_in_array_1 = require("./is-similar-text-in-array");
var constants_1 = require("../constants");
var get_sorted_import_specifiers_1 = require("./get-sorted-import-specifiers");
var get_import_nodes_matched_group_1 = require("./get-import-nodes-matched-group");
/**
* This function returns import nodes with alphabeticaly sorted modules
* @param node Import declaration node
*/
var getSortedModulesImport = function (node) {
node.specifiers.sort(function (a, b) {
if (a.type !== b.type) {
return a.type === 'ImportDefaultSpecifier' ? -1 : 1;
}
return javascript_natural_sort_1.default(a.local.name, b.local.name);
});
return node;
};
/**
* This function returns all the nodes which are in the importOrder array.

@@ -41,55 +40,58 @@ * The plugin considered these import nodes as local import declarations.

javascript_natural_sort_1.default.insensitive = options.importOrderCaseInsensitive;
var importOrder = options.importOrder;
var importOrderSeparation = options.importOrderSeparation, importOrderSortSpecifiers = options.importOrderSortSpecifiers;
var originalNodes = nodes.map(lodash_1.clone);
var newLine = options.importOrderSeparation && nodes.length > 1 ? constants_1.newLineNode : null;
var sortedNodesByImportOrder = options.importOrder.reduce(function (res, val) {
var x = originalNodes.filter(function (node) { return node.source.value.match(new RegExp(val)) !== null; });
// remove "found" imports from the list of nodes
lodash_1.pull.apply(void 0, __spreadArray([originalNodes], x));
if (x.length > 0) {
x.sort(function (a, b) { return javascript_natural_sort_1.default(a.source.value, b.source.value); });
if (res.length > 0) {
return lodash_1.compact(__spreadArray(__spreadArray(__spreadArray([], res), [newLine]), x));
}
return x;
var finalNodes = [];
if (!importOrder.includes(constants_1.THIRD_PARTY_MODULES_SPECIAL_WORD)) {
importOrder = __spreadArray([constants_1.THIRD_PARTY_MODULES_SPECIAL_WORD], importOrder);
}
var importOrderGroups = importOrder.reduce(function (groups, regexp) {
var _a;
return (__assign(__assign({}, groups), (_a = {}, _a[regexp] = [], _a)));
}, {});
var importOrderWithOutThirdPartyPlaceholder = importOrder.filter(function (group) { return group !== constants_1.THIRD_PARTY_MODULES_SPECIAL_WORD; });
for (var _i = 0, originalNodes_1 = originalNodes; _i < originalNodes_1.length; _i++) {
var node = originalNodes_1[_i];
var matchedGroup = get_import_nodes_matched_group_1.getImportNodesMatchedGroup(node, importOrderWithOutThirdPartyPlaceholder);
importOrderGroups[matchedGroup].push(node);
}
for (var _a = 0, importOrder_1 = importOrder; _a < importOrder_1.length; _a++) {
var group = importOrder_1[_a];
var groupNodes = importOrderGroups[group];
if (groupNodes.length === 0)
continue;
var sortedInsideGroup = groupNodes.sort(function (a, b) {
return javascript_natural_sort_1.default(a.source.value, b.source.value);
});
// Sort the import specifiers
if (importOrderSortSpecifiers) {
sortedInsideGroup.forEach(function (node) {
return get_sorted_import_specifiers_1.getSortedImportSpecifiers(node);
});
}
return res;
}, []);
var sortedNodesNotInImportOrder = originalNodes.filter(function (node) {
return !is_similar_text_in_array_1.isSimilarTextExistInArray(options.importOrder, node.source.value);
});
sortedNodesNotInImportOrder.sort(function (a, b) {
return javascript_natural_sort_1.default(a.source.value, b.source.value);
});
var shouldAddNewLineInBetween = sortedNodesNotInImportOrder.length > 0 && options.importOrderSeparation;
if (options.sortModules) {
sortedNodesByImportOrder
.filter(function (node) {
return node.type === 'ImportDeclaration';
})
.forEach(function (node) { return getSortedModulesImport(node); });
sortedNodesNotInImportOrder.forEach(function (node) {
return getSortedModulesImport(node);
});
finalNodes.push.apply(finalNodes, sortedInsideGroup);
if (importOrderSeparation) {
finalNodes.push(constants_1.newLineNode);
}
}
var allSortedNodes = lodash_1.compact(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], sortedNodesNotInImportOrder), [
shouldAddNewLineInBetween ? constants_1.newLineNode : null
]), sortedNodesByImportOrder), [
constants_1.newLineNode, // insert a newline after all sorted imports
]));
if (finalNodes.length > 0 && !importOrderSeparation) {
// a newline after all imports
finalNodes.push(constants_1.newLineNode);
}
// maintain a copy of the nodes to extract comments from
var sortedNodesClone = allSortedNodes.map(lodash_1.clone);
var finalNodesClone = finalNodes.map(lodash_1.clone);
var firstNodesComments = nodes[0].leadingComments;
// Remove all comments from sorted nodes
allSortedNodes.forEach(types_1.removeComments);
finalNodes.forEach(types_1.removeComments);
// insert comments other than the first comments
allSortedNodes.forEach(function (node, index) {
if (!lodash_1.isEqual(nodes[0].loc, node.loc)) {
types_1.addComments(node, 'leading', sortedNodesClone[index].leadingComments || []);
}
finalNodes.forEach(function (node, index) {
if (lodash_1.isEqual(nodes[0].loc, node.loc))
return;
types_1.addComments(node, 'leading', finalNodesClone[index].leadingComments || []);
});
if (firstNodesComments) {
types_1.addComments(allSortedNodes[0], 'leading', firstNodesComments);
types_1.addComments(finalNodes[0], 'leading', firstNodesComments);
}
return allSortedNodes;
return finalNodes;
};
exports.getSortedNodes = getSortedNodes;
{
"name": "@trivago/prettier-plugin-sort-imports",
"version": "3.0.0-0",
"version": "3.0.0-1",
"description": "A prettier plugins to sort imports in provided RegEx order",

@@ -5,0 +5,0 @@ "main": "lib/src/index.js",

@@ -47,6 +47,9 @@ # Prettier plugin sort imports

#### `importOrder`
A collection of regular expressions in string format. The plugin
A collection of:
- Regular expressions in string format. The plugin
uses [`new RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
to evaluate regular expression. E.g. `node.source.value.match(new RegExp(val))` Here, `val`
is the string provided in import order.
- Special words (optional):
- `<THIRD_PARTY_MODULES>` - marks the position between RegExps, where the not matched imports will be placed. By default, it's the top position (above all the groups in `importOrder`).

@@ -75,7 +78,7 @@ #### `importOrderCaseInsensitive`

#### `sortModules`
#### `importOrderSortSpecifiers`
A boolean value to enable or disable sorting of the imports module declarations.
It is disabled by default
#### `experimentalBabelParserPluginsList`
#### `importOrderParserPlugins`
A collection of parser names for babel parser. The plugin passes this list to babel parser so it can understand the syntaxes used in the file being formatted. The plugin uses prettier itself to figure out the parser it needs to use but if that fails, you can use this field to enforce the usage of the plugins babel needs.

@@ -96,3 +99,3 @@

"importOrderCaseInsensitive": true,
"experimentalBabelParserPluginsList" : ["jsx", "typescript", "[\"decorators\", { \"decoratorsBeforeExport\": true }]"]
"importOrderParserPlugins" : ["jsx", "typescript", "[\"decorators\", { \"decoratorsBeforeExport\": true }]"]
}

@@ -109,7 +112,9 @@ ```

After, the plugin sorts the _local imports_ and _3rd party imports_ using
[natural sort algorithm](https://en.wikipedia.org/wiki/Natural_sort_order),
with case-insensitivity specified by `importOrderCaseInsensitive` (or false by default).
In the end, the plugin returns final imports with _3rd party imports_ on top and
_local imports_ at the end.
[natural sort algorithm](https://en.wikipedia.org/wiki/Natural_sort_order).
In the end, the plugin returns final imports with _3rd party imports_ on top and _local imports_ at the end.
The _3rd party imports_ position (it's top by default) can be overrided using the `<THIRD_PARTY_MODULES>` special word.
### FAQ / Troubleshooting

@@ -142,2 +147,16 @@

#### Q. How can I move `react` and `classnames` to place between my RegEx imports without hardcoding?
You can define the `<THIRD_PARTY_MODULES>` special word in the `importOrder`. For example above, the `importOrder` would be like `["^@ui/(.*)$", "^@server/(.*)$", "<THIRD_PARTY_MODULES>", '^[./]']`.
Now, the final output would be as follows:
```ecmascript 6
import p from '@ui/p';
import q from '@ui/q';
import a from '@server/a';
import z from '@server/z';
import classnames from 'classnames';
import React from 'react';
import s from './';
```
#### Q. How can I run examples in this project ?

@@ -174,3 +193,3 @@ There is a _examples_ directory. The examples file can be formatted by using

```
To solve this issue, you can use the new option `experimentalBabelParserPluginsList` in your `.prettierrc` and pass an array of plugin names to be used.
To solve this issue, you can use the new option `importOrderParserPlugins` in your `.prettierrc` and pass an array of plugin names to be used.

@@ -177,0 +196,0 @@ ### Compatibility

@@ -1,6 +0,6 @@

"use strict";
'use strict';
const fs = require("fs");
const extname = require("path").extname;
const prettier = require("prettier");
const fs = require('fs');
const extname = require('path').extname;
const prettier = require('prettier');

@@ -10,6 +10,6 @@ function run_spec(dirname, parsers, options) {

{
plugins: ["./src"],
tabWidth: 4
plugins: ['./src'],
tabWidth: 4,
},
options
options,
);

@@ -22,26 +22,30 @@

fs.readdirSync(dirname).forEach(filename => {
const path = dirname + "/" + filename;
fs.readdirSync(dirname).forEach((filename) => {
const path = dirname + '/' + filename;
if (
extname(filename) !== ".snap" &&
extname(filename) !== '.snap' &&
fs.lstatSync(path).isFile() &&
filename[0] !== "." &&
filename !== "ppsi.spec.js"
filename[0] !== '.' &&
filename !== 'ppsi.spec.js'
) {
const source = read(path).replace(/\r\n/g, "\n");
const source = read(path).replace(/\r\n/g, '\n');
const mergedOptions = Object.assign({}, options, {
parser: parsers[0]
parser: parsers[0],
});
const output = prettyprint(source, path, mergedOptions);
test(`${filename} - ${mergedOptions.parser}-verify`, () => {
expect(
raw(source + "~".repeat(80) + "\n" + output)
).toMatchSnapshot(filename);
try {
expect(
raw(source + '~'.repeat(80) + '\n' + output),
).toMatchSnapshot(filename);
} catch (e) {
console.error(e, path);
}
});
parsers.slice(1).forEach(parserName => {
parsers.slice(1).forEach((parserName) => {
test(`${filename} - ${parserName}-verify`, () => {
const verifyOptions = Object.assign(mergedOptions, {
parser: parserName
parser: parserName,
});

@@ -51,3 +55,3 @@ const verifyOutput = prettyprint(

path,
verifyOptions
verifyOptions,
);

@@ -64,14 +68,14 @@ expect(output).toEqual(verifyOutput);

if (Array.isArray(ast)) {
return ast.map(e => stripLocation(e));
return ast.map((e) => stripLocation(e));
}
if (typeof ast === "object") {
if (typeof ast === 'object') {
const newObj = {};
for (const key in ast) {
if (
key === "loc" ||
key === "range" ||
key === "raw" ||
key === "comments" ||
key === "parent" ||
key === "prev"
key === 'loc' ||
key === 'range' ||
key === 'raw' ||
key === 'comments' ||
key === 'parent' ||
key === 'prev'
) {

@@ -96,6 +100,6 @@ continue;

{
filepath: filename
filepath: filename,
},
options
)
options,
),
);

@@ -105,3 +109,3 @@ }

function read(filename) {
return fs.readFileSync(filename, "utf8");
return fs.readFileSync(filename, 'utf8');
}

@@ -115,6 +119,6 @@

function raw(string) {
if (typeof string !== "string") {
throw new Error("Raw snapshots have to be strings.");
if (typeof string !== 'string') {
throw new Error('Raw snapshots have to be strings.');
}
return { [Symbol.for("raw")]: string };
return { [Symbol.for('raw')]: string };
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc