Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions doom.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { defineConfig } from "@alauda/doom/config";
import { join } from "node:path";
import { blogPostResolver } from "./plugins/plugin-post-resolver";

export default defineConfig({
title: "Alauda Knowledge",
import { defineConfig } from "@alauda/doom/config";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { blogPostResolver } from "./plugins/plugin-post-resolver/index.js";

const __dirname = dirname(fileURLToPath(import.meta.url));

export default defineConfig({
title: "Alauda Knowledge",
base: "/knowledge/",
description:
"Welcome to Alauda's Knowledgebase information center. Find resources for resolving problems and troubleshooting.",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "doomslayer",
"type": "module",
"packageManager": "yarn@4.13.0",
"devDependencies": {
"@alauda/doom": "^1.20.0",
Expand Down
8 changes: 4 additions & 4 deletions plugins/plugin-post-resolver/BlogPostResolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "node:path";
import fs, { PathLike } from "node:fs";
import { RspressPlugin } from "@rspress/shared";
import type { RspressPlugin } from "@rspress/shared";
import {
addPost,
getPostInfo,
Expand All @@ -9,9 +9,9 @@ import {
postProducts,
resetPostInfo,
sortPostInfos,
} from "./PostData";
import { PluginOptions } from "./types";
import { deDuplicate } from "./utils";
} from "./PostData.js";
import type { PluginOptions } from "./types.js";
import { deDuplicate } from "./utils.js";

function traverseFolder(
folderPath: PathLike,
Expand Down
4 changes: 2 additions & 2 deletions plugins/plugin-post-resolver/PostData.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import path from "node:path";
import dayjs from "dayjs";
import grayMatter from "gray-matter";
import { PostInfo } from "./types";
import type { PostInfo } from "./types.js";
import {
excerptFilter,
extractTitle,
generateRoutePath,
getGitLastUpdatedTimeStamp,
normalizeTags,
transformTime,
} from "./utils";
} from "./utils.js";

export const postInfos: PostInfo[] = [];
export const postProducts: string[] = [];
Expand Down
20 changes: 10 additions & 10 deletions plugins/plugin-post-resolver/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { blogPostResolver } from './BlogPostResolver'
import { postInfos, postProducts, postKinds } from './PostData'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
import { blogPostResolver } from "./BlogPostResolver.js";
import { postInfos, postProducts, postKinds } from "./PostData.js";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc.js";
import timezone from "dayjs/plugin/timezone.js";

dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.tz.setDefault('Asia/Shanghai')
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault("Asia/Shanghai");

export * from './types'
export * from "./types.js";

export { blogPostResolver, postInfos, postProducts, postKinds }
export { blogPostResolver, postInfos, postProducts, postKinds };
12 changes: 6 additions & 6 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
plugins: {
"@tailwindcss/postcss": {},
autoprefixer: {},
},
};
export default {
plugins: {
"@tailwindcss/postcss": {},
autoprefixer: {},
},
};
12 changes: 6 additions & 6 deletions theme/components/HomeContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import {
PRODUCTS_SESSION_KEY,
usePersistSearchParams,
useSessionStorage,
} from "../../hooks/SessionStorage";
import { Card } from "../Card";
import Checkbox from "../Checkbox";
import Pagination from "../Pagination";
import { PostList } from "../PostList";
import Search from "../Search";
} from "../../hooks/SessionStorage.js";
import { Card } from "../Card/index.js";
import Checkbox from "../Checkbox/index.js";
import Pagination from "../Pagination/index.js";
import { PostList } from "../PostList/index.js";
import Search from "../Search/index.js";
import React from "react";

const SEARCHED_LIMIT = 1000;
Expand Down
8 changes: 4 additions & 4 deletions theme/components/PostList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { useI18n, usePageData } from "@rspress/core/runtime";
import { Badge } from "@rspress/core/theme-original";
import { FC, useMemo } from "react";

import { PostInfo } from "../../../plugins/plugin-post-resolver";
import { DocID } from "../DocID";
import EmptyState from "../Empty";
import { LinkCard } from "../LinkCard";
import type { PostInfo } from "../../../plugins/plugin-post-resolver/types.js";
import { DocID } from "../DocID/index.js";
import EmptyState from "../Empty/index.js";
import { LinkCard } from "../LinkCard/index.js";

interface PostListProps {
postList: PostInfo[];
Expand Down
2 changes: 1 addition & 1 deletion theme/components/SidebarMenu/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { useSidebarMenu } from './useSidebarMenu';
export { useSidebarMenu } from "./useSidebarMenu.js";

10 changes: 5 additions & 5 deletions theme/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Layout from "./layout";
import HomeLayout from "./layout/HomeLayout";
import { DocLayout } from "./layout/DocLayout";
import Layout from "./layout/index.js";
import HomeLayout from "./layout/HomeLayout/index.js";
import { DocLayout } from "./layout/DocLayout/index.js";

export { HomeLayout, Layout, DocLayout };

export * from "@rspress/core/theme-original";

// 导出本地实现的组件
export { Card } from "./components/Card";
export { LinkCard } from "./components/LinkCard";
export { Card } from "./components/Card/index.js";
export { LinkCard } from "./components/LinkCard/index.js";
14 changes: 7 additions & 7 deletions theme/layout/DocLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useFrontmatter } from '@rspress/core/runtime';
import {
DocContent,
DocFooter,
import {
DocContent,
DocFooter,
Outline,
Overview,
useWatchToc,
} from '@rspress/core/theme-original';
import clsx from 'clsx';
import React from 'react';
import { useSidebarMenu } from '../../components/SidebarMenu';
} from '@rspress/core/theme-original';
import clsx from 'clsx';
import React from 'react';
import { useSidebarMenu } from '../../components/SidebarMenu/index.js';

export interface DocLayoutProps {
beforeSidebar?: React.ReactNode;
Expand Down
6 changes: 3 additions & 3 deletions theme/layout/HomeLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { usePageData } from "@rspress/core/runtime";
import { ReactNode } from "react";

import { HomeBanner } from "../../components/HomeBanner";
import { HomeContent } from "../../components/HomeContent";
import React from "react";
import { HomeBanner } from "../../components/HomeBanner/index.js";
import { HomeContent } from "../../components/HomeContent/index.js";
import React from "react";

const HomeLayout: React.FC<{ children: ReactNode }> = ({ children }) => {
return (
Expand Down
63 changes: 58 additions & 5 deletions theme/layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
getCustomMDXComponent,
} from "@rspress/core/theme-original";
import { useEffect } from "react";
import { postInfos } from "virtual-post-data";

import { BreadCrumb } from "../components/BreadCrumb";
import { DocID } from "../components/DocID";
import { EditOnGithub } from "../components/EditOnGithub";
import HomeLayout from "./HomeLayout";
import { BreadCrumb } from "../components/BreadCrumb/index.js";
import { DocID } from "../components/DocID/index.js";
import { EditOnGithub } from "../components/EditOnGithub/index.js";
import HomeLayout from "./HomeLayout/index.js";
import { getPathname, shouldDownload } from "theme/utils/download";

export function normalizeTags(tags: string | string[]): string[] {
Expand All @@ -23,6 +24,16 @@ export function normalizeTags(tags: string | string[]): string[] {
return [tags];
}

function normalizePostId(id?: string): string {
return id?.trim().toLowerCase() || "";
}

const initialHref = typeof window === "undefined" ? "" : window.location.href;

function getInitialHref(): string {
return initialHref || window.location.href;
}

const Badges = () => {
const { page } = usePageData();
const kinds = normalizeTags(
Expand All @@ -46,9 +57,51 @@ const Badges = () => {
};

export default () => {
const { page } = usePageData();

useEffect(() => {
if (typeof window === "undefined") {
return;
}

const currentUrl = new URL(getInitialHref());
const postId = currentUrl.searchParams.get("id")?.trim();
const normalizedPostId = normalizePostId(postId);

if (normalizedPostId) {
const matchedPost =
postInfos.find(
(post) =>
normalizePostId(post.id) === normalizedPostId &&
post.locale === page.lang
) ||
postInfos.find(
(post) => normalizePostId(post.id) === normalizedPostId
);
Comment on lines +71 to +80
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid redirecting to an arbitrary locale on fallback.

If the same id exists in multiple locales, the second find() ignores page.lang and can send users to the wrong language variant. A safer fallback is to ignore locale only when there is exactly one candidate for that id.

Suggested fix
-    if (normalizedPostId) {
-      const matchedPost =
-        postInfos.find(
-          (post) =>
-            normalizePostId(post.id) === normalizedPostId &&
-            post.locale === page.lang
-        ) ||
-        postInfos.find(
-          (post) => normalizePostId(post.id) === normalizedPostId
-        );
+    if (normalizedPostId) {
+      const candidates = postInfos.filter(
+        (post) => normalizePostId(post.id) === normalizedPostId
+      );
+      const matchedPost =
+        candidates.find((post) => post.locale === page.lang) ??
+        (candidates.length === 1 ? candidates[0] : undefined);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (normalizedPostId) {
const matchedPost =
postInfos.find(
(post) =>
normalizePostId(post.id) === normalizedPostId &&
post.locale === page.lang
) ||
postInfos.find(
(post) => normalizePostId(post.id) === normalizedPostId
);
if (normalizedPostId) {
const candidates = postInfos.filter(
(post) => normalizePostId(post.id) === normalizedPostId
);
const matchedPost =
candidates.find((post) => post.locale === page.lang) ??
(candidates.length === 1 ? candidates[0] : undefined);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@theme/layout/index.tsx` around lines 71 - 80, The current matching logic for
normalizedPostId can return a post from any locale because the fallback
postInfos.find(...) ignores page.lang; change this by first collecting
candidates where normalizePostId(post.id) === normalizedPostId, then set
matchedPost to the candidate that also matches page.lang if present, otherwise
only use the single candidate when candidates.length === 1; update the code
around normalizedPostId / matchedPost / postInfos / normalizePostId to implement
this conditional-fallback behavior so you never redirect to an arbitrary locale
when multiple candidates exist.


if (matchedPost) {
const nextUrl = new URL(
withBase(
matchedPost.route.endsWith(".html")
? matchedPost.route
: `${matchedPost.route}.html`
),
currentUrl.origin
);

currentUrl.searchParams.delete("id");
nextUrl.search = currentUrl.searchParams.toString();
nextUrl.hash = currentUrl.hash;

if (nextUrl.toString() !== currentUrl.toString()) {
window.location.replace(nextUrl.toString());
return;
}
}
}

window.parent.postMessage(window.location.href, "*");
}, []);
}, [page.lang]);

return (
<Layout
Expand Down
Loading