eslint-plugin-next-route-params
Version:
eslint rule to enforce correct route parameters for Next.js
149 lines (148 loc) • 5.27 kB
JavaScript
;
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"));
}