Skip to content

Commit

Permalink
fix: escape HTML correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
learosema committed Oct 19, 2024
1 parent ec374b8 commit 3d32c7f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/builtin-filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function last(amount = 1) {
* @returns escaped html
*/
export function htmlentities(str) {
return str.replace(/\&/, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
return str?.replace(/\&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
}

/**
Expand Down
125 changes: 70 additions & 55 deletions tests/builtin-filters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,67 +3,82 @@ import assert from 'node:assert/strict';
import path from 'node:path'
import { handleTemplateFile } from '../src/transforms/template-data.js';
import { SissiConfig } from '../src/sissi-config.js';
import { htmlentities } from '../src/builtin-filters.js';
describe('builtin filters', () => {

const dummyResolver = (map) => (...paths) => map.get(path.normalize(path.join(...paths)));

it('should format numbers', async () => {
const config = new SissiConfig();
describe('htmlentities', () => {
it('should not crash when nullish value is passed', () => {
assert.equal(htmlentities(undefined), undefined);
});

const vFS = new Map();
vFS.set('index.html', '{{ thousandPi | numberFormat: numberFormatOptions, "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { thousandPi: Math.PI * 1e3, numberFormatOptions: {maximumFractionDigits: 2, minimumFractionDigits: 2} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '3.141,59');
});

it('should format currencies', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ million | currency: "eur", "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { million: 1e6 };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '1.000.000,00 €');
it('should escape HTML', () => {
const expected = '&lt;h1&gt;Hello World&lt;/h1&gt;\n&lt;p&gt;Cow &amp; Son&lt;/p&gt;'
const result = htmlentities('<h1>Hello World</h1>\n<p>Cow & Son</p>');
assert.equal(result, expected);
});
});

it('should format dates', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ newYear | date: dateFormatOptions, "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { newYear: new Date('2025-04-01'), dateFormatOptions: {"day": "2-digit", "month": "2-digit", "year": "numeric"} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '01.04.2025');
});

it('should serialize json', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ answer | json }}');

config.resolve = dummyResolver(vFS);

const data = { answer: {result: 42} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '{"result":42}');
describe('integration with template engine', () => {
it('should format numbers via numberFormat filter', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ thousandPi | numberFormat: numberFormatOptions, "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { thousandPi: Math.PI * 1e3, numberFormatOptions: {maximumFractionDigits: 2, minimumFractionDigits: 2} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '3.141,59');
});

it('should format currencies via currency filter', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ million | currency: "eur", "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { million: 1e6 };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '1.000.000,00 €');
});

it('should format dates via date filter', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ newYear | date: dateFormatOptions, "de-DE" }}');

config.resolve = dummyResolver(vFS);

const data = { newYear: new Date('2025-04-01'), dateFormatOptions: {"day": "2-digit", "month": "2-digit", "year": "numeric"} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '01.04.2025');
});

it('should serialize json', async () => {
const config = new SissiConfig();

const vFS = new Map();
vFS.set('index.html', '{{ answer | json }}');

config.resolve = dummyResolver(vFS);

const data = { answer: {result: 42} };

const result = await handleTemplateFile(config, data, 'index.html');

assert.equal(result.content, '{"result":42}');
});
});
});

0 comments on commit 3d32c7f

Please sign in to comment.