From 4ebe7fc5665b2428ab85ac1da888a2661a6fe94d Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 4 Oct 2023 19:56:44 -0300 Subject: external-links, test: fandom page links, custom "transform" --- src/strings-default.yaml | 7 ++ src/util/external-links.js | 98 +++++++++++++++++++++- .../test/snapshot/linkExternal.js.test.cjs | 18 ++++ test/snapshot/linkExternal.js | 7 ++ 4 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/strings-default.yaml b/src/strings-default.yaml index 58f8401b..d194adde 100644 --- a/src/strings-default.yaml +++ b/src/strings-default.yaml @@ -505,6 +505,13 @@ misc: deviantart: "DeviantArt" + fandom: + _: "Fandom" + + mspaintadventures: + _: "MSPA Wiki" + page: "MSPA Wiki ({PAGE})" + homestuck: _: "Homestuck" page: "Homestuck (page {PAGE})" diff --git a/src/util/external-links.js b/src/util/external-links.js index 0b8b4ab6..57b6c3f6 100644 --- a/src/util/external-links.js +++ b/src/util/external-links.js @@ -6,6 +6,7 @@ import { isObject, isStringNonEmpty, optional, + validateAllPropertyValues, validateArrayItems, validateInstanceOf, validateProperties, @@ -35,10 +36,24 @@ export const isExternalLinkContext = is(...externalLinkContexts); const isRegExp = validateInstanceOf(RegExp); +export const isExternalLinkTransformCommand = + is(...[ + 'decode-uri', + 'find-replace', + ]); + +export const isExternalLinkTransformSpec = + anyOf( + isExternalLinkTransformCommand, + validateProperties({ + [validateProperties.allowOtherKeys]: true, + command: isExternalLinkTransformCommand, + })); + export const isExternalLinkExtractSpec = validateProperties({ prefix: optional(isStringNonEmpty), - + transform: optional(validateArrayItems(isExternalLinkTransformSpec)), url: optional(isRegExp), domain: optional(isRegExp), pathname: optional(isRegExp), @@ -79,7 +94,7 @@ export const isExternalLinkSpec = handle: optional(isExternalLinkExtractSpec), // TODO: This should validate each value with isExternalLinkExtractSpec. - custom: optional(isObject), + custom: optional(validateAllPropertyValues(isExternalLinkExtractSpec)), })); export const fallbackDescriptor = { @@ -267,6 +282,44 @@ export const externalLinkSpec = [ icon: 'deviantart', }, + { + match: { + domain: 'mspaintadventures.fandom.com', + pathname: /^wiki\/(.+)\/?$/, + }, + + platform: 'fandom', + substring: 'mspaintadventures.page', + + normal: 'custom', + icon: 'globe', + + custom: { + page: { + pathname: /^wiki\/(.+)\/?$/, + transform: [ + {command: 'decode-uri'}, + {command: 'find-replace', find: /_/g, replace: ' '}, + ], + }, + }, + }, + + { + match: {domain: 'mspaintadventures.fandom.com'}, + + platform: 'fandom', + substring: 'mspaintadventures', + + icon: 'globe', + }, + + { + match: {domain: 'fandom.com'}, + platform: 'fandom', + icon: 'globe', + }, + { match: {domain: 'homestuck.com'}, platform: 'homestuck', @@ -422,6 +475,7 @@ export function extractPartFromExternalLink(url, extract) { let regexen = []; let tests = []; + let transform = []; let prefix = ''; if (extract instanceof RegExp) { @@ -434,6 +488,32 @@ export function extractPartFromExternalLink(url, extract) { prefix = value; continue; + case 'transform': + for (const entry of value) { + const command = + (typeof entry === 'string' + ? command + : entry.command); + + const options = + (typeof entry === 'string' + ? {} + : entry); + + switch (command) { + case 'decode-uri': + transform.push(value => + decodeURIComponent(value)); + break; + + case 'find-replace': + transform.push(value => + value.replace(options.find, options.replace)); + break; + } + } + continue; + case 'url': tests.push(url); break; @@ -459,17 +539,27 @@ export function extractPartFromExternalLink(url, extract) { } } + let value; for (const {regex, test} of stitchArrays({ regex: regexen, test: tests, })) { const match = test.match(regex); if (match) { - return prefix + (match[1] ?? match[0]); + value = prefix + (match[1] ?? match[0]); + break; } } - return null; + if (!value) { + return null; + } + + for (const fn of transform) { + value = fn(value); + } + + return value; } export function extractAllCustomPartsFromExternalLink(url, custom) { diff --git a/tap-snapshots/test/snapshot/linkExternal.js.test.cjs b/tap-snapshots/test/snapshot/linkExternal.js.test.cjs index a9116be4..1327ba02 100644 --- a/tap-snapshots/test/snapshot/linkExternal.js.test.cjs +++ b/tap-snapshots/test/snapshot/linkExternal.js.test.cjs @@ -64,6 +64,12 @@ exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > context buzinkai.newgrounds.com music.solatrus.com types.pl +community.fandom.com +community.fandom.com +community.fandom.com +mspaintadventures.fandom.com +mspaintadventures.fandom.com +mspaintadventures.fandom.com ` exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > context: generic, style: normal 1`] = ` @@ -80,6 +86,12 @@ exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > context Newgrounds Bandcamp (music.solatrus.com) Mastodon (types.pl) +Fandom +Fandom +Fandom +MSPA Wiki +MSPA Wiki +MSPA Wiki (Draconian Dignitary) ` exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > context: generic, style: platform 1`] = ` @@ -96,6 +108,12 @@ exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > context Newgrounds Bandcamp Mastodon +Fandom +Fandom +Fandom +Fandom +Fandom +Fandom ` exports[`test/snapshot/linkExternal.js > TAP > linkExternal (snapshot) > unknown domain (arbitrary world wide web path) 1`] = ` diff --git a/test/snapshot/linkExternal.js b/test/snapshot/linkExternal.js index 434372a9..92cb8947 100644 --- a/test/snapshot/linkExternal.js +++ b/test/snapshot/linkExternal.js @@ -42,6 +42,13 @@ testContentFunctions(t, 'linkExternal (snapshot)', async (t, evaluate) => { // Just one custom domain of each platform is OK here 'https://music.solatrus.com/', 'https://types.pl/', + + 'https://community.fandom.com/', + 'https://community.fandom.com/wiki/', + 'https://community.fandom.com/wiki/Community_Central', + 'https://mspaintadventures.fandom.com/', + 'https://mspaintadventures.fandom.com/wiki/', + 'https://mspaintadventures.fandom.com/wiki/Draconian_Dignitary', ]); quickSnapshotAllStyles('album', [ -- cgit 1.3.0-6-gf8a5