eslint-plugin-canonical
Version:
Canonical linting rules for ESLint.
145 lines (144 loc) • 5.74 kB
JavaScript
;
/* eslint-disable @typescript-eslint/no-non-null-assertion */
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @file Rule to ensure that filenames match the exports of the file
* @author Stefan Lau
* @see https://github.com/selaux/eslint-plugin-filenames/blob/32fc70dd7572211d1e5b97e06ec7a005c77fe8d4/lib/rules/match-exported.js
*/
const node_path_1 = __importDefault(require("node:path"));
const lodash_1 = require("lodash");
const utilities_1 = require("../utilities");
const transformMap = {
camel: lodash_1.camelCase,
kebab: lodash_1.kebabCase,
pascal(name) {
return (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(name));
},
snake: lodash_1.snakeCase,
};
const getStringToCheckAgainstExport = (parsed, replacePattern) => {
const directoryArray = parsed.dir.split(node_path_1.default.sep);
const lastDirectory = directoryArray[directoryArray.length - 1];
if ((0, utilities_1.isIndexFile)(parsed)) {
return lastDirectory;
}
return replacePattern ? parsed.name.replace(replacePattern, '') : parsed.name;
};
const getTransformsFromOptions = (option) => {
const usedTransforms = (option === null || option === void 0 ? void 0 : option.push) ? option : [option];
return usedTransforms.map((name) => {
return transformMap[name];
});
};
const transform = (exportedName, transforms) => {
return transforms.map((format) => {
return format ? format(exportedName) : exportedName;
});
};
const anyMatch = (expectedExport, transformedNames) => {
return transformedNames.includes(expectedExport);
};
const getWhatToMatchMessage = (transforms) => {
if (transforms.length === 1 && !transforms[0]) {
return 'the exported name';
}
if (transforms.length > 1) {
return 'any of the exported and transformed names';
}
return 'the exported and transformed name';
};
exports.default = (0, utilities_1.createRule)({
create: (context, [options]) => {
var _a;
const filename = (_a = context.filename) !== null && _a !== void 0 ? _a : context.getFilename();
return {
Program(node) {
const transforms = getTransformsFromOptions(options.transforms);
const replacePattern = options.suffix
? new RegExp(options.suffix, 'u')
: undefined;
const absoluteFilename = node_path_1.default.resolve(filename);
const parsed = (0, utilities_1.parseFilename)(absoluteFilename);
const shouldIgnore = (0, utilities_1.isIgnoredFilename)(filename);
const exportedName = (0, utilities_1.getExportedName)(node, Boolean(options.matchCallExpression));
const isExporting = Boolean(exportedName);
const expectedExport = getStringToCheckAgainstExport(parsed, replacePattern);
const transformedNames = transform(exportedName, transforms);
const everythingIsIndex = exportedName === 'index' && parsed.name === 'index';
const matchesExported = anyMatch(expectedExport, transformedNames) || everythingIsIndex;
if (shouldIgnore || !isExporting || matchesExported) {
return;
}
context.report({
data: {
expectedExport,
exportName: transformedNames.join("', '"),
extension: parsed.ext,
name: parsed.base,
whatToMatch: getWhatToMatchMessage(transforms),
},
messageId: (0, utilities_1.isIndexFile)(parsed) ? 'indexFile' : 'regularFile',
node,
});
},
};
},
defaultOptions: [
{
matchCallExpression: false,
suffix: null,
transforms: null,
},
],
meta: {
docs: {
description: 'Match the file name against the default exported value in the module.',
},
messages: {
indexFile: "The directory '{{expectedExport}}' must be named '{{exportName}}', after the exported value of its index file.",
regularFile: "Filename '{{expectedExport}}' must match {{whatToMatch}} '{{exportName}}'.",
},
schema: [
{
properties: {
matchCallExpression: {
type: 'boolean',
},
suffix: {
oneOf: [
{
type: 'string',
},
{
type: 'null',
},
],
},
transforms: {
oneOf: [
{
items: {
type: 'string',
},
type: 'array',
},
{
type: 'string',
},
{
type: 'null',
},
],
},
},
type: 'object',
},
],
type: 'suggestion',
},
name: 'filename-match-exported',
});