UNPKG

@rushstack/eslint-plugin

Version:

An ESLint plugin providing supplementary rules for use with the @rushstack/eslint-config package

95 lines 4.51 kB
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. import * as path from 'node:path'; import { ESLintUtils, TSESTree } from '@typescript-eslint/utils'; // Regex to parse out the import target from the specifier. Expected formats are: // - '<target>' // - '<loader>!<target>' // - '<target>?<loader-options>' // - '<loader>!<target>?<loader-options>' const LOADER_CAPTURE_GROUP = 'loader'; const IMPORT_TARGET_CAPTURE_GROUP = 'importTarget'; const LOADER_OPTIONS_CAPTURE_GROUP = 'loaderOptions'; const SPECIFIER_REGEX = new RegExp(`^((?<${LOADER_CAPTURE_GROUP}>(!|-!|!!).+)!)?` + `(?<${IMPORT_TARGET_CAPTURE_GROUP}>[^!?]+)` + `(\\?(?<${LOADER_OPTIONS_CAPTURE_GROUP}>.*))?$`); export function getFilePathFromContext(context) { return context.physicalFilename || context.filename; } export function getRootDirectoryFromContext(context) { /* * Precedence of root directory resolution: * 1. parserOptions.tsconfigRootDir if available (since set by repo maintainer) * 2. tsconfig.json directory if available (but might be in a subfolder) * 3. TS Program current directory if available * 4. ESLint working directory (probably wrong, but better than nothing?) */ const tsConfigRootDir = context.parserOptions?.tsconfigRootDir; if (tsConfigRootDir) { return tsConfigRootDir; } try { const program = (context.sourceCode?.parserServices ?? ESLintUtils.getParserServices(context)).program; const compilerOptions = program?.getCompilerOptions(); const tsConfigPath = compilerOptions?.configFilePath; if (tsConfigPath) { const tsConfigDir = path.dirname(tsConfigPath); return tsConfigDir; } // Next, try to get the current directory from the TS program const rootDirectory = program?.getCurrentDirectory(); if (rootDirectory) { return rootDirectory; } } catch { // Ignore the error if we cannot retrieve a TS program } // Last resort: use ESLint's current working directory return context.getCwd?.(); } export function parseImportSpecifierFromExpression(importExpression) { if (!importExpression || importExpression.type !== TSESTree.AST_NODE_TYPES.Literal || typeof importExpression.value !== 'string') { // Can't determine the path of the import target, return return undefined; } // Extract the target of the import, stripping out webpack loaders and query strings. The regex will // also ensure that the import target is a relative path. const specifierMatch = importExpression.value.match(SPECIFIER_REGEX); if (!specifierMatch?.groups) { // Can't determine the path of the import target, return return undefined; } const loader = specifierMatch.groups[LOADER_CAPTURE_GROUP]; const importTarget = specifierMatch.groups[IMPORT_TARGET_CAPTURE_GROUP]; const loaderOptions = specifierMatch.groups[LOADER_OPTIONS_CAPTURE_GROUP]; return { loader, importTarget, loaderOptions }; } export function serializeImportSpecifier(parsedImportPath) { const { loader, importTarget, loaderOptions } = parsedImportPath; return `${loader ? `${loader}!` : ''}${importTarget}${loaderOptions ? `?${loaderOptions}` : ''}`; } export function getImportPathFromExpression(importExpression, relativeImportsOnly = true) { const parsedImportSpecifier = parseImportSpecifierFromExpression(importExpression); if (!parsedImportSpecifier || (relativeImportsOnly && !parsedImportSpecifier.importTarget.startsWith('.'))) { // The import target isn't a path, return return undefined; } return parsedImportSpecifier?.importTarget; } export function getImportAbsolutePathFromExpression(context, importExpression, relativeImportsOnly = true) { const importPath = getImportPathFromExpression(importExpression, relativeImportsOnly); if (importPath === undefined) { // Can't determine the absolute path of the import target, return return undefined; } const filePath = getFilePathFromContext(context); const fileDirectory = path.dirname(filePath); // Combine the import path with the absolute path of the file parent directory to get the // absolute path of the import target return path.resolve(fileDirectory, importPath); } //# sourceMappingURL=LintUtilities.js.map