@botonic/plugin-contentful
Version:
Botonic Plugin Contentful is one of the **[available](https://github.com/hubtype/botonic/tree/master/packages)** plugins for Botonic. **[Contentful](http://www.contentful.com)** is a CMS (Content Management System) which manages contents of a great variet
165 lines • 6.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.I18nEntryTraverser = exports.LoggerContentfulVisitor = exports.VisitedField = void 0;
const tslib_1 = require("tslib");
const button_1 = require("./contents/button");
class VisitedField {
constructor(entry, locale, field, value) {
this.entry = entry;
this.locale = locale;
this.field = field;
this.value = value;
}
}
exports.VisitedField = VisitedField;
class LoggerContentfulVisitor {
constructor(visitor) {
this.visitor = visitor;
}
name() {
return this.visitor.name();
}
visitEntry(entry) {
this.log('visitEntry', entry);
return this.visitor.visitEntry(entry);
}
visitStringField(field) {
this.log('visitStringField', field.entry, field.field);
return this.visitor.visitStringField(field);
}
visitMultipleStringField(field) {
this.log('visitMultipleStringField', field.entry, field.field);
return this.visitor.visitMultipleStringField(field);
}
visitOtherField(field) {
this.log('visitOtherField', field.entry, field.field);
return this.visitor.visitOtherField(field);
}
visitSingleReference(field) {
this.log('visitSingleReference', field.entry, field.field);
return this.visitor.visitSingleReference(field);
}
visitMultipleReference(field) {
this.log('visitMultipleReference', field.entry, field.field);
return this.visitor.visitMultipleReference(field);
}
log(method, entry, field) {
const on = field
? LoggerContentfulVisitor.describeField(entry, field.id)
: LoggerContentfulVisitor.describeEntry(entry);
console.log(`Visiting '${this.visitor.name()}.${method}' on ${on}`);
}
static describeEntry(entry) {
if (!entry.sys.contentType) {
return `entry with id ${entry.sys.id}`;
}
return `entry of type ${entry.sys.contentType.sys.id} (id:${entry.sys.id})`;
}
static describeField(entry, name) {
// cannot stringify field values because they may contain circular references
return `field '${name}' of ${LoggerContentfulVisitor.describeEntry(entry)}`;
}
}
exports.LoggerContentfulVisitor = LoggerContentfulVisitor;
/**
* Traverser a contentful Entry which has been requested for all locales.
* Limitations. It does not fetch entries from references which have not yet been delivered.
* ATTENTION Due to the complexity of traversing links with potential circular references, it stops recursion on button
* callbacks. This causes some entries to get wrong values.
*/
class I18nEntryTraverser {
constructor(api, visitor) {
this.api = api;
this.visitor = visitor;
this.visited = new Set();
}
traverse(entry, context) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
//in the future we might extending to traverse all locales
console.assert(context.locale);
console.assert(context.ignoreFallbackLocale);
const promise = this.traverseCore(entry, context);
this.visited.add(entry.sys.id);
return promise;
});
}
traverseCore(entry, context) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
entry = Object.assign(Object.assign({}, entry), { fields: Object.assign({}, entry.fields) });
const fields = entry.fields;
if (!entry.sys.contentType) {
// it's a file or a dangling reference
return entry;
}
const contentType = yield this.api.getContentType(entry.sys.contentType.sys.id);
for (const fieldId in fields) {
const field = contentType.fields.find(f => f.id == fieldId);
const i18nValue = Object.assign({}, fields[fieldId]);
const locale = field.localized
? context.locale
: Object.keys(i18nValue)[0];
const vf = new VisitedField(entry, locale, field, i18nValue);
fields[fieldId] = yield this.traverseField(context, vf);
}
entry = this.visitor.visitEntry(entry);
return entry;
});
}
traverseField(context, vf) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let val = vf.value[vf.locale];
const visitOrTraverse = (val) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this.visited.has(val.sys.id) && val.sys.id >= vf.entry.sys.id) {
// break deadlock if contents have cyclic dependencies
return val;
}
return this.traverse(val, context);
});
if (vf.field.type === 'Symbol' || vf.field.type === 'Text') {
return this.visitor.visitStringField(vf);
}
else if (vf.field.type == 'Link') {
if (val) {
val = this.stopRecursionOnButtonCallbacks(vf.field, val);
vf.value[vf.locale] = visitOrTraverse(val);
}
return this.visitor.visitSingleReference(vf);
}
else if (this.isArrayOfType(vf.field, 'Link')) {
if (val) {
val = yield Promise.all(val.map(v => visitOrTraverse(v)));
vf.value[vf.locale] = val;
}
return this.visitor.visitMultipleReference(vf);
}
else if (this.isArrayOfType(vf.field, 'Symbol')) {
return this.visitor.visitMultipleStringField(vf);
}
else {
return this.visitor.visitOtherField(vf);
}
});
}
isArrayOfType(field, itemType) {
var _a;
return field.type == 'Array' && ((_a = field.items) === null || _a === void 0 ? void 0 : _a.type) == itemType;
}
/**
* When a content has a button with another content reference, we just need the referred content id
* to create the content. Hence, we stop traversing.
*/
stopRecursionOnButtonCallbacks(field, val) {
var _a;
if (field.id !== 'target') {
return val;
}
if (!val.fields ||
val.fields.payload ||
((_a = val.sys.contentType) === null || _a === void 0 ? void 0 : _a.sys.id) == button_1.ButtonDelivery.BUTTON_CONTENT_TYPE) {
return val;
}
return Object.assign(Object.assign({}, val), { fields: {} });
}
}
exports.I18nEntryTraverser = I18nEntryTraverser;
//# sourceMappingURL=traverser.js.map