Repository: 11ty/eleventy (js)

Issue:
Deduplicate tags after merging
**Is your feature request related to a problem? Please describe.**
When I'm generating a collection on my site, I sometimes use data merging to provide tags common to the series and then tag individual posts further. If I happen to forget that I already have a tag for a given collection, I end up with duplicate tags. This isn't terrible, but it can easily mean that I have duplicates in the JSON Feed I generate.

**Describe the solution you'd like**
Tags (and indeed data in general) should be deduplicated; at a minimum it should be *possible* to deduplicate.

**Describe alternatives you've considered**
- Just keep manually making sure to avoid duplicates
- Deduplicate manually anywhere the collection is used

**Additional context**
N/A


Pull request description:
Deduplicate tags when using deepDataMerge
Resolves #1810.

As described in #1810, tags can be duplicated through a data deep merge if they appear in more than one place.

I can't think of a reason why anyone needs a tag to appear more than once within the data cascade, so this uses `new Set` to deduplicate the output.

Hopefully this is OK!

Patch:
diff --git a/src/TemplateData.js b/src/TemplateData.js
index bf90503d..92eeaa14 100755
--- a/src/TemplateData.js
+++ b/src/TemplateData.js
@@ -586,6 +586,9 @@ class TemplateData {
       } else if (data.tags === null) {
         data.tags = [];
       }
+
+      // Deduplicate tags
+      data.tags = [...new Set(data.tags)];
     }
 
     return data;


Test patch:
diff --git a/test/TemplateTest.js b/test/TemplateTest.js
index 8c590884..dd92d6fc 100644
--- a/test/TemplateTest.js
+++ b/test/TemplateTest.js
@@ -1489,6 +1489,26 @@ test("Data Cascade Tag Merge (Deep merge)", async (t) => {
   t.deepEqual(data.tags.sort(), ["tagA", "tagB", "tagC", "tagD"]);
 });
 
+test("Data Cascade Tag Merge (Deep Merge - Deduplication)", async (t) => {
+  let eleventyConfig = new TemplateConfig();
+  // Default changed in 1.0
+  // eleventyConfig.userConfig.setDataDeepMerge(true);
+  let dataObj = new TemplateData("./test/stubs/", eleventyConfig);
+  await dataObj.cacheData();
+
+  let tmpl = getNewTemplate(
+    "./test/stubs/data-cascade/template.njk",
+    "./test/stubs/",
+    "./dist",
+    dataObj,
+    null,
+    eleventyConfig
+  );
+
+  let data = await tmpl.getData();
+  t.deepEqual(data.tags.sort(), ["tagA", "tagB", "tagC", "tagD"]);
+});
+
 test("Data Cascade Tag Merge (Shallow merge)", async (t) => {
   let eleventyConfig = new TemplateConfig();
   // Default changed in 1.0
diff --git a/test/stubs/data-cascade/template.11tydata.js b/test/stubs/data-cascade/template.11tydata.js
index c28b80b7..d78ea3ab 100644
--- a/test/stubs/data-cascade/template.11tydata.js
+++ b/test/stubs/data-cascade/template.11tydata.js
@@ -1,8 +1,8 @@
 module.exports = {
   parent: {
     child: 2,
-    datafile: true
+    datafile: true,
   },
   datafile: true,
-  tags: ["tagC", "tagD"]
+  tags: ["tagC", "tagD", "tagD"],
 };