mirror of
https://github.com/fmhy/edit.git
synced 2025-07-29 23:32:17 +10:00
feat: custom transformer composable
This commit is contained in:
parent
5636b5487a
commit
422ffec7e8
5 changed files with 295 additions and 210 deletions
|
@ -1,5 +1,4 @@
|
|||
import consola from 'consola'
|
||||
import { basename } from 'pathe'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import { defineConfig } from 'vitepress'
|
||||
import {
|
||||
|
@ -13,7 +12,7 @@ import {
|
|||
import { generateFeed, generateImages, generateMeta } from './hooks'
|
||||
import { defs, emojiRender, movePlugin } from './markdown/emoji'
|
||||
import { toggleStarredPlugin } from './markdown/toggleStarred'
|
||||
import { transformer } from './transformer'
|
||||
import { transforms } from './transformer'
|
||||
|
||||
// @unocss-include
|
||||
|
||||
|
@ -57,7 +56,7 @@ export default defineConfig({
|
|||
UnoCSS({
|
||||
configFile: '../unocss.config.ts'
|
||||
}),
|
||||
transformer(),
|
||||
transforms(),
|
||||
{
|
||||
name: 'custom:adjust-order',
|
||||
configResolved(c) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { ContentData, SiteConfig } from 'vitepress'
|
|||
import { type SatoriOptions, satoriVue } from 'x-satori/vue'
|
||||
import { renderAsync } from '@resvg/resvg-js'
|
||||
import consola from 'consola'
|
||||
import { headers } from '../transformer'
|
||||
import { headers } from '../transformer/constants'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const __fonts = resolve(__dirname, '../fonts')
|
||||
|
@ -71,19 +71,19 @@ async function generateImage({
|
|||
const _page = getPage(url)
|
||||
const title =
|
||||
frontmatter.layout === 'home'
|
||||
? (frontmatter.hero.name ?? frontmatter.title)
|
||||
? frontmatter.hero.name ?? frontmatter.title
|
||||
: frontmatter.title
|
||||
? frontmatter.title
|
||||
: _page?.title
|
||||
|
||||
const description =
|
||||
frontmatter.layout === 'home'
|
||||
? (frontmatter.hero.tagline ?? frontmatter.description)
|
||||
? frontmatter.hero.tagline ?? frontmatter.description
|
||||
: frontmatter.description
|
||||
? frontmatter.description
|
||||
: _page?.description
|
||||
|
||||
consola.info(url, title, description)
|
||||
// consola.info(url, title, description)
|
||||
const options: SatoriOptions = {
|
||||
width: 1200,
|
||||
height: 628,
|
||||
|
|
|
@ -1,128 +1,9 @@
|
|||
import { basename } from 'pathe'
|
||||
import type { Plugin } from 'vitepress'
|
||||
import { replaceUnderscore, transformer } from './transformer/core'
|
||||
import { excluded, getHeader } from './transformer/constants'
|
||||
|
||||
interface Header {
|
||||
[file: string]: { title: string; description: string }
|
||||
}
|
||||
|
||||
export const headers: Header = {
|
||||
'adblockvpnguide.md': {
|
||||
title: 'Adblocking / Privacy',
|
||||
description: "Adblocking, Privacy, VPN's, Proxies, Antivirus"
|
||||
},
|
||||
'ai.md': {
|
||||
title: 'Artificial Intelligence',
|
||||
description: 'Chat Bots, Text Generators, Image Generators, ChatGPT Tools'
|
||||
},
|
||||
'android-iosguide.md': {
|
||||
title: 'Android / iOS',
|
||||
description: 'Apps, Jailbreaking, Android Emulators'
|
||||
},
|
||||
'audiopiracyguide.md': {
|
||||
title: 'Music / Podcasts / Radio',
|
||||
description: 'Stream Audio, Download Audio, Torrent Audio'
|
||||
},
|
||||
'beginners-guide.md': {
|
||||
title: 'Beginners Guide',
|
||||
description: 'A Guide for Beginners to Piracy'
|
||||
},
|
||||
'downloadpiracyguide.md': {
|
||||
title: 'Downloading',
|
||||
description: 'Download Sites, Software Sites, Open Directories'
|
||||
},
|
||||
'edupiracyguide.md': {
|
||||
title: 'Educational',
|
||||
description: 'Courses, Documentaries, Learning Resources'
|
||||
},
|
||||
'gamingpiracyguide.md': {
|
||||
title: 'Gaming / Emulation',
|
||||
description: 'Download Games, ROMs, Gaming Tools'
|
||||
},
|
||||
'linuxguide.md': {
|
||||
title: 'Linux / MacOS',
|
||||
description: 'Apps, Software Sites, Gaming'
|
||||
},
|
||||
'miscguide.md': {
|
||||
title: 'Miscellaneous',
|
||||
description: 'Extensions, Indexes, News, Health, Food, Fun'
|
||||
},
|
||||
'nsfwpiracy.md': {
|
||||
title: 'NSFW',
|
||||
description: 'NSFW Indexes, Streaming, Downloading'
|
||||
},
|
||||
'non-english.md': {
|
||||
title: 'Non-English',
|
||||
description: 'International Piracy Sites'
|
||||
},
|
||||
'readingpiracyguide.md': {
|
||||
title: 'Books / Comics / Manga',
|
||||
description: 'Books, Comics, Magazines, Newspapers'
|
||||
},
|
||||
'gaming-tools.md': {
|
||||
title: 'Gaming Tools',
|
||||
description: 'Gaming Optimization, Game Launchers, Multiplayer'
|
||||
},
|
||||
'devtools.md': {
|
||||
title: 'Developer Tools',
|
||||
description: 'Git, Hosting, App Dev, Software Dev'
|
||||
},
|
||||
'img-tools.md': {
|
||||
title: 'Image Tools',
|
||||
description: 'Image Editors, Generators, Compress'
|
||||
},
|
||||
'audio-tools.md': {
|
||||
title: 'Audio Tools',
|
||||
description: 'Audio Players, Audio Editors, Audio Downloaders'
|
||||
},
|
||||
'system-tools.md': {
|
||||
title: 'System Tools',
|
||||
description: 'System Tools, Hardware Tools, Windows ISOs, Customization'
|
||||
},
|
||||
'file-tools.md': {
|
||||
title: 'File Tools',
|
||||
description: 'Download Managers, File Hosting, File Archivers'
|
||||
},
|
||||
'video-tools.md': {
|
||||
title: 'Video Tools',
|
||||
description: 'Video Players, Video Editors, Live Streaming, Animation'
|
||||
},
|
||||
'text-tools.md': {
|
||||
title: 'Text Tools',
|
||||
description: 'Text Editors, Pastebins, Fonts, Translators'
|
||||
},
|
||||
'internet-tools.md': {
|
||||
title: 'Internet Tools',
|
||||
description: 'Browsers, Extensions, Search Engines'
|
||||
},
|
||||
'social-media-tools.md': {
|
||||
title: 'Social Media Tools',
|
||||
description: 'Discord Tools, Reddit Tools, YouTube Tools'
|
||||
},
|
||||
'storage.md': {
|
||||
title: 'Storage',
|
||||
description: 'Sections too big to fit on main pages'
|
||||
},
|
||||
'torrentpiracyguide.md': {
|
||||
title: 'Torrenting',
|
||||
description: 'Torrent Clients, Torrent Sites, Trackers'
|
||||
},
|
||||
'videopiracyguide.md': {
|
||||
title: 'Movies / TV / Anime',
|
||||
description: 'Stream Videos, Download Videos, Torrent Videos'
|
||||
},
|
||||
'base64.md': {
|
||||
title: 'Base64',
|
||||
description: 'Base64 storage'
|
||||
},
|
||||
'unsafesites.md': {
|
||||
title: 'Unsafe Sites',
|
||||
description: 'Unsafe/harmful sites to avoid.'
|
||||
}
|
||||
} as const
|
||||
|
||||
const excluded = ['readme.md', 'single-page', 'feedback.md', 'index.md']
|
||||
|
||||
export function transformer(): Plugin {
|
||||
export function transforms(): Plugin {
|
||||
return {
|
||||
name: 'custom:transform-content',
|
||||
enforce: 'pre',
|
||||
|
@ -151,48 +32,56 @@ export function transformer(): Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
function getHeader(id: string) {
|
||||
const title =
|
||||
'<div class="space-y-2 not-prose"><h1 class="text-4xl font-extrabold tracking-tight text-primary underline lg:text-5xl lg:leading-[3.5rem]">'
|
||||
|
||||
const description = '<p class="text-black dark:text-text-2">'
|
||||
|
||||
const data = headers[id]
|
||||
let header = '---\n'
|
||||
header += `title: "${data.title}"\n`
|
||||
header += `description: ${data.description}\n`
|
||||
header += '---\n'
|
||||
header += `${title}${data.title}</h1>\n`
|
||||
header += `${description}${data.description}</p></div>\n\n`
|
||||
return header
|
||||
}
|
||||
|
||||
export function transformGuide(text: string): string {
|
||||
const _text = text
|
||||
.replace(/\[TOC\]\n/gm, '')
|
||||
.replace(/\*\*Table of Contents\*\*\n\[TOC2\]\n/gm, '')
|
||||
.replace(/# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm, '')
|
||||
.replace(/!!!note\s(.+?)\n/gm, '\n:::info\n$1\n:::\n')
|
||||
.replace(/!!!info\s(.+?)\n/gm, '\n:::info\n$1\n:::\n')
|
||||
.replace(/!!!warning\s(.+?)\n/gm, ':::warning\n$1\n:::\n')
|
||||
.replace(/>\s(.+?)\n/gm, '> $1\n\n')
|
||||
.replace(/\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm, '')
|
||||
.replace(/!!!\s(.+?)\n/gm, ':::info\n$1\n:::\n')
|
||||
.replace(/\n\*\*\[/gm, '\n* **[')
|
||||
.replace(/>(.*)\n\n(.*)/gm, ':::details $1\n$2\n:::')
|
||||
return _text
|
||||
}
|
||||
|
||||
function replaceUnderscore(text: string): string {
|
||||
const pattern = /\/#[\w\-]+(?:_[\w]+)*/g
|
||||
const matches = text.match(pattern) || []
|
||||
let _text = text
|
||||
for (const match of matches) {
|
||||
const replacement = match.replace(/_/g, '-')
|
||||
_text = _text.replace(match, replacement)
|
||||
}
|
||||
return _text
|
||||
}
|
||||
export const transformGuide = (text: string): string =>
|
||||
transformer(text)
|
||||
.transform('Beginners Guide', [
|
||||
{
|
||||
name: 'TOC',
|
||||
find: /\[TOC\]\n/gm,
|
||||
replace: ''
|
||||
},
|
||||
{
|
||||
name: 'TOC2',
|
||||
find: /\*\*Table of Contents\*\*\n\[TOC2\]\n/gm,
|
||||
replace: ''
|
||||
},
|
||||
{
|
||||
name: 'Beginners Guide',
|
||||
find: /# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n/gm,
|
||||
replace: ''
|
||||
},
|
||||
{
|
||||
name: 'Note',
|
||||
find: /!!!note\s(.+?)\n/gm,
|
||||
replace: '\n:::info\n$1\n:::\n'
|
||||
},
|
||||
{
|
||||
name: 'Info',
|
||||
find: /!!!info\s(.+?)\n/gm,
|
||||
replace: '\n:::info\n$1\n:::\n'
|
||||
},
|
||||
{
|
||||
name: 'Warning',
|
||||
find: /!!!warning\s(.+?)\n/gm,
|
||||
replace: ':::warning\n$1\n:::\n'
|
||||
},
|
||||
{
|
||||
name: 'Quote',
|
||||
find: />\s(.+?)\n/gm,
|
||||
replace: '> $1\n\n'
|
||||
},
|
||||
{
|
||||
name: 'Back to Top',
|
||||
find: /\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm,
|
||||
replace: ''
|
||||
},
|
||||
{
|
||||
name: 'Back to Top',
|
||||
find: /\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*/gm,
|
||||
replace: ''
|
||||
}
|
||||
])
|
||||
.getText()
|
||||
|
||||
export function transform(text: string): string {
|
||||
let _text = text
|
||||
|
@ -362,42 +251,50 @@ export function transform(text: string): string {
|
|||
return _text
|
||||
}
|
||||
|
||||
function transformLinks(text: string): string {
|
||||
const _text = text
|
||||
// Transform Discord links to icons
|
||||
.replace(
|
||||
/\[Discord\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>'
|
||||
)
|
||||
// Transform GitHub links to icons
|
||||
.replace(
|
||||
/\[GitHub\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
|
||||
)
|
||||
// Fallback for GitHub
|
||||
.replace(
|
||||
/\[Github\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
|
||||
)
|
||||
// Transform GitLab links to icons
|
||||
.replace(
|
||||
/\[GitLab\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
|
||||
)
|
||||
// Fallback for GitLab
|
||||
.replace(
|
||||
/\[Gitlab\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
|
||||
)
|
||||
// Transform Telegram links to icons
|
||||
.replace(
|
||||
/\[Telegram\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="Telegram" class="i-mdi:telegram" /></a>'
|
||||
)
|
||||
// Transform Subreddit links to icons
|
||||
.replace(
|
||||
/\[Subreddit\]\(([^\)]*?)\)/gm,
|
||||
'<a target="_blank" href="$1"><div alt="Reddit" class="i-mdi:reddit" /></a>'
|
||||
)
|
||||
return _text
|
||||
}
|
||||
const transformLinks = (text: string): string =>
|
||||
transformer(text)
|
||||
.transform('Links to Icons', [
|
||||
{
|
||||
name: 'Discord',
|
||||
find: /\[Discord\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="Discord" class="i-carbon:logo-discord" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'GitHub',
|
||||
find: /\[GitHub\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'GitHub Fallback',
|
||||
find: /\[Github\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="GitHub" class="i-carbon:logo-github mb-1" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'GitLab',
|
||||
find: /\[GitLab\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'GitLab Fallback',
|
||||
find: /\[Gitlab\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="GitLab" class="i-carbon:logo-gitlab" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'Telegram',
|
||||
find: /\[Telegram\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="Telegram" class="i-mdi:telegram" /></a>'
|
||||
},
|
||||
{
|
||||
name: 'Subreddit',
|
||||
find: /\[Subreddit\]\(([^\)]*?)\)/gm,
|
||||
replace:
|
||||
'<a target="_blank" href="$1"><div alt="Reddit" class="i-mdi:reddit" /></a>'
|
||||
}
|
||||
])
|
||||
.getText()
|
||||
|
|
136
docs/.vitepress/transformer/constants.ts
Normal file
136
docs/.vitepress/transformer/constants.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
interface Header {
|
||||
[file: string]: { title: string; description: string }
|
||||
}
|
||||
|
||||
export const headers: Header = {
|
||||
'adblockvpnguide.md': {
|
||||
title: 'Adblocking / Privacy',
|
||||
description: "Adblocking, Privacy, VPN's, Proxies, Antivirus"
|
||||
},
|
||||
'ai.md': {
|
||||
title: 'Artificial Intelligence',
|
||||
description: 'Chat Bots, Text Generators, Image Generators, ChatGPT Tools'
|
||||
},
|
||||
'android-iosguide.md': {
|
||||
title: 'Android / iOS',
|
||||
description: 'Apps, Jailbreaking, Android Emulators'
|
||||
},
|
||||
'audiopiracyguide.md': {
|
||||
title: 'Music / Podcasts / Radio',
|
||||
description: 'Stream Audio, Download Audio, Torrent Audio'
|
||||
},
|
||||
'beginners-guide.md': {
|
||||
title: 'Beginners Guide',
|
||||
description: 'A Guide for Beginners to Piracy'
|
||||
},
|
||||
'downloadpiracyguide.md': {
|
||||
title: 'Downloading',
|
||||
description: 'Download Sites, Software Sites, Open Directories'
|
||||
},
|
||||
'edupiracyguide.md': {
|
||||
title: 'Educational',
|
||||
description: 'Courses, Documentaries, Learning Resources'
|
||||
},
|
||||
'gamingpiracyguide.md': {
|
||||
title: 'Gaming / Emulation',
|
||||
description: 'Download Games, ROMs, Gaming Tools'
|
||||
},
|
||||
'linuxguide.md': {
|
||||
title: 'Linux / MacOS',
|
||||
description: 'Apps, Software Sites, Gaming'
|
||||
},
|
||||
'miscguide.md': {
|
||||
title: 'Miscellaneous',
|
||||
description: 'Extensions, Indexes, News, Health, Food, Fun'
|
||||
},
|
||||
'nsfwpiracy.md': {
|
||||
title: 'NSFW',
|
||||
description: 'NSFW Indexes, Streaming, Downloading'
|
||||
},
|
||||
'non-english.md': {
|
||||
title: 'Non-English',
|
||||
description: 'International Piracy Sites'
|
||||
},
|
||||
'readingpiracyguide.md': {
|
||||
title: 'Books / Comics / Manga',
|
||||
description: 'Books, Comics, Magazines, Newspapers'
|
||||
},
|
||||
'gaming-tools.md': {
|
||||
title: 'Gaming Tools',
|
||||
description: 'Gaming Optimization, Game Launchers, Multiplayer'
|
||||
},
|
||||
'devtools.md': {
|
||||
title: 'Developer Tools',
|
||||
description: 'Git, Hosting, App Dev, Software Dev'
|
||||
},
|
||||
'img-tools.md': {
|
||||
title: 'Image Tools',
|
||||
description: 'Image Editors, Generators, Compress'
|
||||
},
|
||||
'audio-tools.md': {
|
||||
title: 'Audio Tools',
|
||||
description: 'Audio Players, Audio Editors, Audio Downloaders'
|
||||
},
|
||||
'system-tools.md': {
|
||||
title: 'System Tools',
|
||||
description: 'System Tools, Hardware Tools, Windows ISOs, Customization'
|
||||
},
|
||||
'file-tools.md': {
|
||||
title: 'File Tools',
|
||||
description: 'Download Managers, File Hosting, File Archivers'
|
||||
},
|
||||
'video-tools.md': {
|
||||
title: 'Video Tools',
|
||||
description: 'Video Players, Video Editors, Live Streaming, Animation'
|
||||
},
|
||||
'text-tools.md': {
|
||||
title: 'Text Tools',
|
||||
description: 'Text Editors, Pastebins, Fonts, Translators'
|
||||
},
|
||||
'internet-tools.md': {
|
||||
title: 'Internet Tools',
|
||||
description: 'Browsers, Extensions, Search Engines'
|
||||
},
|
||||
'social-media-tools.md': {
|
||||
title: 'Social Media Tools',
|
||||
description: 'Discord Tools, Reddit Tools, YouTube Tools'
|
||||
},
|
||||
'storage.md': {
|
||||
title: 'Storage',
|
||||
description: 'Sections too big to fit on main pages'
|
||||
},
|
||||
'torrentpiracyguide.md': {
|
||||
title: 'Torrenting',
|
||||
description: 'Torrent Clients, Torrent Sites, Trackers'
|
||||
},
|
||||
'videopiracyguide.md': {
|
||||
title: 'Movies / TV / Anime',
|
||||
description: 'Stream Videos, Download Videos, Torrent Videos'
|
||||
},
|
||||
'base64.md': {
|
||||
title: 'Base64',
|
||||
description: 'Base64 storage'
|
||||
},
|
||||
'unsafesites.md': {
|
||||
title: 'Unsafe Sites',
|
||||
description: 'Unsafe/harmful sites to avoid.'
|
||||
}
|
||||
} as const
|
||||
|
||||
export const excluded = ['readme.md', 'single-page', 'feedback.md', 'index.md']
|
||||
|
||||
export function getHeader(id: string) {
|
||||
const title =
|
||||
'<div class="space-y-2 not-prose"><h1 class="text-4xl font-extrabold tracking-tight text-primary underline lg:text-5xl lg:leading-[3.5rem]">'
|
||||
|
||||
const description = '<p class="text-black dark:text-text-2">'
|
||||
|
||||
const data = headers[id]
|
||||
let header = '---\n'
|
||||
header += `title: "${data.title}"\n`
|
||||
header += `description: ${data.description}\n`
|
||||
header += '---\n'
|
||||
header += `${title}${data.title}</h1>\n`
|
||||
header += `${description}${data.description}</p></div>\n\n`
|
||||
return header
|
||||
}
|
53
docs/.vitepress/transformer/core.ts
Normal file
53
docs/.vitepress/transformer/core.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import consola from 'consola'
|
||||
|
||||
type Transform = {
|
||||
name: string
|
||||
find: string | RegExp
|
||||
replace: string | ((match: string) => string)
|
||||
}
|
||||
|
||||
type TransformerFunc = (name: string, transforms: Transform[]) => Replacer
|
||||
|
||||
interface Replacer {
|
||||
transform: TransformerFunc
|
||||
getText(): string
|
||||
}
|
||||
|
||||
export const transformer = (text: string) => {
|
||||
const handler: ProxyHandler<{ text: string }> = {
|
||||
get(target, prop) {
|
||||
if (prop === 'transform') {
|
||||
return (name: string, transforms: Transform[]): Replacer => {
|
||||
consola.debug(`Starting transform ${name} with ${transforms}`)
|
||||
|
||||
transforms.forEach(({ name, find, replace }) => {
|
||||
consola.debug(`Transforming ${name} with ${find}`)
|
||||
target.text = target.text.replace(find, replace as any)
|
||||
})
|
||||
|
||||
// @ts-expect-error - Proxy is not typed
|
||||
return proxy
|
||||
}
|
||||
}
|
||||
if (prop === 'getText') {
|
||||
return () => target.text
|
||||
}
|
||||
return Reflect.get(target, prop)
|
||||
}
|
||||
}
|
||||
|
||||
const target = { text }
|
||||
const proxy = new Proxy(target, handler)
|
||||
return proxy as unknown as Replacer
|
||||
}
|
||||
|
||||
export function replaceUnderscore(text: string): string {
|
||||
const pattern = /\/#[\w\-]+(?:_[\w]+)*/g
|
||||
const matches = text.match(pattern) || []
|
||||
let _text = text
|
||||
for (const match of matches) {
|
||||
const replacement = match.replace(/_/g, '-')
|
||||
_text = _text.replace(match, replacement)
|
||||
}
|
||||
return _text
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue