Skip to content

⬅️ Back to Table of Contents

πŸ“„ consistent-type-exports.ts

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 6
πŸ“¦ Imports 11
πŸ“Š Variables & Constants 11
πŸ“ Interfaces 2
πŸ“‘ Type Aliases 2

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/consistent-type-exports.ts

πŸ“¦ Imports

Name Source
TSESLint @typescript-eslint/utils
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
AST_TOKEN_TYPES @typescript-eslint/utils
createRule ../util
formatWordList ../util
getParserServices ../util
isClosingBraceToken ../util
isOpeningBraceToken ../util
nullThrows ../util
NullThrowsReasons ../util

Variables & Constants

Name Type Kind Value Exported
sourceExportsMap Record<string, SourceExports> const {} βœ—
aliasedSymbol any const `tsutils.isSymbolFlagSet(
symbol,
ts.SymbolFlags.Alias,
)
? checker.getAliasedSymbol(symbol)
: symbol` βœ—
source string const getSourceFromExport(node) ?? 'undefined' βœ—
sourceExports SourceExports const `(sourceExportsMap[source]
reportValueExports: [],
source,
typeOnlyNamedExport: null,
valueOnlyNamedExport: null,
})` βœ—
typeBasedSpecifiers TSESTree.ExportSpecifier[] const [] βœ—
inlineTypeSpecifiers TSESTree.ExportSpecifier[] const [] βœ—
valueSpecifiers TSESTree.ExportSpecifier[] const [] βœ—
exportNames any const allExportNames[0] βœ—
typeSpecifiers any[] let/var [...typeBasedSpecifiers, ...inlineTypeSpecifiers] βœ—
exportedName any const `specifier.exported.type === AST_NODE_TYPES.Literal
? specifier.exported.raw
: specifier.exported.name` βœ—
localName any const `specifier.local.type === AST_NODE_TYPES.Literal
? specifier.local.raw
: specifier.local.name` βœ—

Functions

isSymbolTypeBased(symbol: ts.Symbol | undefined): boolean | undefined

Code
function isSymbolTypeBased(
      symbol: ts.Symbol | undefined,
    ): boolean | undefined {
      if (!symbol) {
        return undefined;
      }

      const aliasedSymbol = tsutils.isSymbolFlagSet(
        symbol,
        ts.SymbolFlags.Alias,
      )
        ? checker.getAliasedSymbol(symbol)
        : symbol;

      if (checker.isUnknownSymbol(aliasedSymbol)) {
        return undefined;
      }

      return !(aliasedSymbol.flags & ts.SymbolFlags.Value);
    }
  • JSDoc:

    /**
         * Helper for identifying if a symbol resolves to a
         * JavaScript value or a TypeScript type.
         *
         * @returns True/false if is a type or not, or undefined if the specifier
         * can't be resolved.
         */
    

  • Parameters:

  • symbol: ts.Symbol | undefined
  • Return Type: boolean | undefined
  • Calls:
  • tsutils.isSymbolFlagSet
  • checker.getAliasedSymbol
  • checker.isUnknownSymbol

fixExportInsertType(fixer: TSESLint.RuleFixer, sourceCode: Readonly<TSESLint.SourceCode>, node: TSESTree.ExportNamedDeclaration): IterableIterator<TSESLint.RuleFix>

Code
function* fixExportInsertType(
  fixer: TSESLint.RuleFixer,
  sourceCode: Readonly<TSESLint.SourceCode>,
  node: TSESTree.ExportNamedDeclaration,
): IterableIterator<TSESLint.RuleFix> {
  const exportToken = nullThrows(
    sourceCode.getFirstToken(node),
    NullThrowsReasons.MissingToken('export', node.type),
  );

  yield fixer.insertTextAfter(exportToken, ' type');

  for (const specifier of node.specifiers) {
    if (specifier.exportKind === 'type') {
      const kindToken = nullThrows(
        sourceCode.getFirstToken(specifier),
        NullThrowsReasons.MissingToken('export', specifier.type),
      );
      const firstTokenAfter = nullThrows(
        sourceCode.getTokenAfter(kindToken, {
          includeComments: true,
        }),
        'Missing token following the export kind.',
      );

      yield fixer.removeRange([kindToken.range[0], firstTokenAfter.range[0]]);
    }
  }
}
  • JSDoc:

    /**
     * Inserts "type" into an export.
     *
     * Example:
     *
     * export type { Foo } from 'foo';
     *        ^^^^
     */
    

  • Parameters:

  • fixer: TSESLint.RuleFixer
  • sourceCode: Readonly<TSESLint.SourceCode>
  • node: TSESTree.ExportNamedDeclaration
  • Return Type: IterableIterator<TSESLint.RuleFix>
  • Calls:
  • nullThrows (from ../util)
  • sourceCode.getFirstToken
  • NullThrowsReasons.MissingToken
  • fixer.insertTextAfter
  • sourceCode.getTokenAfter
  • fixer.removeRange

fixSeparateNamedExports(fixer: TSESLint.RuleFixer, sourceCode: Readonly<TSESLint.SourceCode>, report: ReportValueExport): IterableIterator<TSESLint.RuleFix>

