All files / src/services imports.ts

100% Statements 55/55
100% Branches 29/29
100% Functions 15/15
100% Lines 49/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                    6x                       6x 113x     6x 19x   19x 77x 77x   64x 1x   63x     64x     19x     6x   140x       140x 13x 8x               127x     6x       27x 44x   27x 63x 63x   44x         131x       70x       40x 40x   41x     40x     6x     4x 20x         6x     23x 140x 134x 24x     110x       110x 110x     140x   8x   13x   37x   76x   6x      
import { SourceCode } from "eslint";
import {
  Node,
  Program,
  ImportSpecifier,
  ImportDeclaration,
  ImportDefaultSpecifier,
  ImportNamespaceSpecifier,
} from "estree";
 
const DEFAULT_SORT_INDEX = 100;
 
type ImportSpecifierNode =
  | ImportSpecifier
  | ImportDefaultSpecifier
  | ImportNamespaceSpecifier;
 
export type CalculateSortOpts = {
  sortBySpecifier?: boolean;
  disableLineSorts: boolean;
};
 
export function isImportDeclaration(node: Node): node is ImportDeclaration {
  return node.type === "ImportDeclaration";
}
 
export function getImportsWithNodesBetween(program: Program) {
  const nodes = [];
 
  for (let i = 0, lastMatchedIndex = null; i < program.body.length; i++) {
    const node = program.body[i];
    if (!isImportDeclaration(node)) continue;
 
    if (lastMatchedIndex !== null && lastMatchedIndex !== i - 1) {
      nodes.push(...program.body.slice(lastMatchedIndex + 1, i + 1));
    } else {
      nodes.push(node);
    }
 
    lastMatchedIndex = i;
  }
 
  return nodes as ImportDeclaration[];
}
 
export function getImportType(node?: ImportDeclaration) {
  /* istanbul ignore if */
  if (!node) {
    return null;
  }
 
  if (!node.specifiers || !node.specifiers.length) {
    if (isImportDeclaration(node)) {
      return "ImportFileSpecifier";
    }
 
    /* istanbul ignore next */
    return null;
  }
 
  // treat import React, { useState } from 'react' as defaults by the type of the first specifier
  return node.specifiers[0].type;
}
 
export function getFirstNotSorted<T extends Node>(
  imports: T[],
  calculateSortIndex: (node?: T) => number
) {
  const isNodesSorted = (a: T, b: T) =>
    calculateSortIndex(a) <= calculateSortIndex(b);
 
  return imports.find((current, i) => {
    const next = imports[i + 1];
    if (next === undefined) return false;
 
    return !isNodesSorted(current, next);
  });
}
 
function getNodeLength(node: Node, sourceCode: SourceCode) {
  return sourceCode.getText(node).length;
}
 
function getImportLength(node: ImportDeclaration, sourceCode: SourceCode) {
  return getNodeLength(node, sourceCode);
}
 
function getSpecifiersLength(node: ImportDeclaration, sourceCode: SourceCode) {
  const commaLength = 1;
  const specifiersLength = node.specifiers.reduce(
    (length: number, node: Node) =>
      getNodeLength(node, sourceCode) + commaLength + length,
    0
  );
  return specifiersLength - commaLength;
}
 
export const createCalculateSpecifierSortIndex = (
  sourceCode: SourceCode,
  options: CalculateSortOpts
) => (node?: ImportSpecifierNode) =>
  node && !options.disableLineSorts
    ? getNodeLength(node, sourceCode)
    /* istanbul ignore next */
    : DEFAULT_SORT_INDEX;
 
export const createCalculateSortIndex = (
  sourceCode: SourceCode,
  options: CalculateSortOpts
) => (node?: ImportDeclaration) => {
  const includeLineLength = (initialIndex: number) => {
    if (!node || options.disableLineSorts) {
      return initialIndex;
    }
 
    const criterion = options.sortBySpecifier
      ? getSpecifiersLength(node, sourceCode)
      : getImportLength(node, sourceCode);
 
    const lineLengthIndex = criterion / 100;
    return initialIndex + lineLengthIndex;
  };
 
  switch (getImportType(node)) {
    case "ImportFileSpecifier":
      return includeLineLength(1);
    case "ImportNamespaceSpecifier":
      return includeLineLength(2);
    case "ImportDefaultSpecifier":
      return includeLineLength(3);
    case "ImportSpecifier":
      return includeLineLength(4);
    default:
      return DEFAULT_SORT_INDEX;
  }
};