fix(shared): escape attribute values in buildLucideSvg (#4940)

* fix(shared): escape attribute values in buildLucideSvg

Attribute values were interpolated into the SVG string as-is, so a value
containing a double quote, ampersand or angle bracket (for example in a
custom attribute or class name) produced malformed markup.

* Use replace(/x/g) instead of replaceAll for broader TS lib compat

lucide-react-native's tsconfig doesn't include the ES2021 lib that
replaceAll requires, failing typecheck. A global regex replace is
functionally identical here and works under any target.

* Escape the full set of relevant HTML entities in attribute values

Also escape > and ' per review feedback, not just & " <.

* Apply suggestion from @karsa-mistmere

---------

Co-authored-by: Karsa <contact@karsa.org>
This commit is contained in:
Saadanjum0
2026-10-02 09:41:22 +02:00
committed by GitHub
co-authored by Karsa
parent 5a92b9ba26
commit e8a2c60b75
2 changed files with 26 additions and 1 deletions
+12 -1
View File
@@ -1,10 +1,21 @@
import buildLucideIconNode from './buildLucideIconNode';
import type { LucideBuildParams, LucideIconData, LucideIconNode } from './types';
const entities = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
} as const;
const escapeAttribute = (value: string) =>
value.replace(/[&<>"']/g, (char) => entities[char as keyof typeof entities]);
const buildDomNode = ([tagName, attributes, children = []]: LucideIconNode): string =>
`<${tagName} ${Object.entries(attributes)
.filter(([, value]) => value !== undefined && value !== null)
.map(([attrName, value]) => `${attrName}="${String(value)}"`)
.map(([attrName, value]) => `${attrName}="${escapeAttribute(String(value))}"`)
.join(' ')}>${children?.map((child) => buildDomNode(child)).join('')}</${tagName}>`;
/**
@@ -0,0 +1,14 @@
import { describe, it, expect } from 'vitest';
import buildLucideSvg from '../src/build/buildLucideSvg';
const icon = { name: 'dot', size: 24, node: [['circle', { cx: 12, cy: 12, r: 1 }]] } as const;
describe('buildLucideSvg', () => {
it('should escape special characters in attribute values', () => {
const svg = buildLucideSvg(icon as any, {
attributes: { 'data-label': 'a\'s "quoted" <b> & c' },
});
expect(svg).toContain('data-label="a&#39;s &quot;quoted&quot; &lt;b&gt; &amp; c"');
});
});