unplugin-convention-routes
Version:
File system base router plugin for unplugin
795 lines (775 loc) • 27.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/index.ts
import path3 from "node:path";
import process4 from "node:process";
import { createUnplugin } from "unplugin";
// src/core/context.ts
import { existsSync, writeFileSync } from "node:fs";
import path2, { join as join2, resolve as resolve3 } from "node:path";
import process3 from "node:process";
import { slash as slash4, toArray as toArray2 } from "@antfu/utils";
import chokidar from "chokidar";
// src/core/files.ts
import { join } from "node:path";
import { slash as slash2 } from "@antfu/utils";
import fg from "fast-glob";
// src/core/utils.ts
import { resolve, win32 } from "node:path";
import { slash } from "@antfu/utils";
import Debug from "debug";
// src/core/constants.ts
var MODULE_IDS = [
"~pages",
"~react-pages",
"~solid-pages",
"pages-generated",
"virtual:generated-pages",
"virtual:generated-pages-react"
];
var ROUTE_IMPORT_NAME = "__pages_import_$1__";
var dynamicRouteRE = /^\[(.+)\]$/;
var cacheAllRouteRE = /^\[\.{3}(.*)\]$/;
var replaceDynamicRouteRE = /^\[(?:\.{3})?(.*)\]$/;
var nuxtDynamicRouteRE = /^_(.*)$/;
var nuxtCacheAllRouteRE = /^_$/;
var countSlashRE = /\//g;
var replaceIndexRE = /\/?index$/;
// src/core/utils.ts
var debug = {
// hmr: Debug('unplugin-convention-routes:hmr'),
routeBlock: Debug("unplugin-convention-routes:routeBlock"),
options: Debug("unplugin-convention-routes:options"),
pages: Debug("unplugin-convention-routes:pages"),
search: Debug("unplugin-convention-routes:search"),
env: Debug("unplugin-convention-routes:env"),
cache: Debug("unplugin-convention-routes:cache"),
resolver: Debug("unplugin-convention-routes:resolver")
};
function extsToGlob(extensions) {
return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
}
function countSlash(value) {
return (value.match(countSlashRE) || []).length;
}
function isPagesDir(path4, options) {
for (const page of options.dirs) {
const dirPath = slash(resolve(options.root, page.dir));
if (path4.startsWith(dirPath))
return true;
}
return false;
}
function isTarget(path4, options) {
return isPagesDir(path4, options) && options.extensionsRE.test(path4);
}
function isDynamicRoute(routePath, nuxtStyle = false) {
return nuxtStyle ? nuxtDynamicRouteRE.test(routePath) : dynamicRouteRE.test(routePath);
}
function isCatchAllRoute(routePath, nuxtStyle = false) {
return nuxtStyle ? nuxtCacheAllRouteRE.test(routePath) : cacheAllRouteRE.test(routePath);
}
function resolveImportMode(filepath, options) {
const mode = options.importMode;
if (typeof mode === "function")
return mode(filepath, options);
return mode;
}
function normalizeCase(str, caseSensitive) {
if (!caseSensitive)
return str.toLocaleLowerCase();
return str;
}
function normalizeName(name, isDynamic, nuxtStyle = false) {
if (!isDynamic)
return name;
return nuxtStyle ? name.replace(nuxtDynamicRouteRE, "$1") || "all" : name.replace(replaceDynamicRouteRE, "$1");
}
function buildReactRoutePath(node, nuxtStyle = false) {
const isDynamic = isDynamicRoute(node, nuxtStyle);
const isCatchAll = isCatchAllRoute(node, nuxtStyle);
const normalizedName = normalizeName(node, isDynamic, nuxtStyle);
if (isDynamic) {
if (isCatchAll)
return "*";
return `:${normalizedName}`;
}
return `${normalizedName}`;
}
function buildReactRemixRoutePath(node) {
const escapeStart = "[";
const escapeEnd = "]";
let result = "";
let rawSegmentBuffer = "";
let inEscapeSequence = 0;
let skipSegment = false;
for (let i = 0; i < node.length; i++) {
let isNewEscapeSequence2 = function() {
return !inEscapeSequence && char === escapeStart && lastChar !== escapeStart;
}, isCloseEscapeSequence2 = function() {
return inEscapeSequence && char === escapeEnd && nextChar !== escapeEnd;
}, isStartOfLayoutSegment2 = function() {
return char === "_" && nextChar === "_" && !rawSegmentBuffer;
};
var isNewEscapeSequence = isNewEscapeSequence2, isCloseEscapeSequence = isCloseEscapeSequence2, isStartOfLayoutSegment = isStartOfLayoutSegment2;
const char = node.charAt(i);
const lastChar = i > 0 ? node.charAt(i - 1) : void 0;
const nextChar = i < node.length - 1 ? node.charAt(i + 1) : void 0;
if (skipSegment) {
if (char === "/" || char === "." || char === win32.sep)
skipSegment = false;
continue;
}
if (isNewEscapeSequence2()) {
inEscapeSequence++;
continue;
}
if (isCloseEscapeSequence2()) {
inEscapeSequence--;
continue;
}
if (inEscapeSequence) {
result += char;
continue;
}
if (char === "/" || char === win32.sep || char === ".") {
if (rawSegmentBuffer === "index" && result.endsWith("index"))
result = result.replace(replaceIndexRE, "");
else result += "/";
rawSegmentBuffer = "";
continue;
}
if (isStartOfLayoutSegment2()) {
skipSegment = true;
continue;
}
rawSegmentBuffer += char;
if (char === "$") {
result += typeof nextChar === "undefined" ? "*" : ":";
continue;
}
result += char;
}
if (rawSegmentBuffer === "index" && result.endsWith("index"))
result = result.replace(replaceIndexRE, "");
return result || void 0;
}
// src/core/files.ts
function getPageDirs(PageOptions, root, exclude) {
const dirs = fg.sync(slash2(PageOptions.dir), {
ignore: exclude,
onlyDirectories: true,
dot: true,
unique: true,
cwd: root
});
const pageDirs = dirs.map((dir) => __spreadProps(__spreadValues({}, PageOptions), {
dir
}));
return pageDirs;
}
function getPageFiles(path4, options, pageOptions) {
var _a;
const {
exclude,
extensions
} = options;
const ext = extsToGlob(extensions);
const pattern = (_a = (pageOptions == null ? void 0 : pageOptions.filePatern) || (pageOptions == null ? void 0 : pageOptions.filePattern)) != null ? _a : `**/*.${ext}`;
const files = fg.sync(pattern, {
ignore: exclude,
onlyFiles: true,
cwd: path4
}).map((p) => slash2(join(path4, p)));
return files;
}
// src/core/initVirualPackage.ts
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
function initVirtualPackage() {
copyFile("node_modules/unplugin-convention-routes/virtual-package", "node_modules/~unplugin-convention-routes");
}
function copyFile(copiedPath, resultPath) {
const _copiedPath = path.join(process.cwd(), copiedPath);
const _resultPath = path.join(process.cwd(), resultPath);
fs.cpSync(_copiedPath, _resultPath, { recursive: true });
}
// src/core/options.ts
import { resolve as resolve2 } from "node:path";
import process2 from "node:process";
import { slash as slash3, toArray } from "@antfu/utils";
// src/core/stringify.ts
var componentRE = /"(?:component|element)":("(.*?)")/g;
var hasFunctionRE = /"(?:props|beforeEnter)":("(.*?)")/g;
var multilineCommentsRE = /\/\*(.|[\r\n])*?\*\//g;
var singlelineCommentsRE = /\/\/.*/g;
function replaceFunction(_, value) {
if (value instanceof Function || typeof value === "function") {
const fnBody = value.toString().replace(multilineCommentsRE, "").replace(singlelineCommentsRE, "").replace(/(\s)/g, "");
if (fnBody.length < 8 || fnBody.substring(0, 8) !== "function")
return `_NuFrRa_${fnBody}`;
return fnBody;
}
return value;
}
function stringifyRoutes(preparedRoutes, options) {
const importsMap = /* @__PURE__ */ new Map();
function getImportString(path4, importName) {
var _a, _b;
const mode = resolveImportMode(path4, options);
return mode === "sync" ? `import ${importName} from "${path4}"` : `const ${importName} = ${((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.dynamicImport) == null ? void 0 : _b.call(_a, path4)) || `() => import("${path4}")`}`;
}
function componentReplacer(str, replaceStr, path4) {
var _a, _b;
let importName = importsMap.get(path4);
if (!importName)
importName = ROUTE_IMPORT_NAME.replace("$1", `${importsMap.size}`);
importsMap.set(path4, importName);
importName = ((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.component) == null ? void 0 : _b.call(_a, importName)) || importName;
return str.replace(replaceStr, importName);
}
function functionReplacer(str, replaceStr, content) {
if (content.startsWith("function"))
return str.replace(replaceStr, content);
if (content.startsWith("_NuFrRa_"))
return str.replace(replaceStr, content.slice(8));
return str;
}
const stringRoutes = JSON.stringify(preparedRoutes, replaceFunction).replace(componentRE, componentReplacer).replace(hasFunctionRE, functionReplacer);
const imports = Array.from(importsMap).map((args) => getImportString(...args));
return {
imports,
stringRoutes
};
}
function generateClientCode(routes, options) {
var _a, _b;
const { imports, stringRoutes } = stringifyRoutes(routes, options);
const code = `${imports.join(";\n")};
const routes = ${stringRoutes};
export default routes;`;
return ((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.final) == null ? void 0 : _b.call(_a, code)) || code;
}
// src/core/resolvers/react.ts
function prepareRoutes(routes, options, parent) {
var _a, _b;
for (const route of routes) {
if (parent)
route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
if (route.children)
route.children = prepareRoutes(route.children, options, route);
delete route.rawRoute;
Object.assign(route, ((_b = options.extendRoute) == null ? void 0 : _b.call(options, route, parent)) || {});
}
return routes;
}
async function computeReactRoutes(ctx) {
var _a, _b;
const { routeStyle, caseSensitive = false, importPath } = ctx.options;
const nuxtStyle = routeStyle === "nuxt";
const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
const routes = [];
pageRoutes.forEach((page) => {
const pathNodes = page.route.split("/");
const element = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
let parentRoutes = routes;
for (let i = 0; i < pathNodes.length; i++) {
const node = pathNodes[i];
const route = {
caseSensitive,
path: "",
rawRoute: pathNodes.slice(0, i + 1).join("/")
};
if (i === pathNodes.length - 1)
route.element = element;
const isIndexRoute = normalizeCase(node, caseSensitive).endsWith("index");
if (!route.path && isIndexRoute) {
route.path = "/";
} else if (!isIndexRoute) {
if (routeStyle === "remix")
route.path = buildReactRemixRoutePath(node);
else
route.path = buildReactRoutePath(node, nuxtStyle);
}
const parent = parentRoutes.find((parent2) => {
return pathNodes.slice(0, i).join("/") === parent2.rawRoute;
});
if (parent) {
parent.children = parent.children || [];
parentRoutes = parent.children;
}
const exits = parentRoutes.some((parent2) => {
return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
});
if (!exits)
parentRoutes.push(route);
}
});
let finalRoutes = prepareRoutes(routes, ctx.options);
finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
return finalRoutes;
}
async function resolveReactRoutes(ctx) {
var _a, _b;
const finalRoutes = await computeReactRoutes(ctx);
let client = generateClientCode(finalRoutes, ctx.options);
client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
return client;
}
function reactResolver() {
return {
resolveModuleIds() {
return ["~react-pages", "virtual:generated-pages-react"];
},
resolveExtensions() {
return ["tsx", "jsx", "ts", "js"];
},
async resolveRoutes(ctx) {
return resolveReactRoutes(ctx);
},
async getComputedRoutes(ctx) {
return computeReactRoutes(ctx);
},
stringify: {
component: (path4) => `React.createElement(${path4})`,
dynamicImport: (path4) => `React.lazy(() => import("${path4}"))`,
final: (code) => `import React from "react";
${code}`
}
};
}
// src/core/resolvers/solid.ts
function prepareRoutes2(options, routes, parent) {
var _a, _b;
for (const route of routes) {
if (parent)
route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
if (route.children)
route.children = prepareRoutes2(options, route.children, route);
delete route.rawRoute;
Object.assign(route, ((_b = options.extendRoute) == null ? void 0 : _b.call(options, route, parent)) || {});
}
return routes;
}
async function computeSolidRoutes(ctx) {
var _a, _b;
const { routeStyle, caseSensitive = false, importPath } = ctx.options;
const nuxtStyle = routeStyle === "nuxt";
const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
const routes = [];
pageRoutes.forEach((page) => {
const pathNodes = page.route.split("/");
const component = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
const element = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
let parentRoutes = routes;
for (let i = 0; i < pathNodes.length; i++) {
const node = pathNodes[i];
const normalizedPath = normalizeCase(node, caseSensitive);
const route = {
path: "",
rawRoute: pathNodes.slice(0, i + 1).join("/")
};
const parent = parentRoutes.find(
(parent2) => pathNodes.slice(0, i).join("/") === parent2.rawRoute
);
if (parent) {
parent.children = parent.children || [];
parentRoutes = parent.children;
}
if (i === pathNodes.length - 1) {
route.element = element;
route.component = component;
}
if (normalizedPath === "index") {
if (!route.path)
route.path = "/";
} else if (normalizedPath !== "index") {
if (routeStyle === "remix")
route.path = buildReactRemixRoutePath(node) || "";
else
route.path = buildReactRoutePath(node, nuxtStyle) || "";
}
const exist = parentRoutes.some((parent2) => {
return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
});
if (!exist)
parentRoutes.push(route);
}
});
let finalRoutes = prepareRoutes2(ctx.options, routes);
finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
return finalRoutes;
}
async function resolveSolidRoutes(ctx) {
var _a, _b;
const finalRoutes = await computeSolidRoutes(ctx);
let client = generateClientCode(finalRoutes, ctx.options);
client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
return client;
}
function solidResolver() {
return {
resolveModuleIds() {
return ["~solid-pages"];
},
resolveExtensions() {
return ["tsx", "jsx", "ts", "js"];
},
async resolveRoutes(ctx) {
return resolveSolidRoutes(ctx);
},
async getComputedRoutes(ctx) {
return computeSolidRoutes(ctx);
},
stringify: {
dynamicImport: (path4) => `Solid.lazy(() => import("${path4}"))`,
final: (code) => `import * as Solid from "solid-js";
${code}`
}
};
}
// src/core/resolvers/vue.ts
function prepareRoutes3(ctx, routes, parent) {
var _a, _b, _c, _d;
for (const route of routes) {
if (route.name)
route.name = route.name.replace(new RegExp(`${ctx.options.routeNameSeparator}index$`), "");
if (parent)
route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
if (route.children)
route.children = prepareRoutes3(ctx, route.children, route);
if ((_b = route.children) == null ? void 0 : _b.find((c) => c.name === route.name))
delete route.name;
route.props = true;
delete route.rawRoute;
if (route.customBlock) {
Object.assign(route, route.customBlock || {});
delete route.customBlock;
}
Object.assign(route, ((_d = (_c = ctx.options).extendRoute) == null ? void 0 : _d.call(_c, route, parent)) || {});
}
return routes;
}
async function computeVueRoutes(ctx, customBlockMap) {
var _a, _b;
const { routeStyle, caseSensitive = false, importPath, routeNameSeparator } = ctx.options;
const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
const routes = [];
pageRoutes.forEach((page) => {
const pathNodes = page.route.split("/");
const component = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
const customBlock = customBlockMap.get(page.path);
const route = {
name: "",
path: "",
component,
customBlock,
rawRoute: page.route
};
let parentRoutes = routes;
let dynamicRoute = false;
for (let i = 0; i < pathNodes.length; i++) {
const node = pathNodes[i];
const nuxtStyle = routeStyle === "nuxt";
const isDynamic = isDynamicRoute(node, nuxtStyle);
const isCatchAll = isCatchAllRoute(node, nuxtStyle);
const normalizedName = normalizeName(node, isDynamic, nuxtStyle);
const normalizedPath = normalizeCase(normalizedName, caseSensitive);
if (isDynamic)
dynamicRoute = true;
route.name += route.name ? `${routeNameSeparator}${normalizedName}` : normalizedName;
const parent = parentRoutes.find((parent2) => {
return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
});
if (parent) {
parent.children = parent.children || [];
parentRoutes = parent.children;
route.path = "";
} else if (normalizedPath === "index") {
if (!route.path)
route.path = "/";
} else if (normalizedPath !== "index") {
if (isDynamic) {
route.path += `/:${normalizedName}`;
if (isCatchAll) {
if (i === 0)
route.path += "(.*)*";
else
route.path += "(.*)";
} else if (nuxtStyle && i === pathNodes.length - 1) {
const isIndexFound = pageRoutes.find(({ route: route2 }) => {
return route2 === page.route.replace(pathNodes[i], "index");
});
if (!isIndexFound)
route.path += "?";
}
} else {
route.path += `/${normalizedPath}`;
}
}
}
if (dynamicRoute)
parentRoutes.push(route);
else
parentRoutes.unshift(route);
});
let finalRoutes = prepareRoutes3(ctx, routes);
finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
return finalRoutes;
}
async function resolveVueRoutes(ctx, customBlockMap) {
var _a, _b;
const finalRoutes = await computeVueRoutes(ctx, customBlockMap);
let client = generateClientCode(finalRoutes, ctx.options);
client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
return client;
}
function vueResolver() {
const customBlockMap = /* @__PURE__ */ new Map();
return {
resolveExtensions() {
return ["vue", "ts", "js"];
},
resolveModuleIds() {
return ["~pages", "pages-generated", "virtual:generated-pages"];
},
async resolveRoutes(ctx) {
return resolveVueRoutes(ctx, customBlockMap);
},
async getComputedRoutes(ctx) {
return computeVueRoutes(ctx, customBlockMap);
}
// hmr: {
// added: async (ctx, path) => checkCustomBlockChange(ctx, path),
// changed: async (ctx, path) => checkCustomBlockChange(ctx, path),
// removed: async (_ctx, path) => {
// customBlockMap.delete(path)
// },
// },
};
}
// src/core/options.ts
function resolvePageDirs(dirs, root, exclude) {
dirs = toArray(dirs);
return dirs.flatMap((dir) => {
const option = typeof dir === "string" ? { dir, baseRoute: "" } : dir;
option.dir = slash3(resolve2(root, option.dir)).replace(`${root}/`, "");
option.baseRoute = option.baseRoute.replace(/^\//, "").replace(/\/$/, "");
return getPageDirs(option, root, exclude);
});
}
var syncIndexResolver = (filepath, options) => {
for (const page of options.dirs) {
if (page.baseRoute === "" && filepath.startsWith(`/${page.dir}/index`))
return "sync";
}
return "async";
};
function getResolver(originalResolver) {
let resolver = originalResolver || "vue";
if (typeof resolver !== "string")
return resolver;
switch (resolver) {
case "vue":
resolver = vueResolver();
break;
case "react":
resolver = reactResolver();
break;
case "solid":
resolver = solidResolver();
break;
default:
throw new Error(`Unsupported resolver: ${resolver}`);
}
return resolver;
}
function resolveOptions(userOptions, projectRoot) {
var _a;
const {
dirs = userOptions.pagesDir || ["src/pages"],
routeBlockLang = "json5",
exclude = ["node_modules", ".git", "**/__*__/**"],
caseSensitive = false,
syncIndex = true,
routeNameSeparator = "-",
extendRoute,
onRoutesGenerated,
onClientGenerated
} = userOptions;
const root = projectRoot || slash3(process2.cwd());
const importMode = userOptions.importMode || (syncIndex ? syncIndexResolver : "async");
const importPath = userOptions.importPath || "relative";
const resolver = getResolver(userOptions.resolver);
const extensions = userOptions.extensions || resolver.resolveExtensions();
const extensionsRE = new RegExp(`\\.(${extensions.join("|")})$`);
const resolvedDirs = resolvePageDirs(dirs, root, exclude);
const routeStyle = userOptions.nuxtStyle ? "nuxt" : userOptions.routeStyle || "next";
const moduleIds = userOptions.moduleId ? [userOptions.moduleId] : ((_a = resolver.resolveModuleIds) == null ? void 0 : _a.call(resolver)) || MODULE_IDS;
const resolvedOptions = {
dirs: resolvedDirs,
routeStyle,
routeBlockLang,
moduleIds,
root,
extensions,
importMode,
importPath,
exclude,
caseSensitive,
resolver,
extensionsRE,
extendRoute,
onRoutesGenerated,
onClientGenerated,
routeNameSeparator
};
return resolvedOptions;
}
// src/core/context.ts
var directoryToWatch = "src/pages";
var PageContext = class {
constructor(userOptions, projectRoot = process3.cwd()) {
// private _server: ViteDevServer | undefined
this._pageRouteMap = /* @__PURE__ */ new Map();
this.rawOptions = userOptions;
this.root = slash4(projectRoot);
debug.env("root", this.root);
this.options = resolveOptions(userOptions, this.root);
debug.options(this.options);
if (this.rawOptions.watcher) {
this.watcher = chokidar.watch(directoryToWatch, {
ignored: /(^|[/\\])\../,
// 忽略隐藏文件
persistent: true,
// 持续监视
ignoreInitial: true
// 忽略初始扫描
});
this.setupWatcher(this.watcher);
}
this.searchGlob().then(() => {
this.writeFile();
});
}
// setupViteServer(server: ViteDevServer) {
// if (this._server === server)
// return
// this._server = server
// this.setupWatcher(server.watcher)
// }
setupWatcher(watcher) {
watcher.on("unlink", async (path4) => {
path4 = `${process3.cwd()}\\${path4}`;
path4 = slash4(path4);
if (!isTarget(path4, this.options))
return;
await this.removePage(path4);
this.onUpdate();
});
watcher.on("add", async (path4) => {
path4 = `${process3.cwd()}\\${path4}`;
path4 = slash4(path4);
if (!isTarget(path4, this.options))
return;
const page = this.options.dirs.find((i) => path4.startsWith(slash4(resolve3(this.root, i.dir))));
await this.addPage(path4, page);
this.onUpdate();
});
}
async addPage(path4, pageDir) {
for (const p of toArray2(path4)) {
const pageDirPath = slash4(resolve3(this.root, pageDir.dir));
const extension = this.options.extensions.find((ext) => p.endsWith(`.${ext}`));
if (!extension)
continue;
const route = slash4(join2(pageDir.baseRoute, p.replace(`${pageDirPath}/`, "").replace(`.${extension}`, "")));
this._pageRouteMap.set(p, {
path: p,
route
});
}
}
async removePage(path4) {
debug.pages("remove", path4);
this._pageRouteMap.delete(path4);
}
onUpdate() {
this.writeFile();
}
async writeFile() {
const fullPath = path2.join(process3.cwd(), "node_modules", "~unplugin-convention-routes");
if (!existsSync(fullPath)) {
initVirtualPackage();
}
const result = await this.resolveRoutes();
const resolver = this.rawOptions.resolver;
writeFileSync(path2.join(fullPath, `${resolver}.js`), result);
}
async resolveRoutes() {
return this.options.resolver.resolveRoutes(this);
}
async searchGlob() {
const pageDirFiles = this.options.dirs.map((page) => {
const pagesDirPath = slash4(resolve3(this.options.root, page.dir));
const files = getPageFiles(pagesDirPath, this.options, page);
debug.search(page.dir, files);
return __spreadProps(__spreadValues({}, page), {
files: files.map((file) => slash4(file))
});
});
for (const page of pageDirFiles)
await this.addPage(page.files, page);
debug.cache(this.pageRouteMap);
}
get debug() {
return debug;
}
get pageRouteMap() {
return this._pageRouteMap;
}
};
// src/index.ts
var unpluginFactory = (userOptions = {
resolver: "vue"
}) => {
const ctx = new PageContext(userOptions);
return {
name: "unplugin-convention-routes",
buildEnd() {
var _a;
(_a = ctx.watcher) == null ? void 0 : _a.close();
},
resolveId(id) {
if (["~unplugin-convention-routes/react", "~unplugin-convention-routes/vue", "~unplugin-convention-routes/solid"].includes(id)) {
return path3.resolve(process4.cwd(), "node_modules", "~unplugin-convention-routes", `${id.split("/")[1]}.js`);
}
return null;
}
};
};
var unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);
var src_default = unplugin;
export {
unpluginFactory,
unplugin,
src_default
};