UNPKG

sortier

Version:
112 lines (111 loc) 4.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sortImportDeclarationSpecifiers = sortImportDeclarationSpecifiers; const log_utils_js_1 = require("../../utilities/log-utils.js"); const sort_utils_js_1 = require("../../utilities/sort-utils.js"); function sortImportDeclarationSpecifiers(specifiers, comments, fileContents, options) { const cleanedOptions = ensureOptions(options); fileContents = sortSingleSpecifier(specifiers, comments, fileContents, cleanedOptions); return fileContents; } function sortSingleSpecifier(specifiers, comments, fileContents, options) { // If there is one or less specifiers, there is not anything to sort if (specifiers.length <= 1) { return fileContents; } const unsortedSpecifiers = specifiers.map((specifier) => { const importedName = specifier.imported != null ? specifier.imported.name : specifier.local.name; let start = specifier.start || specifier.range[0]; const end = specifier.end || specifier.range[1]; // Modify start based on the importKind if needed switch (specifier.importKind) { case "typeof": case "type": { // Flow doesn't provide us the range from "type <Specifier>", they only provide // the range of "<specifier>" so we're going to be a bit safe here and do some checks const possibleNewStart = fileContents.lastIndexOf(specifier.importKind, start); const textBetweenOldStartAndNewStart = fileContents.substring(possibleNewStart + specifier.importKind.length, start); const isNonWhitespaceBetweenOldStartAndNewStart = textBetweenOldStartAndNewStart.match(/\S/) != null; if (isNonWhitespaceBetweenOldStartAndNewStart) { return null; } start = possibleNewStart; break; } case "value": case undefined: case null: break; default: // If it's a type we haven't encountered, return null so we don't sort return null; } return { importKind: specifier.importKind, importedName: importedName, isDefaultImportType: specifier.type.indexOf("Default") !== -1, isInterface: nameIsLikelyInterface(importedName), range: [start, end], }; }); if (unsortedSpecifiers.includes(null)) { // If something weird happened when parsing the specifiers, exit without sorting log_utils_js_1.LogUtils.log(log_utils_js_1.LoggerVerboseOption.Diagnostic, "Encountered issue parsing import specifiers, skipping sorting this node"); return fileContents; } // First create an object to remember all that we care about const sortedSpecifiers = unsortedSpecifiers.slice(); // Sort them by name let everythingRank = options.groups.indexOf("*"); if (everythingRank === -1) { everythingRank = 0; } let interfaceRank = options.groups.indexOf("interfaces"); if (interfaceRank === -1) { interfaceRank = everythingRank; } let typeRanking = options.groups.indexOf("types"); if (typeRanking === -1) { typeRanking = everythingRank; } sortedSpecifiers.sort((a, b) => { let aRank = everythingRank; if (a.isInterface) { aRank = interfaceRank; } if (a.importKind === "type" || a.importKind === "typeof") { aRank = typeRanking; } if (a.isDefaultImportType) { aRank = aRank - options.groups.length; } let bRank = everythingRank; if (b.isInterface) { bRank = interfaceRank; } if (b.importKind === "type" || b.importKind === "typeof") { bRank = typeRanking; } if (b.isDefaultImportType) { bRank = bRank - options.groups.length; } if (aRank === bRank) { return (0, sort_utils_js_1.compare)(a.importedName, b.importedName); } return aRank - bRank; }); return (0, sort_utils_js_1.reorderValues)(fileContents, comments, unsortedSpecifiers, sortedSpecifiers); } function nameIsLikelyInterface(name) { return name.length >= 2 && name[0] === "I" && "A" <= name[1] && name[1] <= "Z"; } function ensureOptions(options) { if (options == null) { return { groups: ["*", "interfaces", "types"], }; } return { groups: options.groups || ["*", "interfaces", "types"], }; }