From 34105446ef5721aaae70ef6b0093e1680df779cd Mon Sep 17 00:00:00 2001 From: Chris Burnell Date: Fri, 26 May 2023 22:54:57 +0100 Subject: [PATCH] make webmentions/webmentionsAll Global Data return flat array, webmentionByUrl return filtered --- .editorconfig | 6 +- .prettierrc | 21 ++-- README.md | 180 +++++++++++++++++----------------- eleventy-cache-webmentions.js | 122 ++++++++++++++++++----- package.json | 10 +- 5 files changed, 210 insertions(+), 129 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9297d31..d75be91 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,11 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -[*.md] +[*.{json,svg,toml,yaml,yml}] indent_style = space indent_size = 2 + +[*.md] +indent_style = space +indent_size = 4 trim_trailing_whitespace = false diff --git a/.prettierrc b/.prettierrc index 1e81472..c38b808 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,13 @@ -# .prettierrc -semi: false -printWidth: 9999 -tabWidth: 4 -overrides: - - files: "*.md" - options: - tabWidth: 2 +{ + "semi": false, + "printWidth": 9999, + "tabWidth": 4, + "overrides": [ + { + "files": "*.json", + "options": { + "tabWidth": 2 + } + } + ] +} diff --git a/README.md b/README.md index d33e54d..4b0ed6d 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ I wrote a quicker and simpler guide to getting this Eleventy plugin working that ## Installation -- **With npm:** `npm install @chrisburnell/eleventy-cache-webmentions` -- **Direct download:** [https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip](https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip) +- **With npm:** `npm install @chrisburnell/eleventy-cache-webmentions` +- **Direct download:** [https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip](https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip) Once installed there are **two** more **required** set-up steps: @@ -21,12 +21,12 @@ Inside your Eleventy config file (typically `.eleventy.js`), use `addPlugin`: const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions") module.exports = function (eleventyConfig) { - eleventyConfig.addPlugin(pluginWebmentions, { - // these 3 fields are all required! - domain: "https://example.com", - feed: "https://webmentions.example.com?token=S3cr3tT0k3n", - key: "children", - }) + eleventyConfig.addPlugin(pluginWebmentions, { + // these 3 fields are all required! + domain: "https://example.com", + feed: "https://webmentions.example.com?token=S3cr3tT0k3n", + key: "children", + }) } ``` @@ -38,51 +38,51 @@ Advanced control over how the Webmentions are cached and processed is done by pa const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions") module.exports = function (eleventyConfig) { - eleventyConfig.addPlugin(pluginWebmentions, { - // domain: required or the plugin will not function - // this is the website that you want to pull in Webmentions for - domain: "https://example.com", - // feed: required or the plugin will not function - // defines the URL of your Webmention server where a feed of Webmentions for your domain can be found - feed: "https://webmentions.example.com?token=S3cr3tT0k3n", - // key: required or the plugin will not function - // dictates the key inside the feed where the array of Webmentions is located - key: "children", - // directory: ".cache" by default - // see https://www.11ty.dev/docs/plugins/cache/#cache-directory for more info - directory: ".cache", - // duration: "1d" by default - // see https://www.11ty.dev/docs/plugins/cache/#change-the-cache-duration for more info - duration: "1d", - // uniquekey: "webmentions" by default - // dictates the name sent to eleventy-fetch to name the file - uniqueKey: "webmentions", - // allowedHTML: Object by default - // see https://www.npmjs.com/package/sanitize-html for more info - allowedHTML: { - allowedTags: ["b", "i", "em", "strong", "a"], - allowedAttributes: { - a: ["href"], - }, - }, - // allowlist: [] by default - // array of root URLs from which webmentions are wanted exclusively - allowlist: [], - // blocklist: [] by default - // array of root URLs from which webmentions are not wanted - // exclusively - blocklist: [], - // urlReplacements: {} by default - // object of key:value pairs containing from:to URL replacements - urlReplacements: {}, - // maximumHtmlLength: 2000 by default - // number of characters in the HTML content at which a different - // message is shown instead of the content - maximumHtmlLength: 2000, - // maximumHtmlText: "mentioned this in" by default - // message shown when maximumHtmlLength is reached - maximumHtmlText: "mentioned this in", - }) + eleventyConfig.addPlugin(pluginWebmentions, { + // domain: required or the plugin will not function + // this is the website that you want to pull in Webmentions for + domain: "https://example.com", + // feed: required or the plugin will not function + // defines the URL of your Webmention server where a feed of Webmentions for your domain can be found + feed: "https://webmentions.example.com?token=S3cr3tT0k3n", + // key: required or the plugin will not function + // dictates the key inside the feed where the array of Webmentions is located + key: "children", + // directory: ".cache" by default + // see https://www.11ty.dev/docs/plugins/cache/#cache-directory for more info + directory: ".cache", + // duration: "1d" by default + // see https://www.11ty.dev/docs/plugins/cache/#change-the-cache-duration for more info + duration: "1d", + // uniquekey: "webmentions" by default + // dictates the name sent to eleventy-fetch to name the file + uniqueKey: "webmentions", + // allowedHTML: Object by default + // see https://www.npmjs.com/package/sanitize-html for more info + allowedHTML: { + allowedTags: ["b", "i", "em", "strong", "a"], + allowedAttributes: { + a: ["href"], + }, + }, + // allowlist: [] by default + // array of root URLs from which webmentions are wanted exclusively + allowlist: [], + // blocklist: [] by default + // array of root URLs from which webmentions are not wanted + // exclusively + blocklist: [], + // urlReplacements: {} by default + // object of key:value pairs containing from:to URL replacements + urlReplacements: {}, + // maximumHtmlLength: 2000 by default + // number of characters in the HTML content at which a different + // message is shown instead of the content + maximumHtmlLength: 2000, + // maximumHtmlText: "mentioned this in" by default + // message shown when maximumHtmlLength is reached + maximumHtmlText: "mentioned this in", + }) } ``` @@ -92,9 +92,9 @@ Accessing the plugin in JavaScript in the way shown below will give you an Objec ```javascript const Webmentions = require("@chrisburnell/eleventy-cache-webmentions")(null, { - domain: "https://example.com", - feed: "https://webmentions.example.com?token=S3cr3tT0k3n", - key: "children", + domain: "https://example.com", + feed: "https://webmentions.example.com?token=S3cr3tT0k3n", + key: "children", }) const webmentionsByUrl = await Webmentions() @@ -104,28 +104,28 @@ This can prove to be very useful when building out your pages. Using [Eleventy ```javascript const Webmentions = require("@chrisburnell/eleventy-cache-webmentions")(null, { - domain: "https://example.com", - feed: "https://webmentions.example.com?token=S3cr3tT0k3n", - key: "children", + domain: "https://example.com", + feed: "https://webmentions.example.com?token=S3cr3tT0k3n", + key: "children", }) module.exports = async () => { - const webmentionsByUrl = await Webmentions() - - return { - eleventyComputed: { - webmentions: (data) => { - const webmentionsForUrl = webmentionsByUrl["https://example.com" + data.page.url] || [] - - if (webmentionsForUrl.length) { - return webmentionsForUrl.sort((a, b) => { - return (b.data.published || b.verified_date) - (a.data.published || a.verified_date) - }) - } - return [] - }, - }, - } + const webmentionsByUrl = await Webmentions() + + return { + eleventyComputed: { + webmentions: (data) => { + const webmentionsForUrl = webmentionsByUrl["https://example.com" + data.page.url] || [] + + if (webmentionsForUrl.length) { + return webmentionsForUrl.sort((a, b) => { + return (b.data.published || b.verified_date) - (a.data.published || a.verified_date) + }) + } + return [] + }, + }, + } } ``` @@ -133,11 +133,11 @@ You can now use this data in a number of useful ways, not limited to things like ```javascript module.exports = (eleventyConfig) => { - eleventyConfig.addCollection("popular", (collection) => { - return collection.sort((a, b) => { - return b.data.webmentions.length - a.data.webmentions.length + eleventyConfig.addCollection("popular", (collection) => { + return collection.sort((a, b) => { + return b.data.webmentions.length - a.data.webmentions.length + }) }) - }) } ``` @@ -166,7 +166,7 @@ And, if you need it, the entire Object of sorted Webmentions is available too: ```twig {% raw %}{% set count = 0 %} -{% for url, array in webmentions %} +{% for url, array in webmentionsAll %} {% set count = array.length + count %} {% endfor %}

