sitecoredxg-serialization
Version:
Node.js module for SitecoreDXG that provides serialization and deserialization functionalities to read and parse Rainbow (Unicorn) YAML files and to serialize and deserialize parsed data to/from circular JSON
248 lines (201 loc) • 10.1 kB
JavaScript
/*
* Copyright (c) 2018 Zachary Kniebel. All rights reserved.
*
* NOTICE: All information contained herein is, and remains the
* property of Zachary Kniebel. The intellectual and technical
* concepts contained herein are proprietary to Zachary Kniebel and
* may be covered by U.S. and Foreign Patents, patents in process,
* and are protected by trade secret or copyright law. Dissemination
* of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Zachary
* Kniebel (contact@zacharykniebel.com).
*
*/
/**
* DEPENDENCIES
*/
// node
const fs = require("fs");
const path = require("path");
// third-party
const glob = require("glob");
const yaml = require("js-yaml");
// local
const sitecore_constants = require("../constants/sitecore.js");
const { Template, TemplateSection, TemplateField, TemplateFolder, StandardValues, Database } = require("../types/sitecore.js");
/**
* FUNCTIONS
*/
/**
* @summary parses a Sitecore item tree object from the given list of Sitecore object data
* @param {Array<object>} unicornObjects array of objects from Unicorn
*/
var _parseSitecoreItemTree = function(unicornObjects) {
var sitecoreTree = {};
var sitecoreItems = [];
var getSharedUnicornFieldValue = function(unicornObj, fieldID) {
var sharedFields = unicornObj.SharedFields;
if (!sharedFields || !sharedFields.length) {
return undefined;
}
var field = sharedFields.find(function(field) { return field.ID == fieldID; });
return field ? field.Value : undefined;
};
unicornObjects.forEach(function (obj, idx, arr) {
var item;
// get the parent (if exists)
var parent = sitecoreItems[obj.Parent];
if (obj.Template == sitecore_constants.TEMPLATE_FOLDER_TEMPLATE_ID || obj.Template == sitecore_constants.FOLDER_TEMPLATE_ID) {
item = new TemplateFolder(obj.ID, obj.Template, parent, obj.Path);
if (!parent) { // if root folder add to tree
sitecoreTree[item.ID] = item;
sitecoreItems[item.ID] = item;
} else if (parent instanceof TemplateFolder) {
parent.Children.push(item);
sitecoreItems[item.ID] = item;
} else {
throw `TemplateFolder parent must be a TemplateFolder unless the folder is at the root or layer root - item: ${item.ID} - "${item.Path}"`
}
} else if (obj.Template == sitecore_constants.TEMPLATE_TEMPLATE_ID) {
var baseTemplates = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_BASE_TEMPLATE_FIELD_ID)
.split("\n");
item = new Template(obj.ID, obj.Template, parent, obj.Path, baseTemplates);
if (!parent) {
sitecoreTree[item.ID] = item;
sitecoreItems[item.ID] = item;
} else if (parent instanceof TemplateFolder) {
parent.Children.push(item);
sitecoreItems[item.ID] = item;
} else {
throw `Template parent must be a Template folder unless the template is at the root or layer root - item: ${item.ID} - "${item.Path}"`;
}
} else if (obj.Template == sitecore_constants.TEMPLATE_SECTION_TEMPLATE_ID) {
item = new TemplateSection(obj.ID, obj.Template, parent, obj.Path);
if (!parent) { // usually means template section was added to native Sitecore template
sitecoreTree[item.ID] = item;
sitecoreItems[item.ID] = item;
} else if (!(parent instanceof Template)) {
throw `TemplateSection parent must be a Template - item: ${item.ID} - "${item.Path}"`;
} else {
parent.TemplateSections.push(item);
sitecoreItems[item.ID] = item;
}
} else if (obj.Template == sitecore_constants.TEMPLATE_FIELD_TEMPLATE_ID) {
var fieldType = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_FIELD_TYPE_FIELD_ID);
if (!fieldType) {
throw `Field type is a required field - field: ${obj.ID} - "${obj.Hint}"`;
}
var sortOrderField = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_FIELD_SORTORDER_FIELD_ID);
var sourceField = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_FIELD_SOURCE_FIELD_ID);
var sharedField = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_FIELD_SHARED_FIELD_ID);
var unversionedField = getSharedUnicornFieldValue(obj, sitecore_constants.TEMPLATE_FIELD_UNVERSIONED_FIELD_ID);
item = new TemplateField(obj.ID, obj.Template, parent, obj.Path, fieldType, sortOrderField, sourceField, sharedField, unversionedField);
obj.Languages.forEach(function(language) {
// title field is unversioned so lives in language.Fields and not language.Versions
var titleField = language.Fields
? language.Fields
.find(function(field) { return field.ID == sitecore_constants.TEMPLATE_FIELD_TITLE_FIELD_ID})
: undefined;
if (!titleField || !titleField.Value) {
return;
}
item.addTitle(titleField.Value, language.Language);
});
if (!parent) { // usually means field was added to a native Sitecore template section
sitecoreTree[item.ID] = item;
sitecoreItems[item.ID] = item;
} else if (!(parent instanceof TemplateSection)) {
throw `TemplateField parent must be a TemplateSection - field: ${obj.ID} - "${obj.Path}"`;
} else {
parent.TemplateFields.push(item);
sitecoreItems[item.ID] = item;
}
} else if (parent && obj.Template == parent.ID) { // standard values
item = new StandardValues(obj.ID, obj.Template, parent, obj.Path);
// set shared fields
if (obj.SharedFields) {
obj.SharedFields.forEach(function(field) {
item.setFieldValue(field.ID, field.Value);
});
}
if (obj.Languages) {
obj.Languages.forEach(function(language) {
// set unversioned fields
if (language.Fields) {
language.Fields.forEach(function(field) {
if (!field.Value) {
return;
}
item.setFieldValue(field.ID, field.Value, language.Language);
});
}
// set versioned fields
if (language.Versions) {
language.Versions.forEach(function(version) {
version.Fields.forEach(function(field) {
item.setFieldValue(field.ID, field.Value, language.Language, version.Version);
});
});
}
});
}
parent.StandardValues = item;
sitecoreItems[item.ID] = item;
} else {
// TODO: for production version, this cannot throw, as it is conceivable that a __Standard Values item may have been added to a native Sitecore template
throw `Item template was not of a recognized type - item: ${obj.ID} - "${obj.Path}"`;
}
});
};
/**
* @summary reads and parses the Unicorn data found using the given glob into an array of @see Database objects
* @param {string} unicornSourcesGlob the glob used to retrieve the Unicorn source files
* @returns {Array<Database>} array of parsed @see Database objects
*/
var readAndParseDatabases = function(unicornSourcesGlob) {
var unicornObjects = [];
// get and sort the paths alphabetically, then load and parse the yaml in each
glob.sync(unicornSourcesGlob).forEach(function (file) {
var fileName = path.resolve(file);
var obj = yaml.safeLoad(fs.readFileSync(fileName), { filename: fileName });
obj.SourceFilePath = fileName;
unicornObjects.push(obj);
});
unicornObjects = unicornObjects
.filter(function (obj) {
return obj.Path.startsWith(sitecore_constants.TEMPLATES_ROOT_PATH)
&& !obj.Path.startsWith(sitecore_constants.TEMPLATES_BRANCHES_ROOT_PATH);
})
// sort by path to ensure that parent items are always processed before children
.sort(function(obj1, obj2) {
var path1 = obj1.Path.toLowerCase();
var path2 = obj2.Path.toLowerCase();
if (path1 > path2) {
return 1;
}
if (path1 < path2) {
return -1;
}
return 0;
});
var itemsByDatabase = {};
unicornObjects.forEach(function(obj) {
if (itemsByDatabase[obj.DB]) {
itemsByDatabase[obj.DB].push(obj);
} else {
itemsByDatabase[obj.DB] = [ obj ];
}
});
var databaseNames = Object.keys(itemsByDatabase);
var databases = databaseNames.map(function(databaseName) {
var items = itemsByDatabase[databaseName];
var itemTree = _parseSitecoreItemTree(items);
return new Database(databaseName, itemTree);
});
return databases;
};
/**
* EXPORTS
*/
exports.readAndParseDatabases = readAndParseDatabases;