@sysdoc/sharepoint-util
Version:
A utility library for SharePoint solutions
546 lines (545 loc) • 26.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const nunjucks = require("nunjucks");
const path = require("path");
const fs = require("fs");
const filters_1 = require("../util/filters");
const builtin_1 = require("../sharepoint/builtin");
const xmlformatter_1 = require("../xml/xmlformatter");
const filters_2 = require("../sharepoint/filters");
const util_1 = require("../io/util");
const logger_1 = require("../util/logger");
const util_2 = require("util");
const _ = require("lodash");
const INTERFACES_DIR = 'interfaces';
const SRC_DIR = 'src';
const OUTPUT_DIR = 'deploy';
const TEMPLATES_DIR = 'templates';
function createTransformer(config) {
var ctypes = {};
var fields = {};
var errors = [];
var cfg = {
outputDir: path.resolve(process.cwd(), OUTPUT_DIR),
templatesPaths: config.templatesPaths || [],
srcDir: config.srcDir || (config.rootDir && path.resolve(config.rootDir, SRC_DIR))
};
var env = nunjucks.configure([path.resolve(__dirname, path.join('..', '..', TEMPLATES_DIR)), ...(cfg.templatesPaths || [])], {
trimBlocks: true
});
async function setConfig({ outputDir, rootDir, srcDir, interfacesDir, templatesPaths, consumeContentType }) {
var cwd = process.cwd();
var rootdir = rootDir || cwd;
await util_1.createDirectoryIfNotExist(rootdir, 'Creating Root Directory');
cfg.outputDir = outputDir || path.resolve(rootdir, 'deploy');
await util_1.createDirectoryIfNotExist(cfg.outputDir, 'Creating Output Directory');
cfg.srcDir = srcDir || path.resolve(rootDir || cwd, SRC_DIR);
await util_1.createDirectoryIfNotExist(cfg.srcDir, 'Creating Source Directory');
cfg.interfacesDir = interfacesDir || path.resolve(rootDir || cwd, path.join(SRC_DIR, INTERFACES_DIR));
await util_1.createDirectoryIfNotExist(cfg.interfacesDir, 'Creating Interfaces Directory');
cfg.templatesPaths = templatesPaths;
env = nunjucks.configure([...(cfg.templatesPaths || []), path.resolve(__dirname, path.join('..', '..', TEMPLATES_DIR))], {
trimBlocks: true
});
env.addGlobal('hasAttr', filters_1.hasAttr);
env.addGlobal('getAttr', filters_1.getAttr);
env.addGlobal('getFieldId', filters_2.getFieldId);
env.addGlobal('getContentTypeId', getContentTypeId);
env.addGlobal('getFieldIdByName', getFieldIdByName);
env.addGlobal('getContentTypeIdByName', getContentTypeIdByName);
env.addFilter('removeSpaces', filters_1.removeSpaces);
env.addFilter('parenthesize', filters_1.parenthesize);
env.addFilter('capitalize', filters_1.capitalize);
env.addFilter('lowerize', filters_1.lowerize);
env.addGlobal('hasContentBindings', hasContentBindings);
env.addGlobal('isTaxonomyField', filters_2.isTaxonomyField);
env.addGlobal('generateTaxonomyFieldId', filters_2.generateTaxonomyFieldId);
env.addGlobal('getFieldType', filters_2.getFieldType);
env.addGlobal('getFilePath', getFilePath);
env.addGlobal('getConfig', getConfig);
env.addGlobal('booleanToUpper', filters_2.booleanToUpper);
env.addGlobal('getJsTypeForField', filters_2.getJsTypeForField);
env.addGlobal('log', logger_1.log);
env.addGlobal('isString', filters_1.isString);
env.addGlobal('isObject', util_2.isObject);
env.addGlobal('hasItems', filters_1.hasItems);
env.addGlobal('hasKeys', filters_1.hasKeys);
env.addGlobal('validateContentType', filters_2.validateContentType);
env.addGlobal('addError', addError);
env.addGlobal('getPowershellValue', filters_1.getPowershellValue);
if (consumeContentType) {
env.addGlobal('writeContentType', function (name, id) {
consumeContentType(name, id);
});
}
}
function clearErrors() {
errors = [];
}
function addError(error) {
errors.push(error);
}
function getContentTypeId(contentType) {
if (builtin_1.BuiltInContentType[contentType.parent]) {
return builtin_1.BuiltInContentType[contentType.parent] + '00' + filters_1.getAttr(contentType, 'id').replace(/-/g, '');
}
return getContentTypeId(ctypes[contentType.parent]).replace(/-/g, '') + '00' + filters_1.getAttr(contentType, 'id').replace(/-/g, '');
}
function getContentTypeIdByName(cName) {
return (ctypes[cName] && getContentTypeId(ctypes[cName])) || 'Error not valid ' + cName;
}
function getFieldIdByName(name) {
if (fields[name]) {
return `${filters_1.getAttr(fields[name], 'id')}`;
}
else if (builtin_1.BuiltInFields[name]) {
return builtin_1.BuiltInFields[name];
}
errors.push(`ERROR no field with name ${name}`);
return `ERROR no field with name ${name}`;
}
function hasContentBindings(list) {
if (list.contentTypes) {
var f = list.contentTypes.filter(function (e) {
return e !== "Item";
});
return f.length > 0;
}
return list.contentTypeIds && list.contentTypeIds.length > 0;
}
function addFileds(fis) {
fis.forEach((field) => {
fields[filters_1.getAttr(field, 'name')] = field;
});
}
function addContentTypes(cts) {
cts.forEach((ct) => {
ctypes[filters_1.getAttr(ct, 'name')] = ct;
});
}
async function transform({ spHost, url }, site) {
await setConfig(config);
errors = [];
ctypes = {};
fields = {};
if (!spHost) {
logger_1.logError('Transform', 'spHost parameter is missing');
throw new Error('No spHost provided');
}
addFileds(site.fields);
addContentTypes(site.contentTypes);
if (filters_1.hasAttr(site, 'files')) {
let files = filters_1.getAttr(site, 'files');
files.forEach((file) => {
if (file.isPageLayout) {
}
});
}
if (filters_1.getAttr(site, 'subsites')) {
let subsites = filters_1.getAttr(site, 'subsites');
subsites.forEach((subsite, i) => {
if (filters_1.hasAttr(subsite, 'fields')) {
addFileds(filters_1.getAttr(subsite, 'fields'));
}
if (filters_1.hasAttr(subsite, 'contentTypes')) {
addContentTypes(filters_1.getAttr(subsite, 'contentTypes'));
}
});
}
var postfix = filters_1.getAttr(site, 'version') || '1';
logger_1.log('Provisioning', `Creating site collection provisioning template ${site.url}`);
fs.writeFileSync(path.resolve(cfg.outputDir, `./sitecollection-${site.id}-${postfix}.xml`), formatter.format(env.render('ProvisioningTemplate.xml', {
template: site
})));
logger_1.log('Base Interfaces', 'Creating base interfaces');
createBaseInterfaces(site);
logger_1.log('List Schemas', 'Creating site collection list schemas');
createListSchemas(site);
if (site.subsites) {
site.subsites.forEach((site) => {
logger_1.log('Provisioning', `Creating subsite provisioning template ${site.url}`);
fs.writeFileSync(path.resolve(cfg.outputDir, `./site-${site.id}-${postfix}.xml`), formatter.format(env.render('ProvisioningTemplate.xml', {
template: site
})));
if (site.lists && site.lists.length > 0) {
logger_1.log('List Schemas', `Creating subsite list schemas ${site.url}`);
createListSchemas(site);
}
});
}
site.spHost = site.spHost || spHost;
if (!site.spHost.endsWith('/')) {
site.spHost += '/';
}
site.url = site.url || url;
site.siteCollectionUrl = url;
logger_1.log('Provisioning', `Creating functions.ps1`);
fs.writeFileSync(path.resolve(cfg.outputDir, `./functions.ps1`), env.render('Functions.ps1.njk', {
template: site,
postfix,
spHost: site.spHost,
url: site.url,
libDir: cfg.outputDir
}));
logger_1.log('Provisioning', `Creating deploy.ps1`);
fs.writeFileSync(path.resolve(cfg.outputDir, `./deploy-${postfix}.ps1`), env.render('Deployment.ps1.njk', {
template: site,
postfix,
spHost: site.spHost,
url: site.url,
}));
}
function getConfig(key) {
return cfg[key];
}
function getFilePath(fileName) {
return ".\\" + fileName;
}
var formatter = new xmlformatter_1.XmlFormatter({
preferSpaces: true,
});
function getBuiltInContentTypeFields(contentTypeName, childFields = []) {
return [].concat([
{
name: "Title",
type: "Text"
}
], childFields);
}
function getFieldsForContentType(contentType, childFields = []) {
if (!contentType) {
logger_1.logError('Get Fields For Content Type', `Undefined content type provided`);
errors.push(`Undefined content type provided`);
throw new Error(`Content type cannot be undefined`);
}
var ff = [].concat(childFields, contentType.fields.map((e) => {
if (!fields[e]) {
errors.push('Get Fields For Content Type' + `: Field ${e} does not exist`);
logger_1.logError('Get Fields For Content Type', `Field ${e} does not exist`);
throw new Error(`Field ${e} does not exist`);
}
return fields[e];
}));
if (ctypes[contentType.parent]) {
return getFieldsForContentType(ctypes[contentType.parent], ff);
}
else if (builtin_1.BuiltInContentType[contentType.parent]) {
return getBuiltInContentTypeFields(contentType.parent, ff);
}
else {
logger_1.log('Error', `Couldn't fint parent content type ${contentType.parent} for contentType ${contentType.name}`);
return ff;
}
}
function createBaseInterfaces(site) {
var fileName = `${cfg.interfacesDir}/CommonType.ts`;
logger_1.log('Creating Base Interfaces', `Creating CommonType.ts at ${fileName}`);
fs.writeFileSync(fileName, nunjucks.render('CommonType.ts.njk', {}));
fileName = `${cfg.interfacesDir}/User.ts`;
logger_1.log('Creating Base Interfaces', `Creating User.ts at ${fileName}`);
fs.writeFileSync(fileName, nunjucks.render('User.ts.njk', {}));
fileName = `${cfg.interfacesDir}/ListItemAttachment.ts`;
logger_1.log('Creating Base Interfaces', `Creating ListItemAttachment.ts at ${fileName}`);
fs.writeFileSync(fileName, nunjucks.render('ListItemAttachment.ts.njk', {}));
}
function createListSchemas(site) {
site.lists.forEach((e) => {
var fileName = `${cfg.outputDir}/${site.id}-${e.title}.ts`;
let tx = {};
var fields = null;
var contentTypeName = !e.contentTypes || e.contentTypes.length === 0 ? "Item" : e.contentTypes[0];
if (contentTypeName !== "Item" && !ctypes[contentTypeName]) {
logger_1.logError('Content type not found', `Content type ${contentTypeName} does not exist`);
throw new Error(`Could not find definition for content type ${contentTypeName}.`);
}
fields = !e.contentTypes || e.contentTypes.length === 0 ? getBuiltInContentTypeFields("Item") : getFieldsForContentType(ctypes[contentTypeName]);
fields.forEach((e) => {
tx[e.name] = e.type;
});
logger_1.log('List Schemas', `Creating list schema for list ${e.title}`);
fs.writeFileSync(fileName, nunjucks.render('ListSchema.ts.njk', {
listTitle: (e.title),
schema: JSON.stringify(tx, null, ' ')
}));
if (e['interface']) {
logger_1.log('List Schemas', `Creating interface for list ${e.title}`);
var interfaceFileName = `${cfg.interfacesDir}/${e['interface']}.ts`;
fs.writeFileSync(interfaceFileName, nunjucks.render('ListInterface.ts.njk', {
fields,
list: e
}));
}
});
}
function validate(site) {
return _validate(site, {
lists: {},
contentTypes: {},
fields: {},
termGroups: {},
termSets: {},
errors: [],
cleanActions: [],
});
}
function _validate(site, cleanConfig) {
(site.fields || []).forEach((f) => {
cleanConfig.fields[f.name] = f;
});
(site.contentTypes || []).forEach((f) => {
cleanConfig.contentTypes[f.name] = f;
});
(site.lists || []).forEach((f) => {
cleanConfig.lists[f.title] = f;
});
(site.termGroups || []).forEach((f) => {
cleanConfig.termGroups[f.name] = f;
});
// @ts-ignore
const termSets = _(site.termGroups || []).map((e) => e.termSets).flatten().value();
termSets.forEach((f) => {
cleanConfig.termSets[f.name] = f;
});
if (site.navigation) {
if (site.navigation.global) {
if (site.navigation.global.navType && site.navigation.global.navType.toLowerCase() === 'managed') {
const tset = termSets.find((e) => {
return e.id === site.navigation.global.termSetId;
});
if (!tset) {
logger_1.logError('Validation', `Site global navigation is using a term set that does not exist ${site.navigation.global.termSetId}`);
cleanConfig.errors.push(`Site global navigation is using a term set that does not exist ${site.navigation.global.termSetId}`);
}
}
}
if (site.navigation.current) {
if (site.navigation.current.navType && site.navigation.current.navType.toLowerCase() === 'managed') {
const tset = termSets.find((e) => {
return e.id === site.navigation.current.termSetId;
});
if (!tset) {
logger_1.logError('Validation', `Site current navigation is using a term set that does not exist ${site.navigation.current.termSetId}`);
cleanConfig.errors.push(`Site current navigation is using a term set that does not exist ${site.navigation.current.termSetId}`);
}
}
}
}
if (filters_1.hasAttr(site, 'files')) {
let files = filters_1.getAttr(site, 'files');
files.forEach((file) => {
if (file.isPageLayout) {
}
});
}
(site.fields || []).forEach((field) => {
if (field.type && (field.type.toLowerCase().indexOf('lookup') !== -1)) {
if (field.listTitle) {
if (!cleanConfig.lists[field.listTitle]) {
cleanConfig.cleanActions.push({
name: `Delete this field ${field.name}`,
value: `delete.${site.url}.${field.id}`,
fn: () => {
site.fields = site.fields.filter((e) => {
return e.name !== field.name;
});
}
});
logger_1.logError('Validation', `Lookup field ${field.name} uses a list that does not exist ${field.listTitle}`);
errors.push(`Lookup field ${field.name} uses a list that does not exist ${field.listTitle}`);
}
}
else {
cleanConfig.cleanActions.push({
name: `Delete this field ${field.name}`,
value: `delete.${site.url}.${field.name}`,
fn: () => {
site.fields = site.fields.filter((e) => {
return e.name !== field.name;
});
}
});
logger_1.logError('Validation', `Lookup field ${field.name} missing 'listTitle' field. Please specify a lookup list`);
errors.push(`Lookup field ${field.name} missing 'listTitle' field. Please specify a lookup list`);
}
}
else if (field.type && (field.type.toLowerCase().indexOf('taxonomy') !== -1)) {
if (field.termGroupName) {
if (!cleanConfig.termGroups[field.termGroupName]) {
cleanConfig.cleanActions.push({
name: `Create term set ${field.termSetName} in ${field.termGroupName}`,
fn: () => {
var termGroup = {
name: field.termGroupName,
termSets: []
};
if (field.termSetName) {
termGroup.termSets.push({
id: filters_2.generateGuid(),
name: field.termSetName
});
}
site.termGroups.push({
name: field.termGroupName,
});
},
value: `createTermGroup.${site.url}.${field.id}`,
});
logger_1.logError('Validation', `Taxonomy field ${field.name} refers to a group name that does not exist ${field.termGroupName}`);
errors.push(`Taxonomy field ${field.name} refers to a group name that does not exist ${field.termGroupName}`);
}
else {
var termGroup = cleanConfig.termGroups[field.termGroupName];
if (termGroup.termSets && termGroup.termSets.length) {
var tset = termGroup.termSets.find((e) => {
return e.name === field.termSetName;
});
cleanConfig.cleanActions.push({
name: `Remove field ${field.name}`,
fn: () => {
site.fields = site.fields.filter((e) => {
return e.name !== field.name;
});
},
value: `delete.${site.url}.${field.id}`,
});
if (!tset) {
cleanConfig.cleanActions.push({
name: `Create term set ${field.termSetName} in ${field.termGroupName}`,
fn: () => {
termGroup.termSets.push({
name: field.termSetName,
id: filters_2.generateGuid(),
});
},
value: `createTermSet.${site.url}.${field.id}`,
});
logger_1.logError('Validation', `Taxonomy field ${field.name} refers to a term set that does not exist in term gorup ${field.termGroupname}`);
cleanConfig.errors.push(`Taxonomy field ${field.name} refers to a term set that does not exist in term gorup ${field.termGroupname}`);
}
}
else {
cleanConfig.cleanActions.push({
name: `Create term set ${field.termSetName} in ${field.termGroupName}`,
fn: () => {
termGroup.termSets.push({
name: field.termSetName,
id: filters_2.generateGuid(),
});
},
value: `createTermSet.${site.url}.${field.name}`,
});
logger_1.logError('Validation', `Taxonomy field ${field.name} refers to a term set ${field.termSetName} in a term group ${field.termGroupName} that has no term sets`);
}
}
}
else {
logger_1.logError('Validation', `Taxonomy field ${field.name} is missing a 'termGroupName' attribute.`);
}
if (!field.termSetName) {
logger_1.logError('Validation', `Taxonomy field ${field.name} is missing a 'termSetName' attribute.`);
}
}
});
(site.contentTypes || []).forEach((contentType) => {
(contentType.fields || []).forEach((f) => {
if (!cleanConfig.fields[f]) {
cleanConfig.cleanActions.push({
name: `Remove field ${f} from content type ${contentType.name}`,
value: `remove.field.${f}.contentType.${site.url}.${contentType.id}`,
fn: () => {
contentType.fields = contentType.fields.filter((e) => {
return e !== f;
});
}
});
cleanConfig.cleanActions.push({
name: `Create field ${f} for content type ${contentType.name}`,
value: `create.field.${f}.contentType.${site.url}.${contentType.id}`,
fn: () => {
return {
action: 'addField',
param: {
name: f
}
};
}
});
logger_1.logError('Validation', `Content type ${contentType.name} contains field that does not exist ${f}`);
errors.push(`Content type ${contentType.name} contains field that does not exist ${f}`);
}
});
if (contentType.parent) {
if (!cleanConfig.contentTypes[contentType.parent] && !builtin_1.BuiltInContentType[contentType.parent]) {
cleanConfig.cleanActions.push({
name: `Create content type ${contentType.parent}`,
value: `field.${contentType.name}.${contentType.parent}`,
fn: (generator) => {
return {
action: 'addContentType',
param: {
name: contentType.parent
}
};
}
});
logger_1.logError('Validation', `Parent content type ${contentType.parent} for content type ${contentType.name} does not exist`);
errors.push(`Parent content type ${contentType.parent} for content type ${contentType.name} does not exist`);
}
}
});
(site.lists || []).forEach((e) => {
(e.contentTypes || []).forEach((ct) => {
if (!cleanConfig.contentTypes[ct] && !builtin_1.BuiltInContentType[ct]) {
cleanConfig.cleanActions.push({
name: `Remove content type ${ct} from list ${e.title}`,
value: `contentType.${site.url}.remove.${e.title}.${ct}`,
fn: (generator) => {
e.contentTypes = e.contentTypes.filter(e => e !== ct);
}
});
cleanConfig.cleanActions.push({
name: `Create content type ${ct}`,
value: `contentType.${site.url}.create.${ct}`,
fn: (generator) => {
return {
action: 'addContentType',
param: {
name: ct
}
};
}
});
logger_1.logError('Validation', `List ${e.title} contains a content types that does not exist ${ct}`);
errors.push(`List ${e.title} contains a content types that does not exist ${ct}`);
}
});
});
if (filters_1.getAttr(site, 'subsites')) {
let subsites = filters_1.getAttr(site, 'subsites');
subsites.forEach((subsite, i) => {
return _validate(subsite, cleanConfig);
});
}
return cleanConfig;
}
// function clean(site){
// return _clean(site,{
// contentTypes:{},
// fields:{},
// lists:{},
// termSets:{},
// termGroups:{},
// errors:[]
// });
// }
return {
setConfig,
transform,
validate,
// clean,
get errors() {
return errors;
}
};
}
exports.createTransformer = createTransformer;