Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export function render(tree?: Node | Node[], options: Options = {}): string {
function makeAttr(key: string, attrValue: string | number | boolean, quoteStyle = 1): string {
if (quoteStyle === 1) {
// Single Quote
return ` ${key}='${attrValue}'`;
return makeSingleQuotedAttr(key, attrValue);
}

if (quoteStyle === 2) {
Expand All @@ -288,9 +288,19 @@ export function render(tree?: Node | Node[], options: Options = {}): string {

// Smart Quote
if (typeof attrValue === 'string' && attrValue.includes('"')) {
return ` ${key}='${attrValue}'`;
return makeSingleQuotedAttr(key, attrValue);
}

return ` ${key}="${attrValue}"`;
}

function makeSingleQuotedAttr(key: string, attrValue: string | number | boolean): string {
// A `'` can't appear inside single quotes,
// so such values are double-quoted with `"` escaped instead.
if (typeof attrValue === 'string' && attrValue.includes('\'')) {
return ` ${key}="${attrValue.replace(/"/g, '"')}"`;
}

return ` ${key}='${attrValue}'`;
}
}
30 changes: 30 additions & 0 deletions test/test-core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ test('{Attrs} {String} (json)', t => {
t.is(render(fixture), expected);
});

test('{Attrs} {String} (json with apostrophe)', t => {
const fixture = {
attrs: {
'x-data': '{"a":"it\'s"}',
},
};

const expected = '<div x-data="{&quot;a&quot;:&quot;it\'s&quot;}"></div>';

t.is(render(fixture), expected);
});

test('{Content} {String}', t => {
const fixture = {content: 'Hello world!'};
const expected = '<div>Hello world!</div>';
Expand Down Expand Up @@ -546,6 +558,24 @@ test('{Options} {quoteStyle} 0 - smart quote', t => {
t.is(render(fixture, options), expected);
});

test('{Options} {quoteStyle} 1 - single quote with apostrophe', t => {
const options = {quoteStyle: quoteStyleEnum.Single};

const fixture = {tag: 'img', attrs: {alt: 'it\'s'}};
const expected = '<img alt="it\'s">';

t.is(render(fixture, options), expected);
});

test('{Options} {quoteStyle} 0 - smart quote with apostrophe', t => {
const options = {replaceQuote: false, quoteStyle: quoteStyleEnum.Smart};

const fixture = {tag: 'img', attrs: {alt: '"it\'s"'}};
const expected = '<img alt="&quot;it\'s&quot;">';

t.is(render(fixture, options), expected);
});

test('{QuoteStyle} for width/height attrs in img', t => {
const fixture = {
tag: 'img',
Expand Down