Repository: ProjectEvergreen/greenwood (js)

Issue:
pages from external source plugins not actually put in collections
### What happened?

in <https://github.com/lschierer/EvonyTKRTips/blob/greenwood/packages/greenwood/src/plugins/collections/generals.ts> I am creating a bunch of pages.  I know the pages are working because I can both hit them and they show up in the sidebar that I'm generating with getContent and getContentByRoute

those pages are setting the collection key in the front matter.  in <packages/greenwood/src/pages/Generals/details.ts> there is a getBody function that essentially just puts a custom element in place.  I'm doing it that way because the using a call to getContentByCollection in the <packages/greenwood/src/pages/Generals/details.ts> file caused a connection refused error trying to start dev mode

that component is defined at <https://github.com/lschierer/EvonyTKRTips/blob/greenwood/packages/greenwood/src/components/generals/GeneralsList.ts> and I can see its loading because if I put some text in there the text displays. I also see the debug out put I've defined in the component. 

however the list element is empty and the debug block at line 25 of that file tells me that the call to getContentByCollection and the resulting map/filter pair returned 0

splitting the get from the map/filter into two different calls, and putting a debug between them, the getContentByCollection returned 1 entry instead of the expected 95.
and that page is one that is defined in src/pgaes not one from the external source plugin

thus I conclude that pages generated by the external source plugin are not actually inserted into the collection. 

### Steps to reproduce

1. create an external source plugin that creates some pages
2. set the external source plugin to populate the front matter for those pages with a collection key. 
3. create an page in src/pages that should show the contents of the collection. It should list an entry for every page in the collection. 
4. run greenwood in dev mode. 
5. navigate to your collection list page created in step 3.  See that it is blank. 
6. navigate to one of the pages you created.  see it does in fact exist. 

### Environment

I'm using 
```
lschiere@80a997121f31:~/src/schierer/EvonyTKRTips/packages/greenwood$ grep greenwood package.json 
    "dev": "NODE_OPTIONS='--experimental-strip-types --import @greenwood/cli/register' greenwood develop",
    "start": "NODE_OPTIONS='--import @greenwood/cli/register' greenwood develop",
    "build": "NODE_OPTIONS='--import @greenwood/cli/register' greenwood build",
    "serve": "NODE_OPTIONS='--import @greenwood/cli/register' greenwood serve"
    "@greenwood/cli": "0.32.0-alpha.7",
    "@greenwood/plugin-google-analytics": "0.32.0-alpha.7",
    "@greenwood/plugin-postcss": "0.32.0-alpha.7",
lschiere@80a997121f31:~/src/schierer/EvonyTKRTips/packages/greenwood$ 
```

I'm on OSX,  I'm using pnpm 10.6, with nodejs 22.14.0 


### Additional Context

_No response_

Pull request description:
bug/issue 1468 fix source plugin pages not getting added to collections
<!--
## Submitting a Pull Request
We love contributions and appreciate any help you can offer!
-->

## Related Issue

resolves #1468 

## Documentation 

N / A

## Summary of Changes

1. Ensure pages from source plugins get added to collections

Patch:
diff --git a/packages/cli/src/lifecycles/compile.js b/packages/cli/src/lifecycles/compile.js
index a7961c02..71bb2f81 100644
--- a/packages/cli/src/lifecycles/compile.js
+++ b/packages/cli/src/lifecycles/compile.js
@@ -17,6 +17,7 @@ const generateCompilation = () => {
         manifest: {
           apis: new Map(),
         },
+        collections: {},
       };
 
       console.info("Initializing project config");
