feat: Added indent filter (#188)
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
- Added `split` filter
|
- Added `split` filter
|
||||||
- Allow default string filters to be applied to arrays
|
- Allow default string filters to be applied to arrays
|
||||||
- Similar filters are suggested when unknown filter is used
|
- Similar filters are suggested when unknown filter is used
|
||||||
|
- Added `indent` filter
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class DefaultExtension: Extension {
|
|||||||
registerFilter("lowercase", filter: lowercase)
|
registerFilter("lowercase", filter: lowercase)
|
||||||
registerFilter("join", filter: joinFilter)
|
registerFilter("join", filter: joinFilter)
|
||||||
registerFilter("split", filter: splitFilter)
|
registerFilter("split", filter: splitFilter)
|
||||||
|
registerFilter("indent", filter: indentFilter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,3 +65,49 @@ func splitFilter(value: Any?, arguments: [Any?]) throws -> Any? {
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func indentFilter(value: Any?, arguments: [Any?]) throws -> Any? {
|
||||||
|
guard arguments.count <= 3 else {
|
||||||
|
throw TemplateSyntaxError("'indent' filter can take at most 3 arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
var indentWidth = 4
|
||||||
|
if arguments.count > 0 {
|
||||||
|
guard let value = arguments[0] as? Int else {
|
||||||
|
throw TemplateSyntaxError("'indent' filter width argument must be an Integer (\(String(describing: arguments[0])))")
|
||||||
|
}
|
||||||
|
indentWidth = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var indentationChar = " "
|
||||||
|
if arguments.count > 1 {
|
||||||
|
guard let value = arguments[1] as? String else {
|
||||||
|
throw TemplateSyntaxError("'indent' filter indentation argument must be a String (\(String(describing: arguments[1]))")
|
||||||
|
}
|
||||||
|
indentationChar = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var indentFirst = false
|
||||||
|
if arguments.count > 2 {
|
||||||
|
guard let value = arguments[2] as? Bool else {
|
||||||
|
throw TemplateSyntaxError("'indent' filter indentFirst argument must be a Bool")
|
||||||
|
}
|
||||||
|
indentFirst = value
|
||||||
|
}
|
||||||
|
|
||||||
|
let indentation = [String](repeating: indentationChar, count: indentWidth).joined(separator: "")
|
||||||
|
return indent(stringify(value), indentation: indentation, indentFirst: indentFirst)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func indent(_ content: String, indentation: String, indentFirst: Bool) -> String {
|
||||||
|
guard !indentation.isEmpty else { return content }
|
||||||
|
|
||||||
|
var lines = content.components(separatedBy: .newlines)
|
||||||
|
let firstLine = (indentFirst ? indentation : "") + lines.removeFirst()
|
||||||
|
let result = lines.reduce([firstLine]) { (result, line) in
|
||||||
|
return result + [(line.isEmpty ? "" : "\(indentation)\(line)")]
|
||||||
|
}
|
||||||
|
return result.joined(separator: "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ public struct Variable : Equatable, Resolvable {
|
|||||||
if let number = Number(variable) {
|
if let number = Number(variable) {
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
|
// Boolean literal
|
||||||
|
if let bool = Bool(variable) {
|
||||||
|
return bool
|
||||||
|
}
|
||||||
|
|
||||||
for bit in lookup() {
|
for bit in lookup() {
|
||||||
current = normalize(current)
|
current = normalize(current)
|
||||||
|
|||||||
@@ -244,4 +244,30 @@ func testFilter() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
describe("indent filter") {
|
||||||
|
$0.it("indents content") {
|
||||||
|
let template = Template(templateString: "{{ value|indent:2 }}")
|
||||||
|
let result = try template.render(Context(dictionary: ["value": "One\nTwo"]))
|
||||||
|
try expect(result) == "One\n Two"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can indent with arbitrary character") {
|
||||||
|
let template = Template(templateString: "{{ value|indent:2,\"\t\" }}")
|
||||||
|
let result = try template.render(Context(dictionary: ["value": "One\nTwo"]))
|
||||||
|
try expect(result) == "One\n\t\tTwo"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can indent first line") {
|
||||||
|
let template = Template(templateString: "{{ value|indent:2,\" \",true }}")
|
||||||
|
let result = try template.render(Context(dictionary: ["value": "One\nTwo"]))
|
||||||
|
try expect(result) == " One\n Two"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("does not indent empty lines") {
|
||||||
|
let template = Template(templateString: "{{ value|indent }}")
|
||||||
|
let result = try template.render(Context(dictionary: ["value": "One\n\n\nTwo\n\n"]))
|
||||||
|
try expect(result) == "One\n\n\n Two\n\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,14 @@ func testFilterTag() {
|
|||||||
try expect(try template.render()).toThrow()
|
try expect(try template.render()).toThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$0.it("can render filters with arguments") {
|
||||||
|
let ext = Extension()
|
||||||
|
ext.registerFilter("split", filter: {
|
||||||
|
return ($0 as! String).components(separatedBy: $1[0] as! String)
|
||||||
|
})
|
||||||
|
let env = Environment(extensions: [ext])
|
||||||
|
let result = try env.renderTemplate(string: "{% filter split:\",\"|join:\";\" %}{{ items|join:\",\" }}{% endfilter %}", context: ["items": [1, 2]])
|
||||||
|
try expect(result) == "1;2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ func testVariable() {
|
|||||||
try expect(result) == 3.14
|
try expect(result) == 3.14
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$0.it("can resolve boolean literal") {
|
||||||
|
try expect(Variable("true").resolve(context) as? Bool) == true
|
||||||
|
try expect(Variable("false").resolve(context) as? Bool) == false
|
||||||
|
try expect(Variable("0").resolve(context) as? Int) == 0
|
||||||
|
try expect(Variable("1").resolve(context) as? Int) == 1
|
||||||
|
}
|
||||||
|
|
||||||
$0.it("can resolve a string variable") {
|
$0.it("can resolve a string variable") {
|
||||||
let variable = Variable("name")
|
let variable = Variable("name")
|
||||||
let result = try variable.resolve(context) as? String
|
let result = try variable.resolve(context) as? String
|
||||||
|
|||||||
Reference in New Issue
Block a user