UNPKG

eslint-plugin-next-route-params

Version:

eslint rule to enforce correct route parameters for Next.js

149 lines (148 loc) 5.27 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFileInfo = getFileInfo; const path_1 = __importStar(require("path")); const fs_1 = __importDefault(require("fs")); const semVer = __importStar(require("semver")); const constants_1 = require("./constants"); const toPosixPath = (p) => p.split(path_1.default.sep).join(path_1.posix.sep); const getFilePathToPosix = (filename) => { // const pathFromRoot = path.dirname(context.filename); return toPosixPath(path_1.default.dirname(filename)); }; /** * * @param dirname the dirname containing the folders, the separator must be "/" * @returns true if a folder named "app" is found */ function appRouterFolderExists(dirname) { return dirname.split(path_1.posix.sep).includes("app"); } /** * * * @param dirname the dirname containing the folders, the separator must be "/" * @returns a list of the dynamic parameters and if if they are catch all parameters */ function readFileBasedParameters(dirname) { const folders = dirname.split(path_1.posix.sep); const appPosition = folders.findIndex((folder) => folder === "app"); if (appPosition === -1) { return []; } const result = folders .filter((folder) => folder.startsWith("[") && folder.endsWith("]")) .map((folder) => { const catchAll = folder.startsWith("[..."); const name = folder.slice(catchAll ? 4 : 1, -1); return { catchAll, name, current: false }; }); const lastFolderName = folders[folders.length - 1]; if (lastFolderName?.endsWith("]")) { result[result.length - 1].current = true; } return result; } /** * * @param filename the filename containing the folders * @returns true if the filename is one of Next.js' app router files that accecpt paramaters ({@link https://nextjs.org/docs/app/api-reference/file-conventions}) */ function isAppRouterFile(filename) { return filename !== null; } const FileNameTypeToAllowedPropsMap = { default: [constants_1.PARAMS_PROP_NAME], layout: [...constants_1.ALLOWED_PROPS_FOR_LAYOUT], page: [...constants_1.ALLOWED_PROPS_FOR_PAGE], route: [constants_1.PARAMS_PROP_NAME], }; function getFileInfo(filename) { const parsedPath = path_1.default.parse(filename); const dirname = getFilePathToPosix(filename); const fileNameType = getFilenameType(parsedPath.name); return { isAppRouterFile: isAppRouterFile(fileNameType), appRouterFilename: fileNameType, inInAppRouterFolder: appRouterFolderExists(dirname), params: readFileBasedParameters(dirname), asyncRequestAPI: isAsyncRequestAPI(), allowedPropsForFileNameType: fileNameType ? FileNameTypeToAllowedPropsMap[fileNameType] : null, }; } function getFilenameType(filename) { switch (path_1.default.parse(filename).name) { case "page": return "page"; case "layout": return "layout"; case "default": return "default"; case "route": return "route"; default: return null; } } function isAsyncRequestAPI() { const packageJson = readPackageJson(); if (!packageJson) { return null; } const nextDependency = packageJson.dependencies?.next; if (!nextDependency) { return null; } const minVersion = semVer.minVersion(nextDependency); if (!minVersion) { return null; } const nextVersion = semVer.major(minVersion); if (!nextVersion) { return null; } const isNotAsycRequestAPI = nextVersion > 12 && nextVersion < 14; const isAsycRequestAPI = nextVersion > 14; if (isNotAsycRequestAPI) { return false; } if (isAsycRequestAPI) { return true; } return null; } function readPackageJson() { const packageJsonPath = path_1.default.join(process.cwd(), "package.json"); if (!fs_1.default.existsSync(packageJsonPath)) { return null; } return JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf-8")); }