Skip to content

Commit

Permalink
Fixes #756
Browse files Browse the repository at this point in the history
  • Loading branch information
zachleat committed May 12, 2022
1 parent e88624b commit b3962fb
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 25 deletions.
50 changes: 36 additions & 14 deletions src/Plugins/Pagination.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const lodashChunk = require("lodash/chunk");
const lodashGet = require("lodash/get");
const lodashSet = require("lodash/set");
const { isPlainObject } = require("@11ty/eleventy-utils");

const EleventyBaseError = require("../EleventyBaseError");
const { DeepCopy } = require("../Util/Merge");
const { ProxyWrap } = require("../Util/ProxyWrap");
Expand All @@ -9,7 +11,7 @@ class PaginationConfigError extends EleventyBaseError {}
class PaginationError extends EleventyBaseError {}

class Pagination {
constructor(data, config) {
constructor(tmpl, data, config) {
if (!config) {
throw new PaginationConfigError(
"Expected `config` argument to Pagination class."
Expand All @@ -18,16 +20,26 @@ class Pagination {

this.config = config;

this.setTemplate(tmpl);
this.setData(data);
}

get inputPathForErrorMessages() {
if (this.template) {
return ` (${this.template.inputPath})`;
}
return "";
}

static hasPagination(data) {
return "pagination" in data;
}

hasPagination() {
if (!this.data) {
throw new Error("Missing `setData` call for Pagination object.");
throw new Error(
`Missing \`setData\` call for Pagination object${this.inputPathForErrorMessages}`
);
}
return Pagination.hasPagination(this.data);
}
Expand All @@ -42,9 +54,7 @@ class Pagination {
for (let tag of tags) {
if (`collections.${tag}` === key) {
throw new PaginationError(
`Pagination circular reference${
this.template ? ` on ${this.template.inputPath}` : ""
}, data:\`${key}\` iterates over both the \`${tag}\` tag and also supplies pages to that tag.`
`Pagination circular reference${this.inputPathForErrorMessages}, data:\`${key}\` iterates over both the \`${tag}\` tag and also supplies pages to that tag.`
);
}
}
Expand All @@ -60,10 +70,12 @@ class Pagination {

if (!data.pagination) {
throw new Error(
"Misconfigured pagination data in template front matter (YAML front matter precaution: did you use tabs and not spaces for indentation?)."
`Misconfigured pagination data in template front matter${this.inputPathForErrorMessages} (YAML front matter precaution: did you use tabs and not spaces for indentation?).`
);
} else if (!("size" in data.pagination)) {
throw new Error("Missing pagination size in front matter data.");
throw new Error(
`Missing pagination size in front matter data${this.inputPathForErrorMessages}`
);
}
this.circularReferenceCheck(data);

Expand Down Expand Up @@ -119,7 +131,7 @@ class Pagination {
return this.data.pagination.data;
}

resolveDataToObjectValues() {
shouldResolveDataToObjectValues() {
if ("resolve" in this.data.pagination) {
return this.data.pagination.resolve === "values";
}
Expand Down Expand Up @@ -150,7 +162,7 @@ class Pagination {
let data = lodashGet(target, key, notFoundValue);
if (data === notFoundValue) {
throw new Error(
`Could not find pagination data, went looking for: ${key}`
`Could not find pagination data${this.inputPathForErrorMessages}, went looking for: ${key}`
);
}
return data;
Expand All @@ -160,10 +172,16 @@ class Pagination {
let keys;
if (Array.isArray(this.fullDataSet)) {
keys = this.fullDataSet;
} else if (this.resolveDataToObjectValues()) {
keys = Object.values(this.fullDataSet);
} else if (isPlainObject(this.fullDataSet)) {
if (this.shouldResolveDataToObjectValues()) {
keys = Object.values(this.fullDataSet);
} else {
keys = Object.keys(this.fullDataSet);
}
} else {
keys = Object.keys(this.fullDataSet);
throw new Error(
`Unexpected data found in pagination target${this.inputPathForErrorMessages}: expected an Array or an Object.`
);
}

// keys must be an array
Expand All @@ -190,7 +208,9 @@ class Pagination {

get pagedItems() {
if (!this.data) {
throw new Error("Missing `setData` call for Pagination object.");
throw new Error(
`Missing \`setData\` call for Pagination object${this.inputPathForErrorMessages}`
);
}

const chunks = lodashChunk(this.target, this.size);
Expand Down Expand Up @@ -282,7 +302,9 @@ class Pagination {

async getPageTemplates() {
if (!this.data) {
throw new Error("Missing `setData` call for Pagination object.");
throw new Error(
`Missing \`setData\` call for Pagination object${this.inputPathForErrorMessages}`
);
}

if (!this.hasPagination()) {
Expand Down
3 changes: 1 addition & 2 deletions src/Template.js
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,7 @@ class Template extends TemplateContent {
} else {
// needs collections for pagination items
// but individual pagination entries won’t be part of a collection
this.paging = new Pagination(data, this.config);
this.paging.setTemplate(this);
this.paging = new Pagination(this, data, this.config);

let pageTemplates = await this.paging.getPageTemplates();
return await Promise.all(
Expand Down
4 changes: 2 additions & 2 deletions src/TemplateWriter.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ class TemplateWriter {
} else {
return Promise.reject(
new EleventyTemplateError(
`Having trouble writing template: "${mapEntry.outputPath}"`,
`Having trouble writing to "${mapEntry.outputPath}" from "${mapEntry.inputPath}"`,
e
)
);
Expand All @@ -303,7 +303,7 @@ class TemplateWriter {
this._generateTemplate(mapEntry, to).catch(function (e) {
return Promise.reject(
new EleventyTemplateError(
`Having trouble writing template (second pass): "${mapEntry.outputPath}"`,
`Having trouble writing to (second pass) "${mapEntry.outputPath}" from "${mapEntry.inputPath}"`,
e
)
);
Expand Down
16 changes: 9 additions & 7 deletions test/PaginationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ test("No data passed to pagination", async (t) => {
eleventyConfig
);

let paging = new Pagination({}, tmpl.config);
paging.setTemplate(tmpl);
let paging = new Pagination(tmpl, {}, tmpl.config);

t.is(paging.pagedItems.length, 0);
t.is((await paging.getPageTemplates()).length, 0);
Expand All @@ -36,7 +35,7 @@ test("No pagination", async (t) => {
);

let data = await tmpl.getData();
let paging = new Pagination(data, tmpl.config);
let paging = new Pagination(tmpl, data, tmpl.config);
paging.setTemplate(tmpl);

t.falsy(data.pagination);
Expand All @@ -57,7 +56,7 @@ test("Empty paged data", async (t) => {
);

let data = await tmpl.getData();
let paging = new Pagination(data, tmpl.config);
let paging = new Pagination(tmpl, data, tmpl.config);
paging.setTemplate(tmpl);

t.is(paging.getPageCount(), 0);
Expand All @@ -77,7 +76,7 @@ test("Empty paged data with generatePageOnEmptyData enabled", async (t) => {
);

let data = await tmpl.getData();
let paging = new Pagination(data, tmpl.config);
let paging = new Pagination(tmpl, data, tmpl.config);
paging.setTemplate(tmpl);

t.is(paging.getPageCount(), 1);
Expand All @@ -97,7 +96,7 @@ test("Pagination enabled in frontmatter", async (t) => {
);

let data = await tmpl.getData();
let paging = new Pagination(data, tmpl.config);
let paging = new Pagination(tmpl, data, tmpl.config);
paging.setTemplate(tmpl);

t.truthy(data.testdata);
Expand All @@ -121,7 +120,7 @@ test("Resolve paged data in frontmatter", async (t) => {
);

let data = await tmpl.getData();
let paging = new Pagination(data, tmpl.config);
let paging = new Pagination(tmpl, data, tmpl.config);
paging.setTemplate(tmpl);
t.is(paging._resolveItems().length, 8);
t.is(paging.getPageCount(), 2);
Expand Down Expand Up @@ -612,6 +611,7 @@ test("No circular dependency (does not throw)", (t) => {
let eleventyConfig = new TemplateConfig();

new Pagination(
null,
{
collections: {
tag1: [],
Expand All @@ -632,6 +632,7 @@ test("Circular dependency (pagination iterates over tag1 but also supplies pages
t.throws(() => {
let eleventyConfig = new TemplateConfig();
new Pagination(
null,
{
collections: {
tag1: [],
Expand All @@ -651,6 +652,7 @@ test("Circular dependency (pagination iterates over tag1 but also supplies pages
test("Circular dependency but should not error because it uses eleventyExcludeFromCollections", (t) => {
let eleventyConfig = new TemplateConfig();
new Pagination(
null,
{
eleventyExcludeFromCollections: true,
collections: {
Expand Down

0 comments on commit b3962fb

Please sign in to comment.