Просмотр исходного кода

Refactoring: Rename dotpath into dotnotation (#6369)

* KIND_JSON_DOTPATH -> KIND_JSON_DOTNOTATION

* TYPE_JSON_DOTPATH => TYPE_JSON_DOTNOTATION

* json_dotpath => json_dotnotation

* dotPathsForStandardJsonFeed => dotNotationForStandardJsonFeed

* TYPE_JSON_DOTNOTATION = 'JSON+DotPath' => 'JSON+DotNotation'

* documentation: OPML.md

* convertJsonToRss()

* $dotpaths => $dotnotations

* FreshRSS_Feed_Exception

* comment

* Compatibility TYPE_JSON_DOTPATH

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
maTh 1 год назад
Родитель
Сommit
154a36700c

+ 4 - 4
app/Controllers/feedController.php

@@ -259,7 +259,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
 				if (!empty($xPathSettings)) {
 					$attributes['xpath'] = $xPathSettings;
 				}
-			} elseif ($feed_kind === FreshRSS_Feed::KIND_JSON_DOTPATH) {
+			} elseif ($feed_kind === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
 				$jsonSettings = [];
 				if (Minz_Request::paramString('jsonFeedTitle') !== '') {
 					$jsonSettings['feedTitle'] = Minz_Request::paramString('jsonFeedTitle', true);
@@ -295,7 +295,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
 					$jsonSettings['itemUid'] = Minz_Request::paramString('jsonItemUid', true);
 				}
 				if (!empty($jsonSettings)) {
-					$attributes['json_dotpath'] = $jsonSettings;
+					$attributes['json_dotnotation'] = $jsonSettings;
 				}
 			}
 
@@ -497,10 +497,10 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
 					if ($simplePie === null) {
 						throw new FreshRSS_Feed_Exception('XML+XPath parsing failed for [' . $feed->url(false) . ']');
 					}
-				} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
+				} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
 					$simplePie = $feed->loadJson();
 					if ($simplePie === null) {
-						throw new FreshRSS_Feed_Exception('JSON dotpath parsing failed for [' . $feed->url(false) . ']');
+						throw new FreshRSS_Feed_Exception('JSON dot notation parsing failed for [' . $feed->url(false) . ']');
 					}
 				} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSONFEED) {
 					$simplePie = $feed->loadJson();

+ 2 - 2
app/Controllers/subscriptionController.php

@@ -238,7 +238,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
 					$xPathSettings['itemUid'] = Minz_Request::paramString('xPathItemUid', true);
 				if (!empty($xPathSettings))
 					$feed->_attribute('xpath', $xPathSettings);
-			} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
+			} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
 				$jsonSettings = [];
 				if (Minz_Request::paramString('jsonFeedTitle') !== '') {
 					$jsonSettings['feedTitle'] = Minz_Request::paramString('jsonFeedTitle', true);
@@ -274,7 +274,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
 					$jsonSettings['itemUid'] = Minz_Request::paramString('jsonItemUid', true);
 				}
 				if (!empty($jsonSettings)) {
-					$feed->_attribute('json_dotpath', $jsonSettings);
+					$feed->_attribute('json_dotnotation', $jsonSettings);
 				}
 			}
 

+ 6 - 6
app/Models/Feed.php

