├── .gitignore
├── StringTemplate.xcodeproj
├── xcshareddata
│ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── StringTemplate-Package.xcscheme
├── StringTemplate_Info.plist
├── StringTemplateTests_Info.plist
└── project.pbxproj
├── Contributing.md
├── Package.swift
├── StringTemplate.podspec
├── Sources
├── CharacterSet+Character.swift
├── String+CharacterSet.swift
└── String+Template.swift
├── README.md
├── Tests
└── StringTemplateTests.swift
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 |
5 |
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | *.xcworkspace
15 | !default.xcworkspace
16 | xcuserdata
17 | profile
18 |
19 | /Carthage
20 |
--------------------------------------------------------------------------------
/StringTemplate.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SchemeUserState
5 |
6 | StringTemplate-Package.xcscheme
7 |
8 |
9 | SuppressBuildableAutocreation
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Contributing.md:
--------------------------------------------------------------------------------
1 | ### Sign the CLA
2 |
3 | All contributors to your PR must sign our [Individual Contributor License
4 | Agreement (CLA)][CLA]. The CLA is a short form that ensures that you are
5 | eligible to contribute.
6 |
7 | [CLA]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
8 |
9 | ### Tests
10 |
11 | We require that any new features or bug fixes also include unit tests to cover
12 | the changes.
13 |
--------------------------------------------------------------------------------
/StringTemplate.xcodeproj/StringTemplate_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | FMWK
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "StringTemplate",
8 | platforms: [
9 | .iOS(.v11),
10 | .macOS(.v10_13),
11 | .tvOS(.v11),
12 | .watchOS(.v4),
13 | ],
14 | products: [
15 | .library(
16 | name: "StringTemplate",
17 | targets: ["StringTemplate"]
18 | ),
19 | ],
20 | targets: [
21 | .target(
22 | name: "StringTemplate",
23 | dependencies: [],
24 | path: "Sources"
25 | ),
26 | .testTarget(
27 | name: "StringTemplateTests",
28 | dependencies: ["StringTemplate"],
29 | path: "Tests"
30 | ),
31 | ]
32 | )
33 |
--------------------------------------------------------------------------------
/StringTemplate.xcodeproj/StringTemplateTests_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | BNDL
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/StringTemplate.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'StringTemplate'
3 | spec.version = '2.2.0'
4 | spec.license = 'Apache License, Version 2.0'
5 | spec.homepage = 'https://github.com/square/StringTemplate'
6 | spec.authors = 'Square'
7 | spec.summary = 'String templating for Swift made easy.'
8 | spec.source = { :git => 'https://github.com/square/StringTemplate.git', :tag => "v#{spec.version}" }
9 | spec.source_files = 'Sources/*.swift'
10 | spec.swift_versions = ['4.0', '5.0']
11 |
12 | spec.requires_arc = true
13 | spec.compiler_flags = '-whole-module-optimization'
14 |
15 | spec.ios.deployment_target = '11.0'
16 | spec.osx.deployment_target = '10.13'
17 | spec.watchos.deployment_target = '4.0'
18 | spec.tvos.deployment_target = '11.0'
19 |
20 | spec.pod_target_xcconfig = {
21 | 'APPLICATION_EXTENSION_API_ONLY' => 'YES',
22 | }
23 | end
24 |
--------------------------------------------------------------------------------
/Sources/CharacterSet+Character.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2018 Square, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | extension CharacterSet {
20 | /**
21 | Create a `CharacterSet` from a single character
22 | */
23 | init(character: Character) {
24 | self.init(charactersIn: String(character))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/String+CharacterSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2018 Square, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | extension String {
20 | /**
21 | Remove the characters in the provided `CharacterSet` from `self`.
22 |
23 | - parameter characterSet: The `CharacterSet` containing the characters
24 | that should be removed from `self`.
25 | */
26 | mutating func removeCharacters(in characterSet: CharacterSet) {
27 | var nextSearchRange = range(of: self)
28 |
29 | while let searchRange = nextSearchRange, !searchRange.isEmpty {
30 | guard var characterRange = rangeOfCharacter(from: characterSet, options: .literal, range: searchRange) else {
31 | break
32 | }
33 |
34 | // Make sure not to break up composed character sequences when removing content.
35 | characterRange = rangeOfComposedCharacterSequences(for: characterRange)
36 | removeSubrange(characterRange)
37 |
38 | nextSearchRange = characterRange.lowerBound ..< endIndex
39 | }
40 | }
41 |
42 | /**
43 | Remove the characters in the provided `CharacterSet` from the callee, returning a new instance.
44 |
45 | This is an immutable variant of `removeCharacters(in:)`
46 |
47 | - parameter characterSet: The `CharacterSet` containing the characters
48 | that should be removed from the new string.
49 | - returns: A copy of `self` with the specified characters removed
50 | */
51 | func removingCharacters(in characterSet: CharacterSet) -> String {
52 | var copy = self
53 | copy.removeCharacters(in: characterSet)
54 | return copy
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/StringTemplate.xcodeproj/xcshareddata/xcschemes/StringTemplate-Package.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # StringTemplate
2 |
3 | Quickly and easily apply a template to a target string.
4 |
5 | This library allows you to create light-weight templates and then arbitrarily
6 | apply them to string instances. You can also pass options that will let you
7 | customize the strictness with which a template is applied.
8 |
9 | ## Usage
10 |
11 | ```swift
12 | // Create a template:
13 | let nanpPhoneNumber = String.Template(
14 | placeholderToken: "X",
15 | template: "(XXX) XXX-XXXX"
16 | )
17 |
18 | // And apply it:
19 | let formatted = try? "5125550001".applying(template: nanpPhoneNumber)
20 | print(formatted) // Optional("(512) 555-0001")
21 |
22 | // Allow for partial application:
23 | let partial = try? "512555".applying(template: nanpPhoneNumber, options: [.allowPartial])
24 | print(partial) // Optional("(512) 555-")
25 |
26 | // Allow for overflow application:
27 | let overflow = try? "5125550001111111111".applying(template: nanpPhoneNumber, options: [.allowOverflow])
28 | print(overflow) // Optional("(512) 555-0001")
29 |
30 | // Mutate the string directly:
31 | var str = "5125550001"
32 | try? str.apply(template: nanpPhoneNumber)
33 | print(str) // "(512) 555-0001"
34 | ```
35 |
36 | See [the tests] for more examples.
37 |
38 | [the tests]: Tests/StringTemplateTests.swift
39 |
40 | ## Installation
41 |
42 | ### [Swift Package Manager]
43 |
44 | [Swift Package Manager]: https://swift.org/package-manager/
45 |
46 | Add this project as a dependency in your `Package.swift` file:
47 |
48 | ```swift
49 | dependencies: [
50 | .package(url: "https://github.com/square/StringTemplate.git", .from("1.0.0")),
51 | ]
52 | ```
53 |
54 | ### [Carthage]
55 |
56 | [Carthage]: https://github.com/Carthage/Carthage
57 |
58 | Add the following to your Cartfile:
59 |
60 | ```
61 | github "square/StringTemplate"
62 | ```
63 |
64 | Then run `carthage update`.
65 |
66 | Follow the current instructions in [Carthage's README][carthage-installation]
67 | for up to date installation instructions.
68 |
69 | [carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
70 |
71 | ### [CocoaPods]
72 |
73 | [CocoaPods]: http://cocoapods.org
74 |
75 | Add the following to your [Podfile](http://guides.cocoapods.org/using/the-podfile.html):
76 |
77 | ```ruby
78 | pod 'StringTemplate'
79 | ```
80 |
81 | You will also need to make sure you're opting into using frameworks:
82 |
83 | ```ruby
84 | use_frameworks!
85 | ```
86 |
87 | Then run `pod install` with CocoaPods 0.36 or newer.
88 |
89 | ### Git Submodules
90 |
91 | I guess you could do it this way if that's your thing.
92 |
93 | Add this repo as a submodule, and add the project file to your workspace. You
94 | can then link against `StringTemplate.framework` for your application target.
95 |
96 | [Runes]: https://github.com/thoughtbot/Runes
97 |
98 | ## Contributing
99 |
100 | We love our
101 | [contributors](https://github.com/square/StringTemplate/graphs/contributors)!
102 | Please read our [contributing guidelines](Contributing.md) prior to submitting
103 | a pull request.
104 |
105 | License
106 | -------
107 |
108 | Copyright 2017 Square, Inc.
109 |
110 | Licensed under the Apache License, Version 2.0 (the "License");
111 | you may not use this file except in compliance with the License.
112 | You may obtain a copy of the License at
113 |
114 | http://www.apache.org/licenses/LICENSE-2.0
115 |
116 | Unless required by applicable law or agreed to in writing, software
117 | distributed under the License is distributed on an "AS IS" BASIS,
118 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
119 | See the License for the specific language governing permissions and
120 | limitations under the License.
121 |
--------------------------------------------------------------------------------
/Tests/StringTemplateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2018 Square, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import StringTemplate
18 | import XCTest
19 |
20 | final class StringTemplateTests: XCTestCase {
21 | func testSuccessfulTemplateApplication() {
22 | let phone = String.Template(placeholderToken: "&", template: "(&&&) &&&-&&&&")
23 | let template = String.Template(placeholderToken: "%", template: "%% %%% (%%)*(%%)")
24 |
25 | XCTAssertEqual(try? "5555555555".applying(template: phone), "(555) 555-5555")
26 | XCTAssertEqual(try? "1234567890".applying(template: phone), "(123) 456-7890")
27 | XCTAssertEqual(try? "123456789".applying(template: template), "12 345 (67)*(89)")
28 | XCTAssertEqual(try? "000000000".applying(template: template), "00 000 (00)*(00)")
29 | }
30 |
31 | func testSuccessfulPartialTemplateApplication() {
32 | let phone = String.Template(placeholderToken: "&", template: "(&&&) &&&-&&&&")
33 | let template = String.Template(placeholderToken: "%", template: "%% %%% (%%)*(%%)")
34 |
35 | XCTAssertEqual(try? "5555555555".applying(template: phone, options: [.allowPartial]), "(555) 555-5555")
36 | XCTAssertEqual(try? "5555555".applying(template: phone, options: [.allowPartial]), "(555) 555-5")
37 | XCTAssertEqual(try? "123456".applying(template: phone, options: [.allowPartial]), "(123) 456-")
38 | XCTAssertEqual(try? "12345".applying(template: template, options: [.allowPartial]), "12 345 (")
39 | XCTAssertEqual(try? "0000000".applying(template: template, options: [.allowPartial]), "00 000 (00)*(")
40 | }
41 |
42 | func testSuccessfulOverflowTemplateApplication() {
43 | let phone = String.Template(placeholderToken: "&", template: "(&&&) &&&-&&&&")
44 | let template = String.Template(placeholderToken: "%", template: "%% %%% (%%)*(%%)")
45 |
46 | XCTAssertEqual(try? "5555555555555".applying(template: phone, options: [.allowOverflow]), "(555) 555-5555")
47 | XCTAssertEqual(try? "123456789000".applying(template: phone, options: [.allowOverflow]), "(123) 456-7890")
48 | XCTAssertEqual(try? "1234567890000".applying(template: template, options: [.allowOverflow]), "12 345 (67)*(89)")
49 | XCTAssertEqual(try? "00000000000000".applying(template: template, options: [.allowOverflow]), "00 000 (00)*(00)")
50 | }
51 |
52 | func testUnsuccessfulTemplateApplication() {
53 | let template = String.Template(placeholderToken: "X", template: "XXXX")
54 |
55 | assert(try "123".applying(template: template), throws: String.Template.Error.tooShort)
56 | assert(try "12345".applying(template: template), throws: String.Template.Error.tooLong)
57 | }
58 |
59 | func testUnsuccessfulPartialTemplateApplication() {
60 | let template = String.Template(placeholderToken: "X", template: "XXXX")
61 |
62 | XCTAssertEqual(try? "123".applying(template: template, options: [.allowPartial]), "123")
63 | assert(try "12345".applying(template: template, options: [.allowPartial]), throws: String.Template.Error.tooLong)
64 | }
65 |
66 | func testUnsuccessfulOverflowTemplateApplication() {
67 | let template = String.Template(placeholderToken: "X", template: "XXXX")
68 |
69 | XCTAssertEqual(try? "12345".applying(template: template, options: [.allowOverflow]), "1234")
70 | assert(try "123".applying(template: template, options: [.allowOverflow]), throws: String.Template.Error.tooShort)
71 | }
72 |
73 | func testPreservedCharacters() {
74 | let template = String.Template(placeholderToken: "X", template: "0XXX0", preservedCharacters: .decimalDigits)
75 |
76 | XCTAssertEqual(try? "103".applying(template: template), "01030")
77 | }
78 | }
79 |
80 | // Assert that a throwing function throws a specific error
81 | func assert(_ function: @autoclosure () throws -> T, throws expected: E, file: StaticString = #file, line: UInt = #line) where E: Error & Equatable {
82 | do {
83 | _ = try function()
84 | XCTFail("Expected an error to be thrown", file: file, line: line)
85 | } catch let error as E {
86 | XCTAssertEqual(error, expected, file: file, line: line)
87 | } catch {
88 | XCTFail("Incorrect error type was thrown: \(error)", file: file, line: line)
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/String+Template.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2018 Square, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | import Foundation
18 |
19 | // MARK: -
20 |
21 | extension String {
22 |
23 | // MARK: -
24 |
25 | /**
26 | An opaque reference to a template that can be applied to a `String` instance.
27 |
28 | The internals for this type are intentionally hidden, and shouldn't be a
29 | concern of the caller. You should instead use `String.apply(template:)` (or
30 | one of the variants) in order to use instances of this type.
31 | */
32 | public struct Template {
33 |
34 | // MARK: -
35 |
36 | public enum Error: Swift.Error {
37 | case tooLong
38 | case tooShort
39 | }
40 |
41 | // MARK: -
42 |
43 | /**
44 | Options for how to apply the template
45 | */
46 | public struct Options: OptionSet {
47 | public let rawValue: Int
48 |
49 | public init(rawValue: Int) {
50 | self.rawValue = rawValue
51 | }
52 |
53 | /**
54 | Allow partial application. If this is set, the template will only
55 | be applied for the available characters in the target string, and
56 | the remaining template placeholder characters will be dropped. Any
57 | formatting characters that extend beyond the length of the target
58 | string will still be added to the result.
59 |
60 | ```swift
61 | let template = String.Template(placeholderToken: "X", template: "XXX-XXX")
62 | let string = "123".applying(template: template, options: [.allowPartial])
63 | // string == "123-"
64 | ```
65 | */
66 | public static let allowPartial = Options(rawValue: 1)
67 |
68 | /**
69 | Allow overflow application. If this is set, any characters in the
70 | target string that extend beyond the template will be discarded.
71 |
72 | ```swift
73 | let template = String.Template(placeholderToken: "X", template: "XXX-XXX")
74 | let string = "12345678".applying(template: template, options: [.allowOverflow])
75 | // string == "123-456"
76 | ```
77 | */
78 | public static let allowOverflow = Options(rawValue: 2)
79 | }
80 |
81 | // MARK: - Public Properties
82 |
83 | public let formattingCharacterSet: CharacterSet
84 | public let placeholderToken: Character
85 | public let template: String
86 |
87 | // MARK: - Private Properties
88 |
89 | fileprivate let length: Int
90 |
91 | // MARK: - Life Cycle
92 |
93 | /**
94 | Construct a new `Template`.
95 |
96 | The template will be created from the provided `placeholderToken` and
97 | `template` string. The `placeholderToken` should correspond to the
98 | character used in the template to denote the characters that should be
99 | replaced.
100 |
101 | If you have formatting characters in your template string that might
102 | also appear in your target string, you can use the optional
103 | `preservedCharacters` parameter to mark those characters as needing to
104 | be preserved so that they aren't stripped from the target during
105 | template application.
106 |
107 | For example:
108 |
109 | ```swift
110 | let template = String.Template(placeholderToken: "X", template: "0XX0")
111 | let string = try? "00".applying(template: template)
112 | // string == nil, because the character `0` is treated as a formatting
113 | // character, and so was stripped from the target string during
114 | // application.
115 |
116 | let fixedTemplate = String.Template(placeholderToken: "X", template: "0XX0", preservedCharacters: .decimalDigits)
117 | let fixedString = try? "00".applying(template: fixedTemplate)
118 | // string == "0000", because we explicitly marked decimal digits as
119 | // being preserved characters that should not be stripped from the
120 | // source.
121 | ```
122 |
123 | - parameter placeholderToken: The token used in the template string to
124 | indicate where characters should be replaced.
125 | - parameter template: The template string to use. This string should
126 | represent a specific format and should use the `placeholderToken` to mark
127 | where character replacements will happen.
128 | - parameter preservedCharacters: A character set representing
129 | characters that should be treated as formatting characters, but should
130 | _not_ be stripped from the target string. Defaults to `nil`.
131 | */
132 | public init(placeholderToken: Character, template: String, preservedCharacters: CharacterSet? = nil) {
133 | self.placeholderToken = placeholderToken
134 | self.template = template
135 |
136 | let placeholderCharacters = CharacterSet(character: placeholderToken)
137 | let formatting = template.removingCharacters(in: placeholderCharacters)
138 |
139 | var formattingCharacterSet = CharacterSet(charactersIn: formatting)
140 |
141 | self.length = template.removingCharacters(in: formattingCharacterSet).count
142 |
143 | if let preservedCharacters = preservedCharacters {
144 | formattingCharacterSet.subtract(preservedCharacters)
145 | }
146 |
147 | self.formattingCharacterSet = formattingCharacterSet
148 | }
149 | }
150 |
151 |
152 | // MARK: - Public Methods
153 |
154 | /**
155 | Apply a template to `self` with the provided options. This method mutates
156 | the callee.
157 |
158 | You can use the `options` parameter to conditionally allow partial or
159 | overflow behavior for the template application. This property defaults to
160 | an empty set of options, which will enforce an exact match between the
161 | length of the template and the length of the target.
162 |
163 | See `Template.Options` for more information.
164 |
165 | - parameter template: The `Template` instance to apply to `self`
166 | - parameter options: The `Template.Options` to use when applying the
167 | template. This defaults to `[]`, which results in enforcing an exact match
168 | between the template length and the target string length.
169 | - throws: String.Template.Error if the template application fails, usually
170 | because of a length mismatch.
171 | */
172 | public mutating func apply(template: Template, options: Template.Options = []) throws {
173 | removeCharacters(in: template.formattingCharacterSet)
174 |
175 | try validate(length: template.length, options: options)
176 |
177 | var formatted = template.template
178 | var currentIndex = startIndex;
179 | var formatStringIndex = formatted.firstIndex(of: template.placeholderToken)
180 |
181 | while let placeholderIndex = formatStringIndex, currentIndex < endIndex {
182 | let characterToInsert = String(self[currentIndex])
183 | formatted = formatted.replacingCharacters(in: placeholderIndex...placeholderIndex, with: characterToInsert)
184 |
185 | // Increment our indices
186 | currentIndex = index(currentIndex, offsetBy: 1)
187 | formatStringIndex = formatted[placeholderIndex...].firstIndex(of: template.placeholderToken)
188 | }
189 |
190 | // Only use the part of the string we formatted, defaulting to the whole string if we completed formatting
191 | let end = formatStringIndex ?? formatted.endIndex
192 | self = String(formatted[.. String {
216 | var copy = self
217 | try copy.apply(template: template, options: options)
218 | return copy
219 | }
220 |
221 | // MARK: - Private Methods
222 |
223 | private func validate(length: Int, options: Template.Options) throws {
224 | if !options.contains(.allowOverflow) {
225 | try validateMaxLength(length)
226 | }
227 |
228 | if !options.contains(.allowPartial) {
229 | try validateMinLength(length)
230 | }
231 | }
232 |
233 | private func validateMinLength(_ length: Int) throws {
234 | if count < length {
235 | throw String.Template.Error.tooShort
236 | }
237 | }
238 |
239 | private func validateMaxLength(_ length: Int) throws {
240 | if count > length {
241 | throw String.Template.Error.tooLong
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/StringTemplate.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXAggregateTarget section */
10 | "StringTemplate::StringTemplatePackageTests::ProductTarget" /* StringTemplatePackageTests */ = {
11 | isa = PBXAggregateTarget;
12 | buildConfigurationList = OBJ_32 /* Build configuration list for PBXAggregateTarget "StringTemplatePackageTests" */;
13 | buildPhases = (
14 | );
15 | dependencies = (
16 | OBJ_35 /* PBXTargetDependency */,
17 | );
18 | name = StringTemplatePackageTests;
19 | productName = StringTemplatePackageTests;
20 | };
21 | /* End PBXAggregateTarget section */
22 |
23 | /* Begin PBXBuildFile section */
24 | OBJ_21 /* CharacterSet+Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_8 /* CharacterSet+Character.swift */; };
25 | OBJ_22 /* String+CharacterSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* String+CharacterSet.swift */; };
26 | OBJ_23 /* String+Template.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* String+Template.swift */; };
27 | OBJ_30 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
28 | OBJ_41 /* StringTemplateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* StringTemplateTests.swift */; };
29 | OBJ_43 /* StringTemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "StringTemplate::StringTemplate::Product" /* StringTemplate.framework */; };
30 | /* End PBXBuildFile section */
31 |
32 | /* Begin PBXContainerItemProxy section */
33 | 38FC52B120B734A300CBFDC5 /* PBXContainerItemProxy */ = {
34 | isa = PBXContainerItemProxy;
35 | containerPortal = OBJ_1 /* Project object */;
36 | proxyType = 1;
37 | remoteGlobalIDString = "StringTemplate::StringTemplate";
38 | remoteInfo = StringTemplate;
39 | };
40 | 38FC52B220B734A300CBFDC5 /* PBXContainerItemProxy */ = {
41 | isa = PBXContainerItemProxy;
42 | containerPortal = OBJ_1 /* Project object */;
43 | proxyType = 1;
44 | remoteGlobalIDString = "StringTemplate::StringTemplateTests";
45 | remoteInfo = StringTemplateTests;
46 | };
47 | /* End PBXContainerItemProxy section */
48 |
49 | /* Begin PBXFileReference section */
50 | OBJ_10 /* String+Template.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Template.swift"; sourceTree = ""; };
51 | OBJ_12 /* StringTemplateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTemplateTests.swift; sourceTree = ""; };
52 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
53 | OBJ_8 /* CharacterSet+Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CharacterSet+Character.swift"; sourceTree = ""; };
54 | OBJ_9 /* String+CharacterSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+CharacterSet.swift"; sourceTree = ""; };
55 | "StringTemplate::StringTemplate::Product" /* StringTemplate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StringTemplate.framework; sourceTree = BUILT_PRODUCTS_DIR; };
56 | "StringTemplate::StringTemplateTests::Product" /* StringTemplateTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = StringTemplateTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
57 | /* End PBXFileReference section */
58 |
59 | /* Begin PBXFrameworksBuildPhase section */
60 | OBJ_24 /* Frameworks */ = {
61 | isa = PBXFrameworksBuildPhase;
62 | buildActionMask = 0;
63 | files = (
64 | );
65 | runOnlyForDeploymentPostprocessing = 0;
66 | };
67 | OBJ_42 /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 0;
70 | files = (
71 | OBJ_43 /* StringTemplate.framework in Frameworks */,
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | OBJ_11 /* Tests */ = {
79 | isa = PBXGroup;
80 | children = (
81 | OBJ_12 /* StringTemplateTests.swift */,
82 | );
83 | path = Tests;
84 | sourceTree = SOURCE_ROOT;
85 | };
86 | OBJ_13 /* Products */ = {
87 | isa = PBXGroup;
88 | children = (
89 | "StringTemplate::StringTemplateTests::Product" /* StringTemplateTests.xctest */,
90 | "StringTemplate::StringTemplate::Product" /* StringTemplate.framework */,
91 | );
92 | name = Products;
93 | sourceTree = BUILT_PRODUCTS_DIR;
94 | };
95 | OBJ_5 = {
96 | isa = PBXGroup;
97 | children = (
98 | OBJ_6 /* Package.swift */,
99 | OBJ_7 /* Sources */,
100 | OBJ_11 /* Tests */,
101 | OBJ_13 /* Products */,
102 | );
103 | sourceTree = "";
104 | };
105 | OBJ_7 /* Sources */ = {
106 | isa = PBXGroup;
107 | children = (
108 | OBJ_8 /* CharacterSet+Character.swift */,
109 | OBJ_9 /* String+CharacterSet.swift */,
110 | OBJ_10 /* String+Template.swift */,
111 | );
112 | path = Sources;
113 | sourceTree = SOURCE_ROOT;
114 | };
115 | /* End PBXGroup section */
116 |
117 | /* Begin PBXNativeTarget section */
118 | "StringTemplate::StringTemplate" /* StringTemplate */ = {
119 | isa = PBXNativeTarget;
120 | buildConfigurationList = OBJ_17 /* Build configuration list for PBXNativeTarget "StringTemplate" */;
121 | buildPhases = (
122 | OBJ_20 /* Sources */,
123 | OBJ_24 /* Frameworks */,
124 | );
125 | buildRules = (
126 | );
127 | dependencies = (
128 | );
129 | name = StringTemplate;
130 | productName = StringTemplate;
131 | productReference = "StringTemplate::StringTemplate::Product" /* StringTemplate.framework */;
132 | productType = "com.apple.product-type.framework";
133 | };
134 | "StringTemplate::StringTemplateTests" /* StringTemplateTests */ = {
135 | isa = PBXNativeTarget;
136 | buildConfigurationList = OBJ_37 /* Build configuration list for PBXNativeTarget "StringTemplateTests" */;
137 | buildPhases = (
138 | OBJ_40 /* Sources */,
139 | OBJ_42 /* Frameworks */,
140 | );
141 | buildRules = (
142 | );
143 | dependencies = (
144 | OBJ_44 /* PBXTargetDependency */,
145 | );
146 | name = StringTemplateTests;
147 | productName = StringTemplateTests;
148 | productReference = "StringTemplate::StringTemplateTests::Product" /* StringTemplateTests.xctest */;
149 | productType = "com.apple.product-type.bundle.unit-test";
150 | };
151 | "StringTemplate::SwiftPMPackageDescription" /* StringTemplatePackageDescription */ = {
152 | isa = PBXNativeTarget;
153 | buildConfigurationList = OBJ_26 /* Build configuration list for PBXNativeTarget "StringTemplatePackageDescription" */;
154 | buildPhases = (
155 | OBJ_29 /* Sources */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | );
161 | name = StringTemplatePackageDescription;
162 | productName = StringTemplatePackageDescription;
163 | productType = "com.apple.product-type.framework";
164 | };
165 | /* End PBXNativeTarget section */
166 |
167 | /* Begin PBXProject section */
168 | OBJ_1 /* Project object */ = {
169 | isa = PBXProject;
170 | attributes = {
171 | LastUpgradeCheck = 9999;
172 | };
173 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "StringTemplate" */;
174 | compatibilityVersion = "Xcode 3.2";
175 | developmentRegion = English;
176 | hasScannedForEncodings = 0;
177 | knownRegions = (
178 | English,
179 | en,
180 | );
181 | mainGroup = OBJ_5;
182 | productRefGroup = OBJ_13 /* Products */;
183 | projectDirPath = "";
184 | projectRoot = "";
185 | targets = (
186 | "StringTemplate::StringTemplate" /* StringTemplate */,
187 | "StringTemplate::SwiftPMPackageDescription" /* StringTemplatePackageDescription */,
188 | "StringTemplate::StringTemplatePackageTests::ProductTarget" /* StringTemplatePackageTests */,
189 | "StringTemplate::StringTemplateTests" /* StringTemplateTests */,
190 | );
191 | };
192 | /* End PBXProject section */
193 |
194 | /* Begin PBXSourcesBuildPhase section */
195 | OBJ_20 /* Sources */ = {
196 | isa = PBXSourcesBuildPhase;
197 | buildActionMask = 0;
198 | files = (
199 | OBJ_21 /* CharacterSet+Character.swift in Sources */,
200 | OBJ_22 /* String+CharacterSet.swift in Sources */,
201 | OBJ_23 /* String+Template.swift in Sources */,
202 | );
203 | runOnlyForDeploymentPostprocessing = 0;
204 | };
205 | OBJ_29 /* Sources */ = {
206 | isa = PBXSourcesBuildPhase;
207 | buildActionMask = 0;
208 | files = (
209 | OBJ_30 /* Package.swift in Sources */,
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | };
213 | OBJ_40 /* Sources */ = {
214 | isa = PBXSourcesBuildPhase;
215 | buildActionMask = 0;
216 | files = (
217 | OBJ_41 /* StringTemplateTests.swift in Sources */,
218 | );
219 | runOnlyForDeploymentPostprocessing = 0;
220 | };
221 | /* End PBXSourcesBuildPhase section */
222 |
223 | /* Begin PBXTargetDependency section */
224 | OBJ_35 /* PBXTargetDependency */ = {
225 | isa = PBXTargetDependency;
226 | target = "StringTemplate::StringTemplateTests" /* StringTemplateTests */;
227 | targetProxy = 38FC52B220B734A300CBFDC5 /* PBXContainerItemProxy */;
228 | };
229 | OBJ_44 /* PBXTargetDependency */ = {
230 | isa = PBXTargetDependency;
231 | target = "StringTemplate::StringTemplate" /* StringTemplate */;
232 | targetProxy = 38FC52B120B734A300CBFDC5 /* PBXContainerItemProxy */;
233 | };
234 | /* End PBXTargetDependency section */
235 |
236 | /* Begin XCBuildConfiguration section */
237 | OBJ_18 /* Debug */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | ENABLE_TESTABILITY = YES;
241 | FRAMEWORK_SEARCH_PATHS = (
242 | "$(inherited)",
243 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
244 | );
245 | HEADER_SEARCH_PATHS = "$(inherited)";
246 | INFOPLIST_FILE = StringTemplate.xcodeproj/StringTemplate_Info.plist;
247 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
248 | OTHER_CFLAGS = "$(inherited)";
249 | OTHER_LDFLAGS = "$(inherited)";
250 | OTHER_SWIFT_FLAGS = "$(inherited)";
251 | PRODUCT_BUNDLE_IDENTIFIER = StringTemplate;
252 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
253 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
254 | SKIP_INSTALL = YES;
255 | SWIFT_VERSION = 4.0;
256 | TARGET_NAME = StringTemplate;
257 | };
258 | name = Debug;
259 | };
260 | OBJ_19 /* Release */ = {
261 | isa = XCBuildConfiguration;
262 | buildSettings = {
263 | ENABLE_TESTABILITY = YES;
264 | FRAMEWORK_SEARCH_PATHS = (
265 | "$(inherited)",
266 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
267 | );
268 | HEADER_SEARCH_PATHS = "$(inherited)";
269 | INFOPLIST_FILE = StringTemplate.xcodeproj/StringTemplate_Info.plist;
270 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
271 | OTHER_CFLAGS = "$(inherited)";
272 | OTHER_LDFLAGS = "$(inherited)";
273 | OTHER_SWIFT_FLAGS = "$(inherited)";
274 | PRODUCT_BUNDLE_IDENTIFIER = StringTemplate;
275 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
276 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
277 | SKIP_INSTALL = YES;
278 | SWIFT_VERSION = 4.0;
279 | TARGET_NAME = StringTemplate;
280 | };
281 | name = Release;
282 | };
283 | OBJ_27 /* Debug */ = {
284 | isa = XCBuildConfiguration;
285 | buildSettings = {
286 | LD = /usr/bin/true;
287 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-9.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk";
288 | SWIFT_VERSION = 4.0;
289 | };
290 | name = Debug;
291 | };
292 | OBJ_28 /* Release */ = {
293 | isa = XCBuildConfiguration;
294 | buildSettings = {
295 | LD = /usr/bin/true;
296 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-9.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk";
297 | SWIFT_VERSION = 4.0;
298 | };
299 | name = Release;
300 | };
301 | OBJ_3 /* Debug */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | CLANG_ENABLE_OBJC_ARC = YES;
305 | COMBINE_HIDPI_IMAGES = YES;
306 | COPY_PHASE_STRIP = NO;
307 | DEBUG_INFORMATION_FORMAT = dwarf;
308 | DYLIB_INSTALL_NAME_BASE = "@rpath";
309 | ENABLE_NS_ASSERTIONS = YES;
310 | GCC_OPTIMIZATION_LEVEL = 0;
311 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
312 | MACOSX_DEPLOYMENT_TARGET = 10.13;
313 | ONLY_ACTIVE_ARCH = YES;
314 | OTHER_SWIFT_FLAGS = "-DXcode";
315 | PRODUCT_NAME = "$(TARGET_NAME)";
316 | SDKROOT = macosx;
317 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
318 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE;
319 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
320 | TVOS_DEPLOYMENT_TARGET = 11.0;
321 | USE_HEADERMAP = NO;
322 | WATCHOS_DEPLOYMENT_TARGET = 4.0;
323 | };
324 | name = Debug;
325 | };
326 | OBJ_33 /* Debug */ = {
327 | isa = XCBuildConfiguration;
328 | buildSettings = {
329 | };
330 | name = Debug;
331 | };
332 | OBJ_34 /* Release */ = {
333 | isa = XCBuildConfiguration;
334 | buildSettings = {
335 | };
336 | name = Release;
337 | };
338 | OBJ_38 /* Debug */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
342 | FRAMEWORK_SEARCH_PATHS = (
343 | "$(inherited)",
344 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
345 | );
346 | HEADER_SEARCH_PATHS = "$(inherited)";
347 | INFOPLIST_FILE = StringTemplate.xcodeproj/StringTemplateTests_Info.plist;
348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
349 | OTHER_CFLAGS = "$(inherited)";
350 | OTHER_LDFLAGS = "$(inherited)";
351 | OTHER_SWIFT_FLAGS = "$(inherited)";
352 | SWIFT_VERSION = 4.0;
353 | TARGET_NAME = StringTemplateTests;
354 | };
355 | name = Debug;
356 | };
357 | OBJ_39 /* Release */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
361 | FRAMEWORK_SEARCH_PATHS = (
362 | "$(inherited)",
363 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
364 | );
365 | HEADER_SEARCH_PATHS = "$(inherited)";
366 | INFOPLIST_FILE = StringTemplate.xcodeproj/StringTemplateTests_Info.plist;
367 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
368 | OTHER_CFLAGS = "$(inherited)";
369 | OTHER_LDFLAGS = "$(inherited)";
370 | OTHER_SWIFT_FLAGS = "$(inherited)";
371 | SWIFT_VERSION = 4.0;
372 | TARGET_NAME = StringTemplateTests;
373 | };
374 | name = Release;
375 | };
376 | OBJ_4 /* Release */ = {
377 | isa = XCBuildConfiguration;
378 | buildSettings = {
379 | CLANG_ENABLE_OBJC_ARC = YES;
380 | COMBINE_HIDPI_IMAGES = YES;
381 | COPY_PHASE_STRIP = YES;
382 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
383 | DYLIB_INSTALL_NAME_BASE = "@rpath";
384 | GCC_OPTIMIZATION_LEVEL = s;
385 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
386 | MACOSX_DEPLOYMENT_TARGET = 10.13;
387 | OTHER_SWIFT_FLAGS = "-DXcode";
388 | PRODUCT_NAME = "$(TARGET_NAME)";
389 | SDKROOT = macosx;
390 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
391 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE;
392 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
393 | TVOS_DEPLOYMENT_TARGET = 11.0;
394 | USE_HEADERMAP = NO;
395 | WATCHOS_DEPLOYMENT_TARGET = 4.0;
396 | };
397 | name = Release;
398 | };
399 | /* End XCBuildConfiguration section */
400 |
401 | /* Begin XCConfigurationList section */
402 | OBJ_17 /* Build configuration list for PBXNativeTarget "StringTemplate" */ = {
403 | isa = XCConfigurationList;
404 | buildConfigurations = (
405 | OBJ_18 /* Debug */,
406 | OBJ_19 /* Release */,
407 | );
408 | defaultConfigurationIsVisible = 0;
409 | defaultConfigurationName = Release;
410 | };
411 | OBJ_2 /* Build configuration list for PBXProject "StringTemplate" */ = {
412 | isa = XCConfigurationList;
413 | buildConfigurations = (
414 | OBJ_3 /* Debug */,
415 | OBJ_4 /* Release */,
416 | );
417 | defaultConfigurationIsVisible = 0;
418 | defaultConfigurationName = Release;
419 | };
420 | OBJ_26 /* Build configuration list for PBXNativeTarget "StringTemplatePackageDescription" */ = {
421 | isa = XCConfigurationList;
422 | buildConfigurations = (
423 | OBJ_27 /* Debug */,
424 | OBJ_28 /* Release */,
425 | );
426 | defaultConfigurationIsVisible = 0;
427 | defaultConfigurationName = Release;
428 | };
429 | OBJ_32 /* Build configuration list for PBXAggregateTarget "StringTemplatePackageTests" */ = {
430 | isa = XCConfigurationList;
431 | buildConfigurations = (
432 | OBJ_33 /* Debug */,
433 | OBJ_34 /* Release */,
434 | );
435 | defaultConfigurationIsVisible = 0;
436 | defaultConfigurationName = Release;
437 | };
438 | OBJ_37 /* Build configuration list for PBXNativeTarget "StringTemplateTests" */ = {
439 | isa = XCConfigurationList;
440 | buildConfigurations = (
441 | OBJ_38 /* Debug */,
442 | OBJ_39 /* Release */,
443 | );
444 | defaultConfigurationIsVisible = 0;
445 | defaultConfigurationName = Release;
446 | };
447 | /* End XCConfigurationList section */
448 | };
449 | rootObject = OBJ_1 /* Project object */;
450 | }
451 |
--------------------------------------------------------------------------------