diff --git a/packages/cli/src/lifecycles/graph.js b/packages/cli/src/lifecycles/graph.js
index 0cfe8203..97566d06 100644
--- a/packages/cli/src/lifecycles/graph.js
+++ b/packages/cli/src/lifecycles/graph.js
@@ -30,6 +30,28 @@ function getIdFromRelativePathPath(relativePathPath, extension) {
   return relativePathPath.replace(extension, "").replace("./", "").replace(/\//g, "-");
 }
 
+function trackCollectionsForPage(page, collections) {
+  const pageCollection = page.data?.collection ?? "";
+
+  if (pageCollection) {
+    if (typeof pageCollection === "string") {
+      if (!collections[pageCollection]) {
+        collections[pageCollection] = [];
+      }
+
+      collections[pageCollection].push(page);
+    } else if (Array.isArray(pageCollection)) {
+      pageCollection.forEach((collection) => {
+        if (!collections[collection]) {
+          collections[collection] = [];
+        }
+
+        collections[collection].push(page);
+      });
+    }
+  }
+}
+
 const generateGraph = async (compilation) => {
   // eslint-disable-next-line no-async-promise-executor
   return new Promise(async (resolve, reject) => {
@@ -37,7 +59,6 @@ const generateGraph = async (compilation) => {
       const { context, config } = compilation;
       const { basePath } = config;
       const { pagesDir, userWorkspace, outputDir } = context;
-      const collections = {};
       const customPageFormatPlugins = config.plugins
         .filter((plugin) => plugin.type === "resource" && !plugin.isGreenwoodDefaultPlugin)
         .map((plugin) => plugin.provider(compilation));
@@ -288,27 +309,7 @@ const generateGraph = async (compilation) => {
               pages.push(page);
 
               // handle collections
-              const pageCollection = customData.collection;
-
-              if (pageCollection) {
-                if (typeof pageCollection === "string") {
-                  if (!collections[pageCollection]) {
-                    collections[pageCollection] = [];
-                  }
-
-                  collections[pageCollection].push(page);
-                } else if (Array.isArray(pageCollection)) {
-                  pageCollection.forEach((collection) => {
-                    if (!collections[collection]) {
-                      collections[collection] = [];
-                    }
-
-                    collections[collection].push(page);
-                  });
-                }
-              }
-
-              compilation.collections = collections;
+              trackCollectionsForPage(page, compilation.collections); // collections;
             } else {
               console.warn(`Unsupported format detected for page => ${filename}`);
             }
@@ -382,16 +383,23 @@ const generateGraph = async (compilation) => {
               reject(`ERROR: provided node does not provide a ${missingKey} property.`);
             }
 
-            graph.push({
+            const page = {
               pageHref: null,
-              data: {},
               imports: [],
               resources: [],
               outputHref: new URL(`.${route}index.html`, outputDir).href,
               ...node,
               route: encodeURIComponent(route).replace(/%2F/g, "/"),
+              data: {
+                ...node.data,
+                collection: node.collection ?? "",
+              },
               external: true,
-            });
+            };
+
+            graph.push(page);
+
+            trackCollectionsForPage(page, compilation.collections);
           }
         }
       }


Test patch:
diff --git a/packages/cli/test/cases/build.config.prerender-collections/build.config.prerender-collections.spec.js b/packages/cli/test/cases/build.config.prerender-collections/build.config.prerender-collections.spec.js
index 07972024..2d999f99 100644
--- a/packages/cli/test/cases/build.config.prerender-collections/build.config.prerender-collections.spec.js
+++ b/packages/cli/test/cases/build.config.prerender-collections/build.config.prerender-collections.spec.js
@@ -112,7 +112,7 @@ describe("Build Greenwood With: ", function () {
         });
 
         it("should have the expected number of nav links from all pages in the collection", function () {
-          expect(navLinks.length).to.equal(3);
+          expect(navLinks.length).to.equal(4);
         });
 
         it("should have the expected link content from all pages in the collection", function () {
@@ -127,6 +127,10 @@ describe("Build Greenwood With: ", function () {
           expect(navLinks[2].getAttribute("href")).to.equal("/toc/");
           expect(navLinks[2].getAttribute("title")).to.equal("Table of Contents");
           expect(navLinks[2].textContent).to.equal("Table of Contents");
+
+          expect(navLinks[3].getAttribute("href")).to.equal("/external/");
+          expect(navLinks[3].getAttribute("title")).to.equal("External Page");
+          expect(navLinks[3].textContent).to.equal("External Page");
         });
 
         it("should have the expected inline active frontmatter collection data", function () {
@@ -235,8 +239,8 @@ describe("Build Greenwood With: ", function () {
         });
 
         // includes 404 page
-        it("should have the expected number of post links from all blog pages in the collection (minus the index route)", function () {
-          expect(pageLinks.length).to.equal(6);
+        it("should have the expected number of post links from all pages in the collection (minus the index route)", function () {
+          expect(pageLinks.length).to.equal(7);
         });
       });
     });
diff --git a/packages/cli/test/cases/build.config.prerender-collections/greenwood.config.js b/packages/cli/test/cases/build.config.prerender-collections/greenwood.config.js
index ac59f9f5..6833d43e 100644
--- a/packages/cli/test/cases/build.config.prerender-collections/greenwood.config.js
+++ b/packages/cli/test/cases/build.config.prerender-collections/greenwood.config.js
@@ -1,4 +1,27 @@
 export default {
   activeContent: true,
   prerender: true,
+  plugins: [
+    {
+      name: "External Content Plugin",
+      type: "source",
+      provider: () => {
+        return async function () {
+          return [
+            {
+              id: "external",
+              route: "/external/",
+              title: "External Page",
+              label: "External Page",
+              body: "<h1>External Page</h1>",
+              collection: "nav",
+              data: {
+                order: 4,
+              },
+            },
+          ];
+        };
+      },
+    },
+  ],
 };