Skip to content

Commit 869dc45

Browse files
committed
introduce as the primary API for , deprecating . Update tests to reflect new function names and ensure backward compatibility
1 parent 15c7102 commit 869dc45

4 files changed

Lines changed: 82 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.5.0] - 2026-03-31
6+
7+
- **`getVariantMetadataTags`** is the canonical API for `data-csvariants`; **`getDataCsvariantsAttribute`** is deprecated (delegates to it until removed in a major release).
8+
59
## [1.4.0] - 2026-03-30
610

711
### Enhancement

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Add the following to your Podfile:
4141
let package = Package(
4242
name: "YourProject",
4343
dependencies: [
44-
.package(url: "https://github.com/tid-kijyun/ContentstackUtils.git", from: "1.3.1"),
44+
.package(url: "https://github.com/tid-kijyun/ContentstackUtils.git", from: "1.5.0"),
4545
],
4646
targets: [
4747
.target(
@@ -257,3 +257,7 @@ graphQLClient.fetch (query: ProductsQuery(), cachePolicy: CachePolicy.fetchIgnor
257257
}
258258
```
259259
260+
### Variant metadata (`data-csvariants`)
261+
262+
To build the JSON string for the `data-csvariants` HTML attribute from Delivery API entry JSON, use **`ContentstackUtils.getVariantMetadataTags`**. See [Docs/variant-metadata-api.md](Docs/variant-metadata-api.md) for parameters, return values, and migration from the deprecated `getDataCsvariantsAttribute` APIs.
263+

Sources/ContentstackUtils/ContentstackUtils.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,34 @@ public struct ContentstackUtils {
115115
}
116116
}
117117

118-
public static func getDataCsvariantsAttribute(entry: [String: Any]?, contentTypeUid: String) throws -> [String: Any]{
118+
/// Builds the `data-csvariants` HTML attribute payload from one entry (or `nil` → empty JSON array string).
119+
public static func getVariantMetadataTags(entry: [String: Any]?, contentTypeUid: String) throws -> [String: Any] {
119120
guard let e = entry else {
120121
return ["data-csvariants": "[]"]
121122
}
122-
123123
let payload = try getVariantAliases(entry: e, contentTypeUid: contentTypeUid)
124124
let s = try jsonString(for: [payload])
125125
return ["data-csvariants": s]
126-
127126
}
128127

129-
public static func getDataCsvariantsAttribute(entries: [[String: Any]], contentTypeUid: String) throws -> [String: Any]{
128+
/// Builds the `data-csvariants` HTML attribute payload for multiple entries (empty input → `"[]"`).
129+
public static func getVariantMetadataTags(entries: [[String: Any]], contentTypeUid: String) throws -> [String: Any] {
130130
try validateContentTypeUid(contentTypeUid)
131131
let payloads = try getVariantAliases(entries: entries, contentTypeUid: contentTypeUid)
132132
let s = try jsonString(for: payloads)
133133
return ["data-csvariants": s]
134134
}
135135

136+
@available(*, deprecated, message: "Use getVariantMetadataTags(entry:contentTypeUid:). Will be removed in a future major release.")
137+
public static func getDataCsvariantsAttribute(entry: [String: Any]?, contentTypeUid: String) throws -> [String: Any] {
138+
try getVariantMetadataTags(entry: entry, contentTypeUid: contentTypeUid)
139+
}
140+
141+
@available(*, deprecated, message: "Use getVariantMetadataTags(entries:contentTypeUid:). Will be removed in a future major release.")
142+
public static func getDataCsvariantsAttribute(entries: [[String: Any]], contentTypeUid: String) throws -> [String: Any] {
143+
try getVariantMetadataTags(entries: entries, contentTypeUid: contentTypeUid)
144+
}
145+
136146

137147
private static func validateContentTypeUid(_ contentTypeUid: String) throws {
138148
if contentTypeUid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {

Tests/ContentstackUtilsTests/VariantUtilityTests.swift

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ final class VariantUtilityTests: XCTestCase {
2121
return arr.compactMap { $0 as? [String: Any] }
2222
}
2323

24+
/// JSON string equality is unstable (key order); compare payload semantics.
25+
private func assertSemanticEqualDataCsvariantsPayload(_ a: [String: Any], _ b: [String: Any], file: StaticString = #file, line: UInt = #line) throws {
26+
let sa = try XCTUnwrap(a["data-csvariants"] as? String, file: file, line: line)
27+
let sb = try XCTUnwrap(b["data-csvariants"] as? String, file: file, line: line)
28+
let aArr = try JSONSerialization.jsonObject(with: Data(sa.utf8)) as! [Any]
29+
let bArr = try JSONSerialization.jsonObject(with: Data(sb.utf8)) as! [Any]
30+
XCTAssertEqual(aArr.count, bArr.count, file: file, line: line)
31+
for i in 0..<aArr.count {
32+
guard let da = aArr[i] as? [String: Any], let db = bArr[i] as? [String: Any] else {
33+
XCTFail("Expected object at index \(i)", file: file, line: line)
34+
return
35+
}
36+
XCTAssertEqual(da["entry_uid"] as? String, db["entry_uid"] as? String, file: file, line: line)
37+
XCTAssertEqual(da["contenttype_uid"] as? String, db["contenttype_uid"] as? String, file: file, line: line)
38+
let va = Set(da["variants"] as? [String] ?? [])
39+
let vb = Set(db["variants"] as? [String] ?? [])
40+
XCTAssertEqual(va, vb, file: file, line: line)
41+
}
42+
}
43+
2444
func testGetVariantAliasesSingleEntry() throws {
2545
let root = try TestDecodable.loadJSONObject(named: "variantsSingleEntry")
2646
let entry = try XCTUnwrap(root["entry"] as? [String: Any])
@@ -31,10 +51,10 @@ final class VariantUtilityTests: XCTestCase {
3151
XCTAssertEqual(stringSet(from: result["variants"]), ["cs_personalize_0_0", "cs_personalize_0_3"])
3252
}
3353

34-
func testGetDataCsvariantsAttributeSingleEntry() throws {
54+
func testGetVariantMetadataTagsSingleEntry() throws {
3555
let root = try TestDecodable.loadJSONObject(named: "variantsSingleEntry")
3656
let entry = try XCTUnwrap(root["entry"] as? [String: Any])
37-
let wrapper = try ContentstackUtils.getDataCsvariantsAttribute(entry: entry, contentTypeUid: contentTypeUid)
57+
let wrapper = try ContentstackUtils.getVariantMetadataTags(entry: entry, contentTypeUid: contentTypeUid)
3858

3959
let parsed = try parseDataCsvariantsArray(wrapper)
4060
XCTAssertEqual(parsed.count, 1)
@@ -66,10 +86,10 @@ final class VariantUtilityTests: XCTestCase {
6686
XCTAssertEqual((third["variants"] as? [String])?.count, 0)
6787
}
6888

69-
func testGetDataCsvariantsAttributeMultipleEntries() throws {
89+
func testGetVariantMetadataTagsMultipleEntries() throws {
7090
let root = try TestDecodable.loadJSONObject(named: "variantsEntries")
7191
let entries = try XCTUnwrap(root["entries"] as? [[String: Any]])
72-
let wrapper = try ContentstackUtils.getDataCsvariantsAttribute(entries: entries, contentTypeUid: contentTypeUid)
92+
let wrapper = try ContentstackUtils.getVariantMetadataTags(entries: entries, contentTypeUid: contentTypeUid)
7393

7494
let parsed = try parseDataCsvariantsArray(wrapper)
7595
XCTAssertEqual(parsed.count, 3)
@@ -102,11 +122,31 @@ final class VariantUtilityTests: XCTestCase {
102122
}
103123
}
104124

105-
func testGetDataCsvariantsAttributeWhenEntryNil() throws {
106-
let result = try ContentstackUtils.getDataCsvariantsAttribute(entry: nil, contentTypeUid: "landing_page")
125+
func testGetVariantMetadataTagsWhenEntryNil() throws {
126+
let result = try ContentstackUtils.getVariantMetadataTags(entry: nil, contentTypeUid: "landing_page")
107127
XCTAssertEqual(result["data-csvariants"] as? String, "[]")
108128
}
109129

130+
/// Deprecated `getDataCsvariantsAttribute` must match canonical `getVariantMetadataTags` until removal.
131+
func testDeprecatedGetDataCsvariantsAttributeDelegatesToGetVariantMetadataTags() throws {
132+
let root = try TestDecodable.loadJSONObject(named: "variantsSingleEntry")
133+
let entry = try XCTUnwrap(root["entry"] as? [String: Any])
134+
135+
let canonical = try ContentstackUtils.getVariantMetadataTags(entry: entry, contentTypeUid: contentTypeUid)
136+
let deprecated = try ContentstackUtils.getDataCsvariantsAttribute(entry: entry, contentTypeUid: contentTypeUid)
137+
try assertSemanticEqualDataCsvariantsPayload(canonical, deprecated)
138+
139+
let multiRoot = try TestDecodable.loadJSONObject(named: "variantsEntries")
140+
let entries = try XCTUnwrap(multiRoot["entries"] as? [[String: Any]])
141+
let canonicalMany = try ContentstackUtils.getVariantMetadataTags(entries: entries, contentTypeUid: contentTypeUid)
142+
let deprecatedMany = try ContentstackUtils.getDataCsvariantsAttribute(entries: entries, contentTypeUid: contentTypeUid)
143+
try assertSemanticEqualDataCsvariantsPayload(canonicalMany, deprecatedMany)
144+
145+
let nilCanonical = try ContentstackUtils.getVariantMetadataTags(entry: nil, contentTypeUid: "x")
146+
let nilDeprecated = try ContentstackUtils.getDataCsvariantsAttribute(entry: nil, contentTypeUid: "x")
147+
XCTAssertEqual(nilCanonical["data-csvariants"] as? String, nilDeprecated["data-csvariants"] as? String)
148+
}
149+
110150
// MARK: - Edge cases
111151

112152
func testGetVariantAliasesEmptyEntriesArray() throws {
@@ -120,8 +160,8 @@ final class VariantUtilityTests: XCTestCase {
120160
}
121161
}
122162

123-
func testGetDataCsvariantsAttributeEmptyEntriesArray() throws {
124-
let wrapper = try ContentstackUtils.getDataCsvariantsAttribute(entries: [], contentTypeUid: contentTypeUid)
163+
func testGetVariantMetadataTagsEmptyEntriesArray() throws {
164+
let wrapper = try ContentstackUtils.getVariantMetadataTags(entries: [], contentTypeUid: contentTypeUid)
125165
XCTAssertEqual(wrapper["data-csvariants"] as? String, "[]")
126166
}
127167

@@ -175,38 +215,39 @@ final class VariantUtilityTests: XCTestCase {
175215
}
176216
}
177217

178-
func testGetDataCsvariantsAttributeThrowsWhenContentTypeUidEmptyWithEntry() throws {
218+
func testGetVariantMetadataTagsThrowsWhenContentTypeUidEmptyWithEntry() throws {
179219
let root = try TestDecodable.loadJSONObject(named: "variantsSingleEntry")
180220
let entry = try XCTUnwrap(root["entry"] as? [String: Any])
181-
XCTAssertThrowsError(try ContentstackUtils.getDataCsvariantsAttribute(entry: entry, contentTypeUid: "")) { error in
221+
XCTAssertThrowsError(try ContentstackUtils.getVariantMetadataTags(entry: entry, contentTypeUid: "")) { error in
182222
XCTAssertTrue(error is ContentstackUtils.VariantUtilityError)
183223
}
184224
}
185225

186-
func testGetDataCsvariantsAttributeEntriesThrowsWhenContentTypeUidWhitespaceOnly() {
187-
XCTAssertThrowsError(try ContentstackUtils.getDataCsvariantsAttribute(entries: [], contentTypeUid: "\t\n")) { error in
226+
func testGetVariantMetadataTagsEntriesThrowsWhenContentTypeUidWhitespaceOnly() {
227+
XCTAssertThrowsError(try ContentstackUtils.getVariantMetadataTags(entries: [], contentTypeUid: "\t\n")) { error in
188228
XCTAssertTrue(error is ContentstackUtils.VariantUtilityError)
189229
}
190230
}
191231

192232
#if !canImport(ObjectiveC)
193233
static var allTests = [
194234
("testGetVariantAliasesSingleEntry", testGetVariantAliasesSingleEntry),
195-
("testGetDataCsvariantsAttributeSingleEntry", testGetDataCsvariantsAttributeSingleEntry),
235+
("testGetVariantMetadataTagsSingleEntry", testGetVariantMetadataTagsSingleEntry),
196236
("testGetVariantAliasesMultipleEntries", testGetVariantAliasesMultipleEntries),
197-
("testGetDataCsvariantsAttributeMultipleEntries", testGetDataCsvariantsAttributeMultipleEntries),
237+
("testGetVariantMetadataTagsMultipleEntries", testGetVariantMetadataTagsMultipleEntries),
198238
("testGetVariantAliasesThrowsWhenEntryMissingUid", testGetVariantAliasesThrowsWhenEntryMissingUid),
199239
("testGetVariantAliasesThrowsWhenContentTypeUidEmpty", testGetVariantAliasesThrowsWhenContentTypeUidEmpty),
200-
("testGetDataCsvariantsAttributeWhenEntryNil", testGetDataCsvariantsAttributeWhenEntryNil),
240+
("testGetVariantMetadataTagsWhenEntryNil", testGetVariantMetadataTagsWhenEntryNil),
241+
("testDeprecatedGetDataCsvariantsAttributeDelegatesToGetVariantMetadataTags", testDeprecatedGetDataCsvariantsAttributeDelegatesToGetVariantMetadataTags),
201242
("testGetVariantAliasesEmptyEntriesArray", testGetVariantAliasesEmptyEntriesArray),
202243
("testGetVariantAliasesEmptyEntriesThrowsWhenContentTypeUidEmpty", testGetVariantAliasesEmptyEntriesThrowsWhenContentTypeUidEmpty),
203-
("testGetDataCsvariantsAttributeEmptyEntriesArray", testGetDataCsvariantsAttributeEmptyEntriesArray),
244+
("testGetVariantMetadataTagsEmptyEntriesArray", testGetVariantMetadataTagsEmptyEntriesArray),
204245
("testGetVariantAliasesEntryWithoutPublishDetails", testGetVariantAliasesEntryWithoutPublishDetails),
205246
("testGetVariantAliasesEntryWithEmptyVariantsMap", testGetVariantAliasesEntryWithEmptyVariantsMap),
206247
("testGetVariantAliasesSkipsInvalidVariantValues", testGetVariantAliasesSkipsInvalidVariantValues),
207248
("testGetVariantAliasesThrowsWhenUidIsEmptyString", testGetVariantAliasesThrowsWhenUidIsEmptyString),
208-
("testGetDataCsvariantsAttributeThrowsWhenContentTypeUidEmptyWithEntry", testGetDataCsvariantsAttributeThrowsWhenContentTypeUidEmptyWithEntry),
209-
("testGetDataCsvariantsAttributeEntriesThrowsWhenContentTypeUidWhitespaceOnly", testGetDataCsvariantsAttributeEntriesThrowsWhenContentTypeUidWhitespaceOnly),
249+
("testGetVariantMetadataTagsThrowsWhenContentTypeUidEmptyWithEntry", testGetVariantMetadataTagsThrowsWhenContentTypeUidEmptyWithEntry),
250+
("testGetVariantMetadataTagsEntriesThrowsWhenContentTypeUidWhitespaceOnly", testGetVariantMetadataTagsEntriesThrowsWhenContentTypeUidWhitespaceOnly),
210251
]
211252
#endif
212253
}

0 commit comments

Comments
 (0)