feat: escape filters from Jekyll, #443

This commit is contained in:
Yang Jun
2024-05-12 15:05:36 +08:00
committed by Jun Yang
parent 4955e75be7
commit b12eb8ab4b
13 changed files with 169 additions and 14 deletions
+3
View File
@@ -33,6 +33,7 @@ filters:
at_most: at_most.html at_most: at_most.html
capitalize: capitalize.html capitalize: capitalize.html
ceil: ceil.html ceil: ceil.html
cgi_escape: cgi_escape.html
compact: compact.html compact: compact.html
concat: concat.html concat: concat.html
date: date.html date: date.html
@@ -93,10 +94,12 @@ filters:
uniq: uniq.html uniq: uniq.html
unshift: unshift.html unshift: unshift.html
upcase: upcase.html upcase: upcase.html
uri_escape: uri_escape.html
url_decode: url_decode.html url_decode: url_decode.html
url_encode: url_encode.html url_encode: url_encode.html
where: where.html where: where.html
where_exp: where_exp.html where_exp: where_exp.html
xml_escape: xml_escape.html
tags: tags:
overview: overview.html overview: overview.html
+17
View File
@@ -0,0 +1,17 @@
---
title: cgi_escape
---
{% since %}v10.13.0{% endsince %}
CGI escape a string for use in a URL. Replaces any special characters with appropriate `%XX` replacements. CGI escape normally replaces a space with a plus `+` sign.
Input
```liquid
{{ "foo, bar; baz?" | cgi_escape }}
```
Output
```text
foo%2C+bar%3B+baz%3F
```
+1 -1
View File
@@ -11,7 +11,7 @@ Categories | Filters
--- | --- --- | ---
Math | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most Math | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most
String | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last,remove, remove_first, remove_last, truncate, truncatewords, normalize_whitespace String | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last,remove, remove_first, remove_last, truncate, truncatewords, normalize_whitespace
HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br, xml_escape, cgi_escape, uri_escape
Array | slice, map, sort, sort_natural, uniq, where, where_exp, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift Array | slice, map, sort, sort_natural, uniq, where, where_exp, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift
Date | date, date_to_xmlschema, date_to_rfc822, date_to_string, date_to_long_string Date | date, date_to_xmlschema, date_to_rfc822, date_to_string, date_to_long_string
Misc | default, json, jsonify, inspect, raw, to_integer Misc | default, json, jsonify, inspect, raw, to_integer
+19
View File
@@ -0,0 +1,19 @@
---
title: uri_escape
---
{% since %}v10.13.0{% endsince %}
Percent encodes any special characters in a URI. URI escape normally replaces a space with `%20`. [Reserved characters][reserved] will not be escaped.
Input
```liquid
{{ "http://foo.com/?q=foo, \bar?" | uri_escape }}
```
Output
```text
http://foo.com/?q=foo,%20%5Cbar?
```
[reserved]: https://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters
+17
View File
@@ -0,0 +1,17 @@
---
title: xml_escape
---
{% since %}v10.13.0{% endsince %}
Escape some text for use in XML.
Input
```liquid
{{ "Have you read \'James & the Giant Peach\'?" | xml_escape }}
```
Output
```text
Have you read 'James & the Giant Peach'?
```
+17
View File
@@ -0,0 +1,17 @@
---
title: cgi_escape
---
{% since %}v10.13.0{% endsince %}
把字符串 CGI 转义,用于 URL。用对应的 `%XX` 替换特殊字符,空格会被转义为 `+` 号。
输入
```liquid
{{ "foo, bar; baz?" | cgi_escape }}
```
输出
```text
foo%2C+bar%3B+baz%3F
```
+1 -1
View File
@@ -11,7 +11,7 @@ LiquidJS 共支持 40+ 个过滤器,可以分为如下几类:
--- | --- --- | ---
数学 | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most 数学 | plus, minus, modulo, times, floor, ceil, round, divided_by, abs, at_least, at_most
字符串 | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last, remove, remove_first, remove_last, truncate, truncatewords, normalize_whitespace 字符串 | append, prepend, capitalize, upcase, downcase, strip, lstrip, rstrip, strip_newlines, split, replace, replace_first, replace_last, remove, remove_first, remove_last, truncate, truncatewords, normalize_whitespace
HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br HTML/URI | escape, escape_once, url_encode, url_decode, strip_html, newline_to_br, xml_escape, cgi_escape, uri_escape
数组 | slice, map, sort, sort_natural, uniq, where, where_exp, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift 数组 | slice, map, sort, sort_natural, uniq, where, where_exp, group_by, group_by_exp, find, find_exp, first, last, join, reverse, concat, compact, size, push, pop, shift, unshift
日期 | date, date_to_xmlschema, date_to_rfc822, date_to_string, date_to_long_string 日期 | date, date_to_xmlschema, date_to_rfc822, date_to_string, date_to_long_string
其他 | default, json, jsonify, inspect, raw, to_integer 其他 | default, json, jsonify, inspect, raw, to_integer
+19
View File
@@ -0,0 +1,19 @@
---
title: uri_escape
---
{% since %}v10.13.0{% endsince %}
把 URI 中的特殊字符做百分号编码,空格会变成 `%20`。[保留字][reserved] 不会被转义。
输入
```liquid
{{ "http://foo.com/?q=foo, \bar?" | uri_escape }}
```
输出
```text
http://foo.com/?q=foo,%20%5Cbar?
```
[reserved]: https://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters
+17
View File
@@ -0,0 +1,17 @@
---
title: xml_escape
---
{% since %}v10.13.0{% endsince %}
把文本做 XML 转义。
输入
```liquid
{{ "Have you read \'James & the Giant Peach\'?" | xml_escape }}
```
输出
```text
Have you read 'James & the Giant Peach'?
```
+4
View File
@@ -19,6 +19,10 @@ export function escape (str: string) {
return stringify(str).replace(/&|<|>|"|'/g, m => escapeMap[m]) return stringify(str).replace(/&|<|>|"|'/g, m => escapeMap[m])
} }
export function xml_escape (str: string) {
return escape(str)
}
function unescape (str: string) { function unescape (str: string) {
return stringify(str).replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]) return stringify(str).replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m])
} }
+8 -2
View File
@@ -1,4 +1,10 @@
import { stringify } from '../util/underscore' import { stringify } from '../util/underscore'
export const url_decode = (x: string) => stringify(x).split('+').map(decodeURIComponent).join(' ') export const url_decode = (x: string) => decodeURIComponent(stringify(x)).replace(/\+/g, ' ')
export const url_encode = (x: string) => stringify(x).split(' ').map(encodeURIComponent).join('+') export const url_encode = (x: string) => encodeURIComponent(stringify(x)).replace(/%20/g, '+')
export const cgi_escape = (x: string) => encodeURIComponent(stringify(x))
.replace(/%20/g, '+')
.replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase())
export const uri_escape = (x: string) => encodeURI(stringify(x))
.replace(/%5B/g, '[')
.replace(/%5D/g, ']')
+6
View File
@@ -26,6 +26,12 @@ describe('filters/html', function () {
it('should escape nil value to empty string', () => it('should escape nil value to empty string', () =>
test('{{ undefinedValue | escape_once }}', '')) test('{{ undefinedValue | escape_once }}', ''))
}) })
describe('xml_escape', function () {
it('should xml_escape \' and &', function () {
return test('{{ "Have you read \'James & the Giant Peach\'?" | xml_escape }}',
'Have you read &#39;James &amp; the Giant Peach&#39;?')
})
})
describe('newline_to_br', function () { describe('newline_to_br', function () {
it('should support string_with_newlines', function () { it('should support string_with_newlines', function () {
const src = '{% capture string_with_newlines %}\n' + const src = '{% capture string_with_newlines %}\n' +
+40 -10
View File
@@ -1,15 +1,45 @@
import { test } from '../../stub/render' import { Liquid } from '../../../src'
describe('filters/url', function () { describe('filters/url', () => {
describe('url_decode', function () { const liquid = new Liquid()
it('should decode %xx and +', describe('url_decode', () => {
() => test('{{ "%27Stop%21%27+said+Fred" | url_decode }}', "'Stop!' said Fred")) it('should decode %xx and +', () => {
const html = liquid.parseAndRenderSync('{{ "%27Stop%21%27+said+Fred" | url_decode }}')
expect(html).toEqual("'Stop!' said Fred")
})
}) })
describe('url_encode', function () { describe('url_encode', () => {
it('should encode @', it('should encode @', () => {
() => test('{{ "[email protected]" | url_encode }}', 'john%40liquid.com')) const html = liquid.parseAndRenderSync('{{ "[email protected]" | url_encode }}')
it('should encode <space>', expect(html).toEqual('john%40liquid.com')
() => test('{{ "Tetsuro Takara" | url_encode }}', 'Tetsuro+Takara')) })
it('should encode <space>', () => {
const html = liquid.parseAndRenderSync('{{ "Tetsuro Takara" | url_encode }}')
expect(html).toEqual('Tetsuro+Takara')
})
})
describe('cgi_escape', () => {
it('should escape CGI chars', () => {
const html = liquid.parseAndRenderSync('{{ "!\',()*\\"!" | cgi_escape }}')
expect(html).toEqual('%21%27%2C%28%29%2A%22%21')
})
it('should escape space as +', () => {
const html = liquid.parseAndRenderSync('{{ "foo, bar; baz?" | cgi_escape }}')
expect(html).toEqual('foo%2C+bar%3B+baz%3F')
})
})
describe('uri_escape', () => {
it('should escape unsupported chars for uri', () => {
const html = liquid.parseAndRenderSync('{{ "http://foo.com/?q=foo, \\\\bar?" | uri_escape }}')
expect(html).toEqual('http://foo.com/?q=foo,%20%5Cbar?')
})
it('should not escape reserved characters', () => {
const reserved = "!#$&'()*+,/:;=?@[]"
const html = liquid.parseAndRenderSync('{{ reserved | uri_escape }}', { reserved })
expect(html).toEqual(reserved)
})
}) })
}) })