@@ -31,7 +31,7 @@ class FreshRSS_Feed extends Minz_Model {
 	public const KIND_JSON_XPATH = 20;
 
 	public const KIND_JSONFEED = 25;
-	public const KIND_JSON_DOTPATH = 30;
+	public const KIND_JSON_DOTNOTATION = 30;
 
 	public const PRIORITY_IMPORTANT = 20;
 	public const PRIORITY_MAIN_STREAM = 10;
@@ -621,7 +621,7 @@ class FreshRSS_Feed extends Minz_Model {
 	}
 
 	/** @return array<string,string> */
-	private function dotPathsForStandardJsonFeed(): array {
+	private function dotNotationForStandardJsonFeed(): array {
 		return [
 			'feedTitle' => 'title',
 			'item' => 'items',
@@ -662,11 +662,11 @@ class FreshRSS_Feed extends Minz_Model {
 			return null;
 		}
 
-		/** @var array<string,string> $json_dotpath */
-		$json_dotpath = $this->attributeArray('json_dotpath') ?? [];
-		$dotPaths = $this->kind() === FreshRSS_Feed::KIND_JSONFEED ? $this->dotPathsForStandardJsonFeed() : $json_dotpath;
+		/** @var array<string,string> $json_dotnotation */
+		$json_dotnotation = $this->attributeArray('json_dotnotation') ?? [];
+		$dotnotations = $this->kind() === FreshRSS_Feed::KIND_JSONFEED ? $this->dotNotationForStandardJsonFeed() : $json_dotnotation;
 
-		$feedContent = FreshRSS_dotNotation_Util::convertJsonToRss($jf, $feedSourceUrl, $dotPaths, $this->name());
+		$feedContent = FreshRSS_dotNotation_Util::convertJsonToRss($jf, $feedSourceUrl, $dotnotations, $this->name());
 		if ($feedContent == null) {
 			return null;
 		}

+ 2 - 1
app/Services/ExportService.php

@@ -20,7 +20,8 @@ class FreshRSS_Export_Service {
 	public const TYPE_HTML_XPATH = 'HTML+XPath';
 	public const TYPE_XML_XPATH = 'XML+XPath';
 	public const TYPE_RSS_ATOM = 'rss';
-	public const TYPE_JSON_DOTPATH = 'JSON+DotPath';
+	public const TYPE_JSON_DOTPATH = 'JSON+DotPath';	// Legacy 1.24.0-dev
+	public const TYPE_JSON_DOTNOTATION = 'JSON+DotNotation';
 	public const TYPE_JSONFEED = 'JSONFeed';
 
 	/**

+ 3 - 2
app/Services/ImportService.php

@@ -161,8 +161,9 @@ class FreshRSS_Import_Service {
 				case strtolower(FreshRSS_Export_Service::TYPE_XML_XPATH):
 					$feed->_kind(FreshRSS_Feed::KIND_XML_XPATH);
 					break;
+				case strtolower(FreshRSS_Export_Service::TYPE_JSON_DOTNOTATION):
 				case strtolower(FreshRSS_Export_Service::TYPE_JSON_DOTPATH):
-					$feed->_kind(FreshRSS_Feed::KIND_JSON_DOTPATH);
+					$feed->_kind(FreshRSS_Feed::KIND_JSON_DOTNOTATION);
 					break;
 				case strtolower(FreshRSS_Export_Service::TYPE_JSONFEED):
 					$feed->_kind(FreshRSS_Feed::KIND_JSONFEED);
@@ -254,7 +255,7 @@ class FreshRSS_Import_Service {
 				$jsonSettings['itemUid'] = $feed_elt['frss:jsonItemUid'];
 			}
 			if (!empty($jsonSettings)) {
-				$feed->_attribute('json_dotpath', $jsonSettings);
+				$feed->_attribute('json_dotnotation', $jsonSettings);
 			}
 
 			$curl_params = [];

+ 29 - 29
app/Utils/dotNotationUtil.php

@@ -97,11 +97,11 @@ final class FreshRSS_dotNotation_Util
 	 *
 	 * @param array<string> $jf json feed
 	 * @param string $feedSourceUrl the source URL for the feed
-	 * @param array<string,string> $dotPaths dot paths to map JSON into RSS
-	 * @param string $defaultRssTitle Default title of the RSS feed, if not already provided in dotPath `feedTitle`
+	 * @param array<string,string> $dotNotation dot notation to map JSON into RSS
+	 * @param string $defaultRssTitle Default title of the RSS feed, if not already provided in dotNotation `feedTitle`
 	 */
-	public static function convertJsonToRss(array $jf, string $feedSourceUrl, array $dotPaths, string $defaultRssTitle = ''): ?string {
-		if (!isset($dotPaths['item']) || $dotPaths['item'] === '') {
+	public static function convertJsonToRss(array $jf, string $feedSourceUrl, array $dotNotation, string $defaultRssTitle = ''): ?string {
+		if (!isset($dotNotation['item']) || $dotNotation['item'] === '') {
 			return null; //no definition of item path, but we can't scrape anything without knowing this
 		}
 
@@ -112,40 +112,40 @@ final class FreshRSS_dotNotation_Util
 		$view->html_url = $view->rss_url;
 		$view->entries = [];
 
-		$view->rss_title = isset($dotPaths['feedTitle'])
-			? (htmlspecialchars(FreshRSS_dotNotation_Util::getString($jf, $dotPaths['feedTitle']) ?? '', ENT_COMPAT, 'UTF-8') ?: $defaultRssTitle)
+		$view->rss_title = isset($dotNotation['feedTitle'])
+			? (htmlspecialchars(FreshRSS_dotNotation_Util::getString($jf, $dotNotation['feedTitle']) ?? '', ENT_COMPAT, 'UTF-8') ?: $defaultRssTitle)
 			: $defaultRssTitle;
 
-		$jsonItems = FreshRSS_dotNotation_Util::get($jf, $dotPaths['item']);
+		$jsonItems = FreshRSS_dotNotation_Util::get($jf, $dotNotation['item']);
 		if (!is_array($jsonItems) || count($jsonItems) === 0) {
 			return null;
 		}
 
 		foreach ($jsonItems as $jsonItem) {
 			$rssItem = [];
-			$rssItem['link'] = isset($dotPaths['itemUri']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemUri']) ?? '' : '';
+			$rssItem['link'] = isset($dotNotation['itemUri']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemUri']) ?? '' : '';
 			if (empty($rssItem['link'])) {
 				continue;
 			}
-			$rssItem['title'] = isset($dotPaths['itemTitle']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemTitle']) ?? '' : '';
-			$rssItem['author'] = isset($dotPaths['itemAuthor']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemAuthor']) ?? '' : '';
-			$rssItem['timestamp'] = isset($dotPaths['itemTimestamp']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemTimestamp']) ?? '' : '';
+			$rssItem['title'] = isset($dotNotation['itemTitle']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemTitle']) ?? '' : '';
+			$rssItem['author'] = isset($dotNotation['itemAuthor']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemAuthor']) ?? '' : '';
+			$rssItem['timestamp'] = isset($dotNotation['itemTimestamp']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemTimestamp']) ?? '' : '';
 
 			//get simple content, but if a path for HTML content has been provided, replace the simple content with HTML content
-			$rssItem['content'] = isset($dotPaths['itemContent']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemContent']) ?? '' : '';
-			$rssItem['content'] = isset($dotPaths['itemContentHTML'])
-				? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemContentHTML']) ?? ''
+			$rssItem['content'] = isset($dotNotation['itemContent']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemContent']) ?? '' : '';
+			$rssItem['content'] = isset($dotNotation['itemContentHTML'])
+				? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemContentHTML']) ?? ''
 				: $rssItem['content'];
 
-			if (isset($dotPaths['itemTimeFormat']) && is_string($dotPaths['itemTimeFormat'])) {
-				$dateTime = DateTime::createFromFormat($dotPaths['itemTimeFormat'], $rssItem['timestamp']);
+			if (isset($dotNotation['itemTimeFormat']) && is_string($dotNotation['itemTimeFormat'])) {
+				$dateTime = DateTime::createFromFormat($dotNotation['itemTimeFormat'], $rssItem['timestamp']);
 				if ($dateTime != false) {
 					$rssItem['timestamp'] = $dateTime->format(DateTime::ATOM);
 				}
 			}
 
-			if (isset($dotPaths['itemCategories'])) {
-				$jsonItemCategories = FreshRSS_dotNotation_Util::get($jsonItem, $dotPaths['itemCategories']);
+			if (isset($dotNotation['itemCategories'])) {
+				$jsonItemCategories = FreshRSS_dotNotation_Util::get($jsonItem, $dotNotation['itemCategories']);
 				if (is_string($jsonItemCategories) && $jsonItemCategories !== '') {
 					$rssItem['tags'] = [$jsonItemCategories];
 				} elseif (is_array($jsonItemCategories) && count($jsonItemCategories) > 0) {
@@ -158,31 +158,31 @@ final class FreshRSS_dotNotation_Util
 				}
 			}
 
-			$rssItem['thumbnail'] = isset($dotPaths['itemThumbnail']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemThumbnail']) ?? '' : '';
+			$rssItem['thumbnail'] = isset($dotNotation['itemThumbnail']) ? FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemThumbnail']) ?? '' : '';
 
 			//Enclosures?
-			if (isset($dotPaths['itemAttachment'])) {
-				$jsonItemAttachments = FreshRSS_dotNotation_Util::get($jsonItem, $dotPaths['itemAttachment']);
+			if (isset($dotNotation['itemAttachment'])) {
+				$jsonItemAttachments = FreshRSS_dotNotation_Util::get($jsonItem, $dotNotation['itemAttachment']);
 				if (is_array($jsonItemAttachments) && count($jsonItemAttachments) > 0) {
 					$rssItem['attachments'] = [];
 					foreach ($jsonItemAttachments as $attachment) {
 						$rssAttachment = [];
-						$rssAttachment['url'] = isset($dotPaths['itemAttachmentUrl'])
-							? FreshRSS_dotNotation_Util::getString($attachment, $dotPaths['itemAttachmentUrl'])
+						$rssAttachment['url'] = isset($dotNotation['itemAttachmentUrl'])
+							? FreshRSS_dotNotation_Util::getString($attachment, $dotNotation['itemAttachmentUrl'])
 							: '';
-						$rssAttachment['type'] = isset($dotPaths['itemAttachmentType'])
-							? FreshRSS_dotNotation_Util::getString($attachment, $dotPaths['itemAttachmentType'])
+						$rssAttachment['type'] = isset($dotNotation['itemAttachmentType'])
+							? FreshRSS_dotNotation_Util::getString($attachment, $dotNotation['itemAttachmentType'])
 							: '';
-						$rssAttachment['length'] = isset($dotPaths['itemAttachmentLength'])
-							? FreshRSS_dotNotation_Util::get($attachment, $dotPaths['itemAttachmentLength'])
+						$rssAttachment['length'] = isset($dotNotation['itemAttachmentLength'])
+							? FreshRSS_dotNotation_Util::get($attachment, $dotNotation['itemAttachmentLength'])
 							: '';
 						$rssItem['attachments'][] = $rssAttachment;
 					}
 				}
 			}
 
-			if (isset($dotPaths['itemUid'])) {
-				$rssItem['guid'] = FreshRSS_dotNotation_Util::getString($jsonItem, $dotPaths['itemUid']);
+			if (isset($dotNotation['itemUid'])) {
+				$rssItem['guid'] = FreshRSS_dotNotation_Util::getString($jsonItem, $dotNotation['itemUid']);
 			}
 
 			if (empty($rssItem['guid'])) {

+ 4 - 4
app/views/helpers/export/opml.phtml

@@ -27,8 +27,8 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
 			case FreshRSS_Feed::KIND_XML_XPATH:
 				$outline['type'] = FreshRSS_Export_Service::TYPE_XML_XPATH;
 				break;
-			case FreshRSS_Feed::KIND_JSON_DOTPATH:
-				$outline['type'] = FreshRSS_Export_Service::TYPE_JSON_DOTPATH;
+			case FreshRSS_Feed::KIND_JSON_DOTNOTATION:
+				$outline['type'] = FreshRSS_Export_Service::TYPE_JSON_DOTNOTATION;
 				break;
 			case FreshRSS_Feed::KIND_JSONFEED:
 				$outline['type'] = FreshRSS_Export_Service::TYPE_JSONFEED;
@@ -48,9 +48,9 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
 			$outline['frss:xPathItemThumbnail'] = $xPathSettings['itemThumbnail'] ?? null;
 			$outline['frss:xPathItemCategories'] = $xPathSettings['itemCategories'] ?? null;
 			$outline['frss:xPathItemUid'] = $xPathSettings['itemUid'] ?? null;
-		} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH) {
+		} elseif ($feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION) {
 			/** @var array<string,string> */
-			$jsonSettings = $feed->attributeArray('json_dotpath') ?? [];
+			$jsonSettings = $feed->attributeArray('json_dotnotation') ?? [];
 			$outline['frss:jsonItem'] = $jsonSettings['item'] ?? null;
 			$outline['frss:jsonItemTitle'] = $jsonSettings['itemTitle'] ?? null;
 			$outline['frss:jsonItemContent'] = $jsonSettings['itemContent'] ?? null;

+ 3 - 3
app/views/helpers/feed/update.phtml

@@ -413,7 +413,7 @@
 						<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.html_xpath') ?></option>
 						<option value="<?= FreshRSS_Feed::KIND_XML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_XML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.xml_xpath') ?></option>
 						<option value="<?= FreshRSS_Feed::KIND_JSONFEED ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSONFEED ? 'selected="selected"' : '' ?>><?= _t('sub.feed.kind.jsonfeed') ?></option>
-						<option value="<?= FreshRSS_Feed::KIND_JSON_DOTPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSON_DOTPATH ? 'selected="selected"' : '' ?> data-show="json_dotpath"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
+						<option value="<?= FreshRSS_Feed::KIND_JSON_DOTNOTATION ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION ? 'selected="selected"' : '' ?> data-show="json_dotnotation"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
 					</select>
 				</div>
 			</div>
@@ -514,9 +514,9 @@
 			</div>
 		</fieldset>
 
-		<fieldset id="json_dotpath">
+		<fieldset id="json_dotnotation">
 			<?php
-				$jsonSettings = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('json_dotpath') ?? []);
+				$jsonSettings = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('json_dotnotation') ?? []);
 			?>
 			<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.help') ?></p>
 			<div class="form-group">

+ 2 - 2
app/views/subscription/add.phtml

@@ -72,7 +72,7 @@
 						<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH ?>" data-show="html_xpath"><?= _t('sub.feed.kind.html_xpath') ?></option>
 						<option value="<?= FreshRSS_Feed::KIND_XML_XPATH ?>" data-show="html_xpath"><?= _t('sub.feed.kind.xml_xpath') ?></option>
 						<option value="<?= FreshRSS_Feed::KIND_JSONFEED ?>"><?= _t('sub.feed.kind.jsonfeed') ?></option>
-						<option value="<?= FreshRSS_Feed::KIND_JSON_DOTPATH ?>" data-show="json_dotpath"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
+						<option value="<?= FreshRSS_Feed::KIND_JSON_DOTNOTATION ?>" data-show="json_dotnotation"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
 					</select>
 				</div>
 			</div>
@@ -166,7 +166,7 @@
 					</div>
 				</div>
 			</fieldset>
-			<fieldset id="json_dotpath">
+			<fieldset id="json_dotnotation">
 				<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.help') ?></p>
 				<div class="form-group">
 					<label class="group-name" for="jsonFeedTitle"><small><?= _t('sub.feed.kind.json_dotnotation.json') ?></small><br />

+ 12 - 12
docs/en/developers/OPML.md

@@ -44,28 +44,28 @@ The following attributes are using similar naming conventions than [RSS-Bridge](
 * `frss:xPathItemCategories`: XPath expression for extracting a list of categories (tags) from the item context.
 * `frss:xPathItemUid`: XPath expression for extracting an item’s unique ID from the item context. If left empty, a hash is computed automatically.
 
-### JSON+DotPath
+### JSON+DotNotation
 
-* `<outline type="JSON+DotPath" ...`: Similar to `HTML+XPath` but for JSON and using a dot/bracket syntax such as `object.object.array[2].property`.
+* `<outline type="JSON+DotNotation" ...`: Similar to `HTML+XPath` but for JSON and using a dot/bracket syntax such as `object.object.array[2].property`.
 
-* `frss:jsonItem`: JSON dot path for extracting the feed items from the source page.
+* `frss:jsonItem`: JSON dot notation for extracting the feed items from the source page.
 	* Example: `data.items`
-* `frss:jsonItemTitle`: JSON dot path for extracting the item’s title from the item context.
+* `frss:jsonItemTitle`: JSON dot notation for extracting the item’s title from the item context.
 	* Example: `meta.title`
-* `frss:jsonItemContent`: JSON dot path for extracting an item’s content from the item context.
+* `frss:jsonItemContent`: JSON dot notation for extracting an item’s content from the item context.
 	* Example: `content`
-* `frss:jsonItemUri`: JSON dot path for extracting an item link from the item context.
+* `frss:jsonItemUri`: JSON dot notation for extracting an item link from the item context.
 	* Example: `meta.links[0]`
-* `frss:jsonItemAuthor`: JSON dot path for extracting an item author from the item context.
-* `frss:jsonItemTimestamp`: JSON dot path for extracting an item timestamp from the item context. The result will be parsed by [`strtotime()`](https://php.net/strtotime).
+* `frss:jsonItemAuthor`: JSON dot notation for extracting an item author from the item context.
+* `frss:jsonItemTimestamp`: JSON dot notation for extracting an item timestamp from the item context. The result will be parsed by [`strtotime()`](https://php.net/strtotime).
 * `frss:jsonItemTimeFormat`: Date/Time format to parse the timestamp, according to [`DateTime::createFromFormat()`](https://php.net/datetime.createfromformat).
-* `frss:jsonItemThumbnail`: JSON dot path for extracting an item’s thumbnail (image) URL from the item context.
-* `frss:jsonItemCategories`: JSON dot path for extracting a list of categories (tags) from the item context.
-* `frss:jsonItemUid`: JSON dot path for extracting an item’s unique ID from the item context. If left empty, a hash is computed automatically.
+* `frss:jsonItemThumbnail`: JSON dot notation for extracting an item’s thumbnail (image) URL from the item context.
+* `frss:jsonItemCategories`: JSON dot notation for extracting a list of categories (tags) from the item context.
+* `frss:jsonItemUid`: JSON dot notation for extracting an item’s unique ID from the item context. If left empty, a hash is computed automatically.
 
 ### JSON Feed
 
-* `<outline type="JSONFeed" ...`: Uses `JSON+DotPath` behind the scenes to parse a [JSON Feed](https://www.jsonfeed.org/).
+* `<outline type="JSONFeed" ...`: Uses `JSON+DotNotation` behind the scenes to parse a [JSON Feed](https://www.jsonfeed.org/).
 
 ### cURL