Code
function* fixSeparateNamedExports(
  fixer: TSESLint.RuleFixer,
  sourceCode: Readonly<TSESLint.SourceCode>,
  report: ReportValueExport,
): IterableIterator<TSESLint.RuleFix> {
  const { node, inlineTypeSpecifiers, typeBasedSpecifiers, valueSpecifiers } =
    report;
  const typeSpecifiers = [...typeBasedSpecifiers, ...inlineTypeSpecifiers];
  const source = getSourceFromExport(node);
  const specifierNames = typeSpecifiers.map(getSpecifierText).join(', ');

  const exportToken = nullThrows(
    sourceCode.getFirstToken(node),
    NullThrowsReasons.MissingToken('export', node.type),
  );

  // Filter the bad exports from the current line.
  const filteredSpecifierNames = valueSpecifiers
    .map(getSpecifierText)
    .join(', ');
  const openToken = nullThrows(
    sourceCode.getFirstToken(node, isOpeningBraceToken),
    NullThrowsReasons.MissingToken('{', node.type),
  );
  const closeToken = nullThrows(
    sourceCode.getLastToken(node, isClosingBraceToken),
    NullThrowsReasons.MissingToken('}', node.type),
  );

  // Remove exports from the current line which we're going to re-insert.
  yield fixer.replaceTextRange(
    [openToken.range[1], closeToken.range[0]],
    ` ${filteredSpecifierNames} `,
  );

  // Insert the bad exports into a new export line above.
  yield fixer.insertTextBefore(
    exportToken,
    `export type { ${specifierNames} }${source ? ` from '${source}'` : ''};\n`,
  );
}
  • JSDoc:

    /**
     * Separates the exports which mismatch the kind of export the given
     * node represents. For example, a type export's named specifiers which
     * represent values will be inserted in a separate `export` statement.
     */
    

  • Parameters:

  • fixer: TSESLint.RuleFixer
  • sourceCode: Readonly<TSESLint.SourceCode>
  • report: ReportValueExport
  • Return Type: IterableIterator<TSESLint.RuleFix>
  • Calls:
  • getSourceFromExport
  • typeSpecifiers.map(getSpecifierText).join
  • nullThrows (from ../util)
  • sourceCode.getFirstToken
  • NullThrowsReasons.MissingToken
  • valueSpecifiers .map(getSpecifierText) .join
  • sourceCode.getLastToken
  • fixer.replaceTextRange
  • fixer.insertTextBefore
  • Internal Comments:
    // Filter the bad exports from the current line. (x2)
    // Remove exports from the current line which we're going to re-insert. (x2)
    // Insert the bad exports into a new export line above. (x2)
    

fixAddTypeSpecifierToNamedExports(fixer: TSESLint.RuleFixer, report: ReportValueExport): IterableIterator<TSESLint.RuleFix>

Code
function* fixAddTypeSpecifierToNamedExports(
  fixer: TSESLint.RuleFixer,
  report: ReportValueExport,
): IterableIterator<TSESLint.RuleFix> {
  if (report.node.exportKind === 'type') {
    return;
  }

  for (const specifier of report.typeBasedSpecifiers) {
    yield fixer.insertTextBefore(specifier, 'type ');
  }
}
  • Parameters:
  • fixer: TSESLint.RuleFixer
  • report: ReportValueExport
  • Return Type: IterableIterator<TSESLint.RuleFix>
  • Calls:
  • fixer.insertTextBefore

getSourceFromExport(node: TSESTree.ExportNamedDeclaration): string | undefined

Code
function getSourceFromExport(
  node: TSESTree.ExportNamedDeclaration,
): string | undefined {
  if (
    node.source?.type === AST_NODE_TYPES.Literal &&
    typeof node.source.value === 'string'
  ) {
    return node.source.value;
  }

  return undefined;
}
  • JSDoc:

    /**
     * Returns the source of the export, or undefined if the named export has no source.
     */
    

  • Parameters:

  • node: TSESTree.ExportNamedDeclaration
  • Return Type: string | undefined

getSpecifierText(specifier: TSESTree.ExportSpecifier): string

Code
function getSpecifierText(specifier: TSESTree.ExportSpecifier): string {
  const exportedName =
    specifier.exported.type === AST_NODE_TYPES.Literal
      ? specifier.exported.raw
      : specifier.exported.name;
  const localName =
    specifier.local.type === AST_NODE_TYPES.Literal
      ? specifier.local.raw
      : specifier.local.name;

  return `${localName}${
    exportedName !== localName ? ` as ${exportedName}` : ''
  }`;
}
  • JSDoc:

    /**
     * Returns the specifier text for the export. If it is aliased, we take care to return
     * the proper formatting.
     */
    

  • Parameters:

  • specifier: TSESTree.ExportSpecifier
  • Return Type: string

Interfaces

SourceExports

Interface Code
interface SourceExports {
  reportValueExports: ReportValueExport[];
  source: string;
  typeOnlyNamedExport: TSESTree.ExportNamedDeclaration | null;
  valueOnlyNamedExport: TSESTree.ExportNamedDeclaration | null;
}

Properties

Name Type Optional Description
reportValueExports ReportValueExport[] βœ—
source string βœ—
typeOnlyNamedExport TSESTree.ExportNamedDeclaration | null βœ—
valueOnlyNamedExport TSESTree.ExportNamedDeclaration | null βœ—

ReportValueExport

Interface Code
interface ReportValueExport {
  inlineTypeSpecifiers: TSESTree.ExportSpecifier[];
  node: TSESTree.ExportNamedDeclaration;
  typeBasedSpecifiers: TSESTree.ExportSpecifier[];
  valueSpecifiers: TSESTree.ExportSpecifier[];
}

Properties

Name Type Optional Description
inlineTypeSpecifiers TSESTree.ExportSpecifier[] βœ—
node TSESTree.ExportNamedDeclaration βœ—
typeBasedSpecifiers TSESTree.ExportSpecifier[] βœ—
valueSpecifiers TSESTree.ExportSpecifier[] βœ—

Type Aliases

Options

type Options = [
  {
    fixMixedExportsWithInlineTypeSpecifier: boolean;
  },
];

MessageIds

type MessageIds = | 'multipleExportsAreTypes'
  | 'singleExportIsType'
  | 'typeOverValue';