Commit ba9174e
Changed files (2)
src
components
utils
src/components/utils/Markdown.astro
@@ -1,6 +1,7 @@
---
import '@/styles/markdown.css';
import type { HTMLAttributes } from 'astro/types';
+import 'cheerio';
import Replacer from './Replacer.astro';
interface Props extends HTMLAttributes<'article'> {
@@ -46,7 +47,7 @@ const Fragment = bidirectionalReferences ? Replacer : 'Fragment';
---
<article class={className} {...rest}>
- <Fragment pattern={referencePattern} replacer={replacer}>
+ <Fragment option={{ pattern: referencePattern, replacer: replacer }}>
<slot />
</Fragment>
</article>
src/components/utils/Replacer.astro
@@ -1,24 +1,52 @@
---
-export type Props = {
- pattern: string | RegExp;
- replaceValue?: string;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- replacer?: (match: string, ...args: any[]) => string;
-};
-
-const { pattern, replaceValue, replacer } = Astro.props;
+type ReplaceOption =
+ | {
+ /**
+ * The pattern to match in the HTML content.
+ * It can be a string, a regular expression, or null.
+ * - If null, the replacer function will be called with the entire HTML content,
+ * and the replaceValue will be used as the result.
+ * - If a string or RegExp, it will be used to find matches in the HTML content.
+ */
+ pattern: string | RegExp | null;
+ replaceValue: string;
+ }
+ | {
+ pattern: string | RegExp;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ replacer: (match: string, ...args: any[]) => string;
+ }
+ | {
+ pattern: null;
+ replacer: (match: string) => string | Promise<string>;
+ };
-if (replaceValue && replacer) {
- throw new Error('You can only use one of `replaceValue` or `replacer. Please choose one.');
-}
-if (replaceValue === undefined && replacer === undefined) {
- throw new Error('You must provide either `replaceValue` or `replacer`.');
-}
+export type Props =
+ | {
+ option: ReplaceOption;
+ }
+ | {
+ options: ReplaceOption[];
+ };
const raw = await Astro.slots.render('default');
-const html = replacer
- ? raw.replaceAll(pattern, replacer)
- : raw.replaceAll(pattern, replaceValue!);
+
+const replace = async function (html: string, option: ReplaceOption): Promise<string> {
+ if (option.pattern === null) {
+ return 'replacer' in option ? await option.replacer(html) : option.replaceValue;
+ }
+ return 'replacer' in option
+ ? html.replaceAll(option.pattern, option.replacer)
+ : html.replaceAll(option.pattern, option.replaceValue);
+};
+
+let html: string | undefined = undefined;
+if ('options' in Astro.props) {
+ for (const option of Astro.props.options) {
+ html = await replace(html || raw, option);
+ }
+} else if ('option' in Astro.props) html = await replace(raw, Astro.props.option);
+else html = raw;
---
<Fragment set:html={html} />