From 68cb7d0b273457b56b998266bf71979ac3d68d92 Mon Sep 17 00:00:00 2001 From: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:55:16 +0200 Subject: [PATCH] fix(admin-vite-plugin): Generate correct UI Route tree (#9699) --- .../generate-custom-field-hashes.ts | 22 ++++++++- .../src/routes/generate-menu-items.ts | 22 ++++++++- .../src/routes/generate-route-hashes.ts | 15 +++++- .../src/routes/generate-routes.ts | 15 +++++- .../dashboard/src/extensions/routes/utils.ts | 46 +++++++++---------- 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-hashes.ts b/packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-hashes.ts index 94dea86849..16db43e98a 100644 --- a/packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-hashes.ts +++ b/packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-hashes.ts @@ -1,5 +1,12 @@ import fs from "fs/promises" -import { isIdentifier, isObjectProperty, parse, traverse } from "../babel" +import { + File, + isIdentifier, + isObjectProperty, + parse, + ParseResult, + traverse, +} from "../babel" import { logger } from "../logger" import { crawl, generateHash, getParserOptions } from "../utils" import { getConfigArgument } from "./helpers" @@ -41,7 +48,18 @@ async function getCustomFieldContents(file: string): Promise<{ display: string | null }> { const code = await fs.readFile(file, "utf-8") - const ast = parse(code, getParserOptions(file)) + + let ast: ParseResult | null = null + + try { + ast = parse(code, getParserOptions(file)) + } catch (e) { + logger.error(`An error occurred while parsing the file.`, { + file, + error: e, + }) + return { link: null, form: null, display: null } + } let linkContent: string | null = null let formContent: string | null = null diff --git a/packages/admin/admin-vite-plugin/src/routes/generate-menu-items.ts b/packages/admin/admin-vite-plugin/src/routes/generate-menu-items.ts index 19ef309810..b473bf98f5 100644 --- a/packages/admin/admin-vite-plugin/src/routes/generate-menu-items.ts +++ b/packages/admin/admin-vite-plugin/src/routes/generate-menu-items.ts @@ -1,6 +1,13 @@ import fs from "fs/promises" import { outdent } from "outdent" -import { isIdentifier, isObjectProperty, parse, traverse } from "../babel" +import { + File, + isIdentifier, + isObjectProperty, + parse, + ParseResult, + traverse, +} from "../babel" import { logger } from "../logger" import { crawl, @@ -118,7 +125,18 @@ async function getRouteConfig( file: string ): Promise<{ label: boolean; icon: boolean } | null> { const code = await fs.readFile(file, "utf-8") - const ast = parse(code, getParserOptions(file)) + + let ast: ParseResult | null = null + + try { + ast = parse(code, getParserOptions(file)) + } catch (e) { + logger.error(`An error occurred while parsing the file.`, { + file, + error: e, + }) + return null + } let config: { label: boolean; icon: boolean } | null = null diff --git a/packages/admin/admin-vite-plugin/src/routes/generate-route-hashes.ts b/packages/admin/admin-vite-plugin/src/routes/generate-route-hashes.ts index feaacc228a..e852fea3d8 100644 --- a/packages/admin/admin-vite-plugin/src/routes/generate-route-hashes.ts +++ b/packages/admin/admin-vite-plugin/src/routes/generate-route-hashes.ts @@ -1,5 +1,5 @@ import fs from "fs/promises" -import { parse, traverse } from "../babel" +import { File, parse, ParseResult, traverse } from "../babel" import { logger } from "../logger" import { crawl, @@ -42,7 +42,18 @@ async function getRouteContents( file: string ): Promise<{ defaultExport: string | null; config: string | null }> { const code = await fs.readFile(file, "utf-8") - const ast = parse(code, getParserOptions(file)) + + let ast: ParseResult | null = null + + try { + ast = parse(code, getParserOptions(file)) + } catch (e) { + logger.error(`An error occurred while parsing the file.`, { + file, + error: e, + }) + return { defaultExport: null, config: null } + } let defaultExportContent: string | null = null let configContent: string | null = null diff --git a/packages/admin/admin-vite-plugin/src/routes/generate-routes.ts b/packages/admin/admin-vite-plugin/src/routes/generate-routes.ts index eb9d4ed74e..51c71ca54a 100644 --- a/packages/admin/admin-vite-plugin/src/routes/generate-routes.ts +++ b/packages/admin/admin-vite-plugin/src/routes/generate-routes.ts @@ -1,6 +1,6 @@ import fs from "fs/promises" import { outdent } from "outdent" -import { parse } from "../babel" +import { File, parse, ParseResult } from "../babel" import { logger } from "../logger" import { crawl, @@ -88,7 +88,18 @@ async function parseFile( async function isValidRouteFile(file: string): Promise { const code = await fs.readFile(file, "utf-8") - const ast = parse(code, getParserOptions(file)) + + let ast: ParseResult | null = null + + try { + ast = parse(code, getParserOptions(file)) + } catch (e) { + logger.error("An error occurred while parsing the file.", { + file, + error: e, + }) + return false + } try { return await hasDefaultExport(ast) diff --git a/packages/admin/dashboard/src/extensions/routes/utils.ts b/packages/admin/dashboard/src/extensions/routes/utils.ts index 9324ef93ac..903c067d0d 100644 --- a/packages/admin/dashboard/src/extensions/routes/utils.ts +++ b/packages/admin/dashboard/src/extensions/routes/utils.ts @@ -1,6 +1,5 @@ import { ComponentType } from "react" import { RouteObject } from "react-router-dom" -import { ErrorBoundary } from "../../components/utilities/error-boundary" import { RouteExtension, RouteModule } from "../types" /** @@ -28,34 +27,32 @@ export const createRouteMap = ( const root: RouteObject[] = [] const addRoute = ( - pathSegments: string[], + fullPath: string, Component: ComponentType, currentLevel: RouteObject[] ) => { - if (!pathSegments.length) { - return - } + const pathSegments = fullPath.split("/").filter(Boolean) + let currentArray = currentLevel - const [currentSegment, ...remainingSegments] = pathSegments - let route = currentLevel.find((r) => r.path === currentSegment) + for (let i = 0; i < pathSegments.length; i++) { + const segment = pathSegments[i] + let route = currentArray.find((r) => r.path === segment) - if (!route) { - route = { path: currentSegment, children: [] } - currentLevel.push(route) - } + if (!route) { + route = { + path: segment, + lazy: async () => ({ Component }), + } + currentArray.push(route) + } - if (remainingSegments.length === 0) { - route.children ||= [] - route.children.push({ - path: "", - ErrorBoundary: ErrorBoundary, - async lazy() { - return { Component } - }, - }) - } else { - route.children ||= [] - addRoute(remainingSegments, Component, route.children) + if (i < pathSegments.length - 1) { + // This is not the last segment, so we need to move to the next level + if (!route.children) { + route.children = [] + } + currentArray = route.children + } } } @@ -64,8 +61,7 @@ export const createRouteMap = ( const cleanedPath = ignore ? path.replace(ignore, "").replace(/^\/+/, "") : path.replace(/^\/+/, "") - const pathSegments = cleanedPath.split("/").filter(Boolean) - addRoute(pathSegments, Component, root) + addRoute(cleanedPath, Component, root) }) return root