fix: generate random id for svg elements. Fixes #71 (#78)

master
Amio Jin 2023-06-22 15:36:02 +08:00 zatwierdzone przez GitHub
rodzic 25ee3bd4bd
commit 23108a625f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 68 dodań i 44 usunięć

Wyświetl plik

@ -48,6 +48,9 @@ export function badgen ({
const width = sbRectWidth + stRectWidth
const xlink = icon ? ' xmlns:xlink="http://www.w3.org/1999/xlink"' : ''
const gradientId = generateRandomID(5)
const maskId = generateRandomID(5)
label = label ? sanitize(label) : ''
status = sanitize(status)
color = sanitize(color)
@ -74,15 +77,15 @@ export function badgen ({
return `<svg width="${scale * width / 10}" height="${scale * 20}" viewBox="0 0 ${width} 200" xmlns="http://www.w3.org/2000/svg"${xlink} role="img" aria-label="${accessibleText}">
<title>${accessibleText}</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="${gradientId}" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="${width}" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="${maskId}"><rect width="${width}" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#${maskId})">
<rect width="${sbRectWidth}" height="200" fill="#${labelColor}"/>
<rect width="${stRectWidth}" height="200" fill="#${color}" x="${sbRectWidth}"/>
<rect width="${width}" height="200" fill="url(#a)"/>
<rect width="${width}" height="200" fill="url(#${gradientId})"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="${sbTextStart + 10}" y="148" textLength="${sbTextWidth}" fill="#000" opacity="0.25">${label}</text>
@ -101,6 +104,9 @@ function bare ({ status, color = 'blue', style, scale = 1 }: BadgenOptions) {
const stTextWidth = calcWidth(status)
const stRectWidth = stTextWidth + 115
const gradientId = generateRandomID(5)
const maskId = generateRandomID(5)
status = sanitize(status)
color = sanitize(color)
@ -119,14 +125,14 @@ function bare ({ status, color = 'blue', style, scale = 1 }: BadgenOptions) {
return `<svg width="${scale * stRectWidth / 10}" height="${scale * 20}" viewBox="0 0 ${stRectWidth} 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="${status}">
<title>${status}</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="${gradientId}" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="${stRectWidth}" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="${maskId}"><rect width="${stRectWidth}" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#${maskId})">
<rect width="${stRectWidth}" height="200" fill="#${color}" x="0"/>
<rect width="${stRectWidth}" height="200" fill="url(#a)"/>
<rect width="${stRectWidth}" height="200" fill="url(#${gradientId})"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="${stTextWidth}" fill="#000" opacity="0.25">${status}</text>
@ -149,6 +155,17 @@ interface AccessibleTextProps {
label?: string;
}
function generateRandomID(length: number): string {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
function createAccessibleText({label, status}: AccessibleTextProps): string {
const labelPrefix = label ? `${label}: ` : '';
return labelPrefix + status;

Wyświetl plik

@ -8,15 +8,15 @@
exports[`test/badgen.spec.js TAP ensure badgen() correctly escapes string inputs > snapshot 1`] = `
<svg width="191.2" height="20" viewBox="0 0 1912 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="&lt;escape me&gt;: &lt;escape me&gt;">
<title>&lt;escape me&gt;: &lt;escape me&gt;</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="1912" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="1912" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="1036" height="200" fill="#&lt;escape me&gt;"/>
<rect width="876" height="200" fill="#&lt;escape me&gt;" x="1036"/>
<rect width="1912" height="200" fill="url(#a)"/>
<rect width="1912" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="220" y="148" textLength="776" fill="#000" opacity="0.25">&lt;escape me&gt;</text>
@ -31,14 +31,14 @@ exports[`test/badgen.spec.js TAP ensure badgen() correctly escapes string inputs
exports[`test/badgen.spec.js TAP ensure bare() correctly escapes string inputs > snapshot 1`] = `
<svg width="89.1" height="20" viewBox="0 0 891 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="&lt;escape me&gt;">
<title>&lt;escape me&gt;</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="891" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="891" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="891" height="200" fill="#&lt;escape me&gt;" x="0"/>
<rect width="891" height="200" fill="url(#a)"/>
<rect width="891" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="776" fill="#000" opacity="0.25">&lt;escape me&gt;</text>
@ -50,15 +50,15 @@ exports[`test/badgen.spec.js TAP ensure bare() correctly escapes string inputs >
exports[`test/badgen.spec.js TAP generate badge with { label, status } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="804" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="804" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="349" height="200" fill="#555"/>
<rect width="455" height="200" fill="#08C" x="349"/>
<rect width="804" height="200" fill="url(#a)"/>
<rect width="804" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.25">npm</text>
@ -73,15 +73,15 @@ exports[`test/badgen.spec.js TAP generate badge with { label, status } > snapsho
exports[`test/badgen.spec.js TAP generate badge with { label, status, color } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="804" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="804" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="349" height="200" fill="#555"/>
<rect width="455" height="200" fill="#ADF" x="349"/>
<rect width="804" height="200" fill="url(#a)"/>
<rect width="804" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.25">npm</text>
@ -113,15 +113,15 @@ exports[`test/badgen.spec.js TAP generate badge with { label, status, color, sty
exports[`test/badgen.spec.js TAP generate badge with { label, status, icon } > snapshot 1`] = `
<svg width="95.5" height="20" viewBox="0 0 955 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="docker: icon">
<title>docker: icon</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="955" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="955" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="631" height="200" fill="#555"/>
<rect width="324" height="200" fill="#08C" x="631"/>
<rect width="955" height="200" fill="url(#a)"/>
<rect width="955" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="220" y="148" textLength="371" fill="#000" opacity="0.25">docker</text>
@ -170,15 +170,15 @@ exports[`test/badgen.spec.js TAP generate badge with { label, status, style } >
exports[`test/badgen.spec.js TAP generate badge with { status, icon } > snapshot 1`] = `
<svg width="53.6" height="20" viewBox="0 0 536 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="icon">
<title>icon</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="536" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="536" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="212" height="200" fill="#555"/>
<rect width="324" height="200" fill="#08C" x="212"/>
<rect width="536" height="200" fill="url(#a)"/>
<rect width="536" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="172" y="148" textLength="0" fill="#000" opacity="0.25"></text>
@ -193,15 +193,15 @@ exports[`test/badgen.spec.js TAP generate badge with { status, icon } > snapshot
exports[`test/badgen.spec.js TAP generate badge with { status, icon, iconWidth } > snapshot 1`] = `
<svg width="59.6" height="20" viewBox="0 0 596 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="icon">
<title>icon</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="596" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="596" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="272" height="200" fill="#555"/>
<rect width="324" height="200" fill="#08C" x="272"/>
<rect width="596" height="200" fill="url(#a)"/>
<rect width="596" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="232" y="148" textLength="0" fill="#000" opacity="0.25"></text>
@ -216,14 +216,14 @@ exports[`test/badgen.spec.js TAP generate badge with { status, icon, iconWidth }
exports[`test/badgen.spec.js TAP generate bare badge with { status } > snapshot 1`] = `
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="v1.0.0">
<title>v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="470" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="470" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="470" height="200" fill="#08C" x="0"/>
<rect width="470" height="200" fill="url(#a)"/>
<rect width="470" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>
@ -235,14 +235,14 @@ exports[`test/badgen.spec.js TAP generate bare badge with { status } > snapshot
exports[`test/badgen.spec.js TAP generate bare badge with { status, color } > snapshot 1`] = `
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="v1.0.0">
<title>v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<linearGradient id="aaaaa" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="m"><rect width="470" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#m)">
<mask id="aaaaa"><rect width="470" height="200" rx="30" fill="#FFF"/></mask>
<g mask="url(#aaaaa)">
<rect width="470" height="200" fill="#ADF" x="0"/>
<rect width="470" height="200" fill="url(#a)"/>
<rect width="470" height="200" fill="url(#aaaaa)"/>
</g>
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>

Wyświetl plik

@ -2,6 +2,13 @@ const tap = require('tap')
const { badgen } = require('../dist')
const icons = require('./assets/icon-data-uri.js')
const originalMath = global.Math
const mockMath = Object.create(global.Math)
mockMath.random = () => 0.5
tap.beforeEach(async t => { global.Math = mockMath })
tap.afterEach(async t => { global.Math = originalMath })
tap.test('generate badge with { label, status }', t => {
const svg = badgen({ label: 'npm', status: 'v1.0.0' })
t.ok(typeof svg === 'string', 'successfully generated')