UNPKG

eslint-plugin-canonical

Version:
145 lines (144 loc) 5.74 kB
"use strict"; /* 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', });