From f5309a3219fdad197a763451b961fa9f23637c6d Mon Sep 17 00:00:00 2001 From: Michael Kelly Date: Mon, 8 Oct 2018 11:02:20 -0700 Subject: [PATCH] Split extraction methods and ensure they return null when no match is found. Open Graph and selector-based extraction are now separate forms of extraction instead of a single, "fallback" extraction method. --- src/extraction/index.js | 36 +++++++++++++++---- src/extraction/open_graph.js | 33 +++++++++++++++++ .../{fallback => selector}/index.js | 30 +++++++--------- .../{fallback => selector}/selectors.js | 0 4 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 src/extraction/open_graph.js rename src/extraction/{fallback => selector}/index.js (72%) rename src/extraction/{fallback => selector}/selectors.js (100%) diff --git a/src/extraction/index.js b/src/extraction/index.js index 1391a9a..046f383 100644 --- a/src/extraction/index.js +++ b/src/extraction/index.js @@ -10,18 +10,42 @@ import config from 'commerce/config/content'; import extractProductWithFathom from 'commerce/extraction/fathom'; -import extractProductWithFallback from 'commerce/extraction/fallback'; +import extractProductWithFallback from 'commerce/extraction/selector'; +import extractProductWithOpenGraph from 'commerce/extraction/open_graph'; + +/** + * Extraction methods are given the document object for the page, and must + * return either a valid ExtractedProduct, or null if a valid product could not + * be found. + */ +const EXTRACTION_METHODS = [ + extractProductWithFathom, + extractProductWithFallback, + extractProductWithOpenGraph, +]; + +/** + * Perform product extraction, trying each method from EXTRACTION_METHODS in + * order until one of them returns a truthy result. + * @return {ExtractedProduct|null} + */ +function extractProduct() { + for (const extract of EXTRACTION_METHODS) { + const extractedProduct = extract(window.document); + if (extractedProduct) { + return extractedProduct; + } + } + + return null; +} /** * Checks to see if any product information for the page was found, * and if so, sends it to the background script. */ async function attemptExtraction() { - const extractedProduct = ( - extractProductWithFathom(window.document) - || extractProductWithFallback() - ); - + const extractedProduct = extractProduct(); if (extractedProduct) { await browser.runtime.sendMessage({ from: 'content', diff --git a/src/extraction/open_graph.js b/src/extraction/open_graph.js new file mode 100644 index 0000000..144f7fc --- /dev/null +++ b/src/extraction/open_graph.js @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Product extraction via Open Graph tags. + */ + +const OPEN_GRAPH_PROPERTY_VALUES = { + title: 'og:title', + image: 'og:image', + price: 'og:price:amount', +}; + +/** + * Returns any product information available on the page from Open Graph + * tags. + */ +export default function extractProduct() { + const extractedProduct = {}; + for (const [feature, propertyValue] of Object.entries(OPEN_GRAPH_PROPERTY_VALUES)) { + const metaEle = document.querySelector(`meta[property='${propertyValue}']`); + + // Fail early if any required tags aren't found. + if (!metaEle) { + return null; + } + + extractedProduct[feature] = metaEle.getAttribute('content'); + } + + return extractedProduct; +} diff --git a/src/extraction/fallback/index.js b/src/extraction/selector/index.js similarity index 72% rename from src/extraction/fallback/index.js rename to src/extraction/selector/index.js index 6dee32d..ccd87bb 100644 --- a/src/extraction/fallback/index.js +++ b/src/extraction/selector/index.js @@ -10,14 +10,7 @@ * Features: title, image, price */ -import extractionData from 'commerce/extraction/fallback/selectors'; - - -const OPEN_GRAPH_PROPERTY_VALUES = { - title: 'og:title', - image: 'og:image', - price: 'og:price:amount', -}; +import extractionData from 'commerce/extraction/selector/selectors'; /** * Returns any extraction data found for the vendor based on the URL @@ -54,22 +47,23 @@ function findValue(extractors) { /** * Returns any product information available on the page from CSS - * selectors if they exist, otherwise from Open Graph tags. + * selectors if they exist. */ export default function extractProduct() { - const extractedProduct = {}; const featureInfo = getFeatureInfo(); if (featureInfo) { + const extractedProduct = {}; for (const [feature, extractors] of Object.entries(featureInfo)) { - extractedProduct[feature] = findValue(extractors); - } - } else { - for (const [feature, propertyValue] of Object.entries(OPEN_GRAPH_PROPERTY_VALUES)) { - const metaEle = document.querySelector(`meta[property='${propertyValue}']`); - if (metaEle) { - extractedProduct[feature] = metaEle.getAttribute('content'); + const featureValue = findValue(extractors); + if (!featureValue) { + return null; } + + extractedProduct[feature] = featureValue; } + + return extractedProduct; } - return extractedProduct; + + return null; } diff --git a/src/extraction/fallback/selectors.js b/src/extraction/selector/selectors.js similarity index 100% rename from src/extraction/fallback/selectors.js rename to src/extraction/selector/selectors.js