This site has received {{ count }} Webmentions!

{% endraw %} @@ -190,11 +190,11 @@ WEBMENTION_IO_TOKEN=njJql0lKXnotreal4x3Wmd const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions") module.exports = function (eleventyConfig) { - eleventyConfig.addPlugin(pluginWebmentions, { - domain: "https://example.com", - feed: `https://webmention.io/api/mentions.jf2?domain=example.com&per-page=9001&token=${process.env.WEBMENTION_IO_TOKEN}`, - key: "children", - }) + eleventyConfig.addPlugin(pluginWebmentions, { + domain: "https://example.com", + feed: `https://webmention.io/api/mentions.jf2?domain=example.com&per-page=9001&token=${process.env.WEBMENTION_IO_TOKEN}`, + key: "children", + }) } ``` @@ -216,11 +216,11 @@ GO_JAMMING_TOKEN=njJql0lKXnotreal4x3Wmd const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions") module.exports = function (eleventyConfig) { - eleventyConfig.addPlugin(pluginWebmentions, { - domain: "https://example.com", - feed: `https://jam.example.com/webmention/example.com/${process.env.GO_JAMMING_TOKEN}`, - key: "json", - }) + eleventyConfig.addPlugin(pluginWebmentions, { + domain: "https://example.com", + feed: `https://jam.example.com/webmention/example.com/${process.env.GO_JAMMING_TOKEN}`, + key: "json", + }) } ``` diff --git a/eleventy-cache-webmentions.js b/eleventy-cache-webmentions.js index 1a707d8..62e5ac5 100644 --- a/eleventy-cache-webmentions.js +++ b/eleventy-cache-webmentions.js @@ -7,7 +7,9 @@ const absoluteURL = (url, domain) => { try { return new URL(url, domain).toString() } catch (e) { - console.log(`Trying to convert ${url} to be an absolute url with base ${domain} and failed.`) + console.log( + `Trying to convert ${url} to be an absolute url with base ${domain} and failed.` + ) return url } } @@ -19,10 +21,13 @@ const baseUrl = (url) => { } const fixUrl = (url, urlReplacements) => { - return Object.entries(urlReplacements).reduce((accumulator, [key, value]) => { - const regex = new RegExp(key, "g") - return accumulator.replace(regex, value) - }, url) + return Object.entries(urlReplacements).reduce( + (accumulator, [key, value]) => { + const regex = new RegExp(key, "g") + return accumulator.replace(regex, value) + }, + url + ) } const hostname = (value) => { @@ -38,15 +43,30 @@ const epoch = (value) => { } const getPublished = (webmention) => { - return webmention["wm-received"] || webmention?.["data"]["published"] || webmention["verified_date"] || webmention["published"] + return ( + webmention["wm-received"] || + webmention?.["data"]["published"] || + webmention["verified_date"] || + webmention["published"] + ) } const getContent = (webmention) => { - return webmention?.["content"]?.["html"] || webmention?.["content"] || webmention?.["data"]?.["content"] || "" + return ( + webmention?.["content"]?.["html"] || + webmention?.["content"] || + webmention?.["data"]?.["content"] || + "" + ) } const getSource = (webmention) => { - return webmention["url"] || webmention?.["data"]["url"] || webmention["wm-source"] || webmention["source"] + return ( + webmention["url"] || + webmention?.["data"]["url"] || + webmention["wm-source"] || + webmention["source"] + ) } const getTarget = (webmention) => { @@ -54,7 +74,11 @@ const getTarget = (webmention) => { } const getType = (webmention) => { - return webmention["wm-property"] || webmention?.["activity"]["type"] || webmention["type"] + return ( + webmention["wm-property"] || + webmention?.["activity"]["type"] || + webmention["type"] + ) } const defaults = { @@ -74,19 +98,27 @@ const defaults = { const fetchWebmentions = async (options) => { if (!options.domain) { - throw new Error("domain is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information.") + throw new Error( + "domain is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information." + ) } if (!options.feed) { - throw new Error("feed is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information.") + throw new Error( + "feed is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information." + ) } if (!options.key) { - throw new Error("key is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information.") + throw new Error( + "key is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information." + ) } if (!options.uniqueKey) { - throw new Error("uniqueKey is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information.") + throw new Error( + "uniqueKey is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information." + ) } let asset = new AssetCache(options.uniqueKey, options.directory) @@ -103,16 +135,27 @@ const fetchWebmentions = async (options) => { // results since the most recent webmention if (!asset.isCacheValid(options.duration)) { const since = webmentions.length ? getPublished(webmentions[0]) : false - const url = `${options.feed}${since ? `${options.feed.includes("?") ? "&" : "?"}since=${since}` : ""}` + const url = `${options.feed}${ + since + ? `${options.feed.includes("?") ? "&" : "?"}since=${since}` + : "" + }` await fetch(url) .then(async (response) => { if (response.ok) { const feed = await response.json() if (feed[options.key].length) { - webmentions = uniqBy([...feed[options.key], ...webmentions], (entry) => { - return getSource(entry) - }) - console.log(`[${hostname(options.domain)}] ${feed[options.key].length} new Webmentions fetched into cache.`) + webmentions = uniqBy( + [...feed[options.key], ...webmentions], + (entry) => { + return getSource(entry) + } + ) + console.log( + `[${hostname(options.domain)}] ${ + feed[options.key].length + } new Webmentions fetched into cache.` + ) } await asset.save(webmentions, "json") return webmentions @@ -120,7 +163,14 @@ const fetchWebmentions = async (options) => { return Promise.reject(response) }) .catch((error) => { - console.log(`[${hostname(options.domain)}] Something went wrong with your request to ${hostname(options.feed)}!`, error) + console.log( + `[${hostname( + options.domain + )}] Something went wrong with your request to ${hostname( + options.feed + )}!`, + error + ) }) } @@ -168,8 +218,12 @@ const filteredWebmentions = async (options) => { // Fix local URLs based on urlReplacements and sort Webmentions into groups // by target base URL rawWebmentions.forEach((webmention) => { - let url = baseUrl(fixUrl(getTarget(webmention).replace(/\/?$/, "/"), options.urlReplacements)) - + let url = baseUrl( + fixUrl( + getTarget(webmention).replace(/\/?$/, "/"), + options.urlReplacements + ) + ) if (!filtered[url]) { filtered[url] = [] @@ -200,7 +254,10 @@ const getWebmentions = async (options, url, allowedTypes = {}) => { webmentions[url] // filter webmentions by allowed response post types .filter((entry) => { - return typeof allowedTypes === "object" && Object.keys(allowedTypes).length ? allowedTypes.includes(getType(entry)) : true + return typeof allowedTypes === "object" && + Object.keys(allowedTypes).length + ? allowedTypes.includes(getType(entry)) + : true }) // sanitize content of webmentions against HTML limit .map((entry) => { @@ -209,7 +266,9 @@ const getWebmentions = async (options, url, allowedTypes = {}) => { if (html.length) { entry.content = sanitizeHTML(html, options.allowedHTML) if (html.length > options.maximumHtmlLength) { - entry.content = `${options.maximumHtmlText} ${getSource(entry)}` + entry.content = `${ + options.maximumHtmlText + } ${getSource(entry)}` } } @@ -236,13 +295,26 @@ module.exports = (eleventyConfig, options = {}) => { if (eleventyConfig) { // Global Data - eleventyConfig.addGlobalData("webmentions", filteredWebmentions(options)) + const filtered = async () => await filteredWebmentions(options) + eleventyConfig.addGlobalData("webmentionsByUrl", filtered) + const unfiltered = async () => + await filteredWebmentions(options).then((filtered) => + Object.values(filtered).reduce( + (array, webmentions) => [...array, ...webmentions], + [] + ) + ) + eleventyConfig.addGlobalData("webmentionsAll", unfiltered) + eleventyConfig.addGlobalData("webmentions", unfiltered) // Liquid Filter eleventyConfig.addLiquidFilter("getWebmentions", getWebmentionsFilter) // Nunjucks Filter - eleventyConfig.addNunjucksAsyncFilter("getWebmentions", getWebmentionsFilter) + eleventyConfig.addNunjucksAsyncFilter( + "getWebmentions", + getWebmentionsFilter + ) } return { diff --git a/package.json b/package.json index 850b745..86809aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chrisburnell/eleventy-cache-webmentions", - "version": "1.1.5", + "version": "1.2.0", "description": "Fetch and cache webmentions using eleventy-fetch.", "author": "Chris Burnell ", "license": "MIT", @@ -20,13 +20,13 @@ "webmention" ], "devDependencies": { - "eslint": "^8.7.0" + "eslint": "^8.41.0" }, "dependencies": { - "@11ty/eleventy-fetch": "^3.0.0", + "@11ty/eleventy-fetch": "^4.0.0", "lodash": "^4.17.21", - "node-fetch": "^2.6.5", - "sanitize-html": "^2.7.1" + "node-fetch": "^3.3.1", + "sanitize-html": "^2.10.0" }, "main": "eleventy-cache-webmentions.js", "scripts": {