From 7ea357256c855ae0a9a142c14bbd5e7d344ef865 Mon Sep 17 00:00:00 2001 From: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> Date: Tue, 21 May 2024 08:43:10 +0530 Subject: [PATCH] fix: dont escape ampersand twice in title --- package.json | 2 -- pnpm-lock.yaml | 16 ---------------- src/client/app/utils.ts | 2 +- src/client/index.ts | 3 ++- src/node/build/render.ts | 8 ++++---- src/node/markdown/plugins/restoreEntities.ts | 5 +---- src/shared/shared.ts | 11 +++++++++++ 7 files changed, 19 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index bf785dc2..4e378d16 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,6 @@ "@rollup/plugin-replace": "^5.0.5", "@types/cross-spawn": "^6.0.6", "@types/debug": "^4.1.12", - "@types/escape-html": "^1.0.4", "@types/fs-extra": "^11.0.4", "@types/lodash.template": "^4.5.3", "@types/mark.js": "^8.11.12", @@ -150,7 +149,6 @@ "cross-spawn": "^7.0.3", "debug": "^4.3.4", "esbuild": "^0.21.3", - "escape-html": "^1.0.3", "execa": "^9.1.0", "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 949d7928..7a14e9b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,9 +113,6 @@ importers: '@types/debug': specifier: ^4.1.12 version: 4.1.12 - '@types/escape-html': - specifier: ^1.0.4 - version: 1.0.4 '@types/fs-extra': specifier: ^11.0.4 version: 11.0.4 @@ -164,9 +161,6 @@ importers: esbuild: specifier: ^0.21.3 version: 0.21.3 - escape-html: - specifier: ^1.0.3 - version: 1.0.3 execa: specifier: ^9.1.0 version: 9.1.0 @@ -985,9 +979,6 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/escape-html@1.0.4': - resolution: {integrity: sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==} - '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -1645,9 +1636,6 @@ packages: resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==} engines: {node: '>=10'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -3681,8 +3669,6 @@ snapshots: dependencies: '@types/ms': 0.7.34 - '@types/escape-html@1.0.4': {} - '@types/estree@1.0.5': {} '@types/fs-extra@11.0.4': @@ -4498,8 +4484,6 @@ snapshots: escape-goat@3.0.0: {} - escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} esm@3.2.25: {} diff --git a/src/client/app/utils.ts b/src/client/app/utils.ts index dfa5cffc..45496b40 100644 --- a/src/client/app/utils.ts +++ b/src/client/app/utils.ts @@ -13,7 +13,7 @@ import { type AsyncComponentLoader } from 'vue' -export { inBrowser } from '../shared' +export { inBrowser, escapeHtml as _escapeHtml } from '../shared' /** * Join two paths by resolving the slash collision. diff --git a/src/client/index.ts b/src/client/index.ts index 5fde6c5d..75bbfe54 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -21,7 +21,8 @@ export { onContentUpdated, defineClientComponent, withBase, - getScrollOffset + getScrollOffset, + _escapeHtml } from './app/utils' // components diff --git a/src/node/build/render.ts b/src/node/build/render.ts index 1341ae6d..c9b71c81 100644 --- a/src/node/build/render.ts +++ b/src/node/build/render.ts @@ -1,13 +1,14 @@ import { isBooleanAttr } from '@vue/shared' -import escape from 'escape-html' import fs from 'fs-extra' import path from 'path' import { pathToFileURL } from 'url' import { normalizePath, transformWithEsbuild, type Rollup } from 'vite' +import { version } from '../../../package.json' import type { SiteConfig } from '../config' import { EXTERNAL_URL_RE, createTitle, + escapeHtml, mergeHead, notFoundPageData, resolveSiteDataByRoute, @@ -17,7 +18,6 @@ import { type PageData, type SSGContext } from '../shared' -import { version } from '../../../package.json' export async function renderPage( render: (path: string) => Promise, @@ -163,7 +163,7 @@ export async function renderPage( ? '' : '' } - ${escape(title)} + ${escapeHtml(title)} ${ isDescriptionOverridden(head) ? '' @@ -260,7 +260,7 @@ function renderAttrs(attrs: Record): string { return Object.keys(attrs) .map((key) => { if (isBooleanAttr(key)) return ` ${key}` - return ` ${key}="${escape(attrs[key] as string)}"` + return ` ${key}="${escapeHtml(attrs[key] as string)}"` }) .join('') } diff --git a/src/node/markdown/plugins/restoreEntities.ts b/src/node/markdown/plugins/restoreEntities.ts index d5bb80ed..07c71e70 100644 --- a/src/node/markdown/plugins/restoreEntities.ts +++ b/src/node/markdown/plugins/restoreEntities.ts @@ -1,6 +1,7 @@ import type MarkdownIt from 'markdown-it' import type StateCore from 'markdown-it/lib/rules_core/state_core.mjs' import type Token from 'markdown-it/lib/token.mjs' +import { escapeHtml } from '../../shared' export function restoreEntities(md: MarkdownIt): void { md.core.ruler.at('text_join', text_join) @@ -47,7 +48,3 @@ function getContent(token: Token): string { ? '&' : token.content } - -function escapeHtml(str: string): string { - return str.replace(//g, '>').replace(/"/g, '"') -} diff --git a/src/shared/shared.ts b/src/shared/shared.ts index 3cf5ecbe..051c5d09 100644 --- a/src/shared/shared.ts +++ b/src/shared/shared.ts @@ -219,3 +219,14 @@ export function treatAsHtml(filename: string): boolean { export function escapeRegExp(str: string) { return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d') } + +/** + * @internal + */ +export function escapeHtml(str: string): string { + return str + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/&(?![\w#]+;)/g, '&') +}