contentful-migration
Version:
Migration tooling for contentful
180 lines • 7.27 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = __importStar(require("lodash"));
const bluebird_1 = __importDefault(require("bluebird"));
class Fetcher {
constructor(makeRequest, requestBatchSize = 100) {
this.makeRequest = makeRequest;
this.requestBatchSize = requestBatchSize;
}
async getEntriesInIntents(intentList) {
const loadAllEntries = intentList.getIntents().some((intent) => intent.requiresAllEntries());
const ids = _.uniq(intentList
.getIntents()
.filter((intent) => intent.isContentTransform() ||
intent.isEntryDerive() ||
intent.isEntryTransformToType() ||
intent.isEntrySetTags())
.map((intent) => intent.getContentTypeId()));
if (!loadAllEntries && ids.length === 0) {
return [];
}
const filter = {
'sys.archivedAt[exists]': 'false'
};
// If we want to load all entries, we do not need to add the filter specification
// that loads just the entries for related content types
// If we do, then we specify the list of CTs that we want entries for
if (!loadAllEntries) {
filter['sys.contentType.sys.id[in]'] = ids.join(',');
}
const entries = await this.fetchAllPaginatedItems('/entries', filter);
return entries;
}
async getContentTypesInChunks(intentList) {
// Excluding editor interface intents here since, API-wise, editor interfaces don't require
// to know the full details about the associated content type.
// Editor interface intents that require the content type can implement IntentInterface.requiresContentType.
// Also excluding tags here as they are independent of cts.
const ids = _.uniq(intentList
.getIntents()
.filter((intent) => (!intent.isEditorInterfaceIntent() || intent.requiresContentType()) &&
!intent.isTagIntent())
.reduce((ids, intent) => {
const intentIds = intent.getRelatedContentTypeIds();
return ids.concat(intentIds);
}, []));
if (ids.length === 0) {
return [];
}
const filter = {
'sys.id[in]': ids.join(',')
};
const contentTypes = await this.fetchAllPaginatedItems('/content_types', filter);
return contentTypes;
}
async getEditorInterfacesInIntents(intentList) {
const contentTypeIds = _.uniq(intentList
.getIntents()
.filter((intent) => intent.isFieldRename() || intent.isEditorInterfaceIntent())
.reduce((ids, intent) => {
const intentIds = intent.getRelatedContentTypeIds();
return ids.concat(intentIds);
}, []));
let editorInterfaces = new Map();
if (contentTypeIds.length === 0) {
return editorInterfaces;
}
for (let id of contentTypeIds) {
await this.fetchEditorInterface(id, editorInterfaces);
}
return editorInterfaces;
}
async getLocalesForSpace() {
const locales = await this.fetchAllPaginatedItems('/locales');
return locales.map((i) => i.code);
}
async checkContentTypesForDeletedCts(intentList, contentTypes) {
const deletedCtIds = new Set(intentList
.getIntents()
.filter((intent) => intent.isContentTypeDelete())
.map((intent) => intent.getContentTypeId()));
if (deletedCtIds.size === 0) {
return contentTypes;
}
const self = this;
return bluebird_1.default.map(contentTypes, async function (ct) {
if (deletedCtIds.has(ct.id)) {
const response = await self.makeRequest({
method: 'GET',
url: `/entries?sys.contentType.sys.id=${ct.id}`
});
if (response.items.length > 0) {
ct.hasEntries = true;
}
}
return ct;
});
}
async getTagsForEnvironment(intentList) {
// Don't fetch tags if migration does not use any.
if (!intentList.getIntents().some((intent) => intent.requiresAllTags())) {
return [];
}
const tags = await this.fetchAllPaginatedItems('/tags');
return tags;
}
async fetchEditorInterface(id, editorInterfaces) {
try {
const response = await this.makeRequest({
method: 'GET',
url: `/content_types/${id}/editor_interface`
});
editorInterfaces.set(id, response);
}
catch (error) {
if (error.name === 'NotFound') {
// TODO: expose status codes and use that instead.
// Initialize a default structure for newly created content types.
editorInterfaces.set(id, {
sys: {
version: 0
},
controls: []
});
}
else {
throw error;
}
}
}
async fetchAllPaginatedItems(url, params = {}) {
let entities = [];
let skip = 0;
while (true) {
const paramsWithSkip = Object.assign(Object.assign({ limit: this.requestBatchSize, order: 'sys.createdAt' }, params), { skip: skip.toString(10) });
let urlParams = '';
for (const [key, value] of Object.entries(paramsWithSkip)) {
urlParams = `${urlParams}&${key}=${value}`;
}
const response = await this.makeRequest({
method: 'GET',
url: `${url}?${urlParams.substr(1)}`
});
entities = entities.concat(response.items);
skip += response.items.length;
if (skip >= response.total) {
break;
}
}
return entities;
}
}
exports.default = Fetcher;
//# sourceMappingURL=fetcher.js.map