From 66c9a780f055ebe987d29301b6d7b0356f06e234 Mon Sep 17 00:00:00 2001 From: Vikram Kalta <65945391+vkalta@users.noreply.github.com> Date: Mon, 8 Nov 2021 23:34:36 +0530 Subject: [PATCH 01/12] feat: added support to fetch data for only specified content-types, locales --- .babelrc | 2 +- README.md | 18 +- contenttype-data.js | 292 ++++++++++++++++ entry-data.js | 751 ++++++++++++++++++++++++++++++++++++++++ fetch.js | 183 +++++----- gatsby-node.js | 105 +++--- package.json | 6 +- src/contenttype-data.js | 95 +++++ src/entry-data.js | 219 ++++++++++++ src/fetch.js | 174 ++++------ src/gatsby-node.js | 89 ++--- src/utils.js | 19 + utils.js | 23 ++ 13 files changed, 1636 insertions(+), 340 deletions(-) create mode 100644 contenttype-data.js create mode 100644 entry-data.js create mode 100644 src/contenttype-data.js create mode 100644 src/entry-data.js diff --git a/.babelrc b/.babelrc index 8253fda..e6f5ede 100644 --- a/.babelrc +++ b/.babelrc @@ -5,7 +5,7 @@ "@babel/preset-env", { "targets": { - "node": 14.15 + "node": 12.13 }, "forceAllTransforms": true } diff --git a/README.md b/README.md index 91612eb..8789e1c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,23 @@ plugins: [ type_prefix: `Contentstack`, // (default) // Optional: Specify true if you want to download all your contentstack images locally - downloadImages: `boolean_value` + downloadImages: `boolean_value`, + + // Optional: Specify the content types from which you want the plugin to retrieve data. + contentTypes: [‘blog’,’author’] + // This will fetch the data of the ‘blog’ and ‘author’ content types only. + + // Optional: Specify the content types that the plugin should exclude while fetching data of all content types. + excludeContentTypes: [‘home’,’about’] + // This will fetch the data of all the available content types excluding the ‘home’ and ‘about’ content types. + + // Note: Only one of the above options should be used to fetch data. If you add both options to fetch all contentTypes and excludeContentTypes, than only one of the query gets executed. + + // Optional: Include the locales that you want the plugin to fetch data from. + locales: [‘en-us’,’fr-fr’] + // In this case, the plugin will fetch only English (United States) and French (France) language data. + + // Optional: Specify the content types and locales of which you want the plugin to retrieve data. }, }, ] diff --git a/contenttype-data.js b/contenttype-data.js new file mode 100644 index 0000000..7662c7c --- /dev/null +++ b/contenttype-data.js @@ -0,0 +1,292 @@ +'use strict'; + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); + +var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); + +var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); + +var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); + +var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); + +var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); + +var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); + +var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); + +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } + +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } + +var FetchContentTypes = /*#__PURE__*/function () { + function FetchContentTypes() { + (0, _classCallCheck2["default"])(this, FetchContentTypes); + } + + (0, _createClass2["default"])(FetchContentTypes, [{ + key: "getPagedData", + value: function () { + var _getPagedData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { + return _regenerator["default"].wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + case "end": + return _context.stop(); + } + } + }, _callee); + })); + + function getPagedData() { + return _getPagedData.apply(this, arguments); + } + + return getPagedData; + }() + }]); + return FetchContentTypes; +}(); + +var FetchDefaultContentTypes = /*#__PURE__*/function (_FetchContentTypes) { + (0, _inherits2["default"])(FetchDefaultContentTypes, _FetchContentTypes); + + var _super = _createSuper(FetchDefaultContentTypes); + + function FetchDefaultContentTypes() { + (0, _classCallCheck2["default"])(this, FetchDefaultContentTypes); + return _super.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchDefaultContentTypes, [{ + key: "getPagedData", + value: function () { + var _getPagedData2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(url, config, responseKey, fn) { + var query, result; + return _regenerator["default"].wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + query = { + include_global_field_schema: true + }; + _context2.next = 3; + return fn.apply(null, [url, config, responseKey, query]); + + case 3: + result = _context2.sent; + return _context2.abrupt("return", result); + + case 5: + case "end": + return _context2.stop(); + } + } + }, _callee2); + })); + + function getPagedData(_x, _x2, _x3, _x4) { + return _getPagedData2.apply(this, arguments); + } + + return getPagedData; + }() + }]); + return FetchDefaultContentTypes; +}(FetchContentTypes); + +var FetchSpecifiedContentTypes = /*#__PURE__*/function (_FetchContentTypes2) { + (0, _inherits2["default"])(FetchSpecifiedContentTypes, _FetchContentTypes2); + + var _super2 = _createSuper(FetchSpecifiedContentTypes); + + function FetchSpecifiedContentTypes() { + (0, _classCallCheck2["default"])(this, FetchSpecifiedContentTypes); + return _super2.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchSpecifiedContentTypes, [{ + key: "getPagedData", + value: function () { + var _getPagedData3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(url, config, responseKey, fn) { + var query, contentTypes, referredContentTypes, referredContentTypesList, referredContentTypesData, result; + return _regenerator["default"].wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + query = { + query: JSON.stringify({ + uid: { + $in: config.contentTypes + } + }), + include_global_field_schema: true + }; + _context3.next = 3; + return fn.apply(null, [url, config, responseKey, query]); + + case 3: + contentTypes = _context3.sent; + referredContentTypes = new ReferredContentTypes(); + referredContentTypesList = referredContentTypes.getReferredContentTypes(contentTypes); + referredContentTypesData = []; + + if (!referredContentTypesList.length) { + _context3.next = 12; + break; + } + + query.query = JSON.stringify({ + uid: { + $in: referredContentTypesList + } + }); + _context3.next = 11; + return fn.apply(null, [url, config, responseKey, query]); + + case 11: + referredContentTypesData = _context3.sent; + + case 12: + result = contentTypes.concat(referredContentTypesData); + return _context3.abrupt("return", result); + + case 14: + case "end": + return _context3.stop(); + } + } + }, _callee3); + })); + + function getPagedData(_x5, _x6, _x7, _x8) { + return _getPagedData3.apply(this, arguments); + } + + return getPagedData; + }() + }]); + return FetchSpecifiedContentTypes; +}(FetchContentTypes); + +var FetchUnspecifiedContentTypes = /*#__PURE__*/function (_FetchContentTypes3) { + (0, _inherits2["default"])(FetchUnspecifiedContentTypes, _FetchContentTypes3); + + var _super3 = _createSuper(FetchUnspecifiedContentTypes); + + function FetchUnspecifiedContentTypes() { + (0, _classCallCheck2["default"])(this, FetchUnspecifiedContentTypes); + return _super3.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchUnspecifiedContentTypes, [{ + key: "getPagedData", + value: function () { + var _getPagedData4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(url, config, responseKey, fn) { + var query, contentTypes, referredContentTypes, referredContentTypesList, referredContentTypesData, result; + return _regenerator["default"].wrap(function _callee4$(_context4) { + while (1) { + switch (_context4.prev = _context4.next) { + case 0: + query = { + query: JSON.stringify({ + uid: { + $nin: config.excludeContentTypes + } + }), + include_global_field_schema: true + }; + _context4.next = 3; + return fn.apply(null, [url, config, responseKey, query]); + + case 3: + contentTypes = _context4.sent; + referredContentTypes = new ReferredContentTypes(); + referredContentTypesList = referredContentTypes.getReferredContentTypes(contentTypes); + referredContentTypesData = []; + + if (!referredContentTypesList.length) { + _context4.next = 12; + break; + } + + query.query = JSON.stringify({ + uid: { + $in: referredContentTypesList + } + }); + _context4.next = 11; + return fn.apply(null, [url, config, responseKey, query]); + + case 11: + referredContentTypesData = _context4.sent; + + case 12: + result = contentTypes.concat(referredContentTypesData); + return _context4.abrupt("return", result); + + case 14: + case "end": + return _context4.stop(); + } + } + }, _callee4); + })); + + function getPagedData(_x9, _x10, _x11, _x12) { + return _getPagedData4.apply(this, arguments); + } + + return getPagedData; + }() + }]); + return FetchUnspecifiedContentTypes; +}(FetchContentTypes); + +var ReferredContentTypes = /*#__PURE__*/function () { + function ReferredContentTypes() { + (0, _classCallCheck2["default"])(this, ReferredContentTypes); + } + + (0, _createClass2["default"])(ReferredContentTypes, [{ + key: "getReferredContentTypes", + value: function getReferredContentTypes(contentTypes) { + var referredContentTypes = {}; + + for (var i = 0; i < contentTypes.length; i++) { + var contentType = contentTypes[i]; + + for (var j = 0; j < contentType.schema.length; j++) { + var schema = contentType.schema[j]; + + if (schema.data_type === 'reference') { + for (var k = 0; k < schema.reference_to.length; k++) { + // Keep unique values only. + referredContentTypes[schema.reference_to[k]] = null; + } + } + } + } // Remove the content-types if they were already fetched. + + + for (var _i = 0; _i < contentTypes.length; _i++) { + var _contentType = contentTypes[_i].uid; + var keys = Object.keys(referredContentTypes); + + if (keys.includes(_contentType)) { + delete referredContentTypes[_contentType]; + } + } + + return Object.keys(referredContentTypes); + } + }]); + return ReferredContentTypes; +}(); + +exports.FetchContentTypes = FetchContentTypes; +exports.FetchDefaultContentTypes = FetchDefaultContentTypes; +exports.FetchSpecifiedContentTypes = FetchSpecifiedContentTypes; +exports.FetchUnspecifiedContentTypes = FetchUnspecifiedContentTypes; \ No newline at end of file diff --git a/entry-data.js b/entry-data.js new file mode 100644 index 0000000..9402b75 --- /dev/null +++ b/entry-data.js @@ -0,0 +1,751 @@ +'use strict'; + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); + +var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); + +var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); + +var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); + +var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); + +var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); + +var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); + +var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); + +var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); + +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } + +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } + +var FetchEntries = /*#__PURE__*/function () { + function FetchEntries() { + (0, _classCallCheck2["default"])(this, FetchEntries); + } + + (0, _createClass2["default"])(FetchEntries, [{ + key: "fetchSyncData", + value: function () { + var _fetchSyncData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { + return _regenerator["default"].wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + case "end": + return _context.stop(); + } + } + }, _callee); + })); + + function fetchSyncData() { + return _fetchSyncData.apply(this, arguments); + } + + return fetchSyncData; + }() + }]); + return FetchEntries; +}(); + +var FetchDefaultEntries = /*#__PURE__*/function (_FetchEntries) { + (0, _inherits2["default"])(FetchDefaultEntries, _FetchEntries); + + var _super = _createSuper(FetchDefaultEntries); + + function FetchDefaultEntries() { + (0, _classCallCheck2["default"])(this, FetchDefaultEntries); + return _super.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchDefaultEntries, [{ + key: "fetchSyncData", + value: function () { + var _fetchSyncData2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(configOptions, cache, fn) { + var typePrefix, syncData, entryTokenKey, assetTokenKey, _yield$Promise$all, _yield$Promise$all2, syncEntryToken, syncAssetToken, syncEntryParams, syncAssetParams, _yield$Promise$all3, _yield$Promise$all4, syncEntryData, syncAssetData, data, tokenKey, syncToken, syncParams; + + return _regenerator["default"].wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + typePrefix = configOptions.type_prefix || 'Contentstack'; + syncData = {}; + _context2.prev = 2; + + if (!configOptions.expediteBuild) { + _context2.next = 28; + break; + } + + entryTokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-entry-").concat(configOptions.api_key); + assetTokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-asset-").concat(configOptions.api_key); + _context2.next = 8; + return Promise.all([cache.get(entryTokenKey), cache.get(assetTokenKey)]); + + case 8: + _yield$Promise$all = _context2.sent; + _yield$Promise$all2 = (0, _slicedToArray2["default"])(_yield$Promise$all, 2); + syncEntryToken = _yield$Promise$all2[0]; + syncAssetToken = _yield$Promise$all2[1]; + syncEntryParams = syncEntryToken ? { + sync_token: syncEntryToken + } : { + init: true + }; + syncAssetParams = syncAssetToken ? { + sync_token: syncAssetToken + } : { + init: true + }; + syncEntryParams.type = 'entry_published,entry_unpublished,entry_deleted'; + syncAssetParams.type = 'asset_published,asset_unpublished,asset_deleted'; + _context2.next = 18; + return Promise.all([fn.apply(null, [syncEntryParams, configOptions]), fn.apply(null, [syncAssetParams, configOptions])]); + + case 18: + _yield$Promise$all3 = _context2.sent; + _yield$Promise$all4 = (0, _slicedToArray2["default"])(_yield$Promise$all3, 2); + syncEntryData = _yield$Promise$all4[0]; + syncAssetData = _yield$Promise$all4[1]; + data = syncEntryData.data.concat(syncAssetData.data); + syncData.data = data; + _context2.next = 26; + return Promise.all([cache.set(entryTokenKey, syncEntryData.sync_token), cache.set(assetTokenKey, syncAssetData.sync_token)]); + + case 26: + _context2.next = 38; + break; + + case 28: + tokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-").concat(configOptions.api_key); + _context2.next = 31; + return cache.get(tokenKey); + + case 31: + syncToken = _context2.sent; + syncParams = syncToken ? { + sync_token: syncToken + } : { + init: true + }; + _context2.next = 35; + return fn.apply(null, [syncParams, configOptions]); + + case 35: + syncData = _context2.sent; + _context2.next = 38; + return cache.set(tokenKey, syncData.sync_token); + + case 38: + _context2.next = 43; + break; + + case 40: + _context2.prev = 40; + _context2.t0 = _context2["catch"](2); + throw _context2.t0; + + case 43: + return _context2.abrupt("return", syncData); + + case 44: + case "end": + return _context2.stop(); + } + } + }, _callee2, null, [[2, 40]]); + })); + + function fetchSyncData(_x, _x2, _x3) { + return _fetchSyncData2.apply(this, arguments); + } + + return fetchSyncData; + }() + }]); + return FetchDefaultEntries; +}(FetchEntries); + +var FetchSpecifiedContentTypesEntries = /*#__PURE__*/function (_FetchEntries2) { + (0, _inherits2["default"])(FetchSpecifiedContentTypesEntries, _FetchEntries2); + + var _super2 = _createSuper(FetchSpecifiedContentTypesEntries); + + function FetchSpecifiedContentTypesEntries() { + (0, _classCallCheck2["default"])(this, FetchSpecifiedContentTypesEntries); + return _super2.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchSpecifiedContentTypesEntries, [{ + key: "fetchSyncData", + value: function () { + var _fetchSyncData3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(configOptions, cache, fn) { + var _yield$Promise$all5, _yield$Promise$all6, syncEntryData, syncAssetData, syncData; + + return _regenerator["default"].wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + _context3.prev = 0; + _context3.next = 3; + return Promise.all([this.fetchEntries(configOptions, cache, fn), this.fetchAssets(configOptions, cache, fn)]); + + case 3: + _yield$Promise$all5 = _context3.sent; + _yield$Promise$all6 = (0, _slicedToArray2["default"])(_yield$Promise$all5, 2); + syncEntryData = _yield$Promise$all6[0]; + syncAssetData = _yield$Promise$all6[1]; + syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return _context3.abrupt("return", syncData); + + case 12: + _context3.prev = 12; + _context3.t0 = _context3["catch"](0); + throw _context3.t0; + + case 15: + case "end": + return _context3.stop(); + } + } + }, _callee3, this, [[0, 12]]); + })); + + function fetchSyncData(_x4, _x5, _x6) { + return _fetchSyncData3.apply(this, arguments); + } + + return fetchSyncData; + }() + }, { + key: "fetchEntries", + value: function () { + var _fetchEntries = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(configOptions, cache, fn) { + var syncData, typePrefix, contentTypes, i, contentType, tokenKey, syncToken, syncParams, _syncData; + + return _regenerator["default"].wrap(function _callee4$(_context4) { + while (1) { + switch (_context4.prev = _context4.next) { + case 0: + _context4.prev = 0; + syncData = {}; + typePrefix = configOptions.type_prefix || 'Contentstack'; + _context4.next = 5; + return cache.get(typePrefix); + + case 5: + contentTypes = _context4.sent; + i = 0; + + case 7: + if (!(i < contentTypes.length)) { + _context4.next = 25; + break; + } + + contentType = contentTypes[i].uid; + tokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-").concat(contentType, "-").concat(configOptions.api_key); + _context4.next = 12; + return cache.get(tokenKey); + + case 12: + syncToken = _context4.sent; + syncParams = syncToken ? { + sync_token: syncToken + } : { + init: true + }; + syncParams.content_type_uid = contentType; + _context4.next = 17; + return fn.apply(null, [syncParams, configOptions]); + + case 17: + _syncData = _context4.sent; + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); // Caching token for the next sync. + + _context4.next = 22; + return cache.set(tokenKey, _syncData.sync_token); + + case 22: + i++; + _context4.next = 7; + break; + + case 25: + return _context4.abrupt("return", syncData); + + case 28: + _context4.prev = 28; + _context4.t0 = _context4["catch"](0); + throw _context4.t0; + + case 31: + case "end": + return _context4.stop(); + } + } + }, _callee4, null, [[0, 28]]); + })); + + function fetchEntries(_x7, _x8, _x9) { + return _fetchEntries.apply(this, arguments); + } + + return fetchEntries; + }() + }, { + key: "fetchAssets", + value: function () { + var _fetchAssets = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(configOptions, cache, fn) { + var fetchAssetService, syncData; + return _regenerator["default"].wrap(function _callee5$(_context5) { + while (1) { + switch (_context5.prev = _context5.next) { + case 0: + _context5.prev = 0; + fetchAssetService = new FetchAssets(); + _context5.next = 4; + return fetchAssetService.fetchAssets(configOptions, cache, fn); + + case 4: + syncData = _context5.sent; + return _context5.abrupt("return", syncData); + + case 8: + _context5.prev = 8; + _context5.t0 = _context5["catch"](0); + throw _context5.t0; + + case 11: + case "end": + return _context5.stop(); + } + } + }, _callee5, null, [[0, 8]]); + })); + + function fetchAssets(_x10, _x11, _x12) { + return _fetchAssets.apply(this, arguments); + } + + return fetchAssets; + }() + }]); + return FetchSpecifiedContentTypesEntries; +}(FetchEntries); + +var FetchSpecifiedLocalesEntries = /*#__PURE__*/function (_FetchEntries3) { + (0, _inherits2["default"])(FetchSpecifiedLocalesEntries, _FetchEntries3); + + var _super3 = _createSuper(FetchSpecifiedLocalesEntries); + + function FetchSpecifiedLocalesEntries() { + (0, _classCallCheck2["default"])(this, FetchSpecifiedLocalesEntries); + return _super3.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchSpecifiedLocalesEntries, [{ + key: "fetchSyncData", + value: function () { + var _fetchSyncData4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(configOptions, cache, fn) { + var _yield$Promise$all7, _yield$Promise$all8, syncEntryData, syncAssetData, syncData; + + return _regenerator["default"].wrap(function _callee6$(_context6) { + while (1) { + switch (_context6.prev = _context6.next) { + case 0: + _context6.next = 2; + return Promise.all([this.fetchEntries(configOptions, cache, fn), this.fetchAssets(configOptions, cache, fn)]); + + case 2: + _yield$Promise$all7 = _context6.sent; + _yield$Promise$all8 = (0, _slicedToArray2["default"])(_yield$Promise$all7, 2); + syncEntryData = _yield$Promise$all8[0]; + syncAssetData = _yield$Promise$all8[1]; + syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return _context6.abrupt("return", syncData); + + case 9: + case "end": + return _context6.stop(); + } + } + }, _callee6, this); + })); + + function fetchSyncData(_x13, _x14, _x15) { + return _fetchSyncData4.apply(this, arguments); + } + + return fetchSyncData; + }() + }, { + key: "fetchEntries", + value: function () { + var _fetchEntries2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(configOptions, cache, fn) { + var syncData, typePrefix, locales, i, locale, tokenKey, syncToken, syncParams, _syncData; + + return _regenerator["default"].wrap(function _callee7$(_context7) { + while (1) { + switch (_context7.prev = _context7.next) { + case 0: + _context7.prev = 0; + syncData = {}; + typePrefix = configOptions.type_prefix || 'Contentstack'; + locales = configOptions.locales; + i = 0; + + case 5: + if (!(i < locales.length)) { + _context7.next = 23; + break; + } + + locale = locales[i]; + tokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-").concat(locale, "-").concat(configOptions.api_key); + _context7.next = 10; + return cache.get(tokenKey); + + case 10: + syncToken = _context7.sent; + syncParams = syncToken ? { + sync_token: syncToken + } : { + init: true + }; + syncParams.locale = locale; + _context7.next = 15; + return fn.apply(null, [syncParams, configOptions]); + + case 15: + _syncData = _context7.sent; + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); // Caching token for next sync + + _context7.next = 20; + return cache.set(tokenKey, _syncData.sync_token); + + case 20: + i++; + _context7.next = 5; + break; + + case 23: + return _context7.abrupt("return", syncData); + + case 26: + _context7.prev = 26; + _context7.t0 = _context7["catch"](0); + throw _context7.t0; + + case 29: + case "end": + return _context7.stop(); + } + } + }, _callee7, null, [[0, 26]]); + })); + + function fetchEntries(_x16, _x17, _x18) { + return _fetchEntries2.apply(this, arguments); + } + + return fetchEntries; + }() + }, { + key: "fetchAssets", + value: function () { + var _fetchAssets2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(configOptions, cache, fn) { + var fetchAssetService, syncData; + return _regenerator["default"].wrap(function _callee8$(_context8) { + while (1) { + switch (_context8.prev = _context8.next) { + case 0: + _context8.prev = 0; + fetchAssetService = new FetchAssets(); + _context8.next = 4; + return fetchAssetService.fetchAssets(configOptions, cache, fn); + + case 4: + syncData = _context8.sent; + return _context8.abrupt("return", syncData); + + case 8: + _context8.prev = 8; + _context8.t0 = _context8["catch"](0); + throw _context8.t0; + + case 11: + case "end": + return _context8.stop(); + } + } + }, _callee8, null, [[0, 8]]); + })); + + function fetchAssets(_x19, _x20, _x21) { + return _fetchAssets2.apply(this, arguments); + } + + return fetchAssets; + }() + }]); + return FetchSpecifiedLocalesEntries; +}(FetchEntries); + +var FetchSpecifiedLocalesAndContentTypesEntries = /*#__PURE__*/function (_FetchEntries4) { + (0, _inherits2["default"])(FetchSpecifiedLocalesAndContentTypesEntries, _FetchEntries4); + + var _super4 = _createSuper(FetchSpecifiedLocalesAndContentTypesEntries); + + function FetchSpecifiedLocalesAndContentTypesEntries() { + (0, _classCallCheck2["default"])(this, FetchSpecifiedLocalesAndContentTypesEntries); + return _super4.apply(this, arguments); + } + + (0, _createClass2["default"])(FetchSpecifiedLocalesAndContentTypesEntries, [{ + key: "fetchSyncData", + value: function () { + var _fetchSyncData5 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9(configOptions, cache, fn) { + var _yield$Promise$all9, _yield$Promise$all10, syncEntryData, syncAssetData, syncData; + + return _regenerator["default"].wrap(function _callee9$(_context9) { + while (1) { + switch (_context9.prev = _context9.next) { + case 0: + _context9.next = 2; + return Promise.all([this.fetchEntries(configOptions, cache, fn), this.fetchAssets(configOptions, cache, fn)]); + + case 2: + _yield$Promise$all9 = _context9.sent; + _yield$Promise$all10 = (0, _slicedToArray2["default"])(_yield$Promise$all9, 2); + syncEntryData = _yield$Promise$all10[0]; + syncAssetData = _yield$Promise$all10[1]; + syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return _context9.abrupt("return", syncData); + + case 9: + case "end": + return _context9.stop(); + } + } + }, _callee9, this); + })); + + function fetchSyncData(_x22, _x23, _x24) { + return _fetchSyncData5.apply(this, arguments); + } + + return fetchSyncData; + }() + }, { + key: "fetchEntries", + value: function () { + var _fetchEntries3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(configOptions, cache, fn) { + var syncData, typePrefix, contentTypes, locales, i, contentType, j, locale, tokenKey, syncToken, syncParams, _syncData; + + return _regenerator["default"].wrap(function _callee10$(_context10) { + while (1) { + switch (_context10.prev = _context10.next) { + case 0: + _context10.prev = 0; + syncData = {}; + typePrefix = configOptions.type_prefix || 'Contentstack'; + _context10.next = 5; + return cache.get(typePrefix); + + case 5: + contentTypes = _context10.sent; + locales = configOptions.locales; + i = 0; + + case 8: + if (!(i < contentTypes.length)) { + _context10.next = 33; + break; + } + + contentType = contentTypes[i].uid; + j = 0; + + case 11: + if (!(j < locales.length)) { + _context10.next = 30; + break; + } + + locale = locales[j]; + tokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-").concat(contentType, "-").concat(locale, "-").concat(configOptions.api_key); + _context10.next = 16; + return cache.get(tokenKey); + + case 16: + syncToken = _context10.sent; + syncParams = syncToken ? { + sync_token: syncToken + } : { + init: true + }; + syncParams.content_type_uid = contentType; + syncParams.locale = locale; + _context10.next = 22; + return fn.apply(null, [syncParams, configOptions]); + + case 22: + _syncData = _context10.sent; + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); // Caching token for next sync + + _context10.next = 27; + return cache.set(tokenKey, _syncData.sync_token); + + case 27: + j++; + _context10.next = 11; + break; + + case 30: + i++; + _context10.next = 8; + break; + + case 33: + return _context10.abrupt("return", syncData); + + case 36: + _context10.prev = 36; + _context10.t0 = _context10["catch"](0); + throw _context10.t0; + + case 39: + case "end": + return _context10.stop(); + } + } + }, _callee10, null, [[0, 36]]); + })); + + function fetchEntries(_x25, _x26, _x27) { + return _fetchEntries3.apply(this, arguments); + } + + return fetchEntries; + }() + }, { + key: "fetchAssets", + value: function () { + var _fetchAssets3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11(configOptions, cache, fn) { + var fetchAssetService, syncData; + return _regenerator["default"].wrap(function _callee11$(_context11) { + while (1) { + switch (_context11.prev = _context11.next) { + case 0: + _context11.prev = 0; + fetchAssetService = new FetchAssets(); + _context11.next = 4; + return fetchAssetService.fetchAssets(configOptions, cache, fn); + + case 4: + syncData = _context11.sent; + return _context11.abrupt("return", syncData); + + case 8: + _context11.prev = 8; + _context11.t0 = _context11["catch"](0); + throw _context11.t0; + + case 11: + case "end": + return _context11.stop(); + } + } + }, _callee11, null, [[0, 8]]); + })); + + function fetchAssets(_x28, _x29, _x30) { + return _fetchAssets3.apply(this, arguments); + } + + return fetchAssets; + }() + }]); + return FetchSpecifiedLocalesAndContentTypesEntries; +}(FetchEntries); + +var FetchAssets = /*#__PURE__*/function () { + function FetchAssets() { + (0, _classCallCheck2["default"])(this, FetchAssets); + } + + (0, _createClass2["default"])(FetchAssets, [{ + key: "fetchAssets", + value: function () { + var _fetchAssets4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(configOptions, cache, fn) { + var typePrefix, syncData, assetTokenKey, syncAssetToken, syncAssetParams, syncAssetData; + return _regenerator["default"].wrap(function _callee12$(_context12) { + while (1) { + switch (_context12.prev = _context12.next) { + case 0: + typePrefix = configOptions.type_prefix || 'Contentstack'; + _context12.prev = 1; + syncData = {}; + assetTokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-asset-").concat(configOptions.api_key); + _context12.next = 6; + return cache.get(assetTokenKey); + + case 6: + syncAssetToken = _context12.sent; + syncAssetParams = syncAssetToken ? { + sync_token: syncAssetToken + } : { + init: true + }; + syncAssetParams.type = 'asset_published,asset_unpublished,asset_deleted'; + _context12.next = 11; + return fn.apply(null, [syncAssetParams, configOptions]); + + case 11: + syncAssetData = _context12.sent; + syncData.data = syncAssetData.data; + _context12.next = 15; + return cache.set(assetTokenKey, syncAssetData.sync_token); + + case 15: + return _context12.abrupt("return", syncData); + + case 18: + _context12.prev = 18; + _context12.t0 = _context12["catch"](1); + throw _context12.t0; + + case 21: + case "end": + return _context12.stop(); + } + } + }, _callee12, null, [[1, 18]]); + })); + + function fetchAssets(_x31, _x32, _x33) { + return _fetchAssets4.apply(this, arguments); + } + + return fetchAssets; + }() + }]); + return FetchAssets; +}(); + +exports.FetchEntries = FetchEntries; +exports.FetchDefaultEntries = FetchDefaultEntries; +exports.FetchSpecifiedContentTypesEntries = FetchSpecifiedContentTypesEntries; +exports.FetchSpecifiedLocalesEntries = FetchSpecifiedLocalesEntries; +exports.FetchSpecifiedLocalesAndContentTypesEntries = FetchSpecifiedLocalesAndContentTypesEntries; \ No newline at end of file diff --git a/fetch.js b/fetch.js index 20b9fd0..49be7e0 100644 --- a/fetch.js +++ b/fetch.js @@ -1,26 +1,54 @@ -"use strict"; +'use strict'; +/**NPM dependencies */ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); -var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); - var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var queryString = require('query-string'); -var fetch = require('node-fetch'); +var fetch = require('node-fetch'); // eslint-disable-next-line import/no-unresolved + var _require = require('./package.json'), version = _require.version; -var _require2 = require('./utils'), - CODES = _require2.CODES; +var _require2 = require('./contenttype-data'), + FetchDefaultContentTypes = _require2.FetchDefaultContentTypes, + FetchSpecifiedContentTypes = _require2.FetchSpecifiedContentTypes, + FetchUnspecifiedContentTypes = _require2.FetchUnspecifiedContentTypes; + +var _require3 = require('./entry-data'), + FetchDefaultEntries = _require3.FetchDefaultEntries, + FetchSpecifiedContentTypesEntries = _require3.FetchSpecifiedContentTypesEntries, + FetchSpecifiedLocalesEntries = _require3.FetchSpecifiedLocalesEntries, + FetchSpecifiedLocalesAndContentTypesEntries = _require3.FetchSpecifiedLocalesAndContentTypesEntries; + +var _require4 = require('./utils'), + CODES = _require4.CODES; + +var OPTION_CLASS_MAPPING = { + '': FetchDefaultContentTypes, + contentTypes: FetchSpecifiedContentTypes, + excludeContentTypes: FetchUnspecifiedContentTypes, + locales: FetchDefaultContentTypes, + contentTypeslocales: FetchSpecifiedContentTypes, + excludeContentTypeslocales: FetchUnspecifiedContentTypes +}; +var OPTIONS_ENTRIES_CLASS_MAPPING = { + '': FetchDefaultEntries, + contentTypes: FetchSpecifiedContentTypesEntries, + excludeContentTypes: FetchSpecifiedContentTypesEntries, + locales: FetchSpecifiedLocalesEntries, + contentTypeslocales: FetchSpecifiedLocalesAndContentTypesEntries, + excludeContentTypeslocales: FetchSpecifiedLocalesAndContentTypesEntries +}; exports.fetchData = /*#__PURE__*/function () { - var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(configOptions, reporter) { - var syncData, syncEntryParams, syncAssetParams, _yield$Promise$all, _yield$Promise$all2, syncEntryData, syncAssetData, data, syncParams, contentstackData; + var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(configOptions, reporter, cache, contentTypeOption) { + var syncData, entryService, _syncData, contentstackData; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { @@ -28,133 +56,86 @@ exports.fetchData = /*#__PURE__*/function () { case 0: console.time('Fetch Contentstack data'); console.log('Starting to fetch data from Contentstack'); + _context.prev = 2; syncData = {}; + entryService = new OPTIONS_ENTRIES_CLASS_MAPPING[contentTypeOption](); + _context.next = 7; + return entryService.fetchSyncData(configOptions, cache, fetchSyncData); - if (!configOptions.expediteBuild) { - _context.next = 25; - break; - } - - syncEntryParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken - } : { - init: true - }; - syncAssetParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken - } : { - init: true + case 7: + _syncData = _context.sent; + syncData.data = _syncData.data; + contentstackData = { + syncData: syncData.data }; - syncEntryParams.type = 'entry_published, entry_unpublished, entry_deleted'; - syncAssetParams.type = 'asset_published, asset_unpublished, asset_deleted'; - _context.prev = 8; - _context.next = 11; - return Promise.all([fetchSyncData(syncEntryParams, configOptions), fetchSyncData(syncAssetParams, configOptions)]); - - case 11: - _yield$Promise$all = _context.sent; - _yield$Promise$all2 = (0, _slicedToArray2["default"])(_yield$Promise$all, 2); - syncEntryData = _yield$Promise$all2[0]; - syncAssetData = _yield$Promise$all2[1]; - data = syncEntryData.data.concat(syncAssetData.data); - syncData.data = data; - syncData.token = null; - _context.next = 23; - break; - - case 20: - _context.prev = 20; - _context.t0 = _context["catch"](8); - reporter.panic({ - id: CODES.SyncError, - context: { - sourceMessage: "Fetching contentstack data failed [expediteBuild]. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help." - }, - error: _context.t0 + console.timeEnd('Fetch Contentstack data'); + return _context.abrupt("return", { + contentstackData: contentstackData }); - case 23: - _context.next = 35; - break; - - case 25: - syncParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken - } : { - init: true - }; - _context.prev = 26; - _context.next = 29; - return fetchSyncData(syncParams, configOptions); - - case 29: - syncData = _context.sent; - _context.next = 35; - break; - - case 32: - _context.prev = 32; - _context.t1 = _context["catch"](26); + case 14: + _context.prev = 14; + _context.t0 = _context["catch"](2); reporter.panic({ id: CODES.SyncError, context: { sourceMessage: "Fetching contentstack data failed. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help." }, - error: _context.t1 - }); - - case 35: - contentstackData = { - syncData: syncData.data, - sync_token: syncData.sync_token - }; - console.timeEnd('Fetch Contentstack data'); - return _context.abrupt("return", { - contentstackData: contentstackData + error: _context.t0 }); - case 38: + case 17: case "end": return _context.stop(); } } - }, _callee, null, [[8, 20], [26, 32]]); + }, _callee, null, [[2, 14]]); })); - return function (_x, _x2) { + return function (_x, _x2, _x3, _x4) { return _ref.apply(this, arguments); }; }(); exports.fetchContentTypes = /*#__PURE__*/function () { - var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(config) { - var url, responseKey, query, allContentTypes; + var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(config, contentTypeOption) { + var url, responseKey, contentType, allContentTypes; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.prev = 0; config.cdn = config.cdn ? config.cdn : 'https://cdn.contentstack.io/v3'; url = 'content_types'; responseKey = 'content_types'; - query = { - include_global_field_schema: true - }; - _context2.next = 6; - return getPagedData(url, config, responseKey, query); + contentType = new OPTION_CLASS_MAPPING[contentTypeOption](); + _context2.next = 7; + return contentType.getPagedData(url, config, responseKey, getPagedData); - case 6: + case 7: allContentTypes = _context2.sent; return _context2.abrupt("return", allContentTypes); - case 8: + case 11: + _context2.prev = 11; + _context2.t0 = _context2["catch"](0); + reporter.panic({ + id: CODES.SyncError, + context: { + sourceMessage: "Fetching contentstack data failed. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help." + }, + error: _context2.t0 + }); + + case 14: case "end": return _context2.stop(); } } - }, _callee2); + }, _callee2, null, [[0, 11]]); })); - return function (_x3) { + return function (_x5, _x6) { return _ref2.apply(this, arguments); }; }(); @@ -182,7 +163,7 @@ var fetchSyncData = /*#__PURE__*/function () { }, _callee3); })); - return function fetchSyncData(_x4, _x5) { + return function fetchSyncData(_x7, _x8) { return _ref3.apply(this, arguments); }; }(); @@ -195,9 +176,7 @@ var fetchCsData = /*#__PURE__*/function () { switch (_context4.prev = _context4.next) { case 0: query = query || {}; - query.include_count = true; // query.api_key = config.api_key; - // query.access_token = config.delivery_token; - + query.include_count = true; query.environment = config.environment; queryParams = queryString.stringify(query); apiUrl = "".concat(config.cdn, "/").concat(url, "?").concat(queryParams); @@ -232,7 +211,7 @@ var fetchCsData = /*#__PURE__*/function () { }, _callee4); })); - return function fetchCsData(_x6, _x7, _x8) { + return function fetchCsData(_x9, _x10, _x11) { return _ref4.apply(this, arguments); }; }(); @@ -286,7 +265,7 @@ var getPagedData = /*#__PURE__*/function () { }, _callee5); })); - return function getPagedData(_x9, _x10, _x11) { + return function getPagedData(_x12, _x13, _x14) { return _ref5.apply(this, arguments); }; }(); @@ -338,7 +317,7 @@ var getSyncData = /*#__PURE__*/function () { }, _callee6); })); - return function getSyncData(_x12, _x13, _x14, _x15) { + return function getSyncData(_x15, _x16, _x17, _x18) { return _ref6.apply(this, arguments); }; }(); \ No newline at end of file diff --git a/gatsby-node.js b/gatsby-node.js index 42dbc56..e8403eb 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,4 +1,5 @@ -"use strict"; +'use strict'; +/** NPM dependencies */ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); @@ -14,6 +15,8 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } +var fetch = require('node-fetch'); + var _require = require('./normalize'), normalizeEntry = _require.normalizeEntry, sanitizeEntry = _require.sanitizeEntry, @@ -29,7 +32,8 @@ var _require2 = require('./utils'), checkIfUnsupportedFormat = _require2.checkIfUnsupportedFormat, SUPPORTED_FILES_COUNT = _require2.SUPPORTED_FILES_COUNT, IMAGE_REGEXP = _require2.IMAGE_REGEXP, - CODES = _require2.CODES; + CODES = _require2.CODES, + getContentTypeOption = _require2.getContentTypeOption; var _require3 = require('./fetch'), fetchData = _require3.fetchData, @@ -37,8 +41,6 @@ var _require3 = require('./fetch'), var downloadAssets = require('./download-assets'); -var fetch = require('node-fetch'); - var references = []; var groups = []; var fileFields = []; @@ -54,7 +56,7 @@ exports.onPreBootstrap = function (_ref) { exports.createSchemaCustomization = /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(_ref3, configOptions) { - var cache, actions, schema, contentTypes, typePrefix, disableMandatoryFields, createTypes, name, fields; + var cache, actions, schema, contentTypes, typePrefix, disableMandatoryFields, contentTypeOption, createTypes, name, fields; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -63,24 +65,25 @@ exports.createSchemaCustomization = /*#__PURE__*/function () { typePrefix = configOptions.type_prefix || 'Contentstack'; disableMandatoryFields = configOptions.disableMandatoryFields || false; _context.prev = 3; - _context.next = 6; - return fetchContentTypes(configOptions); + contentTypeOption = getContentTypeOption(configOptions); + _context.next = 7; + return fetchContentTypes(configOptions, contentTypeOption); - case 6: + case 7: contentTypes = _context.sent; - _context.next = 9; + _context.next = 10; return cache.set(typePrefix, contentTypes); - case 9: - _context.next = 14; + case 10: + _context.next = 15; break; - case 11: - _context.prev = 11; + case 12: + _context.prev = 12; _context.t0 = _context["catch"](3); console.error('Contentstack fetch content type failed!'); - case 14: + case 15: if (configOptions.enableSchemaGeneration) { createTypes = actions.createTypes; contentTypes.forEach(function (contentType) { @@ -123,12 +126,12 @@ exports.createSchemaCustomization = /*#__PURE__*/function () { })]); } - case 15: + case 16: case "end": return _context.stop(); } } - }, _callee, null, [[3, 11]]); + }, _callee, null, [[3, 12]]); })); return function (_x, _x2) { @@ -138,7 +141,7 @@ exports.createSchemaCustomization = /*#__PURE__*/function () { exports.sourceNodes = /*#__PURE__*/function () { var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(_ref5, configOptions) { - var cache, actions, getNode, getNodes, createNodeId, reporter, createContentDigest, getNodesByType, getCache, createNode, deleteNode, touchNode, typePrefix, tokenKey, syncToken, contentstackData, _yield$fetchData, _contentstackData, syncData, entriesNodeIds, assetsNodeIds, existingNodes, countOfSupportedFormatFiles, deleteContentstackNodes; + var cache, actions, getNode, getNodes, createNodeId, reporter, createContentDigest, getNodesByType, getCache, createNode, deleteNode, touchNode, typePrefix, contentstackData, contentTypeOption, _yield$fetchData, _contentstackData, syncData, entriesNodeIds, assetsNodeIds, existingNodes, countOfSupportedFormatFiles, deleteContentstackNodes; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { @@ -167,32 +170,26 @@ exports.sourceNodes = /*#__PURE__*/function () { createNode = actions.createNode, deleteNode = actions.deleteNode, touchNode = actions.touchNode; // use a custom type prefix if specified typePrefix = configOptions.type_prefix || 'Contentstack'; - tokenKey = "".concat(typePrefix.toLowerCase(), "-sync-token-").concat(configOptions.api_key); - _context2.next = 7; - return cache.get(tokenKey); - - case 7: - syncToken = _context2.sent; - configOptions.syncToken = syncToken || null; - _context2.prev = 9; - _context2.next = 12; - return fetchData(configOptions, reporter); + _context2.prev = 4; + contentTypeOption = getContentTypeOption(configOptions); + _context2.next = 8; + return fetchData(configOptions, reporter, cache, contentTypeOption); - case 12: + case 8: _yield$fetchData = _context2.sent; _contentstackData = _yield$fetchData.contentstackData; contentstackData = _contentstackData; - _context2.next = 17; + _context2.next = 13; return cache.get(typePrefix); - case 17: + case 13: contentstackData.contentTypes = _context2.sent; - _context2.next = 24; + _context2.next = 20; break; - case 20: - _context2.prev = 20; - _context2.t0 = _context2["catch"](9); + case 16: + _context2.prev = 16; + _context2.t0 = _context2["catch"](4); reporter.panic({ id: CODES.SyncError, context: { @@ -202,7 +199,7 @@ exports.sourceNodes = /*#__PURE__*/function () { }); throw _context2.t0; - case 24: + case 20: syncData = contentstackData.syncData.reduce(function (merged, item) { if (!merged[item.type]) { merged[item.type] = []; @@ -270,14 +267,14 @@ exports.sourceNodes = /*#__PURE__*/function () { _context2.t1 = configOptions.downloadImages; if (!_context2.t1) { - _context2.next = 36; + _context2.next = 32; break; } - _context2.next = 36; + _context2.next = 32; return cache.set(SUPPORTED_FILES_COUNT, countOfSupportedFormatFiles); - case 36: + case 32: // adding nodes contentstackData.contentTypes.forEach(function (contentType) { contentType.uid = contentType.uid.replace(/-/g, '_'); @@ -300,12 +297,12 @@ exports.sourceNodes = /*#__PURE__*/function () { }); if (!configOptions.downloadImages) { - _context2.next = 48; + _context2.next = 44; break; } - _context2.prev = 40; - _context2.next = 43; + _context2.prev = 36; + _context2.next = 39; return downloadAssets({ cache: cache, getCache: getCache, @@ -315,16 +312,16 @@ exports.sourceNodes = /*#__PURE__*/function () { reporter: reporter }, typePrefix, configOptions); - case 43: - _context2.next = 48; + case 39: + _context2.next = 44; break; - case 45: - _context2.prev = 45; - _context2.t2 = _context2["catch"](40); + case 41: + _context2.prev = 41; + _context2.t2 = _context2["catch"](36); reporter.info('Something went wrong while downloading assets. Details: ' + _context2.t2); - case 48: + case 44: // deleting nodes syncData.entry_unpublished && syncData.entry_unpublished.forEach(function (item) { return deleteContentstackNodes(item.data, 'entry'); @@ -346,17 +343,14 @@ exports.sourceNodes = /*#__PURE__*/function () { sameContentTypeNodes.forEach(function (node) { return deleteNode(node); }); - }); // Caching token for the next sync - - _context2.next = 55; - return cache.set(tokenKey, contentstackData.sync_token); + }); - case 55: + case 49: case "end": return _context2.stop(); } } - }, _callee2, null, [[9, 20], [40, 45]]); + }, _callee2, null, [[4, 16], [36, 41]]); })); return function (_x3, _x4) { @@ -437,7 +431,10 @@ exports.pluginOptionsSchema = function (_ref7) { expediteBuild: Joi["boolean"]()["default"](false).description("expediteBuild set this to either true or false."), enableSchemaGeneration: Joi["boolean"]()["default"](false).description("Specify true if you want to generate custom schema."), disableMandatoryFields: Joi["boolean"]()["default"](false).description("Specify true if you want to generate optional graphql fields for mandatory Contentstack fields"), - downloadImages: Joi["boolean"]()["default"](false).description("Specify true if you want to download all your contentstack images locally") + downloadImages: Joi["boolean"]()["default"](false).description("Specify true if you want to download all your contentstack images locally"), + contentTypes: Joi.array().items(Joi.string().required()).description("Specify list of content-types to be fetched from contentstack"), + excludeContentTypes: Joi.array().items(Joi.string().required()).description("Specify list of content-types to be excluded while fetching data from contentstack"), + locales: Joi.array().items(Joi.string().required()).description("Specify list of locales to be fetched from contentstack") }).external(validateContentstackAccess); }; diff --git a/package.json b/package.json index 457771a..3eb665d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gatsby-source-contentstack", - "version": "3.0.1", + "version": "3.1.0", "description": "Gatsby source plugin for building websites using Contentstack as a data source", "scripts": { "prepublish": "npm run build", @@ -8,7 +8,7 @@ "watch": "babel -w src --out-dir ." }, "engines": { - "node": ">=14.15.0" + "node": ">=12.13.0" }, "main": "gatsby-node.js", "repository": { @@ -56,7 +56,7 @@ "semantic-release": "^17.4.4" }, "peerDependencies": { - "gatsby": "^4.0.0-alpha-9689ff" + "gatsby": "^3.0.0" }, "husky": { "hooks": { diff --git a/src/contenttype-data.js b/src/contenttype-data.js new file mode 100644 index 0000000..dd1936e --- /dev/null +++ b/src/contenttype-data.js @@ -0,0 +1,95 @@ +'use strict'; + +class FetchContentTypes { + async getPagedData() { } +} + +class FetchDefaultContentTypes extends FetchContentTypes { + async getPagedData(url, config, responseKey, fn) { + const query = { + include_global_field_schema: true + }; + const result = await fn.apply(null, [url, config, responseKey, query]); + return result; + } +} + +class FetchSpecifiedContentTypes extends FetchContentTypes { + async getPagedData(url, config, responseKey, fn) { + const query = { + query: JSON.stringify({ + uid: { $in: config.contentTypes } + }), + include_global_field_schema: true + }; + const contentTypes = await fn.apply(null, [url, config, responseKey, query]); + + const referredContentTypes = new ReferredContentTypes(); + const referredContentTypesList = referredContentTypes.getReferredContentTypes(contentTypes); + + let referredContentTypesData = []; + if (referredContentTypesList.length) { + query.query = JSON.stringify({ uid: { $in: referredContentTypesList } }); + referredContentTypesData = await fn.apply(null, [url, config, responseKey, query]); + } + + const result = contentTypes.concat(referredContentTypesData); + return result; + } +} + +class FetchUnspecifiedContentTypes extends FetchContentTypes { + async getPagedData(url, config, responseKey, fn) { + const query = { + query: JSON.stringify({ + uid: { $nin: config.excludeContentTypes } + }), + include_global_field_schema: true + }; + const contentTypes = await fn.apply(null, [url, config, responseKey, query]); + + const referredContentTypes = new ReferredContentTypes(); + const referredContentTypesList = referredContentTypes.getReferredContentTypes(contentTypes); + + let referredContentTypesData = []; + if (referredContentTypesList.length) { + query.query = JSON.stringify({ uid: { $in: referredContentTypesList } }); + referredContentTypesData = await fn.apply(null, [url, config, responseKey, query]); + } + + const result = contentTypes.concat(referredContentTypesData); + return result; + } +} + +class ReferredContentTypes { + getReferredContentTypes(contentTypes) { + let referredContentTypes = {}; + for (let i = 0; i < contentTypes.length; i++) { + const contentType = contentTypes[i]; + for (let j = 0; j < contentType.schema.length; j++) { + const schema = contentType.schema[j]; + if (schema.data_type === 'reference') { + for (let k = 0; k < schema.reference_to.length; k++) { + // Keep unique values only. + referredContentTypes[schema.reference_to[k]] = null; + } + } + } + } + // Remove the content-types if they were already fetched. + for (let i = 0; i < contentTypes.length; i++) { + const contentType = contentTypes[i].uid; + const keys = Object.keys(referredContentTypes); + if (keys.includes(contentType)) { + delete referredContentTypes[contentType]; + } + } + return Object.keys(referredContentTypes); + } +} + +exports.FetchContentTypes = FetchContentTypes; +exports.FetchDefaultContentTypes = FetchDefaultContentTypes; +exports.FetchSpecifiedContentTypes = FetchSpecifiedContentTypes; +exports.FetchUnspecifiedContentTypes = FetchUnspecifiedContentTypes; \ No newline at end of file diff --git a/src/entry-data.js b/src/entry-data.js new file mode 100644 index 0000000..5e8eedc --- /dev/null +++ b/src/entry-data.js @@ -0,0 +1,219 @@ +'use strict'; + +class FetchEntries { + async fetchSyncData() { } +} + +class FetchDefaultEntries extends FetchEntries { + async fetchSyncData(configOptions, cache, fn) { + const typePrefix = configOptions.type_prefix || 'Contentstack'; + + let syncData = {}; + try { + if (configOptions.expediteBuild) { + const entryTokenKey = `${typePrefix.toLowerCase()}-sync-token-entry-${configOptions.api_key}`; + const assetTokenKey = `${typePrefix.toLowerCase()}-sync-token-asset-${configOptions.api_key}`; + const [syncEntryToken, syncAssetToken] = await Promise.all([cache.get(entryTokenKey), cache.get(assetTokenKey)]) + + const syncEntryParams = syncEntryToken ? { sync_token: syncEntryToken } : { init: true }; + const syncAssetParams = syncAssetToken ? { sync_token: syncAssetToken } : { init: true }; + + syncEntryParams.type = 'entry_published,entry_unpublished,entry_deleted'; + syncAssetParams.type = 'asset_published,asset_unpublished,asset_deleted'; + const [syncEntryData, syncAssetData] = await Promise.all([fn.apply(null, [syncEntryParams, configOptions]), fn.apply(null, [syncAssetParams, configOptions])]); + const data = syncEntryData.data.concat(syncAssetData.data); + syncData.data = data; + await Promise.all([cache.set(entryTokenKey, syncEntryData.sync_token), cache.set(assetTokenKey, syncAssetData.sync_token)]); + } else { + const tokenKey = `${typePrefix.toLowerCase()}-sync-token-${configOptions.api_key}`; + const syncToken = await cache.get(tokenKey); + const syncParams = syncToken ? { sync_token: syncToken } : { init: true }; + + syncData = await fn.apply(null, [syncParams, configOptions]); + // Caching token for the next sync + await cache.set(tokenKey, syncData.sync_token); + } + } catch (error) { + throw error; + } + return syncData; + } +} + +class FetchSpecifiedContentTypesEntries extends FetchEntries { + async fetchSyncData(configOptions, cache, fn) { + try { + const [syncEntryData, syncAssetData] = await Promise.all([ + this.fetchEntries(configOptions, cache, fn), + this.fetchAssets(configOptions, cache, fn) + ]); + + const syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return syncData; + } catch (error) { + throw error; + } + } + + async fetchEntries(configOptions, cache, fn) { + try { + let syncData = {}; + const typePrefix = configOptions.type_prefix || 'Contentstack'; + const contentTypes = await cache.get(typePrefix); + + for (let i = 0; i < contentTypes.length; i++) { + const contentType = contentTypes[i].uid; + const tokenKey = `${typePrefix.toLowerCase()}-sync-token-${contentType}-${configOptions.api_key}`; + + const syncToken = await cache.get(tokenKey); + const syncParams = syncToken ? { sync_token: syncToken } : { init: true }; + syncParams.content_type_uid = contentType; + const _syncData = await fn.apply(null, [syncParams, configOptions]); + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); + // Caching token for the next sync. + await cache.set(tokenKey, _syncData.sync_token); + } + return syncData; + } catch (error) { + throw error; + } + } + + async fetchAssets(configOptions, cache, fn) { + try { + const fetchAssetService = new FetchAssets(); + const syncData = await fetchAssetService.fetchAssets(configOptions, cache, fn); + return syncData; + } catch (error) { + throw error; + } + } +} + +class FetchSpecifiedLocalesEntries extends FetchEntries { + async fetchSyncData(configOptions, cache, fn) { + const [syncEntryData, syncAssetData] = await Promise.all([ + this.fetchEntries(configOptions, cache, fn), + this.fetchAssets(configOptions, cache, fn) + ]); + + const syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return syncData; + } + + async fetchEntries(configOptions, cache, fn) { + try { + let syncData = {}; + const typePrefix = configOptions.type_prefix || 'Contentstack'; + const locales = configOptions.locales; + + for (let i = 0; i < locales.length; i++) { + const locale = locales[i]; + const tokenKey = `${typePrefix.toLowerCase()}-sync-token-${locale}-${configOptions.api_key}`; + + const syncToken = await cache.get(tokenKey); + const syncParams = syncToken ? { sync_token: syncToken } : { init: true }; + syncParams.locale = locale; + const _syncData = await fn.apply(null, [syncParams, configOptions]); + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); + // Caching token for next sync + await cache.set(tokenKey, _syncData.sync_token); + } + return syncData; + } catch (error) { + throw error; + } + } + + async fetchAssets(configOptions, cache, fn) { + try { + const fetchAssetService = new FetchAssets(); + const syncData = await fetchAssetService.fetchAssets(configOptions, cache, fn); + return syncData; + } catch (error) { + throw error; + } + } +} + +class FetchSpecifiedLocalesAndContentTypesEntries extends FetchEntries { + async fetchSyncData(configOptions, cache, fn) { + const [syncEntryData, syncAssetData] = await Promise.all([ + this.fetchEntries(configOptions, cache, fn), + this.fetchAssets(configOptions, cache, fn) + ]); + + const syncData = {}; + syncData.data = syncEntryData.data.concat(syncAssetData.data); + return syncData; + } + + async fetchEntries(configOptions, cache, fn) { + try { + let syncData = {}; + const typePrefix = configOptions.type_prefix || 'Contentstack'; + const contentTypes = await cache.get(typePrefix); + const locales = configOptions.locales; + + for (let i = 0; i < contentTypes.length; i++) { + const contentType = contentTypes[i].uid; + for (let j = 0; j < locales.length; j++) { + const locale = locales[j]; + const tokenKey = `${typePrefix.toLowerCase()}-sync-token-${contentType}-${locale}-${configOptions.api_key}`; + + const syncToken = await cache.get(tokenKey); + const syncParams = syncToken ? { sync_token: syncToken } : { init: true }; + syncParams.content_type_uid = contentType; + syncParams.locale = locale; + const _syncData = await fn.apply(null, [syncParams, configOptions]); + syncData.data = syncData.data || []; + syncData.data = syncData.data.concat(_syncData.data); + // Caching token for next sync + await cache.set(tokenKey, _syncData.sync_token); + } + } + return syncData; + } catch (error) { + throw error; + } + } + + async fetchAssets(configOptions, cache, fn) { + try { + const fetchAssetService = new FetchAssets(); + const syncData = await fetchAssetService.fetchAssets(configOptions, cache, fn); + return syncData; + } catch (error) { + throw error; + } + } +} + +class FetchAssets { + async fetchAssets(configOptions, cache, fn) { + const typePrefix = configOptions.type_prefix || 'Contentstack'; + try { + let syncData = {}; + const assetTokenKey = `${typePrefix.toLowerCase()}-sync-token-asset-${configOptions.api_key}`; + const syncAssetToken = await cache.get(assetTokenKey); + const syncAssetParams = syncAssetToken ? { sync_token: syncAssetToken } : { init: true }; + syncAssetParams.type = 'asset_published,asset_unpublished,asset_deleted'; + const syncAssetData = await fn.apply(null, [syncAssetParams, configOptions]); + syncData.data = syncAssetData.data; + await cache.set(assetTokenKey, syncAssetData.sync_token); + return syncData; + } catch (error) { + throw error; + } + } +} + +exports.FetchEntries = FetchEntries; +exports.FetchDefaultEntries = FetchDefaultEntries; +exports.FetchSpecifiedContentTypesEntries = FetchSpecifiedContentTypesEntries; +exports.FetchSpecifiedLocalesEntries = FetchSpecifiedLocalesEntries; +exports.FetchSpecifiedLocalesAndContentTypesEntries = FetchSpecifiedLocalesAndContentTypesEntries; \ No newline at end of file diff --git a/src/fetch.js b/src/fetch.js index 5af7947..6d0c208 100644 --- a/src/fetch.js +++ b/src/fetch.js @@ -1,92 +1,72 @@ +'use strict'; +/**NPM dependencies */ const queryString = require('query-string'); const fetch = require('node-fetch'); -const { - version, - // eslint-disable-next-line import/no-unresolved -} = require('./package.json'); -const {CODES} = require('./utils'); +// eslint-disable-next-line import/no-unresolved +const { version } = require('./package.json'); +const { FetchDefaultContentTypes, FetchSpecifiedContentTypes, FetchUnspecifiedContentTypes } = require('./contenttype-data'); +const { FetchDefaultEntries, FetchSpecifiedContentTypesEntries, FetchSpecifiedLocalesEntries, FetchSpecifiedLocalesAndContentTypesEntries } = require('./entry-data'); +const { CODES } = require('./utils'); + +const OPTION_CLASS_MAPPING = { + '': FetchDefaultContentTypes, + contentTypes: FetchSpecifiedContentTypes, + excludeContentTypes: FetchUnspecifiedContentTypes, + locales: FetchDefaultContentTypes, + contentTypeslocales: FetchSpecifiedContentTypes, + excludeContentTypeslocales: FetchUnspecifiedContentTypes, +}; +const OPTIONS_ENTRIES_CLASS_MAPPING = { + '': FetchDefaultEntries, + contentTypes: FetchSpecifiedContentTypesEntries, + excludeContentTypes: FetchSpecifiedContentTypesEntries, + locales: FetchSpecifiedLocalesEntries, + contentTypeslocales: FetchSpecifiedLocalesAndContentTypesEntries, + excludeContentTypeslocales: FetchSpecifiedLocalesAndContentTypesEntries, +}; -exports.fetchData = async (configOptions, reporter) => { +exports.fetchData = async (configOptions, reporter, cache, contentTypeOption) => { console.time('Fetch Contentstack data'); console.log('Starting to fetch data from Contentstack'); - let syncData = {}; - - if (configOptions.expediteBuild) { - const syncEntryParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken, - } : { - init: true, - }; - - const syncAssetParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken, - } : { - init: true, - }; - - syncEntryParams.type = 'entry_published, entry_unpublished, entry_deleted'; - syncAssetParams.type = 'asset_published, asset_unpublished, asset_deleted'; - - try { - const [syncEntryData, syncAssetData] = await Promise.all([fetchSyncData(syncEntryParams, configOptions), fetchSyncData(syncAssetParams, configOptions)]); - const data = syncEntryData.data.concat(syncAssetData.data); - syncData.data = data; - syncData.token = null; - } catch (error) { - reporter.panic({ - id: CODES.SyncError, - context: { - sourceMessage: `Fetching contentstack data failed [expediteBuild]. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help.` - }, - error - }); - } - } else { - const syncParams = configOptions.syncToken ? { - sync_token: configOptions.syncToken, - } : { - init: true, - }; - - try { - syncData = await fetchSyncData(syncParams, configOptions); - } catch (error) { - reporter.panic({ - id: CODES.SyncError, - context: { - sourceMessage: `Fetching contentstack data failed. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help.` - }, - error - }); - } + try { + let syncData = {}; + const entryService = new OPTIONS_ENTRIES_CLASS_MAPPING[contentTypeOption](); + const _syncData = await entryService.fetchSyncData(configOptions, cache, fetchSyncData); + syncData.data = _syncData.data; + const contentstackData = { syncData: syncData.data }; + + console.timeEnd('Fetch Contentstack data'); + + return { contentstackData }; + } catch (error) { + reporter.panic({ + id: CODES.SyncError, + context: { sourceMessage: `Fetching contentstack data failed. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help.` }, + error + }); } - - const contentstackData = { - syncData: syncData.data, - sync_token: syncData.sync_token, - }; - - console.timeEnd('Fetch Contentstack data'); - - return { - contentstackData, - }; }; -exports.fetchContentTypes = async (config) => { - config.cdn = config.cdn ? config.cdn : 'https://cdn.contentstack.io/v3'; - - const url = 'content_types'; - const responseKey = 'content_types'; - const query = { - include_global_field_schema: true, - }; - const allContentTypes = await getPagedData(url, config, responseKey, query); - return allContentTypes; +exports.fetchContentTypes = async (config, contentTypeOption) => { + try { + config.cdn = config.cdn ? config.cdn : 'https://cdn.contentstack.io/v3'; + + const url = 'content_types'; + const responseKey = 'content_types'; + const contentType = new OPTION_CLASS_MAPPING[contentTypeOption](); + const allContentTypes = await contentType.getPagedData(url, config, responseKey, getPagedData); + return allContentTypes; + } catch (error) { + reporter.panic({ + id: CODES.SyncError, + context: { sourceMessage: `Fetching contentstack data failed. Please check https://www.contentstack.com/docs/developers/apis/content-delivery-api/ for more help.` }, + error + }); + } }; const fetchSyncData = async (query, config) => { @@ -98,8 +78,6 @@ const fetchSyncData = async (query, config) => { const fetchCsData = async (url, config, query) => { query = query || {}; query.include_count = true; - // query.api_key = config.api_key; - // query.access_token = config.delivery_token; query.environment = config.environment; const queryParams = queryString.stringify(query); const apiUrl = `${config.cdn}/${url}?${queryParams}`; @@ -128,15 +106,7 @@ const fetchCsData = async (url, config, query) => { }); }; -const getPagedData = async ( - url, - config, - responseKey, - query = {}, - skip = 0, - limit = 100, - aggregatedResponse = null, -) => { +const getPagedData = async (url, config, responseKey, query = {}, skip = 0, limit = 100, aggregatedResponse = null) => { query.skip = skip; query.limit = limit; query.include_global_field_schema = true; @@ -147,26 +117,12 @@ const getPagedData = async ( aggregatedResponse = aggregatedResponse.concat(response[responseKey]); } if (skip + limit <= response.count) { - return getPagedData( - url, - config, - responseKey, - query = {}, - skip + limit, - limit, - aggregatedResponse, - ); + return getPagedData(url, config, responseKey, query = {}, skip + limit, limit, aggregatedResponse); } return aggregatedResponse; }; -const getSyncData = async ( - url, - config, - query, - responseKey, - aggregatedResponse = null, -) => { +const getSyncData = async (url, config, query, responseKey, aggregatedResponse = null) => { const response = await fetchCsData(url, config, query); if (!aggregatedResponse) { aggregatedResponse = {}; @@ -179,15 +135,7 @@ const getSyncData = async ( aggregatedResponse.sync_token = response.sync_token ? response.sync_token : aggregatedResponse.sync_token; } if (response.pagination_token) { - return getSyncData( - url, - config, - query = { - pagination_token: response.pagination_token, - }, - responseKey, - aggregatedResponse, - ); + return getSyncData(url, config, query = { pagination_token: response.pagination_token }, responseKey, aggregatedResponse); } return aggregatedResponse; }; diff --git a/src/gatsby-node.js b/src/gatsby-node.js index 68bc015..b201ee5 100644 --- a/src/gatsby-node.js +++ b/src/gatsby-node.js @@ -1,22 +1,14 @@ -const { - normalizeEntry, - sanitizeEntry, - processContentType, - processEntry, - processAsset, - makeEntryNodeUid, - makeAssetNodeUid, - buildCustomSchema, - extendSchemaWithDefaultEntryFields, -} = require('./normalize'); -const {checkIfUnsupportedFormat,SUPPORTED_FILES_COUNT, IMAGE_REGEXP, CODES}=require('./utils'); +'use strict'; +/** NPM dependencies */ +const fetch = require('node-fetch'); +const { normalizeEntry, sanitizeEntry, processContentType, processEntry, processAsset, + makeEntryNodeUid, makeAssetNodeUid, buildCustomSchema, extendSchemaWithDefaultEntryFields, +} = require('./normalize'); +const { checkIfUnsupportedFormat, SUPPORTED_FILES_COUNT, IMAGE_REGEXP, CODES, getContentTypeOption }=require('./utils'); const { fetchData, fetchContentTypes } = require('./fetch'); - const downloadAssets = require('./download-assets'); -const fetch = require('node-fetch'); - let references = []; let groups = []; let fileFields = []; @@ -28,18 +20,15 @@ exports.onPreBootstrap = ({ reporter }) => { } }; -exports.createSchemaCustomization = async ({ - cache, - actions, - schema, -}, configOptions) => { - +exports.createSchemaCustomization = async ({ cache, actions, schema }, configOptions) => { let contentTypes; const typePrefix = configOptions.type_prefix || 'Contentstack'; const disableMandatoryFields = configOptions.disableMandatoryFields || false; try { - contentTypes = await fetchContentTypes(configOptions); + const contentTypeOption = getContentTypeOption(configOptions); + contentTypes = await fetchContentTypes(configOptions, contentTypeOption); + // Caching content-types because we need to be able to support multiple stacks. await cache.set(typePrefix, contentTypes); } catch (error) { console.error('Contentstack fetch content type failed!'); @@ -49,19 +38,8 @@ exports.createSchemaCustomization = async ({ contentTypes.forEach(contentType => { const contentTypeUid = contentType.uid.replace(/-/g, '_'); const name = `${typePrefix}_${contentTypeUid}`; - const extendedSchema = extendSchemaWithDefaultEntryFields( - contentType.schema - ); - let result = buildCustomSchema( - extendedSchema, - [], - [], - [], - [], - name, - typePrefix, - disableMandatoryFields - ); + const extendedSchema = extendSchemaWithDefaultEntryFields(contentType.schema); + let result = buildCustomSchema(extendedSchema, [], [], [], [], name, typePrefix, disableMandatoryFields); references = references.concat(result.references); groups = groups.concat(result.groups); fileFields = fileFields.concat(result.fileFields); @@ -102,29 +80,15 @@ exports.createSchemaCustomization = async ({ } }; -exports.sourceNodes = async ({ - cache, - actions, - getNode, - getNodes, - createNodeId, - reporter, - createContentDigest, - getNodesByType, - getCache, -}, configOptions) => { +exports.sourceNodes = async ({ cache, actions, getNode, getNodes, createNodeId, reporter, createContentDigest, getNodesByType, getCache }, configOptions) => { const { createNode, deleteNode, touchNode } = actions; - // use a custom type prefix if specified const typePrefix = configOptions.type_prefix || 'Contentstack'; - const tokenKey = `${typePrefix.toLowerCase()}-sync-token-${configOptions.api_key}`; - const syncToken = await cache.get(tokenKey); - - configOptions.syncToken = syncToken || null; let contentstackData; try { - const { contentstackData: _contentstackData } = await fetchData(configOptions, reporter); + const contentTypeOption = getContentTypeOption(configOptions); + const { contentstackData: _contentstackData } = await fetchData(configOptions, reporter, cache, contentTypeOption); contentstackData = _contentstackData; contentstackData.contentTypes = await cache.get(typePrefix); } catch (error) { @@ -150,15 +114,10 @@ exports.sourceNodes = async ({ const entriesNodeIds = new Set(); const assetsNodeIds = new Set(); - const existingNodes = getNodes().filter( - n => n.internal.owner === 'gatsby-source-contentstack' - ); + const existingNodes = getNodes().filter(n => n.internal.owner === 'gatsby-source-contentstack'); existingNodes.forEach(n => { - if ( - n.internal.type !== `${typePrefix}ContentTypes` && - n.internal.type !== `${typePrefix}_assets` - ) { + if (n.internal.type !== `${typePrefix}ContentTypes` && n.internal.type !== `${typePrefix}_assets`) { entriesNodeIds.add(n.id); } if (n.internal.type === `${typePrefix}_assets`) { @@ -299,13 +258,8 @@ exports.sourceNodes = async ({ const sameContentTypeNodes = getNodes().filter( n => n.internal.type === `${typePrefix}_${item.content_type_uid}` ); - sameContentTypeNodes.forEach(node => - deleteNode(node) - ); + sameContentTypeNodes.forEach(node => deleteNode(node)); }); - - // Caching token for the next sync - await cache.set(tokenKey, contentstackData.sync_token); }; @@ -394,7 +348,10 @@ exports.pluginOptionsSchema = ({ Joi }) => { expediteBuild: Joi.boolean().default(false).description(`expediteBuild set this to either true or false.`), enableSchemaGeneration: Joi.boolean().default(false).description(`Specify true if you want to generate custom schema.`), disableMandatoryFields: Joi.boolean().default(false).description(`Specify true if you want to generate optional graphql fields for mandatory Contentstack fields`), - downloadImages: Joi.boolean().default(false).description(`Specify true if you want to download all your contentstack images locally`) + downloadImages: Joi.boolean().default(false).description(`Specify true if you want to download all your contentstack images locally`), + contentTypes: Joi.array().items(Joi.string().required()).description(`Specify list of content-types to be fetched from contentstack`), + excludeContentTypes: Joi.array().items(Joi.string().required()).description(`Specify list of content-types to be excluded while fetching data from contentstack`), + locales: Joi.array().items(Joi.string().required()).description(`Specify list of locales to be fetched from contentstack`), }).external(validateContentstackAccess) } diff --git a/src/utils.js b/src/utils.js index d0cf9ac..ea26fa0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -46,3 +46,22 @@ exports.CODES = { SyncError: '10001', APIError: '10002' }; + +exports.getContentTypeOption = configOptions => { + const contentTypeOptions = ['contentTypes', 'excludeContentTypes']; + const configOptionKeys = Object.keys(configOptions); + + let contentTypeOption = ''; + + for (let i = 0; i < configOptionKeys.length; i++) { + const configOptionKey = configOptionKeys[i]; + if (contentTypeOptions.includes(configOptionKey)) { + contentTypeOption = configOptionKey; + break; + } + } + if (configOptions.locales?.length) { + contentTypeOption += 'locales'; + } + return contentTypeOption; +}; \ No newline at end of file diff --git a/utils.js b/utils.js index c542cf1..e2b9c74 100644 --- a/utils.js +++ b/utils.js @@ -47,4 +47,27 @@ exports.IMAGE_REGEXP = new RegExp('https://(stag-images|(eu-)?images).(blz-)?con exports.CODES = { SyncError: '10001', APIError: '10002' +}; + +exports.getContentTypeOption = function (configOptions) { + var _configOptions$locale; + + var contentTypeOptions = ['contentTypes', 'excludeContentTypes']; + var configOptionKeys = Object.keys(configOptions); + var contentTypeOption = ''; + + for (var i = 0; i < configOptionKeys.length; i++) { + var configOptionKey = configOptionKeys[i]; + + if (contentTypeOptions.includes(configOptionKey)) { + contentTypeOption = configOptionKey; + break; + } + } + + if ((_configOptions$locale = configOptions.locales) !== null && _configOptions$locale !== void 0 && _configOptions$locale.length) { + contentTypeOption += 'locales'; + } + + return contentTypeOption; }; \ No newline at end of file From 28a32da7400af0c1f3d01ef725b2a3490c60aaf3 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Sun, 12 Dec 2021 17:12:33 +0530 Subject: [PATCH 02/12] feat: added support for gatsby plugin image --- extend-node-type.js | 148 +++++++++++++++++++++++ gatsby-node.js | 9 +- gatsby-plugin-image.js | 240 +++++++++++++++++++++++++++++++++++++ image-helper.js | 56 +++++++++ package.json | 1 + schemes.js | 71 +++++++++++ src/extend-node-type.js | 50 ++++++++ src/gatsby-node.js | 2 + src/gatsby-plugin-image.js | 135 +++++++++++++++++++++ src/image-helper.js | 50 ++++++++ src/schemes.js | 32 +++++ 11 files changed, 792 insertions(+), 2 deletions(-) create mode 100644 extend-node-type.js create mode 100644 gatsby-plugin-image.js create mode 100644 image-helper.js create mode 100644 schemes.js create mode 100644 src/extend-node-type.js create mode 100644 src/gatsby-plugin-image.js create mode 100644 src/image-helper.js create mode 100644 src/schemes.js diff --git a/extend-node-type.js b/extend-node-type.js new file mode 100644 index 0000000..74a05b2 --- /dev/null +++ b/extend-node-type.js @@ -0,0 +1,148 @@ +'use strict'; + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); + +var _typeof = require("@babel/runtime/helpers/typeof"); + +var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); + +var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); + +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } + +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +var _require = require('gatsby/graphql'), + GraphQLBoolean = _require.GraphQLBoolean, + GraphQLInt = _require.GraphQLInt, + GraphQLJSON = _require.GraphQLJSON; + +var _require2 = require('./gatsby-plugin-image'), + resolveGatsbyImageData = _require2.resolveGatsbyImageData; + +var _require3 = require('./schemes'), + ImageResizingBehavior = _require3.ImageResizingBehavior, + ImageCropFocusType = _require3.ImageCropFocusType; + +exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { + var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(_ref2, configOptions) { + var type, cache, typePrefix, getGatsbyImageData, gatsbyImageData; + return _regenerator["default"].wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + type = _ref2.type, cache = _ref2.cache; + typePrefix = configOptions.type_prefix || 'Contentstack'; + + if (!(type.name !== "".concat(typePrefix, "_assets"))) { + _context3.next = 4; + break; + } + + return _context3.abrupt("return", {}); + + case 4: + // gatsby-plugin-image + getGatsbyImageData = /*#__PURE__*/function () { + var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() { + var _yield$import, getGatsbyImageFieldConfig, fieldConfig; + + return _regenerator["default"].wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + _context2.next = 2; + return Promise.resolve().then(function () { + return _interopRequireWildcard(require('gatsby-plugin-image/graphql-utils')); + }); + + case 2: + _yield$import = _context2.sent; + getGatsbyImageFieldConfig = _yield$import.getGatsbyImageFieldConfig; + fieldConfig = getGatsbyImageFieldConfig( /*#__PURE__*/function () { + var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { + var _len, + args, + _key, + _args = arguments; + + return _regenerator["default"].wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + for (_len = _args.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = _args[_key]; + } + + return _context.abrupt("return", resolveGatsbyImageData.apply(void 0, args.concat([{ + cache: cache + }]))); + + case 2: + case "end": + return _context.stop(); + } + } + }, _callee); + })); + + return function () { + return _ref4.apply(this, arguments); + }; + }(), {// jpegProgressive: { + // type: GraphQLBoolean, + // defaultValue: true, + // }, + // resizingBehavior: { + // type: ImageResizingBehavior, + // }, + // cropFocus: { + // type: ImageCropFocusType, + // }, + // cornerRadius: { + // type: GraphQLInt, + // defaultValue: 0, + // // description: '' + // }, + // quality: { + // type: GraphQLInt, + // defaultValue: 50, + // } + }); + fieldConfig.type = GraphQLJSON; + return _context2.abrupt("return", fieldConfig); + + case 7: + case "end": + return _context2.stop(); + } + } + }, _callee2); + })); + + return function getGatsbyImageData() { + return _ref3.apply(this, arguments); + }; + }(); + + _context3.next = 7; + return getGatsbyImageData(); + + case 7: + gatsbyImageData = _context3.sent; + return _context3.abrupt("return", { + gatsbyImageData: gatsbyImageData + }); + + case 9: + case "end": + return _context3.stop(); + } + } + }, _callee3); + })); + + return function (_x, _x2) { + return _ref.apply(this, arguments); + }; +}(); \ No newline at end of file diff --git a/gatsby-node.js b/gatsby-node.js index e8403eb..d441abf 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -41,6 +41,9 @@ var _require3 = require('./fetch'), var downloadAssets = require('./download-assets'); +var _require4 = require('./extend-node-type'), + setFieldsOnGraphQLNodeType = _require4.setFieldsOnGraphQLNodeType; + var references = []; var groups = []; var fileFields = []; @@ -358,6 +361,8 @@ exports.sourceNodes = /*#__PURE__*/function () { }; }(); +exports.setFieldsOnGraphQLNodeType = setFieldsOnGraphQLNodeType; + exports.createResolvers = function (_ref6) { var createResolvers = _ref6.createResolvers; var resolvers = {}; @@ -454,8 +459,8 @@ var ERROR_MAP = (_ERROR_MAP = {}, (0, _defineProperty2["default"])(_ERROR_MAP, C var coreSupportsOnPluginInit; try { - var _require4 = require('gatsby-plugin-utils'), - isGatsbyNodeLifecycleSupported = _require4.isGatsbyNodeLifecycleSupported; + var _require5 = require('gatsby-plugin-utils'), + isGatsbyNodeLifecycleSupported = _require5.isGatsbyNodeLifecycleSupported; if (isGatsbyNodeLifecycleSupported('onPluginInit')) { coreSupportsOnPluginInit = 'stable'; diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js new file mode 100644 index 0000000..1eda3ee --- /dev/null +++ b/gatsby-plugin-image.js @@ -0,0 +1,240 @@ +'use strict'; + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); + +var _typeof = require("@babel/runtime/helpers/typeof"); + +var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); + +var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); + +var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); + +var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); + +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } + +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +var _require = require('gatsby-core-utils'), + fetchRemoteFile = _require.fetchRemoteFile; + +var _require2 = require('fs'), + readFile = _require2.readFile; + +var _require3 = require('./image-helper'), + createUrl = _require3.createUrl, + mimeTypeExtensions = _require3.mimeTypeExtensions, + validImageFormats = _require3.validImageFormats, + isImage = _require3.isImage; + +var unresolvedBase64Cache = {}; +var resolvedBase64Cache = {}; + +var getBase64Image = exports.getBase64Image = function (props, cache) { + var aspectRatio = props.aspectRatio; + var originalFormat = props.image.file.contentType.split('/')[1]; + var toFormat = props.options.toFormat; + + var imageOptions = _objectSpread(_objectSpread({}, props.options), {}, { + toFormat: toFormat, + width: 20, + height: Math.floor(20 * aspectRatio) + }); + + var csImageUrl = createUrl(props.baseUrl, imageOptions); + var resolvedUrl = resolvedBase64Cache[csImageUrl]; + + if (resolvedUrl) { + return resolvedUrl; + } + + var inflightUrl = unresolvedBase64Cache[csImageUrl]; + + if (inflightUrl) { + return inflightUrl; + } + + var loadImage = /*#__PURE__*/function () { + var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { + var contentType, extension, absolutePath, base64; + return _regenerator["default"].wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + contentType = props.image.file.contentType; + extension = mimeTypeExtensions[contentType]; + _context.next = 4; + return fetchRemoteFile({ + url: csImageUrl, + cache: cache, + ext: extension + }); + + case 4: + absolutePath = _context.sent; + _context.next = 7; + return readFile(absolutePath).toString('base64'); + + case 7: + base64 = _context.sent; + return _context.abrupt("return", "data:image/".concat(toFormat || originalFormat, ";base64,").concat(base64)); + + case 9: + case "end": + return _context.stop(); + } + } + }, _callee); + })); + + return function loadImage() { + return _ref.apply(this, arguments); + }; + }(); + + var promise = loadImage(); + unresolvedBase64Cache[csImageUrl] = promise; + return promise.then(function (body) { + delete unresolvedBase64Cache[csImageUrl]; + resolvedBase64Cache[csImageUrl] = body; + }); +}; + +function getBasicImageProps(image, args) { + var aspectRatio; + + if (args.width && args.height) { + aspectRatio = args.width / args.height; + } else { + aspectRatio = image.file.details.image.width / image.file.details.image.height; + } + + return { + baseUrl: image.file.url, + contentType: image.file.contentType, + aspectRatio: aspectRatio, + width: image.file.details.image.width, + height: image.file.details.image.height + }; +} // Generate image source data for gatsby-plugin-image + + +function generateImageSource(filename, width, height, toFormat, imageTransformOptions) { + var jpegProgressive = imageTransformOptions.jpegProgressive, + quality = imageTransformOptions.quality, + cropFocus = imageTransformOptions.cropFocus, + backgroundColor = imageTransformOptions.backgroundColor, + resizingBehavior = imageTransformOptions.resizingBehavior, + cornerRadius = imageTransformOptions.cornerRadius; + + if (!validImageFormats.includes(toFormat)) { + console.warn("[gatsby-source-contentstack] Invalid image format \"".concat(toFormat, "\". Supported types are ").concat(validImageFormats.join(', '))); + return; + } + + var src = createUrl(filename, { + width: width, + height: height, + toFormat: toFormat, + resizingBehavior: resizingBehavior, + background: backgroundColor === null || backgroundColor === void 0 ? void 0 : backgroundColor.replace('#', 'rgb:'), + quality: quality, + jpegProgressive: jpegProgressive, + cropFocus: cropFocus, + cornerRadius: cornerRadius + }); + return { + width: width, + height: height, + format: toFormat, + src: src + }; +} + +exports.resolveGatsbyImageData = /*#__PURE__*/function () { + var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(image, options, context, info, _ref3) { + var cache, _yield$import, generateImageData, _getBasicImageProps, baseUrl, contentType, width, height, _contentType$split, _contentType$split2, format, imageProps, placeholderDataURI; + + return _regenerator["default"].wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + cache = _ref3.cache; + + if (isImage(image)) { + _context2.next = 3; + break; + } + + return _context2.abrupt("return", null); + + case 3: + _context2.next = 5; + return Promise.resolve().then(function () { + return _interopRequireWildcard(require('gatsby-plugin-image')); + }); + + case 5: + _yield$import = _context2.sent; + generateImageData = _yield$import.generateImageData; + _getBasicImageProps = getBasicImageProps(image, options), baseUrl = _getBasicImageProps.baseUrl, contentType = _getBasicImageProps.contentType, width = _getBasicImageProps.width, height = _getBasicImageProps.height; + _contentType$split = contentType.split('/'), _contentType$split2 = (0, _slicedToArray2["default"])(_contentType$split, 2), format = _contentType$split2[1]; + + if (format === 'jpeg') { + format = 'jpg'; + } + + imageProps = generateImageData(_objectSpread(_objectSpread({}, options), {}, { + pluginName: 'gatsby-source-contentstack', + sourceMetadata: { + width: width, + height: height, + format: format + }, + filename: baseUrl, + generateImageSource: generateImageSource, + options: options + })); + placeholderDataURI = null; + + if (!(options.placeholder === 'blurred')) { + _context2.next = 16; + break; + } + + _context2.next = 15; + return getBase64Image({ + baseUrl: baseUrl, + image: image, + options: options + }, cache); + + case 15: + placeholderDataURI = _context2.sent; + + case 16: + if (placeholderDataURI) { + imageProps.placeholder = { + fallback: placeholderDataURI + }; + } + + return _context2.abrupt("return", imageProps); + + case 18: + case "end": + return _context2.stop(); + } + } + }, _callee2); + })); + + return function (_x, _x2, _x3, _x4, _x5) { + return _ref2.apply(this, arguments); + }; +}(); \ No newline at end of file diff --git a/image-helper.js b/image-helper.js new file mode 100644 index 0000000..d8db027 --- /dev/null +++ b/image-helper.js @@ -0,0 +1,56 @@ +'use strict'; + +var _require = require('url'), + URLSearchParams = _require.URLSearchParams; // Determine the proper file extension based on mime type + + +var mimeTypeExtensions = { + 'image/jpeg': '.jpg', + 'image/jpg': '.jpg', + 'image/gif': '.gif', + 'image/png': '.png', + 'image/webp': '.webp' +}; // Supported image formats by contentstack image API + +var validImageFormats = ['jpg', 'png', 'webp', 'gif']; + +var isImage = function isImage(image) { + var _image$file; + + return !!mimeTypeExtensions[image === null || image === void 0 ? void 0 : (_image$file = image.file) === null || _image$file === void 0 ? void 0 : _image$file.contentType]; +}; // Creates a Contentstack image url + + +var createUrl = function createUrl(imgUrl) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + // If radius is -1, we need to pass max to the API. + var cornerRadius = options.cornerRadius === -1 ? 'max' : options.cornerRadius; // Convert to Contentstack names and filter out undefined/null values. + + var urlArgs = { + w: options.width || undefined, + h: options.height || undefined, + fl: options.toFormat === 'jpg' && options.jpegProgressive ? 'progressive' : undefined, + q: options.quality || undefined, + fm: options.toFormat || undefined, + fit: options.resizingBehavior || undefined, + f: options.background || undefined, + bg: options.background || undefined, + r: cornerRadius || undefined + }; + var searchParams = new URLSearchParams(); + + for (var key in urlArgs) { + if (typeof urlArgs[key] !== 'undefined') { + var _urlArgs$key; + + searchParams.append(key, (_urlArgs$key = urlArgs[key]) !== null && _urlArgs$key !== void 0 ? _urlArgs$key : ''); + } + } + + return "https://".concat(imgUrl, "?").concat(searchParams.toString()); +}; + +exports.mimeTypeExtensions = mimeTypeExtensions; +exports.validImageFormats = validImageFormats; +exports.isImage = isImage; +exports.createUrl = createUrl; \ No newline at end of file diff --git a/package.json b/package.json index 3eb665d..3e5085a 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "license": "MIT", "dependencies": { + "gatsby-core-utils": "^3.3.0", "gatsby-source-filesystem": "^3.13.0", "node-fetch": "2.1.2", "progress": "^2.0.3", diff --git a/schemes.js b/schemes.js new file mode 100644 index 0000000..9cd67ce --- /dev/null +++ b/schemes.js @@ -0,0 +1,71 @@ +'use strict'; + +var _require = require('gatsby/graphql'), + GraphQLEnumType = _require.GraphQLEnumType; + +exports.ImageResizingBehavior = new GraphQLEnumType({ + name: 'ImageResizingBehavior', + values: { + NO_CHANGE: { + value: '' + }, + PAD: { + value: 'pad', + description: 'Same as default resizing, but adds padding so that generated image has the specified dimensions.' + }, + CROP: { + value: 'crop', + description: 'Crop a part of the original image to match the specified size.' + }, + FILL: { + value: 'fill', + description: 'Crop the image to the specified dimensions, if the original image is smaller than these dimensions, then the image will be upscaled.' + }, + THUMB: { + value: 'thumb', + description: 'When used in association with the f parameter below, creates a thumbnail from the image based on a focus area.' + }, + SCALE: { + value: 'scale', + description: 'Scale the image regardless of the original aspect ratio.' + } + } +}); +exports.ImageCropFocusType = new GraphQLEnumType({ + name: 'ContentstackImageCropFocus', + values: { + TOP: { + value: "top" + }, + TOP_LEFT: { + value: "top_left" + }, + TOP_RIGHT: { + value: "top_right" + }, + BOTTOM: { + value: "bottom" + }, + BOTTOM_RIGHT: { + value: "bottom_left" + }, + BOTTOM_LEFT: { + value: "bottom_right" + }, + RIGHT: { + value: "right" + }, + LEFT: { + value: "left" + }, + FACE: { + value: "face" + }, + FACES: { + value: "faces" + }, + CENTER: { + value: "center" + } + } +}); \ No newline at end of file diff --git a/src/extend-node-type.js b/src/extend-node-type.js new file mode 100644 index 0000000..137d097 --- /dev/null +++ b/src/extend-node-type.js @@ -0,0 +1,50 @@ +'use strict'; + +const { GraphQLBoolean, GraphQLInt, GraphQLJSON } = require('gatsby/graphql'); + +const { resolveGatsbyImageData } = require('./gatsby-plugin-image'); +const { ImageResizingBehavior, ImageCropFocusType } = require('./schemes'); + +exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { + const typePrefix = configOptions.type_prefix || 'Contentstack'; + if (type.name !== `${typePrefix}_assets`) { + return {}; + } + + // gatsby-plugin-image + const getGatsbyImageData = async () => { + const { getGatsbyImageFieldConfig } = await import('gatsby-plugin-image/graphql-utils'); + + const fieldConfig = getGatsbyImageFieldConfig( + async (...args) => resolveGatsbyImageData(...args, { cache }), + { + // jpegProgressive: { + // type: GraphQLBoolean, + // defaultValue: true, + // }, + // resizingBehavior: { + // type: ImageResizingBehavior, + // }, + // cropFocus: { + // type: ImageCropFocusType, + // }, + // cornerRadius: { + // type: GraphQLInt, + // defaultValue: 0, + // // description: '' + // }, + // quality: { + // type: GraphQLInt, + // defaultValue: 50, + // } + } + ); + + fieldConfig.type = GraphQLJSON; + + return fieldConfig; + }; + + const gatsbyImageData = await getGatsbyImageData(); + return { gatsbyImageData }; +}; \ No newline at end of file diff --git a/src/gatsby-node.js b/src/gatsby-node.js index b201ee5..b09a8fb 100644 --- a/src/gatsby-node.js +++ b/src/gatsby-node.js @@ -8,6 +8,7 @@ const { normalizeEntry, sanitizeEntry, processContentType, processEntry, process const { checkIfUnsupportedFormat, SUPPORTED_FILES_COUNT, IMAGE_REGEXP, CODES, getContentTypeOption }=require('./utils'); const { fetchData, fetchContentTypes } = require('./fetch'); const downloadAssets = require('./download-assets'); +const { setFieldsOnGraphQLNodeType } = require('./extend-node-type'); let references = []; let groups = []; @@ -262,6 +263,7 @@ exports.sourceNodes = async ({ cache, actions, getNode, getNodes, createNodeId, }); }; +exports.setFieldsOnGraphQLNodeType = setFieldsOnGraphQLNodeType; exports.createResolvers = ({ createResolvers }) => { const resolvers = {}; diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js new file mode 100644 index 0000000..7e4a16a --- /dev/null +++ b/src/gatsby-plugin-image.js @@ -0,0 +1,135 @@ +'use strict'; + +const { fetchRemoteFile } = require('gatsby-core-utils'); +const { readFile } = require('fs'); + +const { createUrl, mimeTypeExtensions, validImageFormats, isImage } = require('./image-helper'); + +const unresolvedBase64Cache = {}; +const resolvedBase64Cache = {}; + +const getBase64Image = exports.getBase64Image = (props, cache) => { + const { aspectRatio } = props; + const originalFormat = props.image.file.contentType.split('/')[1]; + const toFormat = props.options.toFormat; + const imageOptions = { + ...props.options, + toFormat, + width: 20, + height: Math.floor(20 * aspectRatio), + }; + + const csImageUrl = createUrl(props.baseUrl, imageOptions); + + const resolvedUrl = resolvedBase64Cache[csImageUrl]; + if (resolvedUrl) { + return resolvedUrl; + } + + const inflightUrl = unresolvedBase64Cache[csImageUrl]; + if (inflightUrl) { + return inflightUrl; + } + + const loadImage = async () => { + const { file: { contentType } } = props.image; + const extension = mimeTypeExtensions[contentType]; + const absolutePath = await fetchRemoteFile({ + url: csImageUrl, + cache, + ext: extension, + }); + const base64 = (await readFile(absolutePath).toString('base64')); + return `data:image/${toFormat || originalFormat};base64,${base64}`; + }; + + const promise = loadImage(); + unresolvedBase64Cache[csImageUrl] = promise; + + return promise.then(body => { + delete unresolvedBase64Cache[csImageUrl]; + resolvedBase64Cache[csImageUrl] = body; + }); +}; + +function getBasicImageProps(image, args) { + let aspectRatio; + if (args.width && args.height) { + aspectRatio = args.width / args.height; + } else { + aspectRatio = image.file.details.image.width / image.file.details.image.height; + } + + return { + baseUrl: image.file.url, + contentType: image.file.contentType, + aspectRatio, + width: image.file.details.image.width, + height: image.file.details.image.height, + }; +} + +// Generate image source data for gatsby-plugin-image +function generateImageSource(filename, width, height, toFormat, imageTransformOptions) { + const { + jpegProgressive, + quality, + cropFocus, + backgroundColor, + resizingBehavior, + cornerRadius, + } = imageTransformOptions; + + if (!validImageFormats.includes(toFormat)) { + console.warn(`[gatsby-source-contentstack] Invalid image format "${toFormat}". Supported types are ${validImageFormats.join(', ')}`); + return; + } + + const src = createUrl(filename, { + width, + height, + toFormat, + resizingBehavior, + background: backgroundColor?.replace('#', 'rgb:'), + quality, + jpegProgressive, + cropFocus, + cornerRadius, + }); + + return { width, height, format: toFormat, src }; +} + +exports.resolveGatsbyImageData = async (image, options, context, info, { cache }) => { + if (!isImage(image)) return null; + + const { generateImageData } = await import('gatsby-plugin-image'); + + const { baseUrl, contentType, width, height } = getBasicImageProps(image, options); + + let [, format] = contentType.split('/'); + if (format === 'jpeg') { + format = 'jpg'; + } + + const imageProps = generateImageData({ + ...options, + pluginName: 'gatsby-source-contentstack', + sourceMetadata: { width, height, format }, + filename: baseUrl, + generateImageSource, + options, + }); + + let placeholderDataURI = null; + + if (options.placeholder === 'blurred') { + placeholderDataURI = await getBase64Image({ baseUrl, image, options }, cache); + } + + if (placeholderDataURI) { + imageProps.placeholder = { fallback: placeholderDataURI }; + } + + return imageProps; +} \ No newline at end of file diff --git a/src/image-helper.js b/src/image-helper.js new file mode 100644 index 0000000..8df8a5f --- /dev/null +++ b/src/image-helper.js @@ -0,0 +1,50 @@ +'use strict'; + +const { URLSearchParams } = require('url'); + +// Determine the proper file extension based on mime type +const mimeTypeExtensions = { + 'image/jpeg': '.jpg', + 'image/jpg': '.jpg', + 'image/gif': '.gif', + 'image/png': '.png', + 'image/webp': '.webp', +}; + +// Supported image formats by contentstack image API +const validImageFormats = ['jpg', 'png', 'webp', 'gif']; + +const isImage = image => !!mimeTypeExtensions[image?.file?.contentType]; + +// Creates a Contentstack image url +const createUrl = (imgUrl, options = {}) => { + // If radius is -1, we need to pass max to the API. + const cornerRadius = options.cornerRadius === -1 ? 'max' : options.cornerRadius; + + // Convert to Contentstack names and filter out undefined/null values. + const urlArgs = { + w: options.width || undefined, + h: options.height || undefined, + fl: options.toFormat === 'jpg' && options.jpegProgressive ? 'progressive' : undefined, + q: options.quality || undefined, + fm: options.toFormat || undefined, + fit: options.resizingBehavior || undefined, + f: options.background || undefined, + bg: options.background || undefined, + r: cornerRadius || undefined, + }; + + const searchParams = new URLSearchParams(); + for (const key in urlArgs) { + if (typeof urlArgs[key] !== 'undefined') { + searchParams.append(key, urlArgs[key] ?? ''); + } + } + + return `https://${imgUrl}?${searchParams.toString()}`; +}; + +exports.mimeTypeExtensions = mimeTypeExtensions; +exports.validImageFormats = validImageFormats; +exports.isImage = isImage; +exports.createUrl = createUrl; \ No newline at end of file diff --git a/src/schemes.js b/src/schemes.js new file mode 100644 index 0000000..e4db1ea --- /dev/null +++ b/src/schemes.js @@ -0,0 +1,32 @@ +'use strict'; + +const { GraphQLEnumType } = require('gatsby/graphql'); + +exports.ImageResizingBehavior = new GraphQLEnumType({ + name: 'ImageResizingBehavior', + values: { + NO_CHANGE: { value: '' }, + PAD: { value: 'pad', description: 'Same as default resizing, but adds padding so that generated image has the specified dimensions.' }, + CROP: { value: 'crop', description: 'Crop a part of the original image to match the specified size.' }, + FILL: { value: 'fill', description: 'Crop the image to the specified dimensions, if the original image is smaller than these dimensions, then the image will be upscaled.' }, + THUMB: { value: 'thumb', description: 'When used in association with the f parameter below, creates a thumbnail from the image based on a focus area.' }, + SCALE: { value: 'scale', description: 'Scale the image regardless of the original aspect ratio.' }, + } +}); + +exports.ImageCropFocusType = new GraphQLEnumType({ + name: 'ContentstackImageCropFocus', + values: { + TOP: { value: `top` }, + TOP_LEFT: { value: `top_left` }, + TOP_RIGHT: { value: `top_right` }, + BOTTOM: { value: `bottom` }, + BOTTOM_RIGHT: { value: `bottom_left` }, + BOTTOM_LEFT: { value: `bottom_right` }, + RIGHT: { value: `right` }, + LEFT: { value: `left` }, + FACE: { value: `face` }, + FACES: { value: `faces` }, + CENTER: { value: `center` }, + }, +}); \ No newline at end of file From a4358fcfae4f7140ce810e6b24c70eccf4a97e63 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Mon, 13 Dec 2021 20:09:42 +0530 Subject: [PATCH 03/12] fix: fixed image property access issues and pass options to resolver api --- extend-node-type.js | 39 +++++++++++++++++++------------------- gatsby-plugin-image.js | 10 +++++----- image-helper.js | 4 +--- src/extend-node-type.js | 38 ++++++++++++++++++------------------- src/gatsby-plugin-image.js | 12 ++++++------ src/image-helper.js | 2 +- 6 files changed, 52 insertions(+), 53 deletions(-) diff --git a/extend-node-type.js b/extend-node-type.js index 74a05b2..8b9de6c 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -89,25 +89,26 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { return function () { return _ref4.apply(this, arguments); }; - }(), {// jpegProgressive: { - // type: GraphQLBoolean, - // defaultValue: true, - // }, - // resizingBehavior: { - // type: ImageResizingBehavior, - // }, - // cropFocus: { - // type: ImageCropFocusType, - // }, - // cornerRadius: { - // type: GraphQLInt, - // defaultValue: 0, - // // description: '' - // }, - // quality: { - // type: GraphQLInt, - // defaultValue: 50, - // } + }(), { + jpegProgressive: { + type: GraphQLBoolean, + defaultValue: true + }, + resizingBehavior: { + type: ImageResizingBehavior + }, + cropFocus: { + type: ImageCropFocusType + }, + cornerRadius: { + type: GraphQLInt, + defaultValue: 0 // description: '' + + }, + quality: { + type: GraphQLInt, + defaultValue: 50 + } }); fieldConfig.type = GraphQLJSON; return _context2.abrupt("return", fieldConfig); diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 1eda3ee..3ad41fd 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -111,15 +111,15 @@ function getBasicImageProps(image, args) { if (args.width && args.height) { aspectRatio = args.width / args.height; } else { - aspectRatio = image.file.details.image.width / image.file.details.image.height; + aspectRatio = image.dimension.width / image.dimension.height; } return { - baseUrl: image.file.url, - contentType: image.file.contentType, + baseUrl: image.url, + contentType: image.content_type, aspectRatio: aspectRatio, - width: image.file.details.image.width, - height: image.file.details.image.height + width: image.dimension.width, + height: image.dimension.height }; } // Generate image source data for gatsby-plugin-image diff --git a/image-helper.js b/image-helper.js index d8db027..56084ae 100644 --- a/image-helper.js +++ b/image-helper.js @@ -15,9 +15,7 @@ var mimeTypeExtensions = { var validImageFormats = ['jpg', 'png', 'webp', 'gif']; var isImage = function isImage(image) { - var _image$file; - - return !!mimeTypeExtensions[image === null || image === void 0 ? void 0 : (_image$file = image.file) === null || _image$file === void 0 ? void 0 : _image$file.contentType]; + return !!mimeTypeExtensions[image === null || image === void 0 ? void 0 : image.content_type]; }; // Creates a Contentstack image url diff --git a/src/extend-node-type.js b/src/extend-node-type.js index 137d097..2116a47 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -18,25 +18,25 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { const fieldConfig = getGatsbyImageFieldConfig( async (...args) => resolveGatsbyImageData(...args, { cache }), { - // jpegProgressive: { - // type: GraphQLBoolean, - // defaultValue: true, - // }, - // resizingBehavior: { - // type: ImageResizingBehavior, - // }, - // cropFocus: { - // type: ImageCropFocusType, - // }, - // cornerRadius: { - // type: GraphQLInt, - // defaultValue: 0, - // // description: '' - // }, - // quality: { - // type: GraphQLInt, - // defaultValue: 50, - // } + jpegProgressive: { + type: GraphQLBoolean, + defaultValue: true, + }, + resizingBehavior: { + type: ImageResizingBehavior, + }, + cropFocus: { + type: ImageCropFocusType, + }, + cornerRadius: { + type: GraphQLInt, + defaultValue: 0, + // description: '' + }, + quality: { + type: GraphQLInt, + defaultValue: 50, + } } ); diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index 7e4a16a..5757e23 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -57,15 +57,15 @@ function getBasicImageProps(image, args) { if (args.width && args.height) { aspectRatio = args.width / args.height; } else { - aspectRatio = image.file.details.image.width / image.file.details.image.height; + aspectRatio = image.dimension.width / image.dimension.height; } return { - baseUrl: image.file.url, - contentType: image.file.contentType, - aspectRatio, - width: image.file.details.image.width, - height: image.file.details.image.height, + baseUrl: image.url, + contentType: image.content_type, + aspectRatio: aspectRatio, + width: image.dimension.width, + height: image.dimension.height }; } diff --git a/src/image-helper.js b/src/image-helper.js index 8df8a5f..2337df3 100644 --- a/src/image-helper.js +++ b/src/image-helper.js @@ -14,7 +14,7 @@ const mimeTypeExtensions = { // Supported image formats by contentstack image API const validImageFormats = ['jpg', 'png', 'webp', 'gif']; -const isImage = image => !!mimeTypeExtensions[image?.file?.contentType]; +const isImage = image => !!mimeTypeExtensions[image?.content_type]; // Creates a Contentstack image url const createUrl = (imgUrl, options = {}) => { From bab6603cb93814a9229075e8e279af3818b97ede Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Mon, 13 Dec 2021 21:09:37 +0530 Subject: [PATCH 04/12] fix: fixed query params of contentstack image api --- extend-node-type.js | 15 +++++++++++---- gatsby-plugin-image.js | 2 +- image-helper.js | 33 +++++++++++++++------------------ src/extend-node-type.js | 14 ++++++++++---- src/gatsby-plugin-image.js | 2 +- src/image-helper.js | 31 +++++++++++++------------------ 6 files changed, 51 insertions(+), 46 deletions(-) diff --git a/extend-node-type.js b/extend-node-type.js index 8b9de6c..0a0257a 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -15,7 +15,8 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && var _require = require('gatsby/graphql'), GraphQLBoolean = _require.GraphQLBoolean, GraphQLInt = _require.GraphQLInt, - GraphQLJSON = _require.GraphQLJSON; + GraphQLJSON = _require.GraphQLJSON, + GraphQLString = _require.GraphQLString; var _require2 = require('./gatsby-plugin-image'), resolveGatsbyImageData = _require2.resolveGatsbyImageData; @@ -95,16 +96,22 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { defaultValue: true }, resizingBehavior: { - type: ImageResizingBehavior + type: GraphQLString }, - cropFocus: { - type: ImageCropFocusType + crop: { + type: GraphQLString }, cornerRadius: { type: GraphQLInt, defaultValue: 0 // description: '' }, + trim: { + type: GraphQLString + }, + pad: { + type: GraphQLString + }, quality: { type: GraphQLInt, defaultValue: 50 diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 3ad41fd..68d86e6 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -124,7 +124,7 @@ function getBasicImageProps(image, args) { } // Generate image source data for gatsby-plugin-image -function generateImageSource(filename, width, height, toFormat, imageTransformOptions) { +function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { var jpegProgressive = imageTransformOptions.jpegProgressive, quality = imageTransformOptions.quality, cropFocus = imageTransformOptions.cropFocus, diff --git a/image-helper.js b/image-helper.js index 56084ae..4dce17a 100644 --- a/image-helper.js +++ b/image-helper.js @@ -21,31 +21,28 @@ var isImage = function isImage(image) { var createUrl = function createUrl(imgUrl) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - // If radius is -1, we need to pass max to the API. - var cornerRadius = options.cornerRadius === -1 ? 'max' : options.cornerRadius; // Convert to Contentstack names and filter out undefined/null values. - - var urlArgs = { - w: options.width || undefined, - h: options.height || undefined, - fl: options.toFormat === 'jpg' && options.jpegProgressive ? 'progressive' : undefined, - q: options.quality || undefined, - fm: options.toFormat || undefined, + var queryParams = { + width: options.width || undefined, + height: options.height || undefined, + format: options.toFormat, + quality: options.quality || undefined, + crop: options.crop || undefined, fit: options.resizingBehavior || undefined, - f: options.background || undefined, - bg: options.background || undefined, - r: cornerRadius || undefined + 'bg-color': options.background || undefined }; var searchParams = new URLSearchParams(); - for (var key in urlArgs) { - if (typeof urlArgs[key] !== 'undefined') { - var _urlArgs$key; + for (var key in queryParams) { + if (typeof queryParams[key] !== 'undefined') { + var _queryParams$key; - searchParams.append(key, (_urlArgs$key = urlArgs[key]) !== null && _urlArgs$key !== void 0 ? _urlArgs$key : ''); + searchParams.append(key, (_queryParams$key = queryParams[key]) !== null && _queryParams$key !== void 0 ? _queryParams$key : ''); } - } + } // {base_url}/v3/assets/{stack_api_key}/{asset_uid}/{version_uid}/filename + // https://images.contentstack.io/v3/assets/blteae40eb499811073/bltc5064f36b5855343/59e0c41ac0eddd140d5a8e3e/owl.jpg?format={format} - return "https://".concat(imgUrl, "?").concat(searchParams.toString()); + + return "".concat(imgUrl, "?").concat(searchParams.toString()); }; exports.mimeTypeExtensions = mimeTypeExtensions; diff --git a/src/extend-node-type.js b/src/extend-node-type.js index 2116a47..5377fe2 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -1,6 +1,6 @@ 'use strict'; -const { GraphQLBoolean, GraphQLInt, GraphQLJSON } = require('gatsby/graphql'); +const { GraphQLBoolean, GraphQLInt, GraphQLJSON, GraphQLString } = require('gatsby/graphql'); const { resolveGatsbyImageData } = require('./gatsby-plugin-image'); const { ImageResizingBehavior, ImageCropFocusType } = require('./schemes'); @@ -23,16 +23,22 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { defaultValue: true, }, resizingBehavior: { - type: ImageResizingBehavior, + type: GraphQLString, }, - cropFocus: { - type: ImageCropFocusType, + crop: { + type: GraphQLString, }, cornerRadius: { type: GraphQLInt, defaultValue: 0, // description: '' }, + trim: { + type: GraphQLString, + }, + pad: { + type: GraphQLString, + }, quality: { type: GraphQLInt, defaultValue: 50, diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index 5757e23..abec037 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -70,7 +70,7 @@ function getBasicImageProps(image, args) { } // Generate image source data for gatsby-plugin-image -function generateImageSource(filename, width, height, toFormat, imageTransformOptions) { +function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { const { jpegProgressive, quality, diff --git a/src/image-helper.js b/src/image-helper.js index 2337df3..6bd1670 100644 --- a/src/image-helper.js +++ b/src/image-helper.js @@ -18,30 +18,25 @@ const isImage = image => !!mimeTypeExtensions[image?.content_type]; // Creates a Contentstack image url const createUrl = (imgUrl, options = {}) => { - // If radius is -1, we need to pass max to the API. - const cornerRadius = options.cornerRadius === -1 ? 'max' : options.cornerRadius; - - // Convert to Contentstack names and filter out undefined/null values. - const urlArgs = { - w: options.width || undefined, - h: options.height || undefined, - fl: options.toFormat === 'jpg' && options.jpegProgressive ? 'progressive' : undefined, - q: options.quality || undefined, - fm: options.toFormat || undefined, + const queryParams = { + width: options.width || undefined, + height: options.height || undefined, + format: options.toFormat, + quality: options.quality || undefined, + crop: options.crop || undefined, fit: options.resizingBehavior || undefined, - f: options.background || undefined, - bg: options.background || undefined, - r: cornerRadius || undefined, + 'bg-color': options.background || undefined, }; const searchParams = new URLSearchParams(); - for (const key in urlArgs) { - if (typeof urlArgs[key] !== 'undefined') { - searchParams.append(key, urlArgs[key] ?? ''); + for (const key in queryParams) { + if (typeof queryParams[key] !== 'undefined') { + searchParams.append(key, queryParams[key] ?? ''); } } - - return `https://${imgUrl}?${searchParams.toString()}`; + // {base_url}/v3/assets/{stack_api_key}/{asset_uid}/{version_uid}/filename + // https://images.contentstack.io/v3/assets/blteae40eb499811073/bltc5064f36b5855343/59e0c41ac0eddd140d5a8e3e/owl.jpg?format={format} + return `${imgUrl}?${searchParams.toString()}`; }; exports.mimeTypeExtensions = mimeTypeExtensions; From 1e7946cf814cf862d3f38b9be6de65918c12761f Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Tue, 14 Dec 2021 11:08:16 +0530 Subject: [PATCH 05/12] fix: minor fixes --- gatsby-plugin-image.js | 14 ++++++++------ src/gatsby-plugin-image.js | 10 ++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 68d86e6..4fa91ac 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -37,7 +37,7 @@ var resolvedBase64Cache = {}; var getBase64Image = exports.getBase64Image = function (props, cache) { var aspectRatio = props.aspectRatio; - var originalFormat = props.image.file.contentType.split('/')[1]; + var originalFormat = props.image.content_type.split('/')[1]; var toFormat = props.options.toFormat; var imageOptions = _objectSpread(_objectSpread({}, props.options), {}, { @@ -61,13 +61,13 @@ var getBase64Image = exports.getBase64Image = function (props, cache) { var loadImage = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { - var contentType, extension, absolutePath, base64; + var content_type, extension, absolutePath, base64; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: - contentType = props.image.file.contentType; - extension = mimeTypeExtensions[contentType]; + content_type = props.image.content_type; + extension = mimeTypeExtensions[content_type]; _context.next = 4; return fetchRemoteFile({ url: csImageUrl, @@ -78,10 +78,10 @@ var getBase64Image = exports.getBase64Image = function (props, cache) { case 4: absolutePath = _context.sent; _context.next = 7; - return readFile(absolutePath).toString('base64'); + return readFile(absolutePath); case 7: - base64 = _context.sent; + base64 = _context.sent.toString('base64'); return _context.abrupt("return", "data:image/".concat(toFormat || originalFormat, ";base64,").concat(base64)); case 9: @@ -102,6 +102,8 @@ var getBase64Image = exports.getBase64Image = function (props, cache) { return promise.then(function (body) { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; + })["catch"](function (error) { + console.log('error--->', error); }); }; diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index abec037..e07b1a6 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -10,7 +10,7 @@ const resolvedBase64Cache = {}; const getBase64Image = exports.getBase64Image = (props, cache) => { const { aspectRatio } = props; - const originalFormat = props.image.file.contentType.split('/')[1]; + const originalFormat = props.image.content_type.split('/')[1]; const toFormat = props.options.toFormat; const imageOptions = { ...props.options, @@ -32,14 +32,14 @@ const getBase64Image = exports.getBase64Image = (props, cache) => { } const loadImage = async () => { - const { file: { contentType } } = props.image; - const extension = mimeTypeExtensions[contentType]; + const { content_type } = props.image; + const extension = mimeTypeExtensions[content_type]; const absolutePath = await fetchRemoteFile({ url: csImageUrl, cache, ext: extension, }); - const base64 = (await readFile(absolutePath).toString('base64')); + const base64 = (await readFile(absolutePath)).toString('base64'); return `data:image/${toFormat || originalFormat};base64,${base64}`; }; @@ -49,6 +49,8 @@ const getBase64Image = exports.getBase64Image = (props, cache) => { return promise.then(body => { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; + }).catch(error => { + console.log('error--->', error); }); }; From bc714adef22b288bf28fba628508ed0bdc2d73a0 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 10:20:57 +0530 Subject: [PATCH 06/12] fix: fixed current version of the package, fixed image options passed to contentstack image api --- package.json | 2 +- src/extend-node-type.js | 6 ------ src/gatsby-plugin-image.js | 12 +++++------- src/image-helper.js | 14 ++++++-------- src/schemes.js | 32 -------------------------------- 5 files changed, 12 insertions(+), 54 deletions(-) delete mode 100644 src/schemes.js diff --git a/package.json b/package.json index 3e5085a..77a14d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gatsby-source-contentstack", - "version": "3.1.0", + "version": "3.1.1", "description": "Gatsby source plugin for building websites using Contentstack as a data source", "scripts": { "prepublish": "npm run build", diff --git a/src/extend-node-type.js b/src/extend-node-type.js index 5377fe2..859c30c 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -3,7 +3,6 @@ const { GraphQLBoolean, GraphQLInt, GraphQLJSON, GraphQLString } = require('gatsby/graphql'); const { resolveGatsbyImageData } = require('./gatsby-plugin-image'); -const { ImageResizingBehavior, ImageCropFocusType } = require('./schemes'); exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { const typePrefix = configOptions.type_prefix || 'Contentstack'; @@ -28,11 +27,6 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { crop: { type: GraphQLString, }, - cornerRadius: { - type: GraphQLInt, - defaultValue: 0, - // description: '' - }, trim: { type: GraphQLString, }, diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index e07b1a6..01b9441 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -1,7 +1,7 @@ 'use strict'; const { fetchRemoteFile } = require('gatsby-core-utils'); -const { readFile } = require('fs'); +const { readFile } = require('fs').promises; const { createUrl, mimeTypeExtensions, validImageFormats, isImage } = require('./image-helper'); @@ -76,10 +76,9 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans const { jpegProgressive, quality, - cropFocus, + crop, backgroundColor, - resizingBehavior, - cornerRadius, + fit, } = imageTransformOptions; if (!validImageFormats.includes(toFormat)) { @@ -91,12 +90,11 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans width, height, toFormat, - resizingBehavior, + fit, background: backgroundColor?.replace('#', 'rgb:'), quality, jpegProgressive, - cropFocus, - cornerRadius, + crop, }); return { width, height, format: toFormat, src }; diff --git a/src/image-helper.js b/src/image-helper.js index 6bd1670..343f707 100644 --- a/src/image-helper.js +++ b/src/image-helper.js @@ -19,13 +19,13 @@ const isImage = image => !!mimeTypeExtensions[image?.content_type]; // Creates a Contentstack image url const createUrl = (imgUrl, options = {}) => { const queryParams = { - width: options.width || undefined, - height: options.height || undefined, + width: options.width, + height: options.height, format: options.toFormat, - quality: options.quality || undefined, - crop: options.crop || undefined, - fit: options.resizingBehavior || undefined, - 'bg-color': options.background || undefined, + quality: options.quality, + crop: options.crop, + fit: options.fit, + 'bg-color': options.background, }; const searchParams = new URLSearchParams(); @@ -34,8 +34,6 @@ const createUrl = (imgUrl, options = {}) => { searchParams.append(key, queryParams[key] ?? ''); } } - // {base_url}/v3/assets/{stack_api_key}/{asset_uid}/{version_uid}/filename - // https://images.contentstack.io/v3/assets/blteae40eb499811073/bltc5064f36b5855343/59e0c41ac0eddd140d5a8e3e/owl.jpg?format={format} return `${imgUrl}?${searchParams.toString()}`; }; diff --git a/src/schemes.js b/src/schemes.js deleted file mode 100644 index e4db1ea..0000000 --- a/src/schemes.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const { GraphQLEnumType } = require('gatsby/graphql'); - -exports.ImageResizingBehavior = new GraphQLEnumType({ - name: 'ImageResizingBehavior', - values: { - NO_CHANGE: { value: '' }, - PAD: { value: 'pad', description: 'Same as default resizing, but adds padding so that generated image has the specified dimensions.' }, - CROP: { value: 'crop', description: 'Crop a part of the original image to match the specified size.' }, - FILL: { value: 'fill', description: 'Crop the image to the specified dimensions, if the original image is smaller than these dimensions, then the image will be upscaled.' }, - THUMB: { value: 'thumb', description: 'When used in association with the f parameter below, creates a thumbnail from the image based on a focus area.' }, - SCALE: { value: 'scale', description: 'Scale the image regardless of the original aspect ratio.' }, - } -}); - -exports.ImageCropFocusType = new GraphQLEnumType({ - name: 'ContentstackImageCropFocus', - values: { - TOP: { value: `top` }, - TOP_LEFT: { value: `top_left` }, - TOP_RIGHT: { value: `top_right` }, - BOTTOM: { value: `bottom` }, - BOTTOM_RIGHT: { value: `bottom_left` }, - BOTTOM_LEFT: { value: `bottom_right` }, - RIGHT: { value: `right` }, - LEFT: { value: `left` }, - FACE: { value: `face` }, - FACES: { value: `faces` }, - CENTER: { value: `center` }, - }, -}); \ No newline at end of file From dea5920d3f5e9b43e27e24b573e938404ee89bce Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 10:24:05 +0530 Subject: [PATCH 07/12] fix: updated build --- extend-node-type.js | 9 --------- gatsby-plugin-image.js | 23 ++++++++++------------- image-helper.js | 16 +++++++--------- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/extend-node-type.js b/extend-node-type.js index 0a0257a..42d4638 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -21,10 +21,6 @@ var _require = require('gatsby/graphql'), var _require2 = require('./gatsby-plugin-image'), resolveGatsbyImageData = _require2.resolveGatsbyImageData; -var _require3 = require('./schemes'), - ImageResizingBehavior = _require3.ImageResizingBehavior, - ImageCropFocusType = _require3.ImageCropFocusType; - exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(_ref2, configOptions) { var type, cache, typePrefix, getGatsbyImageData, gatsbyImageData; @@ -101,11 +97,6 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { crop: { type: GraphQLString }, - cornerRadius: { - type: GraphQLInt, - defaultValue: 0 // description: '' - - }, trim: { type: GraphQLString }, diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 4fa91ac..ca39a08 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -23,14 +23,13 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va var _require = require('gatsby-core-utils'), fetchRemoteFile = _require.fetchRemoteFile; -var _require2 = require('fs'), - readFile = _require2.readFile; +var readFile = require('fs').promises.readFile; -var _require3 = require('./image-helper'), - createUrl = _require3.createUrl, - mimeTypeExtensions = _require3.mimeTypeExtensions, - validImageFormats = _require3.validImageFormats, - isImage = _require3.isImage; +var _require2 = require('./image-helper'), + createUrl = _require2.createUrl, + mimeTypeExtensions = _require2.mimeTypeExtensions, + validImageFormats = _require2.validImageFormats, + isImage = _require2.isImage; var unresolvedBase64Cache = {}; var resolvedBase64Cache = {}; @@ -129,10 +128,9 @@ function getBasicImageProps(image, args) { function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { var jpegProgressive = imageTransformOptions.jpegProgressive, quality = imageTransformOptions.quality, - cropFocus = imageTransformOptions.cropFocus, + crop = imageTransformOptions.crop, backgroundColor = imageTransformOptions.backgroundColor, - resizingBehavior = imageTransformOptions.resizingBehavior, - cornerRadius = imageTransformOptions.cornerRadius; + fit = imageTransformOptions.fit; if (!validImageFormats.includes(toFormat)) { console.warn("[gatsby-source-contentstack] Invalid image format \"".concat(toFormat, "\". Supported types are ").concat(validImageFormats.join(', '))); @@ -143,12 +141,11 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans width: width, height: height, toFormat: toFormat, - resizingBehavior: resizingBehavior, + fit: fit, background: backgroundColor === null || backgroundColor === void 0 ? void 0 : backgroundColor.replace('#', 'rgb:'), quality: quality, jpegProgressive: jpegProgressive, - cropFocus: cropFocus, - cornerRadius: cornerRadius + crop: crop }); return { width: width, diff --git a/image-helper.js b/image-helper.js index 4dce17a..c9ca955 100644 --- a/image-helper.js +++ b/image-helper.js @@ -22,13 +22,13 @@ var isImage = function isImage(image) { var createUrl = function createUrl(imgUrl) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var queryParams = { - width: options.width || undefined, - height: options.height || undefined, + width: options.width, + height: options.height, format: options.toFormat, - quality: options.quality || undefined, - crop: options.crop || undefined, - fit: options.resizingBehavior || undefined, - 'bg-color': options.background || undefined + quality: options.quality, + crop: options.crop, + fit: options.fit, + 'bg-color': options.background }; var searchParams = new URLSearchParams(); @@ -38,9 +38,7 @@ var createUrl = function createUrl(imgUrl) { searchParams.append(key, (_queryParams$key = queryParams[key]) !== null && _queryParams$key !== void 0 ? _queryParams$key : ''); } - } // {base_url}/v3/assets/{stack_api_key}/{asset_uid}/{version_uid}/filename - // https://images.contentstack.io/v3/assets/blteae40eb499811073/bltc5064f36b5855343/59e0c41ac0eddd140d5a8e3e/owl.jpg?format={format} - + } return "".concat(imgUrl, "?").concat(searchParams.toString()); }; From b38d862cc86670cccb232368b98c39839bdfd059 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 11:25:14 +0530 Subject: [PATCH 08/12] fix: fixed trim and pad options passed to resolver --- src/extend-node-type.js | 6 +----- src/gatsby-plugin-image.js | 12 +++--------- src/image-helper.js | 2 ++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/extend-node-type.js b/src/extend-node-type.js index 859c30c..d6c7e27 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -17,11 +17,7 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { const fieldConfig = getGatsbyImageFieldConfig( async (...args) => resolveGatsbyImageData(...args, { cache }), { - jpegProgressive: { - type: GraphQLBoolean, - defaultValue: true, - }, - resizingBehavior: { + fit: { type: GraphQLString, }, crop: { diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index 01b9441..0b0aaf3 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -50,7 +50,7 @@ const getBase64Image = exports.getBase64Image = (props, cache) => { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; }).catch(error => { - console.log('error--->', error); + // TODO: add a logger here. }); }; @@ -74,7 +74,6 @@ function getBasicImageProps(image, args) { // Generate image source data for gatsby-plugin-image function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { const { - jpegProgressive, quality, crop, backgroundColor, @@ -87,14 +86,9 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans } const src = createUrl(filename, { - width, - height, - toFormat, - fit, + width, height, toFormat, fit, background: backgroundColor?.replace('#', 'rgb:'), - quality, - jpegProgressive, - crop, + quality, crop, trim, pad, }); return { width, height, format: toFormat, src }; diff --git a/src/image-helper.js b/src/image-helper.js index 343f707..b4306dd 100644 --- a/src/image-helper.js +++ b/src/image-helper.js @@ -25,6 +25,8 @@ const createUrl = (imgUrl, options = {}) => { quality: options.quality, crop: options.crop, fit: options.fit, + trim: options.trim, + pad: options.pad, 'bg-color': options.background, }; From 95861c1f455375cb91683e25dde505f60588a19f Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 11:29:23 +0530 Subject: [PATCH 09/12] fix: updated build --- extend-node-type.js | 6 +----- gatsby-plugin-image.js | 11 +++++------ image-helper.js | 2 ++ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/extend-node-type.js b/extend-node-type.js index 42d4638..dee6657 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -87,11 +87,7 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { return _ref4.apply(this, arguments); }; }(), { - jpegProgressive: { - type: GraphQLBoolean, - defaultValue: true - }, - resizingBehavior: { + fit: { type: GraphQLString }, crop: { diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index ca39a08..4bd4675 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -101,8 +101,7 @@ var getBase64Image = exports.getBase64Image = function (props, cache) { return promise.then(function (body) { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; - })["catch"](function (error) { - console.log('error--->', error); + })["catch"](function (error) {// TODO: add a logger here. }); }; @@ -126,8 +125,7 @@ function getBasicImageProps(image, args) { function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { - var jpegProgressive = imageTransformOptions.jpegProgressive, - quality = imageTransformOptions.quality, + var quality = imageTransformOptions.quality, crop = imageTransformOptions.crop, backgroundColor = imageTransformOptions.backgroundColor, fit = imageTransformOptions.fit; @@ -144,8 +142,9 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans fit: fit, background: backgroundColor === null || backgroundColor === void 0 ? void 0 : backgroundColor.replace('#', 'rgb:'), quality: quality, - jpegProgressive: jpegProgressive, - crop: crop + crop: crop, + trim: trim, + pad: pad }); return { width: width, diff --git a/image-helper.js b/image-helper.js index c9ca955..a8f9ab1 100644 --- a/image-helper.js +++ b/image-helper.js @@ -28,6 +28,8 @@ var createUrl = function createUrl(imgUrl) { quality: options.quality, crop: options.crop, fit: options.fit, + trim: options.trim, + pad: options.pad, 'bg-color': options.background }; var searchParams = new URLSearchParams(); From 05f36fad933901d6c75e2c03886a0fd83cce1b80 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 22:41:15 +0530 Subject: [PATCH 10/12] fix: added proper logging for error and a new error code for image api --- src/extend-node-type.js | 8 ++++---- src/gatsby-node.js | 7 ++++++- src/gatsby-plugin-image.js | 22 ++++++++++++---------- src/utils.js | 3 ++- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/extend-node-type.js b/src/extend-node-type.js index d6c7e27..99ddcb9 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -1,10 +1,10 @@ 'use strict'; -const { GraphQLBoolean, GraphQLInt, GraphQLJSON, GraphQLString } = require('gatsby/graphql'); +const { GraphQLInt, GraphQLJSON, GraphQLString } = require('gatsby/graphql'); const { resolveGatsbyImageData } = require('./gatsby-plugin-image'); -exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { +exports.setFieldsOnGraphQLNodeType = async ({ type, cache, reporter }, configOptions) => { const typePrefix = configOptions.type_prefix || 'Contentstack'; if (type.name !== `${typePrefix}_assets`) { return {}; @@ -15,7 +15,7 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { const { getGatsbyImageFieldConfig } = await import('gatsby-plugin-image/graphql-utils'); const fieldConfig = getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), + async (...args) => resolveGatsbyImageData(...args, { cache, reporter }), { fit: { type: GraphQLString, @@ -32,7 +32,7 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache }, configOptions) => { quality: { type: GraphQLInt, defaultValue: 50, - } + }, } ); diff --git a/src/gatsby-node.js b/src/gatsby-node.js index b09a8fb..e8bcd4f 100644 --- a/src/gatsby-node.js +++ b/src/gatsby-node.js @@ -367,7 +367,12 @@ const ERROR_MAP = { text: context => context.sourceMessage, level: `ERROR`, type: `PLUGIN` - } + }, + [CODES.ImageAPIError]: { + text: context => context.sourceMessage, + level: `ERROR`, + type: `PLUGIN` + }, }; let coreSupportsOnPluginInit; diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index 0b0aaf3..733b240 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -4,11 +4,12 @@ const { fetchRemoteFile } = require('gatsby-core-utils'); const { readFile } = require('fs').promises; const { createUrl, mimeTypeExtensions, validImageFormats, isImage } = require('./image-helper'); +const { CODES } = require('./utils'); const unresolvedBase64Cache = {}; const resolvedBase64Cache = {}; -const getBase64Image = exports.getBase64Image = (props, cache) => { +const getBase64Image = exports.getBase64Image = (props, cache, reporter) => { const { aspectRatio } = props; const originalFormat = props.image.content_type.split('/')[1]; const toFormat = props.options.toFormat; @@ -50,7 +51,13 @@ const getBase64Image = exports.getBase64Image = (props, cache) => { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; }).catch(error => { - // TODO: add a logger here. + reporter.panic({ + id: CODES.ImageAPIError, + context: { + sourceMessage: `Error occurred while fetching image. Please find the image url here: ${props.baseUrl}`, + }, + error, + }); }); }; @@ -73,12 +80,7 @@ function getBasicImageProps(image, args) { // Generate image source data for gatsby-plugin-image function generateImageSource(filename, width, height, toFormat, _fit, imageTransformOptions) { - const { - quality, - crop, - backgroundColor, - fit, - } = imageTransformOptions; + const { quality, crop, backgroundColor, fit, trim, pad } = imageTransformOptions; if (!validImageFormats.includes(toFormat)) { console.warn(`[gatsby-source-contentstack] Invalid image format "${toFormat}". Supported types are ${validImageFormats.join(', ')}`); @@ -94,7 +96,7 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans return { width, height, format: toFormat, src }; } -exports.resolveGatsbyImageData = async (image, options, context, info, { cache }) => { +exports.resolveGatsbyImageData = async (image, options, context, info, { cache, reporter }) => { if (!isImage(image)) return null; const { generateImageData } = await import('gatsby-plugin-image'); @@ -118,7 +120,7 @@ exports.resolveGatsbyImageData = async (image, options, context, info, { cache } let placeholderDataURI = null; if (options.placeholder === 'blurred') { - placeholderDataURI = await getBase64Image({ baseUrl, image, options }, cache); + placeholderDataURI = await getBase64Image({ baseUrl, image, options }, cache, reporter); } if (placeholderDataURI) { diff --git a/src/utils.js b/src/utils.js index ea26fa0..bded73b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -44,7 +44,8 @@ exports.IMAGE_REGEXP = new RegExp('https://(stag-images|(eu-)?images).(blz-)?con exports.CODES = { SyncError: '10001', - APIError: '10002' + APIError: '10002', + ImageAPIError: '10003', }; exports.getContentTypeOption = configOptions => { From eb391b6ceaec549fa077f23fd21b00c896a602f9 Mon Sep 17 00:00:00 2001 From: Vikram Kalta Date: Wed, 15 Dec 2021 22:46:52 +0530 Subject: [PATCH 11/12] fix: updated build --- extend-node-type.js | 8 ++++---- gatsby-node.js | 6 ++++++ gatsby-plugin-image.js | 24 ++++++++++++++++++------ utils.js | 3 ++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/extend-node-type.js b/extend-node-type.js index dee6657..7855263 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -13,7 +13,6 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } var _require = require('gatsby/graphql'), - GraphQLBoolean = _require.GraphQLBoolean, GraphQLInt = _require.GraphQLInt, GraphQLJSON = _require.GraphQLJSON, GraphQLString = _require.GraphQLString; @@ -23,12 +22,12 @@ var _require2 = require('./gatsby-plugin-image'), exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(_ref2, configOptions) { - var type, cache, typePrefix, getGatsbyImageData, gatsbyImageData; + var type, cache, reporter, typePrefix, getGatsbyImageData, gatsbyImageData; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: - type = _ref2.type, cache = _ref2.cache; + type = _ref2.type, cache = _ref2.cache, reporter = _ref2.reporter; typePrefix = configOptions.type_prefix || 'Contentstack'; if (!(type.name !== "".concat(typePrefix, "_assets"))) { @@ -72,7 +71,8 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { } return _context.abrupt("return", resolveGatsbyImageData.apply(void 0, args.concat([{ - cache: cache + cache: cache, + reporter: reporter }]))); case 2: diff --git a/gatsby-node.js b/gatsby-node.js index d441abf..585324a 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -455,6 +455,12 @@ var ERROR_MAP = (_ERROR_MAP = {}, (0, _defineProperty2["default"])(_ERROR_MAP, C }, level: "ERROR", type: "PLUGIN" +}), (0, _defineProperty2["default"])(_ERROR_MAP, CODES.ImageAPIError, { + text: function text(context) { + return context.sourceMessage; + }, + level: "ERROR", + type: "PLUGIN" }), _ERROR_MAP); var coreSupportsOnPluginInit; diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 4bd4675..5ab8bbf 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -31,10 +31,13 @@ var _require2 = require('./image-helper'), validImageFormats = _require2.validImageFormats, isImage = _require2.isImage; +var _require3 = require('./utils'), + CODES = _require3.CODES; + var unresolvedBase64Cache = {}; var resolvedBase64Cache = {}; -var getBase64Image = exports.getBase64Image = function (props, cache) { +var getBase64Image = exports.getBase64Image = function (props, cache, reporter) { var aspectRatio = props.aspectRatio; var originalFormat = props.image.content_type.split('/')[1]; var toFormat = props.options.toFormat; @@ -101,7 +104,14 @@ var getBase64Image = exports.getBase64Image = function (props, cache) { return promise.then(function (body) { delete unresolvedBase64Cache[csImageUrl]; resolvedBase64Cache[csImageUrl] = body; - })["catch"](function (error) {// TODO: add a logger here. + })["catch"](function (error) { + reporter.panic({ + id: CODES.ImageAPIError, + context: { + sourceMessage: "Error occurred while fetching image. Please find the image url here: ".concat(props.baseUrl) + }, + error: error + }); }); }; @@ -128,7 +138,9 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans var quality = imageTransformOptions.quality, crop = imageTransformOptions.crop, backgroundColor = imageTransformOptions.backgroundColor, - fit = imageTransformOptions.fit; + fit = imageTransformOptions.fit, + trim = imageTransformOptions.trim, + pad = imageTransformOptions.pad; if (!validImageFormats.includes(toFormat)) { console.warn("[gatsby-source-contentstack] Invalid image format \"".concat(toFormat, "\". Supported types are ").concat(validImageFormats.join(', '))); @@ -156,13 +168,13 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans exports.resolveGatsbyImageData = /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(image, options, context, info, _ref3) { - var cache, _yield$import, generateImageData, _getBasicImageProps, baseUrl, contentType, width, height, _contentType$split, _contentType$split2, format, imageProps, placeholderDataURI; + var cache, reporter, _yield$import, generateImageData, _getBasicImageProps, baseUrl, contentType, width, height, _contentType$split, _contentType$split2, format, imageProps, placeholderDataURI; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: - cache = _ref3.cache; + cache = _ref3.cache, reporter = _ref3.reporter; if (isImage(image)) { _context2.next = 3; @@ -210,7 +222,7 @@ exports.resolveGatsbyImageData = /*#__PURE__*/function () { baseUrl: baseUrl, image: image, options: options - }, cache); + }, cache, reporter); case 15: placeholderDataURI = _context2.sent; diff --git a/utils.js b/utils.js index e2b9c74..4fc1643 100644 --- a/utils.js +++ b/utils.js @@ -46,7 +46,8 @@ exports.SUPPORTED_FILES_COUNT = 'SUPPORTED_FILES_COUNT'; exports.IMAGE_REGEXP = new RegExp('https://(stag-images|(eu-)?images).(blz-)?contentstack.(io|com)/v3/assets/'); exports.CODES = { SyncError: '10001', - APIError: '10002' + APIError: '10002', + ImageAPIError: '10003' }; exports.getContentTypeOption = function (configOptions) { From 653a836af0f1eb57e03c3c648e798c9c1dce3835 Mon Sep 17 00:00:00 2001 From: Vikram Kalta <65945391+vkalta@users.noreply.github.com> Date: Wed, 12 Jan 2022 11:14:34 +0530 Subject: [PATCH 12/12] refactor: added user friendly error messages for missing dependencies and updated Readme file. --- README.md | 82 ++++++++++++++++++++++++++++++++++++-- extend-node-type.js | 44 +++++++++++--------- gatsby-node.js | 6 +++ gatsby-plugin-image.js | 8 ++-- package.json | 3 +- src/extend-node-type.js | 63 ++++++++++++++++------------- src/gatsby-node.js | 5 +++ src/gatsby-plugin-image.js | 3 +- src/utils.js | 1 + utils.js | 3 +- 10 files changed, 162 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 8789e1c..d2680fc 100644 --- a/README.md +++ b/README.md @@ -46,17 +46,17 @@ plugins: [ downloadImages: `boolean_value`, // Optional: Specify the content types from which you want the plugin to retrieve data. - contentTypes: [‘blog’,’author’] + contentTypes: [‘blog’,’author’], // This will fetch the data of the ‘blog’ and ‘author’ content types only. // Optional: Specify the content types that the plugin should exclude while fetching data of all content types. - excludeContentTypes: [‘home’,’about’] + excludeContentTypes: [‘home’,’about’], // This will fetch the data of all the available content types excluding the ‘home’ and ‘about’ content types. // Note: Only one of the above options should be used to fetch data. If you add both options to fetch all contentTypes and excludeContentTypes, than only one of the query gets executed. // Optional: Include the locales that you want the plugin to fetch data from. - locales: [‘en-us’,’fr-fr’] + locales: [‘en-us’,’fr-fr’], // In this case, the plugin will fetch only English (United States) and French (France) language data. // Optional: Specify the content types and locales of which you want the plugin to retrieve data. @@ -183,6 +183,82 @@ Remember that gatbsy-image doesn’t support GIF and SVG images. To use GIF image, Gatsby recommends to import the image directly. In SVG, creating multiple variants of the image doesn’t make sense because it is vector-based graphics that you can freely scale without losing quality. +### The new gatsby image plugin + +The gatsby-image plugin lets you add responsive images to your site. By using this plugin, you can format and produce images of various qualities and sizes. + +## Prerequisites + +To use this, you need to have the following plugins installed: + +- gatsby-plugin-image +- gatsby-plugin-sharp +- gatsby-transformer-sharp + +# Description + +Next step is to add an image to your page query and use the gatsbyImageData resolver to pass arguments that will configure your image. + +The gatsbyImageData resolver allows you to pass arguments to format and configure your images. +Using the Contentstack Image delivery APIs you can perform various operations on the images by passing the necessary parameters. + +Lets understand this with an example. +In the below example we have added several parameters to format the image. + +```query MyQuery { + allContentstackBlog { + edges { + node { + title + image { + title + gatsbyImageData( + layout: CONSTRAINED + crop: "100,100" + trim: "25,25,100,100" + backgroundColor:"cccccc" + pad: "25,25,25,25" + ) + } + } + } + } +}``` + +Lets understand some parameters that we defined: +layout: This defines the layout of the image, it can be CONSTRAINED, FIXED or FULL_WIDTH. +The crop, trim, backgroundColor and pad parameters configure the image according to the values inserted by the user. + +Note: To learn more about these parameters and other available options, read our detailed documentation on Contentstack Image delivery APIs. https://www.contentstack.com/docs/developers/apis/image-delivery-api/. + +This query below returns the URL for a 20px-wide image, to use as a blurred placeholder. +The image is downloaded and converted to a base64-encoded data URI. + +Here’s an example of the same: +```query MyQuery { + allContentstackBlog { + edges { + node { + title + image { + title + filename + url + gatsbyImageData( + layout: CONSTRAINED + placeholder: BLURRED + crop: "100,100" + trim: "25,25,100,100" + backgroundColor:"cccccc" + pad: "25,25,25,25" + ) + } + } + } + } +}``` + +For more information checkout gatsby's documentation on usage of the new image plugin. https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/adding-gatsby-image-support/ [gatsby]: https://www.gatsbyjs.org/ [contentstack]: https://www.contentstack.com/ \ No newline at end of file diff --git a/extend-node-type.js b/extend-node-type.js index 7855263..8a3619e 100644 --- a/extend-node-type.js +++ b/extend-node-type.js @@ -20,6 +20,9 @@ var _require = require('gatsby/graphql'), var _require2 = require('./gatsby-plugin-image'), resolveGatsbyImageData = _require2.resolveGatsbyImageData; +var _require3 = require('./utils'), + CODES = _require3.CODES; + exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(_ref2, configOptions) { var type, cache, reporter, typePrefix, getGatsbyImageData, gatsbyImageData; @@ -47,35 +50,29 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { while (1) { switch (_context2.prev = _context2.next) { case 0: - _context2.next = 2; + _context2.prev = 0; + _context2.next = 3; return Promise.resolve().then(function () { return _interopRequireWildcard(require('gatsby-plugin-image/graphql-utils')); }); - case 2: + case 3: _yield$import = _context2.sent; getGatsbyImageFieldConfig = _yield$import.getGatsbyImageFieldConfig; fieldConfig = getGatsbyImageFieldConfig( /*#__PURE__*/function () { - var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { - var _len, - args, - _key, - _args = arguments; - + var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(image, options) { return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: - for (_len = _args.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = _args[_key]; - } - - return _context.abrupt("return", resolveGatsbyImageData.apply(void 0, args.concat([{ + return _context.abrupt("return", resolveGatsbyImageData({ + image: image, + options: options, cache: cache, reporter: reporter - }]))); + })); - case 2: + case 1: case "end": return _context.stop(); } @@ -83,7 +80,7 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { }, _callee); })); - return function () { + return function (_x3, _x4) { return _ref4.apply(this, arguments); }; }(), { @@ -107,12 +104,23 @@ exports.setFieldsOnGraphQLNodeType = /*#__PURE__*/function () { fieldConfig.type = GraphQLJSON; return _context2.abrupt("return", fieldConfig); - case 7: + case 10: + _context2.prev = 10; + _context2.t0 = _context2["catch"](0); + reporter.panic({ + id: CODES.MissingDependencyError, + context: { + sourceMessage: "Gatsby plugin image is required. Please check https://github.com/contentstack/gatsby-source-contentstack#the-new-gatsby-image-plugin for more help." + }, + error: _context2.t0 + }); + + case 13: case "end": return _context2.stop(); } } - }, _callee2); + }, _callee2, null, [[0, 10]]); })); return function getGatsbyImageData() { diff --git a/gatsby-node.js b/gatsby-node.js index 585324a..129917a 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -461,6 +461,12 @@ var ERROR_MAP = (_ERROR_MAP = {}, (0, _defineProperty2["default"])(_ERROR_MAP, C }, level: "ERROR", type: "PLUGIN" +}), (0, _defineProperty2["default"])(_ERROR_MAP, CODES.MissingDependencyError, { + text: function text(context) { + return context.sourceMessage; + }, + level: "ERROR", + type: "PLUGIN" }), _ERROR_MAP); var coreSupportsOnPluginInit; diff --git a/gatsby-plugin-image.js b/gatsby-plugin-image.js index 5ab8bbf..fa18137 100644 --- a/gatsby-plugin-image.js +++ b/gatsby-plugin-image.js @@ -167,14 +167,14 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans } exports.resolveGatsbyImageData = /*#__PURE__*/function () { - var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(image, options, context, info, _ref3) { - var cache, reporter, _yield$import, generateImageData, _getBasicImageProps, baseUrl, contentType, width, height, _contentType$split, _contentType$split2, format, imageProps, placeholderDataURI; + var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(_ref3) { + var image, options, cache, reporter, _yield$import, generateImageData, _getBasicImageProps, baseUrl, contentType, width, height, _contentType$split, _contentType$split2, format, imageProps, placeholderDataURI; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: - cache = _ref3.cache, reporter = _ref3.reporter; + image = _ref3.image, options = _ref3.options, cache = _ref3.cache, reporter = _ref3.reporter; if (isImage(image)) { _context2.next = 3; @@ -244,7 +244,7 @@ exports.resolveGatsbyImageData = /*#__PURE__*/function () { }, _callee2); })); - return function (_x, _x2, _x3, _x4, _x5) { + return function (_x) { return _ref2.apply(this, arguments); }; }(); \ No newline at end of file diff --git a/package.json b/package.json index 77a14d7..4b22cd3 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "semantic-release": "^17.4.4" }, "peerDependencies": { - "gatsby": "^3.0.0" + "gatsby": "^3.0.0", + "gatsby-plugin-image": "^2.0.0-next" }, "husky": { "hooks": { diff --git a/src/extend-node-type.js b/src/extend-node-type.js index 99ddcb9..d8cc5db 100644 --- a/src/extend-node-type.js +++ b/src/extend-node-type.js @@ -3,6 +3,7 @@ const { GraphQLInt, GraphQLJSON, GraphQLString } = require('gatsby/graphql'); const { resolveGatsbyImageData } = require('./gatsby-plugin-image'); +const { CODES } = require('./utils'); exports.setFieldsOnGraphQLNodeType = async ({ type, cache, reporter }, configOptions) => { const typePrefix = configOptions.type_prefix || 'Contentstack'; @@ -12,33 +13,41 @@ exports.setFieldsOnGraphQLNodeType = async ({ type, cache, reporter }, configOpt // gatsby-plugin-image const getGatsbyImageData = async () => { - const { getGatsbyImageFieldConfig } = await import('gatsby-plugin-image/graphql-utils'); - - const fieldConfig = getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache, reporter }), - { - fit: { - type: GraphQLString, - }, - crop: { - type: GraphQLString, - }, - trim: { - type: GraphQLString, - }, - pad: { - type: GraphQLString, - }, - quality: { - type: GraphQLInt, - defaultValue: 50, - }, - } - ); - - fieldConfig.type = GraphQLJSON; - - return fieldConfig; + try { + const { getGatsbyImageFieldConfig } = await import('gatsby-plugin-image/graphql-utils'); + + const fieldConfig = getGatsbyImageFieldConfig( + async (image, options) => resolveGatsbyImageData({ image, options, cache, reporter }), + { + fit: { + type: GraphQLString, + }, + crop: { + type: GraphQLString, + }, + trim: { + type: GraphQLString, + }, + pad: { + type: GraphQLString, + }, + quality: { + type: GraphQLInt, + defaultValue: 50, + }, + } + ); + + fieldConfig.type = GraphQLJSON; + + return fieldConfig; + } catch (error) { + reporter.panic({ + id: CODES.MissingDependencyError, + context: { sourceMessage: `Gatsby plugin image is required. Please check https://github.com/contentstack/gatsby-source-contentstack#the-new-gatsby-image-plugin for more help.` }, + error + }); + } }; const gatsbyImageData = await getGatsbyImageData(); diff --git a/src/gatsby-node.js b/src/gatsby-node.js index e8bcd4f..9be31be 100644 --- a/src/gatsby-node.js +++ b/src/gatsby-node.js @@ -373,6 +373,11 @@ const ERROR_MAP = { level: `ERROR`, type: `PLUGIN` }, + [CODES.MissingDependencyError]: { + text: context => context.sourceMessage, + level: `ERROR`, + type: `PLUGIN`, + }, }; let coreSupportsOnPluginInit; diff --git a/src/gatsby-plugin-image.js b/src/gatsby-plugin-image.js index 733b240..148b0be 100644 --- a/src/gatsby-plugin-image.js +++ b/src/gatsby-plugin-image.js @@ -96,11 +96,10 @@ function generateImageSource(filename, width, height, toFormat, _fit, imageTrans return { width, height, format: toFormat, src }; } -exports.resolveGatsbyImageData = async (image, options, context, info, { cache, reporter }) => { +exports.resolveGatsbyImageData = async ({ image, options, cache, reporter }) => { if (!isImage(image)) return null; const { generateImageData } = await import('gatsby-plugin-image'); - const { baseUrl, contentType, width, height } = getBasicImageProps(image, options); let [, format] = contentType.split('/'); diff --git a/src/utils.js b/src/utils.js index bded73b..5c18e7d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -46,6 +46,7 @@ exports.CODES = { SyncError: '10001', APIError: '10002', ImageAPIError: '10003', + MissingDependencyError: '10004', }; exports.getContentTypeOption = configOptions => { diff --git a/utils.js b/utils.js index 4fc1643..de3a6cd 100644 --- a/utils.js +++ b/utils.js @@ -47,7 +47,8 @@ exports.IMAGE_REGEXP = new RegExp('https://(stag-images|(eu-)?images).(blz-)?con exports.CODES = { SyncError: '10001', APIError: '10002', - ImageAPIError: '10003' + ImageAPIError: '10003', + MissingDependencyError: '10004' }; exports.getContentTypeOption = function (configOptions) {